Skip to content

Commit a1dde71

Browse files
Fix YAML generation and resource parsing for templates
- Disable line wrapping in jsYaml.dump to preserve multi-line command formatting from templates - Handle numeric and object resource values (e.g. gpu: 0) in addition to string shorthand - Show empty placeholder for disabled offer cards Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent f2fa140 commit a1dde71

File tree

3 files changed

+56
-46
lines changed

3 files changed

+56
-46
lines changed

frontend/src/pages/Offers/List/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ export const OfferList: React.FC<OfferListProps> = ({
218218
{...props}
219219
entireCardClickable
220220
items={disabled ? [] : items}
221+
empty={disabled ? ' ' : undefined}
221222
cardDefinition={{
222223
header: (gpu) => gpu.name,
223224
sections,

frontend/src/pages/Runs/Launch/helpers/getRunSpecConfigurationResources.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ const parseRange = (rangeString: string) => {
1919
};
2020

2121
export const getRunSpecConfigurationResources = (json: unknown): TDevEnvironmentConfiguration['resources'] => {
22-
const { gpu, cpu, memory, shm_size, disk } = (json ?? {}) as { [key: string]: string };
22+
const { gpu, cpu, memory, shm_size, disk } = (json ?? {}) as Record<string, unknown>;
2323
const result: TDevEnvironmentConfiguration['resources'] = {};
2424

25-
let gpuResources: TGPUResources = {};
26-
27-
if (typeof gpu === 'string') {
28-
const attributes = ((gpu as string) ?? '').split(':');
25+
if (typeof gpu === 'number') {
26+
result['gpu'] = gpu;
27+
} else if (typeof gpu === 'string') {
28+
const gpuResources: TGPUResources = {};
29+
const attributes = gpu.split(':');
2930

3031
attributes.forEach((attribute, index) => {
3132
if (isVendor(attribute)) {
@@ -52,38 +53,43 @@ export const getRunSpecConfigurationResources = (json: unknown): TDevEnvironment
5253
return;
5354
}
5455
});
55-
} else if (typeof gpu === 'object') {
56-
gpuResources = gpu;
56+
result['gpu'] = gpuResources;
57+
} else if (typeof gpu === 'object' && gpu !== null) {
58+
result['gpu'] = gpu as TGPUResources;
5759
}
5860

59-
result['gpu'] = gpuResources;
60-
61-
if (memory && isMemory(memory)) {
61+
if (typeof memory === 'string' && isMemory(memory)) {
62+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
63+
// @ts-expect-error
6264
result['memory'] = parseRange(memory);
6365
}
6466

6567
if (shm_size) {
66-
const shmSizeNum = parseInt(shm_size, 10);
68+
const shmSizeStr = String(shm_size);
69+
const shmSizeNum = parseInt(shmSizeStr, 10);
6770

6871
if (!isNaN(shmSizeNum)) {
6972
result['shm_size'] = shmSizeNum;
7073
} else {
71-
result['shm_size'] = shm_size;
74+
result['shm_size'] = shmSizeStr;
7275
}
7376
}
7477

7578
if (cpu) {
76-
const cpuNum = parseInt(cpu, 10);
79+
const cpuStr = String(cpu);
80+
const cpuNum = parseInt(cpuStr, 10);
7781

7882
if (!isNaN(cpuNum)) {
7983
result['cpu'] = cpuNum;
8084
} else {
81-
result['cpu'] = cpu;
85+
result['cpu'] = cpuStr;
8286
}
8387
}
8488

85-
if (disk && isMemory(disk)) {
89+
if (typeof disk === 'string' && isMemory(disk)) {
8690
result['disk'] = {
91+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
92+
// @ts-expect-error
8793
size: parseRange(disk),
8894
};
8995
}

frontend/src/pages/Runs/Launch/hooks/useGenerateYaml.ts

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,36 +26,39 @@ export const useGenerateYaml = ({ formValues, configuration, envParam, backends
2626
envEntries.push(...(configuration['env'] as string[]));
2727
}
2828

29-
return jsYaml.dump({
30-
...configuration,
31-
32-
...(name ? { name } : {}),
33-
...(ide ? { ide } : {}),
34-
...(docker ? { docker } : {}),
35-
...(image ? { image } : {}),
36-
...(python ? { python } : {}),
37-
...(envEntries.length > 0 ? { env: envEntries } : {}),
38-
39-
...(gpuEnabled && offer
40-
? {
41-
resources: {
42-
gpu: `${offer.name}:${round(convertMiBToGB(offer.memory_mib))}GB:${renderRange(offer.count)}`,
43-
},
44-
45-
...(backends && backends.length > 0 ? { backends } : {}),
46-
...(offer.spot.length === 1 ? { spot_policy: offer.spot[0] } : {}),
47-
...(offer.spot.length > 1 ? { spot_policy: 'auto' } : {}),
48-
}
49-
: {}),
50-
...(!gpuEnabled ? { resources: { gpu: 0 } } : {}),
51-
52-
...(repo_url || repo_path
53-
? {
54-
repos: [[repo_url?.trim(), repo_path?.trim()].filter(Boolean).join(':')],
55-
}
56-
: {}),
57-
58-
...(working_dir ? { working_dir } : {}),
59-
});
29+
return jsYaml.dump(
30+
{
31+
...configuration,
32+
33+
...(name ? { name } : {}),
34+
...(ide ? { ide } : {}),
35+
...(docker ? { docker } : {}),
36+
...(image ? { image } : {}),
37+
...(python ? { python } : {}),
38+
...(envEntries.length > 0 ? { env: envEntries } : {}),
39+
40+
...(gpuEnabled && offer
41+
? {
42+
resources: {
43+
gpu: `${offer.name}:${round(convertMiBToGB(offer.memory_mib))}GB:${renderRange(offer.count)}`,
44+
},
45+
46+
...(backends && backends.length > 0 ? { backends } : {}),
47+
...(offer.spot.length === 1 ? { spot_policy: offer.spot[0] } : {}),
48+
...(offer.spot.length > 1 ? { spot_policy: 'auto' } : {}),
49+
}
50+
: {}),
51+
...(!gpuEnabled ? { resources: { gpu: 0 } } : {}),
52+
53+
...(repo_url || repo_path
54+
? {
55+
repos: [[repo_url?.trim(), repo_path?.trim()].filter(Boolean).join(':')],
56+
}
57+
: {}),
58+
59+
...(working_dir ? { working_dir } : {}),
60+
},
61+
{ lineWidth: -1 },
62+
);
6063
}, [formValues, configuration, envParam, backends]);
6164
};

0 commit comments

Comments
 (0)