Skip to content

feat(adoption-insights): add Est. Time Saved column to Top Templates card - #3707

Open
rajin-kichannagari wants to merge 11 commits into
redhat-developer:mainfrom
rajin-kichannagari:feat/time-saved-adoption-insights
Open

feat(adoption-insights): add Est. Time Saved column to Top Templates card#3707
rajin-kichannagari wants to merge 11 commits into
redhat-developer:mainfrom
rajin-kichannagari:feat/time-saved-adoption-insights

Conversation

@rajin-kichannagari

Copy link
Copy Markdown
Contributor

Read the rhdh.redhat.com/time-saved annotation from template entities and display a calculated Est. Time Saved column (annotation × execution count) on the Top Templates card. Templates without the annotation show —.

RHDHPLAN-1553 / RHIDP 15188

image

✔️ Checklist

  • [X ] A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • [ X] Tests for new functionality and regression tests for bug fixes
  • [ X] Screenshots attached (for UI changes)

@rhdh-gh-app

rhdh-gh-app Bot commented Jul 7, 2026

Copy link
Copy Markdown

Important

This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior.

Changed Packages

Package Name Package Path Changeset Bump Current Version
app-legacy workspaces/adoption-insights/packages/app-legacy none v0.0.0
app workspaces/adoption-insights/packages/app none v0.0.0
@red-hat-developer-hub/backstage-plugin-adoption-insights workspaces/adoption-insights/plugins/adoption-insights minor v0.9.0

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 23.33333% with 69 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.41%. Comparing base (714fd0c) to head (a5d2616).
⚠️ Report is 40 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3707      +/-   ##
==========================================
- Coverage   56.44%   56.41%   -0.04%     
==========================================
  Files        2383     2387       +4     
  Lines       95609    95699      +90     
  Branches    26731    26735       +4     
==========================================
+ Hits        53968    53989      +21     
- Misses      41403    41473      +70     
+ Partials      238      237       -1     
Flag Coverage Δ *Carryforward flag
adoption-insights 81.79% <23.33%> (-2.76%) ⬇️
ai-integrations 69.06% <ø> (ø) Carriedforward from d4717eb
app-defaults 69.79% <ø> (ø) Carriedforward from d4717eb
augment 46.67% <ø> (ø) Carriedforward from d4717eb
boost 75.92% <ø> (ø) Carriedforward from d4717eb
bulk-import 72.55% <ø> (ø) Carriedforward from d4717eb
cost-management 13.55% <ø> (ø) Carriedforward from d4717eb
dcm 60.72% <ø> (ø) Carriedforward from d4717eb
extensions 56.48% <ø> (ø) Carriedforward from d4717eb
global-floating-action-button 71.18% <ø> (ø) Carriedforward from d4717eb
global-header 62.17% <ø> (ø) Carriedforward from d4717eb
homepage 47.46% <ø> (ø) Carriedforward from d4717eb
install-dynamic-plugins 56.77% <ø> (ø) Carriedforward from d4717eb
intelligent-assistant 74.06% <ø> (ø) Carriedforward from d4717eb
konflux 91.98% <ø> (ø) Carriedforward from d4717eb
lightspeed 69.02% <ø> (ø) Carriedforward from d4717eb
mcp-integrations 83.40% <ø> (ø) Carriedforward from d4717eb
orchestrator 66.79% <ø> (ø) Carriedforward from d4717eb
quickstart 65.04% <ø> (ø) Carriedforward from d4717eb
sandbox 79.56% <ø> (ø) Carriedforward from d4717eb
scorecard 82.97% <ø> (ø) Carriedforward from d4717eb
theme 83.89% <ø> (ø) Carriedforward from d4717eb
translations 5.12% <ø> (ø) Carriedforward from d4717eb
x2a 55.05% <ø> (ø) Carriedforward from d4717eb

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 714fd0c...a5d2616. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

HusneShabbir

This comment was marked as duplicate.

@HusneShabbir HusneShabbir left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tested Locally, /lgtm

Please do not merge this without approvals from @Eswaraiahsapram / @karthikjeeyar .

@karthikjeeyar karthikjeeyar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall the changes looks good, just a couple of observations.

Image

1.5hrs and 8hrs looks cramped especially in a table column where you 're scanning numbers quickly. IMO a space between the number and unit will improve readability.

Comment on lines +28 to +36
const totalMinutes = parsed * count;
if (totalMinutes < 60) {
return `${totalMinutes}min`;
}
const hours = totalMinutes / 60;
if (Number.isInteger(hours)) {
return `${hours}hrs`;
}
return `${hours.toFixed(1)}hrs`;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Units are hardcoded, can we translate them?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@karthikjeeyar, what's your opinion on this? When the duration is more than 24 hours, for example, 28 hours - I think it would be better to display it as 1d 4h instead of 28h. What do you think?

cc - @ShiranHi

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

image

How is this?

@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown

