mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 04:21:52 +00:00
chore(ui): sync Lighthouse context core
This commit is contained in:
@@ -199,7 +199,7 @@ describe("createLighthouseChatStore", () => {
|
||||
displayText: "Prioritize findings",
|
||||
context: {
|
||||
...context,
|
||||
items: context.items.slice(0, 2),
|
||||
items: context.items.slice(0, 3),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -41,27 +41,15 @@ export function compileLighthouseContext(
|
||||
|
||||
const seen = new Set<string>();
|
||||
const items = parsedItems
|
||||
.sort((left, right) => getItemOrder(left) - getItemOrder(right))
|
||||
.filter((item) => {
|
||||
const key = `${item.kind}:${item.id}`;
|
||||
if (seen.has(key)) return false;
|
||||
seen.add(key);
|
||||
return true;
|
||||
})
|
||||
.sort((left, right) => getItemOrder(left) - getItemOrder(right));
|
||||
});
|
||||
|
||||
const completeContext = buildEnvelopeWithinLimits(items);
|
||||
if (completeContext) return completeContext;
|
||||
|
||||
const withoutSummaries = items.filter(
|
||||
(item) =>
|
||||
item.kind === LIGHTHOUSE_CONTEXT_KIND.PAGE ||
|
||||
item.source !== LIGHTHOUSE_CONTEXT_SOURCE.AUTOMATIC,
|
||||
);
|
||||
const selectionContext = buildEnvelopeWithinLimits(withoutSummaries);
|
||||
if (selectionContext) return selectionContext;
|
||||
|
||||
const page = items.find((item) => item.kind === LIGHTHOUSE_CONTEXT_KIND.PAGE);
|
||||
return page ? buildEnvelopeWithinLimits([page]) : undefined;
|
||||
return buildEnvelopeWithProgressiveDegradation(items);
|
||||
}
|
||||
|
||||
function hasDifferentScope(candidate: unknown, scopeKey: string): boolean {
|
||||
@@ -76,7 +64,8 @@ function hasDifferentScope(candidate: unknown, scopeKey: string): boolean {
|
||||
|
||||
function getItemOrder(item: LighthouseContextItem): number {
|
||||
if (item.kind === LIGHTHOUSE_CONTEXT_KIND.PAGE) return 0;
|
||||
return item.source === LIGHTHOUSE_CONTEXT_SOURCE.AUTOMATIC ? 2 : 1;
|
||||
if (item.source === LIGHTHOUSE_CONTEXT_SOURCE.FOCUSED) return 1;
|
||||
return item.source === LIGHTHOUSE_CONTEXT_SOURCE.AUTOMATIC ? 3 : 2;
|
||||
}
|
||||
|
||||
function buildEnvelopeWithinLimits(
|
||||
@@ -94,3 +83,17 @@ function buildEnvelopeWithinLimits(
|
||||
const byteLength = getApiLighthouseContextByteLength(result.data);
|
||||
return byteLength <= LIGHTHOUSE_CONTEXT_MAX_BYTES ? result.data : undefined;
|
||||
}
|
||||
|
||||
function buildEnvelopeWithProgressiveDegradation(
|
||||
items: LighthouseContextItem[],
|
||||
): LighthouseContextEnvelope | undefined {
|
||||
const retainedItems = items.slice(0, 8);
|
||||
|
||||
while (retainedItems.length > 0) {
|
||||
const context = buildEnvelopeWithinLimits(retainedItems);
|
||||
if (context) return context;
|
||||
retainedItems.pop();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -244,10 +244,51 @@ describe("compileLighthouseContext", () => {
|
||||
"finding:finding-1",
|
||||
]);
|
||||
});
|
||||
|
||||
it("should retain the highest-priority duplicate", () => {
|
||||
// Given
|
||||
const scopeKey = "findings:/findings";
|
||||
const items = [
|
||||
{
|
||||
kind: "page",
|
||||
id: "findings",
|
||||
source: "automatic",
|
||||
scopeKey,
|
||||
label: "Findings",
|
||||
path: "/findings",
|
||||
},
|
||||
{
|
||||
kind: "finding",
|
||||
id: "finding-1",
|
||||
source: "selection",
|
||||
scopeKey,
|
||||
label: "Selected finding",
|
||||
findingId: "finding-1",
|
||||
},
|
||||
{
|
||||
kind: "finding",
|
||||
id: "finding-1",
|
||||
source: "focused",
|
||||
scopeKey,
|
||||
label: "Focused finding",
|
||||
findingId: "finding-1",
|
||||
},
|
||||
];
|
||||
|
||||
// When
|
||||
const context = compileLighthouseContext(items, scopeKey);
|
||||
|
||||
// Then
|
||||
expect(context?.items[1]).toMatchObject({
|
||||
id: "finding-1",
|
||||
source: "focused",
|
||||
label: "Focused finding",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when contributors arrive in render order", () => {
|
||||
it("should order page, selection, and summary items deterministically", () => {
|
||||
it("should order page, focused, selection, and summary items deterministically", () => {
|
||||
// Given
|
||||
const scopeKey = "findings:/findings";
|
||||
const items = [
|
||||
@@ -268,6 +309,14 @@ describe("compileLighthouseContext", () => {
|
||||
label: "Selected finding",
|
||||
findingId: "finding-1",
|
||||
},
|
||||
{
|
||||
kind: "finding",
|
||||
id: "finding-focused",
|
||||
source: "focused",
|
||||
scopeKey,
|
||||
label: "Focused finding",
|
||||
findingId: "finding-focused",
|
||||
},
|
||||
{
|
||||
kind: "page",
|
||||
id: "findings",
|
||||
@@ -284,6 +333,7 @@ describe("compileLighthouseContext", () => {
|
||||
// Then
|
||||
expect(context?.items.map((item) => item.id)).toEqual([
|
||||
"findings",
|
||||
"finding-focused",
|
||||
"finding-1",
|
||||
"findings-summary",
|
||||
]);
|
||||
@@ -291,7 +341,7 @@ describe("compileLighthouseContext", () => {
|
||||
});
|
||||
|
||||
describe("when serialized context exceeds 2 KiB", () => {
|
||||
it("should remove automatic summaries before dropping the selection", () => {
|
||||
it("should drop lowest-priority items until the context fits", () => {
|
||||
// Given
|
||||
const scopeKey = "findings:/findings";
|
||||
const page = {
|
||||
@@ -332,6 +382,7 @@ describe("compileLighthouseContext", () => {
|
||||
expect(context?.items.map((item) => item.id)).toEqual([
|
||||
"findings",
|
||||
"finding-1",
|
||||
"summary-0",
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -369,6 +420,64 @@ describe("compileLighthouseContext", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("when context exceeds the eight-item limit", () => {
|
||||
it("should progressively drop only the lowest-priority items", () => {
|
||||
// Given
|
||||
const scopeKey = "findings:/findings";
|
||||
const page = {
|
||||
kind: "page",
|
||||
id: "findings",
|
||||
source: "automatic",
|
||||
scopeKey,
|
||||
label: "Findings",
|
||||
path: "/findings",
|
||||
};
|
||||
const focused = {
|
||||
kind: "finding",
|
||||
id: "focused",
|
||||
source: "focused",
|
||||
scopeKey,
|
||||
label: "Focused finding",
|
||||
findingId: "focused",
|
||||
};
|
||||
const selections = Array.from({ length: 2 }, (_, index) => ({
|
||||
kind: "finding",
|
||||
id: `selection-${index}`,
|
||||
source: "selection",
|
||||
scopeKey,
|
||||
label: `Selected finding ${index}`,
|
||||
findingId: `selection-${index}`,
|
||||
}));
|
||||
const summaries = Array.from({ length: 6 }, (_, index) => ({
|
||||
kind: "finding",
|
||||
id: `summary-${index}`,
|
||||
source: "automatic",
|
||||
scopeKey,
|
||||
label: `Summary ${index}`,
|
||||
findingId: `summary-${index}`,
|
||||
total: index,
|
||||
}));
|
||||
|
||||
// When
|
||||
const context = compileLighthouseContext(
|
||||
[page, ...summaries, ...selections, focused],
|
||||
scopeKey,
|
||||
);
|
||||
|
||||
// Then
|
||||
expect(context?.items.map((item) => item.id)).toEqual([
|
||||
"findings",
|
||||
"focused",
|
||||
"selection-0",
|
||||
"selection-1",
|
||||
"summary-0",
|
||||
"summary-1",
|
||||
"summary-2",
|
||||
"summary-3",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when contributors belong to another page", () => {
|
||||
it("should ignore stale scoped data", () => {
|
||||
// Given / When
|
||||
|
||||
@@ -13,6 +13,7 @@ export type LighthouseContextKind =
|
||||
|
||||
export const LIGHTHOUSE_CONTEXT_SOURCE = {
|
||||
AUTOMATIC: "automatic",
|
||||
FOCUSED: "focused",
|
||||
SELECTION: "selection",
|
||||
MANUAL: "manual",
|
||||
} as const;
|
||||
|
||||
Reference in New Issue
Block a user