57 lines
3.0 KiB
TypeScript
57 lines
3.0 KiB
TypeScript
import { T5_ZOMBIE_MAPS, T6_ZOMBIE_MAPS } from './map-aliases.js';
|
|
import { gameTitle } from './ui/server-labels.js';
|
|
|
|
export interface LibraryVersion {
|
|
id: number; version: number; sha256: string; size: number;
|
|
state: 'untested' | 'tested' | 'test-failed'; uploaded_at: string;
|
|
}
|
|
export interface LibraryScript {
|
|
id: number; name: string; target_rel_path: string;
|
|
scope_type: 'game' | 'map' | null; scope_value: string | null;
|
|
current_version_id: number | null;
|
|
currentVersion: LibraryVersion | null; latestVersion: LibraryVersion | null;
|
|
versionCount: number; servers: string[]; runningBetaId: number | null;
|
|
}
|
|
export type ScriptStatus = 'untested' | 'testing' | 'tested' | 'failed' | 'promoted' | 'empty';
|
|
export const statusLabels: Record<ScriptStatus, string> = {
|
|
untested: 'Needs testing', testing: 'Beta active', tested: 'Test passed',
|
|
failed: 'Test failed', promoted: 'Promoted', empty: 'No versions'
|
|
};
|
|
export function scriptStatus(s: LibraryScript): ScriptStatus {
|
|
if (s.runningBetaId !== null) return 'testing';
|
|
if (!s.latestVersion) return 'empty';
|
|
if (s.latestVersion.id === s.current_version_id) return 'promoted';
|
|
return s.latestVersion.state === 'test-failed' ? 'failed' : s.latestVersion.state;
|
|
}
|
|
export function canTest(s: LibraryScript): boolean {
|
|
return s.runningBetaId === null && s.latestVersion !== null && s.latestVersion.id !== s.current_version_id;
|
|
}
|
|
export function mapLabel(canonical: string): string {
|
|
const matches = [...T5_ZOMBIE_MAPS, ...T6_ZOMBIE_MAPS].filter(m => m.canonical === canonical);
|
|
return matches.length > 1 ? `${matches[0].friendly} + ${matches.length - 1} variants` : matches[0]?.friendly ?? canonical;
|
|
}
|
|
export function scopeLabel(s: Pick<LibraryScript, 'scope_type' | 'scope_value'>): string {
|
|
return s.scope_type === 'game' ? gameTitle(s.scope_value)
|
|
: s.scope_type === 'map' ? mapLabel(s.scope_value ?? '') : 'Unscoped';
|
|
}
|
|
export interface BetaSelection { scriptId: number; versionId: number; }
|
|
export function betaSelectionHref(selections: BetaSelection[]): string {
|
|
const query = new URLSearchParams();
|
|
for (const s of selections) query.append('artifact', `${s.scriptId}:${s.versionId}`);
|
|
return `/betas/new?${query}`;
|
|
}
|
|
export function parseBetaSelection(query: URLSearchParams): BetaSelection[] {
|
|
const values = query.getAll('artifact');
|
|
if (!values.length && query.has('pluginId')) values.push(`${query.get('pluginId')}:${query.get('versionId')}`);
|
|
const seen = new Set<number>();
|
|
return values.map(value => {
|
|
if (!/^[1-9]\d*:[1-9]\d*$/.test(value)) throw new Error('The beta selection link is invalid. Choose artifacts below.');
|
|
const [scriptId, versionId] = value.split(':').map(Number);
|
|
if (!Number.isSafeInteger(scriptId) || !Number.isSafeInteger(versionId) || seen.has(scriptId)) {
|
|
throw new Error('The beta selection link contains invalid or repeated artifacts. Choose artifacts below.');
|
|
}
|
|
seen.add(scriptId);
|
|
return { scriptId, versionId };
|
|
});
|
|
}
|