This is an automated email from the ASF dual-hosted git repository. panyuepeng pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/flink.git
commit 096f031b9502337979c06f067c1289fe03173aaf Author: och5351 <[email protected]> AuthorDate: Wed Apr 15 19:35:12 2026 +0900 [FLINK-38898][runtime-web] Refactor Rescale Details related parts into templates for reusing in Rescales/Overview and Rescales/History Co-authored-by: Yuepeng Pan <[email protected]> Co-authored-by: Matthias Pohl <[email protected]> --- .../pages/job/rescales/job-rescales.component.html | 515 +++++---------------- .../pages/job/rescales/job-rescales.component.less | 42 -- 2 files changed, 103 insertions(+), 454 deletions(-) diff --git a/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.html b/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.html index 1b4342fac02..5bc5c64f5de 100644 --- a/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.html +++ b/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.html @@ -24,9 +24,9 @@ (nzSelectedIndexChange)="refresh()" > <nz-tab nzTitle="Overview"> - <!-- Reusable template for rescale details --> - <ng-template #rescaleDetailsTemplate let-rescale="rescale"> - <div class="overview-rescale-section"> + <!-- Reusable template for rescale details - unified version with containerClass parameter --> + <ng-template #rescaleDetailsTemplate let-rescale="rescale" let-containerClass="containerClass"> + <div [class]="containerClass || 'rescale-details-box'"> <h3><strong>Rescale Details</strong></h3> <div> <span> @@ -251,185 +251,114 @@ </div> </ng-template> - <ng-container *ngIf="rescalesOverview"> - <div class="rescale-header rescale-counts-header"> - <h3><strong>Rescale Counts</strong></h3> - <span class="rescale-time-info"> + <!-- Reusable template for latest rescale section (like checkpoint component) --> + <ng-template #latestRescaleTemplate let-title="title" let-rescale="rescale"> + <tr> + <td> + <strong>{{ title }}</strong> + </td> + <td *ngIf="rescale"> <span> - <strong>Total:</strong> - {{ getTotalRescaleCount() }} + <strong>Start Time:</strong> + {{ rescale.startTimestampInMillis | date: 'yyyy-MM-dd HH:mm:ss.SSS' }} </span> <nz-divider nzType="vertical"></nz-divider> <span> - <strong>In Progress:</strong> - {{ rescalesOverview.rescalesCounts.inProgress }} + <strong>End Time:</strong> + {{ + rescale.endTimestampInMillis + ? (rescale.endTimestampInMillis | date: 'yyyy-MM-dd HH:mm:ss.SSS') + : '-' + }} </span> <nz-divider nzType="vertical"></nz-divider> <span> - <strong>Completed:</strong> - {{ rescalesOverview.rescalesCounts.completed }} + <strong>Duration:</strong> + {{ + (rescale.endTimestampInMillis || Date.now()) - rescale.startTimestampInMillis + | humanizeDuration + }} </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Failed:</strong> - {{ rescalesOverview.rescalesCounts.failed }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Ignored:</strong> - {{ rescalesOverview.rescalesCounts.ignored }} - </span> - </span> - </div> - <nz-divider></nz-divider> - - <ng-container *ngIf="rescalesOverview.latest.completed"> - <div class="rescale-header"> - <h3><strong>Latest Completed Rescale</strong></h3> - <span class="rescale-time-info"> - <span> - <strong>Start Time:</strong> - {{ - rescalesOverview.latest.completed.startTimestampInMillis - | date: 'yyyy-MM-dd HH:mm:ss.SSS' - }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>End Time:</strong> - {{ - rescalesOverview.latest.completed.endTimestampInMillis - ? (rescalesOverview.latest.completed.endTimestampInMillis - | date: 'yyyy-MM-dd HH:mm:ss.SSS') - : '-' - }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Duration:</strong> - {{ - (rescalesOverview.latest.completed.endTimestampInMillis || Date.now()) - - rescalesOverview.latest.completed.startTimestampInMillis | humanizeDuration - }} - </span> - </span> - </div> - <nz-divider></nz-divider> - <ng-container - *ngTemplateOutlet=" - rescaleDetailsTemplate; - context: { rescale: rescalesOverview.latest.completed } - " - ></ng-container> - </ng-container> - <ng-container *ngIf="!rescalesOverview.latest.completed"> - <div class="rescale-header"> - <h3><strong>Latest Completed Rescale</strong></h3> - <span class="rescale-time-info">None</span> - </div> - <nz-divider></nz-divider> - </ng-container> - - <ng-container *ngIf="rescalesOverview.latest.ignored"> - <div class="rescale-header"> - <h3><strong>Latest Ignored Rescale</strong></h3> - <span class="rescale-time-info"> - <span> - <strong>Start Time:</strong> - {{ - rescalesOverview.latest.ignored.startTimestampInMillis - | date: 'yyyy-MM-dd HH:mm:ss.SSS' - }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>End Time:</strong> - {{ - rescalesOverview.latest.ignored.endTimestampInMillis - ? (rescalesOverview.latest.ignored.endTimestampInMillis - | date: 'yyyy-MM-dd HH:mm:ss.SSS') - : '-' - }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Duration:</strong> - {{ - (rescalesOverview.latest.ignored.endTimestampInMillis || Date.now()) - - rescalesOverview.latest.ignored.startTimestampInMillis | humanizeDuration - }} - </span> - </span> - </div> - <nz-divider></nz-divider> - <ng-container - *ngTemplateOutlet=" - rescaleDetailsTemplate; - context: { rescale: rescalesOverview.latest.ignored } - " - ></ng-container> - </ng-container> - <ng-container *ngIf="!rescalesOverview.latest.ignored"> - <div class="rescale-header"> - <h3><strong>Latest Ignored Rescale</strong></h3> - <span class="rescale-time-info">None</span> - </div> - <nz-divider></nz-divider> - </ng-container> + </td> + <td *ngIf="!rescale">None</td> + </tr> + <tr *ngIf="rescale"> + <td colspan="2" class="collapse-td"> + <ng-container + *ngTemplateOutlet="rescaleDetailsTemplate; context: { rescale: rescale }" + ></ng-container> + </td> + </tr> + </ng-template> - <ng-container *ngIf="rescalesOverview.latest.failed"> - <div class="rescale-header"> - <h3><strong>Latest Failed Rescale</strong></h3> - <span class="rescale-time-info"> - <span> - <strong>Start Time:</strong> - {{ - rescalesOverview.latest.failed.startTimestampInMillis - | date: 'yyyy-MM-dd HH:mm:ss.SSS' - }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>End Time:</strong> - {{ - rescalesOverview.latest.failed.endTimestampInMillis - ? (rescalesOverview.latest.failed.endTimestampInMillis - | date: 'yyyy-MM-dd HH:mm:ss.SSS') - : '-' - }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Duration:</strong> - {{ - (rescalesOverview.latest.failed.endTimestampInMillis || Date.now()) - - rescalesOverview.latest.failed.startTimestampInMillis | humanizeDuration - }} - </span> - </span> - </div> - <nz-divider></nz-divider> - <ng-container - *ngTemplateOutlet=" - rescaleDetailsTemplate; - context: { rescale: rescalesOverview.latest.failed } - " - ></ng-container> - </ng-container> - <ng-container *ngIf="!rescalesOverview.latest.failed"> - <div class="rescale-header"> - <h3><strong>Latest Failed Rescale</strong></h3> - <span class="rescale-time-info">None</span> - </div> - <nz-divider></nz-divider> - </ng-container> - </ng-container> + <nz-table + class="no-border small" + [nzData]="rescalesOverview ? [''] : []" + [nzSize]="'small'" + [nzFrontPagination]="false" + [nzShowPagination]="false" + > + <tbody> + <ng-container *ngIf="rescalesOverview"> + <tr> + <td><strong>Rescale Counts</strong></td> + <td> + <span> + <strong>Total:</strong> + {{ getTotalRescaleCount() }} + </span> + <nz-divider nzType="vertical"></nz-divider> + <span> + <strong>In Progress:</strong> + {{ rescalesOverview.rescalesCounts.inProgress }} + </span> + <nz-divider nzType="vertical"></nz-divider> + <span> + <strong>Completed:</strong> + {{ rescalesOverview.rescalesCounts.completed }} + </span> + <nz-divider nzType="vertical"></nz-divider> + <span> + <strong>Failed:</strong> + {{ rescalesOverview.rescalesCounts.failed }} + </span> + <nz-divider nzType="vertical"></nz-divider> + <span> + <strong>Ignored:</strong> + {{ rescalesOverview.rescalesCounts.ignored }} + </span> + </td> + </tr> + <ng-container + *ngTemplateOutlet=" + latestRescaleTemplate; + context: { + title: 'Latest Completed Rescale', + rescale: rescalesOverview.latest.completed + } + " + ></ng-container> + <ng-container + *ngTemplateOutlet=" + latestRescaleTemplate; + context: { title: 'Latest Ignored Rescale', rescale: rescalesOverview.latest.ignored } + " + ></ng-container> + <ng-container + *ngTemplateOutlet=" + latestRescaleTemplate; + context: { title: 'Latest Failed Rescale', rescale: rescalesOverview.latest.failed } + " + ></ng-container> + </ng-container> + </tbody> + </nz-table> </nz-tab> <nz-tab nzTitle="History"> <nz-table class="no-border small" [nzSize]="'small'" - [nzData]="jobRescaleDetails || []" + [nzData]="rescalesHistory || []" [nzFrontPagination]="false" [nzShowPagination]="false" > @@ -524,250 +453,12 @@ <tr [nzExpand]="isExpanded(jobRescaleDetails.rescaleUuid)"> <td colspan="10" *ngIf="isExpanded(jobRescaleDetails.rescaleUuid)" class="collapse-td"> <div class="rescale-details-wrapper"> - <div class="rescale-details-box"> - <h3><strong>Rescale Details</strong></h3> - <tr> - <td> - <span> - <strong>Rescale UUID:</strong> - {{ truncateUuid(jobRescaleDetails.rescaleUuid) }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Requirements ID:</strong> - {{ truncateUuid(jobRescaleDetails.resourceRequirementsUuid) }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Attempt ID:</strong> - {{ jobRescaleDetails.rescaleAttemptId }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Trigger Cause:</strong> - {{ jobRescaleDetails.triggerCause }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Terminal State:</strong> - {{ jobRescaleDetails?.terminalState || '-' }} - </span> - <nz-divider nzType="vertical"></nz-divider> - <span> - <strong>Terminal Reason:</strong> - {{ jobRescaleDetails?.terminatedReason || '-' }} - </span> - </td> - </tr> - <ng-container *ngIf="getDetail(jobRescaleDetails.rescaleUuid) as detail"> - <nz-table - class="small" - [nzData]="detail.vertices | keyvalue" - [nzSize]="'small'" - [nzFrontPagination]="false" - [nzShowPagination]="false" - [nzTitle]="verticesTitle" - [nzBordered]="true" - > - <thead> - <tr> - <th - nz-tooltip - nzTooltipTitle="The unique ID of target JobVertex consists of 32 hexadecimal characters" - > - <strong>ID</strong> - </th> - <th nz-tooltip nzTooltipTitle="The short name of target vertex"> - <strong>Name</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The previous parallelism of target vertex before the current rescale" - > - <strong>Previous Parallelism</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The acquired parallelism of target vertex after the current rescale" - > - <strong>Acquired Parallelism</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The desired parallelism of the target vertex" - > - <strong>Desired Parallelism</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The minimal parallelism of target vertex to run" - > - <strong>Sufficient Parallelism</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The unique ID of the slot sharing group consists of 32 hexadecimal characters" - > - <strong>Slot Sharing Group ID</strong> - </th> - </tr> - </thead> - <tbody> - <tr *ngFor="let vertex of detail.vertices | keyvalue"> - <td nz-tooltip [nzTooltipTitle]="vertex.value.jobVertexId"> - {{ truncateUuid(vertex.value.jobVertexId) }} - </td> - <td nz-tooltip [nzTooltipTitle]="vertex.value.jobVertexName"> - {{ truncateName(vertex.value.jobVertexName) }} - </td> - <td>{{ vertex.value.preRescaleParallelism }}</td> - <td>{{ vertex.value.postRescaleParallelism || '-' }}</td> - <td>{{ vertex.value.desiredParallelism }}</td> - <td>{{ vertex.value.sufficientParallelism }}</td> - <td nz-tooltip [nzTooltipTitle]="vertex.value.slotSharingGroupId"> - {{ truncateUuid(vertex.value.slotSharingGroupId) }} - </td> - </tr> - </tbody> - </nz-table> - - <nz-table - class="small" - [nzData]="detail.slots | keyvalue" - [nzSize]="'small'" - [nzFrontPagination]="false" - [nzShowPagination]="false" - [nzTitle]="slotsTitle" - [nzBordered]="true" - > - <thead> - <tr> - <th - nz-tooltip - nzTooltipTitle="The ID of the slot sharing group to which the slot belongs consists of 32 hexadecimal characters" - > - <strong>Slot Sharing Group ID</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The name of the slot sharing group to which the slot belongs" - > - <strong>Slot Sharing Group Name</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The previous number of slots before the rescale" - > - <strong>Previous Slots</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The acquired number of slots after the rescale" - > - <strong>Acquired Slots</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The desired number of slots of the rescale" - > - <strong>Desired Slots</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The minimal number of slots to deploy tasks in the rescale" - > - <strong>Sufficient Slots</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The required resource profile of the slot sharing group in the rescale" - > - <strong>Required Profile</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The acquired resource profile of the slot sharing group in the rescale" - > - <strong>Acquired Profile</strong> - </th> - </tr> - </thead> - <tbody> - <tr *ngFor="let slot of detail.slots | keyvalue"> - <td nz-tooltip [nzTooltipTitle]="slot.value.slotSharingGroupId"> - {{ truncateUuid(slot.value.slotSharingGroupId) }} - </td> - <td>{{ slot.value.slotSharingGroupName }}</td> - <td>{{ slot.value.preRescaleSlots }}</td> - <td>{{ slot.value.postRescaleSlots || '-' }}</td> - <td>{{ slot.value.desiredSlots }}</td> - <td>{{ slot.value.minimalRequiredSlots }}</td> - <td> - <pre style="margin: 0">{{ - slot.value.requestResourceProfile | json - }}</pre> - </td> - <td> - <pre style="margin: 0">{{ - slot.value.acquiredResourceProfile | json - }}</pre> - </td> - </tr> - </tbody> - </nz-table> - - <nz-table - class="small" - [nzData]="detail.schedulerStates" - [nzSize]="'small'" - [nzFrontPagination]="false" - [nzShowPagination]="false" - [nzTitle]="schedulerStatesTitle" - [nzBordered]="true" - > - <thead> - <tr> - <th nz-tooltip nzTooltipTitle="The scheduler state name"> - <strong>State</strong> - </th> - <th nz-tooltip nzTooltipTitle="The time to enter the state"> - <strong>Enter Time</strong> - </th> - <th nz-tooltip nzTooltipTitle="The time to leave the state"> - <strong>Leave Time</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The duration time from enter time to leave time of the state" - > - <strong>Duration</strong> - </th> - <th - nz-tooltip - nzTooltipTitle="The exception information about current rescale during the state" - > - <strong>Exception</strong> - </th> - </tr> - </thead> - <tbody> - <tr *ngFor="let state of detail.schedulerStates"> - <td>{{ state.state }}</td> - <td> - {{ state.enterTimestampInMillis | date: 'yyyy-MM-dd HH:mm:ss.SSS' }} - </td> - <td> - {{ state.leaveTimestampInMillis | date: 'yyyy-MM-dd HH:mm:ss.SSS' }} - </td> - <td>{{ state.durationInMillis | humanizeDuration }}</td> - <td>{{ state.stringifiedException }}</td> - </tr> - </tbody> - </nz-table> - </ng-container> - - <div *ngIf="!getDetail(jobRescaleDetails.rescaleUuid)">Loading...</div> - </div> + <ng-container + *ngTemplateOutlet=" + rescaleDetailsTemplate; + context: { rescale: jobRescaleDetails, containerClass: 'rescale-details-box' } + " + ></ng-container> </div> </td> </tr> diff --git a/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.less b/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.less index a5ad73dde77..aa43d203d71 100644 --- a/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.less +++ b/flink-runtime-web/web-dashboard/src/app/pages/job/rescales/job-rescales.component.less @@ -31,28 +31,6 @@ > nz-divider { margin: 8px 0; } - - .rescale-header { - display: flex; - align-items: center; - margin-top: 8px; - margin-bottom: 8px; - - h3 { - flex-shrink: 0; - width: 280px; - margin: 0; - } - - .rescale-time-info { - color: rgba(0, 0, 0, 0.85); - font-size: 14px; - } - - &.rescale-counts-header { - margin-top: -2px; - } - } } .ant-tabs-nav-list { @@ -95,26 +73,6 @@ nz-empty { padding: 24px; } -.overview-rescale-section { - margin: 16px 0; - padding: 16px; - border: 1px solid #f0f0f0; - background-color: #fff; - - h3 { - margin-top: 0; - margin-bottom: 8px; - } - - nz-table { - margin-bottom: 16px; - - &:last-child { - margin-bottom: 0; - } - } -} - .rescale-details-wrapper { display: block; box-sizing: border-box;
