mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-11-15 13:26:15 +08:00
* feat: add component health dashboard sections
Add health summary and component health tables with severity filters and expandable check details.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jack Yu <jack.yu@suse.com>
* feat: use health API group for component health resources
Update dashboard resource types to use the health.harvesterhci.io API group.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jack Yu <jack.yu@suse.com>
* feat: add component health ignore controls
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jack Yu <jack.yu@suse.com>
* feat: gate component health behind the componentHealth feature flag
Only show the component health dashboard sections on Harvester v1.10.0 and later.
Signed-off-by: Jack Yu <jack.yu@suse.com>
* fix: address component health review comments
- sort the health summary table by a severity rank
- use buttons instead of anchors for restore and show more actions
- let the affected resources list expand so every resource can be restored
- widen the ignore popup and cap its height
Signed-off-by: Jack Yu <jack.yu@suse.com>
* refactor: split component health into dedicated components
Move the health summary, component health tabs and ignore popup out of
the dashboard page into components/health, and share the constants and
helpers through utils/component-health.
Signed-off-by: Jack Yu <jack.yu@suse.com>
* fix: sort component health by severity rank
Signed-off-by: Jack Yu <jack.yu@suse.com>
* fix: toggle health rows in place and tell empty filters from no checks
- toggle the expanded message and resource ids by mutating the unwrapped
arrays, the template does not pass refs
- show "No checks match the selected filters" when the severity filters
hide existing checks, keep "No issues detected" for a report without
checks
Signed-off-by: Jack Yu <jack.yu@suse.com>
* refactor: fetch component health resources in their own components
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jack Yu <jack.yu@suse.com>
* feat: move health into a Components tab with the checks as sub-rows
The dashboard showed the summary table, then side tabs with a second
table for each component. It is now one table in a new Components tab
next to the Events tabs: one row per component, which opens to its
checks. Rows start closed, and the component name is a button so the
keyboard can open them. The tab only shows when the addon's resources
exist.
The table's own filter box replaces the severity dropdown. It only looks
at the table's own rows and the checks are in the sub-rows, so the rows
give it the text of their checks, a row only shows the checks it found,
and the rows it found open.
Ignoring a check moves from a popover, which cut off its Reason field
and Ignore button, to an RcModal that starts over each time it opens.
Signed-off-by: Marcelo Fukumoto <marcelo.fukumoto@suse.com>
* refactor: use RcButton for the component health buttons
The Ignore modal's button already was one. This moves the rest of them,
the row's Ignore, Restore, the "show more" links and the component name,
off the global btn classes.
Signed-off-by: Marcelo Fukumoto <marcelo.fukumoto@suse.com>
* refactor: manage one ignore rule per check from the row's actions
A check now has one rule, reached through the table's action menu: create
it when the check has none, view, edit or delete it when it has one. View
and edit use the same modal as create. This replaces the Ignore button and
the Restore links, which could only delete a whole rule and said the check
was restored when it wasn't.
The modal's section titles were the radio group's h3, as big as the modal's
own title. They follow what rancher/dashboard does in its forms now.
The actions follow what the user may do. The rules are only loaded with
their schema, and a list that fails no longer empties the table.
Signed-off-by: Marcelo Fukumoto <marcelo.fukumoto@suse.com>
* refactor: let the tables filter by themselves and show resources as chips
The filter had logic of its own on top of the table's. The nested table now
filters its rows the way the outer one does, with what is typed in the box.
Rows no longer open by themselves, which is how the other tables with
sub-rows behave. Expand All and Collapse All are there instead, copied from
what the table has from shell 3.0.15.
Affected resources are chips under the name the UI has for their type, with
the usual counter badge and the API version beside it. Ignored resources are
outlined instead of filled, and the text of an ignored check is muted. The
links use the shell's wording.
The component rows lose Last Updated. The summary only has one time, for its
counts as a whole, so it said nothing about the component in the row. They say
Error instead of Critical, as the checks inside them do. The Node column goes,
as nothing sets its label.
The Components tab shows the number of errors as a badge, as nothing else on
the page tells there are any.
Signed-off-by: Marcelo Fukumoto <marcelo.fukumoto@suse.com>
* fix: name the ignore rule after its check and make its expiry clear
- Name the rule the UI makes after its check, so Kubernetes refuses a
second one for the same check. The row's menu only manages that rule.
- Show the rule's current expiry above the durations, and the new one
under them once a duration is chosen. Edit starts with none chosen,
Save stays off until something changes, and a warning says when an
expired rule would stay expired.
- Delete the rule through the shell's delete prompt, like every other
delete.
- Say which list could not be loaded, instead of showing it as empty.
- Keep the full count of affected resources, say how many ignored ones
are left out of the list, and count them on Show ignored.
- Drop the checks' Last Updated, which is the time of their whole report.
- Leave out the row menu when no check has an action.
- Mark the Components tab with the shell's alert icon when there are
errors, with their number in its tooltip, instead of a badge.
Signed-off-by: Marcelo Fukumoto <marcelo.fukumoto@suse.com>
---------
Signed-off-by: Jack Yu <jack.yu@suse.com>
Signed-off-by: Marcelo Fukumoto <marcelo.fukumoto@suse.com>
Co-authored-by: Jack Yu <jack.yu@suse.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
(cherry picked from commit 67ff2777d6)
106 lines
3.1 KiB
JavaScript
106 lines
3.1 KiB
JavaScript
export const COMPONENT_LABEL = 'health.harvesterhci.io/component';
|
|
export const IGNORE_RULE_SOURCE_LABEL = 'health.harvesterhci.io/source';
|
|
|
|
export const IGNORE_DURATION_DAYS = {
|
|
days7: 7,
|
|
days30: 30,
|
|
forever: 0,
|
|
};
|
|
|
|
export const AFFECTED_RESOURCES_TRUNCATE_COUNT = 3;
|
|
export const MESSAGE_TRUNCATE_LENGTH = 100;
|
|
|
|
export const SEVERITY_COLORS = {
|
|
Error: 'bg-error',
|
|
Warning: 'bg-warning',
|
|
Info: 'bg-info',
|
|
Healthy: 'bg-success',
|
|
};
|
|
|
|
export const HEALTH_SUMMARY_SEVERITY_RANK = {
|
|
Error: 0,
|
|
Warning: 1,
|
|
Healthy: 2,
|
|
};
|
|
|
|
export const COMPONENT_HEALTH_SEVERITIES = ['Error', 'Warning', 'Info'];
|
|
|
|
export function severityColor(severity) {
|
|
return SEVERITY_COLORS[severity] || 'bg-info';
|
|
}
|
|
|
|
export function healthSummarySeverity(row) {
|
|
if (row.errorCount > 0) {
|
|
return 'Error';
|
|
}
|
|
|
|
if (row.warningCount > 0) {
|
|
return 'Warning';
|
|
}
|
|
|
|
return 'Healthy';
|
|
}
|
|
|
|
// the summaries already leave out what is ignored
|
|
export function totalErrorCount(healthSummaries) {
|
|
return (healthSummaries || []).reduce((total, summary) => {
|
|
return Object.values(summary?.status?.components || {}).reduce((sum, counts) => sum + (counts?.errorCount || 0), total);
|
|
}, 0);
|
|
}
|
|
|
|
export function componentOf(componentHealth) {
|
|
return componentHealth?.metadata?.labels?.[COMPONENT_LABEL] || componentHealth?.metadata?.name;
|
|
}
|
|
|
|
export function allAffectedResourceNames(row) {
|
|
return Object.keys(row?.affectedResources?.names || {});
|
|
}
|
|
|
|
// the resources that no HealthIgnoreRule ignores
|
|
export function activeAffectedResourceNames(row) {
|
|
const names = row?.affectedResources?.names || {};
|
|
|
|
return Object.keys(names).filter((name) => !names[name]?.ignored);
|
|
}
|
|
|
|
export function resourceIgnoredBy(row, name) {
|
|
const detail = row?.affectedResources?.names?.[name];
|
|
|
|
return detail?.ignored ? detail.ignoredBy : '';
|
|
}
|
|
|
|
export function ignoredResourceCount(row) {
|
|
return allAffectedResourceNames(row).length - activeAffectedResourceNames(row).length;
|
|
}
|
|
|
|
// what "Show ignored" brings back: the checks ignored as a whole, and the ignored resources of the other checks
|
|
export function ignoredCounts(checks) {
|
|
return (checks || []).reduce((counts, check) => {
|
|
if (check.ignored) {
|
|
counts.checks += 1;
|
|
} else {
|
|
counts.resources += ignoredResourceCount(check);
|
|
}
|
|
|
|
return counts;
|
|
}, { checks: 0, resources: 0 });
|
|
}
|
|
|
|
// the UI keeps one rule per check under this name, so Kubernetes refuses a second one for the same check
|
|
export function ignoreRuleName(componentHealthName, checkName) {
|
|
return `${ componentHealthName }.${ checkName.toLowerCase() }`;
|
|
}
|
|
|
|
export function affectedResourceKind(row) {
|
|
return row?.affectedResources?.kind || '';
|
|
}
|
|
|
|
// what the UI calls that kind, in the singular or plural of how many there are
|
|
export function affectedResourceLabel(row, store) {
|
|
const { apiVersion = '', kind = '' } = row?.affectedResources || {};
|
|
const group = apiVersion.includes('/') ? `${ apiVersion.split('/')[0] }.` : '';
|
|
const schema = store.getters['harvester/schemaFor'](`${ group }${ kind.toLowerCase() }`);
|
|
|
|
return schema ? store.getters['type-map/labelFor'](schema, row.affectedCount) : kind;
|
|
}
|