warn/info/hint notifs in process grp

3clyp50 committed Jan 19, 2026 at 20:52 UTC 41873c99057073edbd2d47bc29bfdc90b0ac8865
2 files changed +45
webui/components/messages/process-group/process-group.css
+8
@@ -268,6 +268,14 @@
268 gap: 2px;
269 }
270
271 +.process-group-header .group-metrics .metric-notifications {
272 + font-weight: 600;
273 +}
274 +
275 +.process-group-header .group-metrics .metric-notifications .material-symbols-outlined {
276 + opacity: 0.85;
277 +}
278 +
279 /* Legacy timestamp/duration (for backwards compatibility) */
280 .process-group-header .group-timestamp {
281 font-size: 0.65rem;
webui/js/messages.js
+37
@@ -1228,6 +1228,7 @@ function createProcessGroup(id) {
1228 <span class="metric-time" title="Start time"><span class="material-symbols-outlined">schedule</span><span class="metric-value">--:--</span></span>
1229 <span class="metric-steps" title="Steps"><span class="material-symbols-outlined">footprint</span><span class="metric-value">0</span></span>
1230 <span class="metric-duration" title="Duration"><span class="material-symbols-outlined">timer</span><span class="metric-value">0s</span></span>
1231 + <span class="metric-notifications" title="Warnings/Info/Hint" hidden><span class="material-symbols-outlined">notifications</span><span class="metric-value">0</span></span>
1232 </span>
1233 `;
1234
@@ -1846,6 +1847,42 @@ function updateProcessGroupHeader(group) {
1847 const metricsEl = group.querySelector(".group-metrics");
1848 const isCompleted = group.classList.contains("process-group-completed");
1849
1850 + const notificationsEl = metricsEl?.querySelector(".metric-notifications");
1851 + if (notificationsEl) {
1852 + const counts = { warning: 0, info: 0, hint: 0 };
1853 + steps.forEach((step) => {
1854 + const stepType = step.getAttribute("data-type");
1855 + if (Object.prototype.hasOwnProperty.call(counts, stepType)) {
1856 + counts[stepType] += 1;
1857 + }
1858 + });
1859 +
1860 + const totalNotifications = counts.warning + counts.info + counts.hint;
1861 + const countEl = notificationsEl.querySelector(".metric-value");
1862 + notificationsEl.classList.remove("status-wrn", "status-inf", "status-hnt");
1863 +
1864 + if (totalNotifications > 0) {
1865 + if (countEl) {
1866 + countEl.textContent = totalNotifications.toString();
1867 + }
1868 + if (counts.warning > 0) {
1869 + notificationsEl.classList.add("status-wrn");
1870 + } else if (counts.info > 0) {
1871 + notificationsEl.classList.add("status-inf");
1872 + } else {
1873 + notificationsEl.classList.add("status-hnt");
1874 + }
1875 + notificationsEl.hidden = false;
1876 + notificationsEl.title = `Warnings: ${counts.warning}, Info: ${counts.info}, Hints: ${counts.hint}`;
1877 + } else {
1878 + if (countEl) {
1879 + countEl.textContent = "0";
1880 + }
1881 + notificationsEl.hidden = true;
1882 + notificationsEl.title = "Warnings/Info/Hint";
1883 + }
1884 + }
1885 +
1886 // If completed, don't update metrics
1887 if (isCompleted) {
1888 return;