Skip to content

Commit 014ddc7

Browse files
authored
feat: update sorting (CM-1293) (#4264)
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
1 parent 57bea95 commit 014ddc7

2 files changed

Lines changed: 35 additions & 29 deletions

File tree

backend/src/api/public/v1/ossprey/packageList.ts

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,38 @@ const LIFECYCLE_SET = new Set<string>(LIFECYCLE_VALUES)
2020

2121
const boolParam = z.preprocess((v) => v === 'true', z.boolean()).default(false)
2222

23-
const querySchema = z.object({
24-
page: z.coerce.number().int().min(1).default(1),
25-
pageSize: z.coerce.number().int().min(1).max(MAX_PAGE_SIZE).default(25),
26-
ecosystem: z.string().trim().optional(),
27-
lifecycle: z.enum(LIFECYCLE_VALUES).optional(),
28-
name: z.string().trim().optional(),
29-
purl: purlFilterSchema,
30-
status: z
31-
.enum([
32-
'unassigned',
33-
'open',
34-
'assessing',
35-
'active',
36-
'needs_attention',
37-
'escalated',
38-
'blocked',
39-
'inactive',
40-
])
41-
.optional(),
42-
healthBand: z.enum(HEALTH_BAND_VALUES).optional(),
43-
vulnSeverity: z.enum(['any', 'high', 'critical', 'none']).optional(),
44-
staleOnly: boolParam,
45-
unstewardedOnly: boolParam,
46-
busFactor1Only: boolParam,
47-
sortBy: z.enum(['name', 'risk', 'impact', 'openVulns', 'health']).default('risk'),
48-
sortDir: z.enum(['asc', 'desc']).default('desc'),
49-
})
23+
const querySchema = z
24+
.object({
25+
page: z.coerce.number().int().min(1).default(1),
26+
pageSize: z.coerce.number().int().min(1).max(MAX_PAGE_SIZE).default(25),
27+
ecosystem: z.string().trim().optional(),
28+
lifecycle: z.enum(LIFECYCLE_VALUES).optional(),
29+
name: z.string().trim().optional(),
30+
purl: purlFilterSchema,
31+
status: z
32+
.enum([
33+
'unassigned',
34+
'open',
35+
'assessing',
36+
'active',
37+
'needs_attention',
38+
'escalated',
39+
'blocked',
40+
'inactive',
41+
])
42+
.optional(),
43+
healthBand: z.enum(HEALTH_BAND_VALUES).optional(),
44+
vulnSeverity: z.enum(['any', 'high', 'critical', 'none']).optional(),
45+
staleOnly: boolParam,
46+
unstewardedOnly: boolParam,
47+
busFactor1Only: boolParam,
48+
sortBy: z.enum(['name', 'risk', 'impact', 'openVulns', 'health']).default('risk'),
49+
sortDir: z.enum(['asc', 'desc']).optional(),
50+
})
51+
.transform((data) => ({
52+
...data,
53+
sortDir: data.sortDir ?? (data.sortBy === 'name' || data.sortBy === 'health' ? 'asc' : 'desc'),
54+
}))
5055

5156
export async function packageListHandler(req: Request, res: Response): Promise<void> {
5257
const params = validateOrThrow(querySchema, req.query)

services/libs/data-access-layer/src/osspckgs/api.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ export async function listPackagesForApi(
436436
} else if (opts.sortBy === 'openVulns') {
437437
sortExpr = '"openVulns"'
438438
} else if (opts.sortBy === 'health') {
439-
sortExpr = 'r_sc.scorecard_score'
439+
sortExpr = 'COALESCE(p.health_score, r_sc.scorecard_score * 10)'
440440
} else if (opts.sortBy === 'risk') {
441441
// Composite risk score: impact + health deficit + vuln exposure + bus factor + staleness
442442
sortExpr = `(
@@ -451,6 +451,7 @@ export async function listPackagesForApi(
451451
sortExpr = 'LOWER(p.name)'
452452
}
453453
const sortDir = opts.sortDir === 'desc' ? 'DESC' : 'ASC'
454+
const nullsDir = sortDir === 'ASC' ? 'NULLS FIRST' : 'NULLS LAST'
454455

455456
// Separate paginated params from filter-only params used by the fallback COUNT query
456457
const queryParams: Record<string, unknown> = {
@@ -568,7 +569,7 @@ export async function listPackagesForApi(
568569
FROM packages p
569570
${laterals}
570571
${where}
571-
ORDER BY ${[exactSort, `${sortExpr} ${sortDir} NULLS LAST`, `p.purl ${sortDir}`].filter(Boolean).join(', ')}
572+
ORDER BY ${[exactSort, `${sortExpr} ${sortDir} ${nullsDir}`, `p.purl ${sortDir}`].filter(Boolean).join(', ')}
572573
LIMIT $(limit) OFFSET $(offset)
573574
`,
574575
queryParams,

0 commit comments

Comments
 (0)