1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-18 21:09:40 +02:00

fix(template): app template v3 error [BE-11998] (#854)

This commit is contained in:
Oscar Zhou 2025-07-05 02:49:33 +12:00 committed by GitHub
parent 8ffe4e284a
commit c20a8b5a68
6 changed files with 21 additions and 19 deletions

View file

@ -40,11 +40,13 @@ func (handler *Handler) fetchTemplates() (*listResponse, *httperror.HandlerError
}
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&body)
if err != nil {
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
return nil, httperror.InternalServerError("Unable to parse template file", err)
}
for i := range body.Templates {
body.Templates[i].ID = portainer.TemplateID(i + 1)
}
return body, nil
}

View file

@ -80,10 +80,7 @@ test('The form should submit the correct request body for a given app template',
// fill in the name and select the docker edge group
const user = userEvent.setup();
await user.type(getByRole('textbox', { name: 'Name *' }), 'my-stack');
await user.type(
getByRole('textbox', { name: 'License key *' }),
'license-123'
);
await user.type(getByRole('textbox', { name: 'License key' }), 'license-123');
const selectElement = getByLabelText('Edge groups');
await selectEvent.select(selectElement, 'docker');

View file

@ -51,7 +51,7 @@ test('calls onChange when input value changes', async () => {
const inputElement = screen.getByDisplayValue(value.VAR1);
await user.clear(inputElement);
expect(onChange).toHaveBeenCalledWith({ VAR1: '' });
expect(onChange).toHaveBeenCalledWith({ VAR1: undefined });
const newValue = 'New Value';
await user.type(inputElement, newValue);
@ -107,11 +107,14 @@ test('validates env vars fieldset', () => {
]);
const validData = { VAR1: 'Value 1', VAR2: 'Value 2' };
const invalidData = { VAR1: '', VAR2: 'Value 2' };
const emptyData = { VAR1: '', VAR2: 'Value 2' };
const undefinedData = { VAR1: undefined, VAR2: 'Value 2' };
const validResult = schema.isValidSync(validData);
const invalidResult = schema.isValidSync(invalidData);
const emptyResult = schema.isValidSync(emptyData);
const undefinedResult = schema.isValidSync(undefinedData);
expect(validResult).toBe(true);
expect(invalidResult).toBe(false);
expect(emptyResult).toBe(true);
expect(undefinedResult).toBe(true);
});

View file

@ -6,7 +6,7 @@ import { TemplateEnv } from '@/react/portainer/templates/app-templates/types';
import { FormControl } from '@@/form-components/FormControl';
import { Input, Select } from '@@/form-components/Input';
type Value = Record<string, string>;
type Value = Record<string, string | undefined>;
export { type Value as EnvVarsValue };
@ -27,7 +27,7 @@ export function EnvVarsFieldset({
<Item
key={env.name}
option={env}
value={values[env.name]}
value={values[env.name] || ''}
onChange={(value) => handleChange(env.name, value)}
errors={errors?.[env.name]}
/>
@ -36,7 +36,7 @@ export function EnvVarsFieldset({
);
function handleChange(name: string, envValue: string) {
onChange({ ...values, [name]: envValue });
onChange({ ...values, [name]: envValue || undefined });
}
}
@ -55,7 +55,7 @@ function Item({
return (
<FormControl
label={option.label || option.name}
required={!option.preset}
required={false}
errors={errors}
inputId={inputId}
>
@ -101,7 +101,9 @@ export function envVarsFieldsetValidation(
): SchemaOf<Value> {
return object(
Object.fromEntries(
definitions.map((v) => [v.name, string().required('Required')])
definitions
.filter((v) => !v.preset)
.map((v) => [v.name, string().optional()])
)
);
}

View file

@ -2,6 +2,6 @@ import { AccessControlFormData } from '@/react/portainer/access-control/types';
export interface FormValues {
name: string;
envVars: Record<string, string>;
envVars: Record<string, string | undefined>;
accessControl: AccessControlFormData;
}

View file

@ -88,10 +88,8 @@ function setTemplatesV3(this: TemplateViewModel, template: AppTemplate) {
this.Id = template.id;
}
let templateV2ID = 0;
function setTemplatesV2(this: TemplateViewModel, template: AppTemplate) {
this.Id = templateV2ID++;
this.Id = template.id;
this.Title = template.title;
this.Type = template.type;
this.Description = template.description;