Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/model/catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,25 @@ describe('helpers', () => {
expect(switchesForRole('spine').map((i) => i.id)).toContain('switch-as7726')
expect(switchesForRole('spine').map((i) => i.id)).not.toContain('switch-as4630')
expect(serversForUsage('management').map((i) => i.id)).toEqual([
'server-mgmt',
'server-mgmt-121h',
'server-mgmt',
])
})

it('sorts eol and withdrawn hardware to the bottom', () => {
const lists = [
serversForUsage('worker'),
serversForUsage('management'),
switchesForRole('leaf'),
]
for (const list of lists) {
const current = list.filter((i) => (i.availability ?? 'current') === 'current')
const eol = list.filter((i) => i.availability === 'eol')
const withdrawn = list.filter((i) => i.availability === 'withdrawn')
expect(list).toEqual([...current, ...eol, ...withdrawn])
}
})

it('offers GPUs only for GPU-capable servers', () => {
expect(gpusForServer('server-microcloud-x13').length).toBeGreaterThan(0)
expect(gpusForServer('server-bigtwin-x11')).toEqual([])
Expand Down
24 changes: 21 additions & 3 deletions src/model/catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -622,18 +622,36 @@ export function portCount(item: CatalogItem, speed: PortSpeed): number {
return item.ports?.find((p) => p.speed === speed)?.count ?? 0
}

// Dropdown order: current hardware first, then eol, then withdrawn.
// Catalog order within each group (the sort is stable).
const availabilityRank: Record<Availability, number> = { current: 0, eol: 1, withdrawn: 2 }

function rankOf(item: CatalogItem): number {
return availabilityRank[item.availability ?? 'current']
}

function byAvailability(a: CatalogItem, b: CatalogItem): number {
return rankOf(a) - rankOf(b)
}

export function switchesForRole(role: SwitchRole): CatalogItem[] {
return Object.values(catalog).filter((i) => i.switchRoles?.includes(role))
return Object.values(catalog)
.filter((i) => i.switchRoles?.includes(role))
.sort(byAvailability)
}

export function serversForUsage(usage: ServerUsage): CatalogItem[] {
return Object.values(catalog).filter((i) => i.serverUsages?.includes(usage))
return Object.values(catalog)
.filter((i) => i.serverUsages?.includes(usage))
.sort(byAvailability)
}

/** GPU models offerable for a server model — empty unless it accepts any. */
export function gpusForServer(serverModelId: string): CatalogItem[] {
if (!catalog[serverModelId]?.gpuCapable) return []
return Object.values(catalog).filter((i) => i.category === 'gpu')
return Object.values(catalog)
.filter((i) => i.category === 'gpu')
.sort(byAvailability)
}

/** How a BOM line names its item: the model people say, else the ordering
Expand Down
Loading