* List presets for a template. * @param templateName - Template name * @param org - Organization name for disambiguation (optional)
(templateName: string, org?: string)
| 915 | * @param org - Organization name for disambiguation (optional) |
| 916 | */ |
| 917 | async listPresets(templateName: string, org?: string): Promise<CoderListPresetsResult> { |
| 918 | try { |
| 919 | const args = ["templates", "presets", "list", templateName, "--output=json"]; |
| 920 | if (org) args.push("--org", org); |
| 921 | const stdout = await this.runCoderJsonCommand(args); |
| 922 | |
| 923 | // Handle empty output or non-JSON info messages (no presets). |
| 924 | // CLI prints "No presets found for template ..." to stdout even with --output=json |
| 925 | // because the Go handler returns early before the formatter runs. |
| 926 | if (!stdout.trim() || !stdout.trimStart().startsWith("[")) { |
| 927 | return { ok: true, presets: [] }; |
| 928 | } |
| 929 | |
| 930 | // CLI returns [{TemplatePreset: {ID, Name, ...}}, ...] wrapper structure |
| 931 | const raw = JSON.parse(stdout) as Array<{ |
| 932 | TemplatePreset: { |
| 933 | ID: string; |
| 934 | Name: string; |
| 935 | Description?: string; |
| 936 | Default?: boolean; |
| 937 | }; |
| 938 | }>; |
| 939 | |
| 940 | return { |
| 941 | ok: true, |
| 942 | presets: raw.map((entry) => ({ |
| 943 | id: entry.TemplatePreset.ID, |
| 944 | name: entry.TemplatePreset.Name, |
| 945 | description: entry.TemplatePreset.Description, |
| 946 | isDefault: entry.TemplatePreset.Default ?? false, |
| 947 | })), |
| 948 | }; |
| 949 | } catch (error) { |
| 950 | const message = sanitizeCoderCliErrorForUi(error); |
| 951 | // Surface CLI failures so the UI doesn't show "No presets" incorrectly. |
| 952 | log.warn("Failed to list Coder presets", { templateName, error }); |
| 953 | return { ok: false, error: message || "Unknown error" }; |
| 954 | } |
| 955 | } |
| 956 | |
| 957 | /** |
| 958 | * Check if a Coder workspace exists by name. |
no test coverage detected