New changes are detected. LGTM label has been removed.

@karthikjeeyar

Copy link
Copy Markdown
Member

Since the new translation keys are added, you must re-generate the api-reports by running yarn build:api-reports:only for the CI to pass.

readonly 'filter.selectKind': string;
readonly 'units.days': string;
readonly 'units.hours': string;
readonly 'units.minutes': string;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't see this units.* strings defined in the ref.ts or in other translation files, can you check if you have missed something to commit?

@rajin-kichannagari
rajin-kichannagari force-pushed the feat/time-saved-adoption-insights branch 2 times, most recently from c36d46f to 76106c5 Compare July 23, 2026 22:22
Rajin Kichannagari and others added 4 commits July 27, 2026 13:28
…card

- Add Est. Time Saved column showing per-template time savings
  (annotation value × execution count) on Top Templates card (RHIDP-15188)
- Add useTimeSavedTotals hook to fetch aggregated time-saved data
- Add formatTimeSaved utility for days/hours/minutes display
- Add NotificationSettings component for frequency preferences
- Add useNotificationPreference hook for GET/PUT preferences
- Add translation keys for units, notifications, and table headers
- Wire AdoptionInsightsNotificationSettings to Settings page

Depends on backend PR for time_saved_totals API and notification
preferences endpoints.

RHDHPLAN-1553 / RHIDP-15188

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Karthik-provided report is for redhat-developer#3713, not this PR.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rajin-kichannagari
rajin-kichannagari force-pushed the feat/time-saved-adoption-insights branch from 8db3df5 to 2a24e10 Compare July 27, 2026 17:31
Rajin Kichannagari and others added 4 commits July 27, 2026 13:37
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Templates component now depends on useTimeSavedTotals hook which
requires DateRangeProvider context. Add mock to prevent test crashes
and update expected output to match translation format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rajin Kichannagari and others added 2 commits July 28, 2026 13:37
Extends the existing "New data shows in top templates" E2E test to
assert the Est. Time Saved column header renders and the third cell
is visible in each template row.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge duplicate imports from adoption-insights package in App.tsx,
replace Promise.resolve with direct return in async getTimeSavedTotals,
and use conventional useState destructuring in useNotificationPreference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
},
),
);
}, [api, startDateRange, endDateRange]);

@karthikjeeyar karthikjeeyar Jul 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We do not have any API like time_saved_totals, I am not sure if you have changed something in recent commits. Few weeks ago, when I first reviewed this PR, it used to read the annotation for an entity and multiply it by the count to arrive at the timeSavedTotal, I think you may have to revert to that state.

Non-existing API is being called to get the data:

Image

Due to the above issue, -- is displayed now.

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Reverted to client-side computation using the entity annotation × count, like it was before. Also dropped the translation keys for the time display in favor of a compact formatter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I believe you can keep the compact formatter and still translate. Given that this plugins support 5 languages and all the user-visible strings are translated, the time display should be too.

The units.days, units.hours, units.minutes keys are still present in all 5 language files (de/es/fr/it/ja) but were removed from ref.ts And formatTimeSavedCompact hardcodes English d/h/m, so a Japanese user sees 1d 6h instead of 1日 6時間. It would recommend passing the t function to the formatter and translate this as well.

…ormat

Remove useTimeSavedTotals backend API call (API doesn't exist without
PR redhat-developer#3946) and compute time saved client-side from entity annotations.
Display in compact "1d 6h" format instead of "1 d 6 h".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@karthikjeeyar karthikjeeyar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The scope of this PR should be the Est. Time Saved column only reading the rhdh.redhat.com/time-saved annotation and displaying it.

Suggestion is to move these Notification feature to a PR which brings in the backend support to store user's notification preferences.

return { days, hours, minutes };
}

export function formatTimeSavedCompact(result: TimeSavedResult): string {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Add unit test coverage for this function.

headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ frequency }),
},
);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

UI breaks when you try changing the values in the dropdown:

Image Image Image

This API endpoint /notification-preferences doesn't exist. I see code where GET and PUT request is made when you try to visit and modify the Time Saved notifcations in Notifications tab.

If you have follow up PR to add this API endpoint, then you should add these frontend components in that PR and I believe this PR should be scoped only to the Est. Time saved, let me know your thoughts.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Dead code. please remove this file.

getNotificationPreference(): Promise<NotificationPreferenceResponse>;
setNotificationPreference(
frequency: NotificationFrequency,
): Promise<NotificationPreferenceResponse>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These functions are basically calling Non-existing API endpoints, Please remove this usage in all the places.

Comment on lines +104 to +117
export type TimeSavedTemplate = {
entityref: string;
execution_count: number;
time_saved_per_execution: number;
total_time_saved_minutes: number;
};

export type TimeSavedTotalsResponse = {
data: {
total_time_saved_minutes: number;
templates: TimeSavedTemplate[];
};
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same as above.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants