+
{
+ return Status[s] as StatusName;
+};
+
+// Convert Status enum to NodeStatus
+export const statusForNode = (s: Status): NodeStatus | undefined => {
+ const name = statusName(s);
+ return name ? NodeStatus[name] : undefined;
+};
+
+// Convert a korrel8r status string to a status enum value
+export const toStatus = (ks: string): Status | undefined => {
+ if (ks.match(/error|critical|fatal/i)) return Status.danger;
+ if (ks.match(/warn(ing)?/i)) return Status.warning;
+ if (ks) return Status.info;
+ return undefined;
+};
+
+// Collect and merge all status counts for the node.
+// Return merges status counts and the most severe status seen.
+export const mergeStatusCounts = (
+ node: korrel8r.Node,
+): [korrel8r.StatusCount[], Status | undefined] => {
+ const m = new Map(); // Original status string, total count.
+ let s = 0;
+ node.queries.forEach((qc) =>
+ qc.statuses.forEach((sc) => {
+ if (!sc.status) return;
+ m.set(sc.status, (m.get(sc.status) ?? 0) + sc.count);
+ s = Math.max(s, toStatus(sc.status));
+ }),
+ );
+ const sc = [...m.entries()].map(([status, count]) => ({ status, count }));
+ return [sc, s || undefined];
+};
diff --git a/web/src/korrel8r/client/index.ts b/web/src/korrel8r/client/index.ts
index af98ba1..150f38f 100644
--- a/web/src/korrel8r/client/index.ts
+++ b/web/src/korrel8r/client/index.ts
@@ -57,6 +57,7 @@ export type {
ListGoalsErrors,
ListGoalsResponse,
ListGoalsResponses,
+ StatusCount,
Neighbors,
Node,
Object,
diff --git a/web/src/korrel8r/client/types.gen.ts b/web/src/korrel8r/client/types.gen.ts
index c810752..d1d21db 100644
--- a/web/src/korrel8r/client/types.gen.ts
+++ b/web/src/korrel8r/client/types.gen.ts
@@ -160,6 +160,24 @@ export type QueryCount = {
* Query for correlation data.
*/
query: Query;
+ /**
+ * Statuses found on data objects for this query.
+ */
+ statuses?: Array;
+};
+
+/**
+ * Status with number of instances found.
+ */
+export type StatusCount = {
+ /**
+ * Status for correlation data.
+ */
+ status: string;
+ /**
+ * Number of instances found, omitted if none.
+ */
+ count?: number;
};
/**
@@ -541,6 +559,10 @@ export type ObjectsData = {
* Query string.
*/
query: Query;
+ /**
+ * Constrains the objects that will be included in results.
+ */
+ constraint?: Constraint;
};
url: '/objects';
};
diff --git a/web/src/korrel8r/types.ts b/web/src/korrel8r/types.ts
index a70067a..b502f67 100644
--- a/web/src/korrel8r/types.ts
+++ b/web/src/korrel8r/types.ts
@@ -248,15 +248,17 @@ export const unixSeconds = (d: Date | undefined): number | undefined => {
return Math.floor(unixMilliseconds(d) / 1000) || undefined;
};
+export type StatusCount = api.StatusCount;
+
export class Node {
id: string;
count: number;
class: Class;
queries: Array;
- error: Error;
+ disabled: string;
/** Construct a type-safe node from an API node.
- * Does not throw, sets the `error` field on error.
+ * Does not throw, sets the `disabled` field if there is an error.
*/
constructor(node: api.Node) {
this.id = node.class;
@@ -264,7 +266,7 @@ export class Node {
try {
this.class = Class.parse(node.class);
} catch (e) {
- this.error = e;
+ this.disabled = e?.message ?? e.toString();
}
this.queries = QueryCount.array(node.queries ?? []);
}
@@ -281,6 +283,7 @@ export class Edge {
export class QueryCount {
query: Query;
count: number;
+ statuses: Array;
error: Error;
/**
@@ -290,6 +293,7 @@ export class QueryCount {
try {
this.count = qc.count;
this.query = Query.parse(qc.query);
+ this.statuses = qc.statuses ?? [];
} catch (e) {
this.error = e;
}