fix(edge/stacks): load template [EE-7109] (#11848)
parent
a28bd349ae
commit
0f5988af49
|
@ -120,10 +120,10 @@ function useTemplate(
|
||||||
id: number | undefined
|
id: number | undefined
|
||||||
) {
|
) {
|
||||||
const customTemplateQuery = useCustomTemplate(id, {
|
const customTemplateQuery = useCustomTemplate(id, {
|
||||||
enabled: !!id && type === 'custom',
|
enabled: type === 'custom',
|
||||||
});
|
});
|
||||||
const appTemplateQuery = useAppTemplate(id, {
|
const appTemplateQuery = useAppTemplate(id, {
|
||||||
enabled: !!id && type === 'app',
|
enabled: type === 'app',
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -13,12 +13,12 @@ import {
|
||||||
edgeStackTemplate,
|
edgeStackTemplate,
|
||||||
upload,
|
upload,
|
||||||
} from '@@/BoxSelector/common-options/build-methods';
|
} from '@@/BoxSelector/common-options/build-methods';
|
||||||
import { WebEditorForm } from '@@/WebEditorForm';
|
|
||||||
import { FileUploadForm } from '@@/form-components/FileUpload';
|
import { FileUploadForm } from '@@/form-components/FileUpload';
|
||||||
|
|
||||||
import { TemplateFieldset } from './TemplateFieldset/TemplateFieldset';
|
import { TemplateFieldset } from './TemplateFieldset/TemplateFieldset';
|
||||||
import { useRenderTemplate } from './useRenderTemplate';
|
import { useRenderTemplate } from './useRenderTemplate';
|
||||||
import { DockerFormValues } from './types';
|
import { DockerFormValues } from './types';
|
||||||
|
import { DockerContentField } from './DockerContentField';
|
||||||
|
|
||||||
const buildMethods = [editor, upload, git, edgeStackTemplate] as const;
|
const buildMethods = [editor, upload, git, edgeStackTemplate] as const;
|
||||||
|
|
||||||
|
@ -78,26 +78,12 @@ export function DockerComposeForm({
|
||||||
|
|
||||||
{(method === editor.value ||
|
{(method === editor.value ||
|
||||||
(method === edgeStackTemplate.value && template)) && (
|
(method === edgeStackTemplate.value && template)) && (
|
||||||
<WebEditorForm
|
<DockerContentField
|
||||||
id="stack-creation-editor"
|
|
||||||
value={values.fileContent}
|
value={values.fileContent}
|
||||||
onChange={(value) => handleChange({ fileContent: value })}
|
onChange={(value) => handleChange({ fileContent: value })}
|
||||||
yaml
|
|
||||||
placeholder="Define or paste the content of your docker compose file here"
|
|
||||||
error={errors?.fileContent}
|
|
||||||
readonly={method === edgeStackTemplate.value && !!template?.GitConfig}
|
readonly={method === edgeStackTemplate.value && !!template?.GitConfig}
|
||||||
data-cy="stack-creation-editor"
|
error={errors?.fileContent}
|
||||||
>
|
/>
|
||||||
You can get more information about Compose file format in the{' '}
|
|
||||||
<a
|
|
||||||
href="https://docs.docker.com/compose/compose-file/"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
official documentation
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</WebEditorForm>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{method === upload.value && (
|
{method === upload.value && (
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { WebEditorForm } from '@@/WebEditorForm';
|
||||||
|
|
||||||
|
export function DockerContentField({
|
||||||
|
error,
|
||||||
|
onChange,
|
||||||
|
readonly,
|
||||||
|
value,
|
||||||
|
}: {
|
||||||
|
value: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
error?: string;
|
||||||
|
readonly?: boolean;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<WebEditorForm
|
||||||
|
id="stack-creation-editor"
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
yaml
|
||||||
|
placeholder="Define or paste the content of your docker compose file here"
|
||||||
|
error={error}
|
||||||
|
readonly={readonly}
|
||||||
|
data-cy="stack-creation-editor"
|
||||||
|
>
|
||||||
|
You can get more information about Compose file format in the{' '}
|
||||||
|
<a
|
||||||
|
href="https://docs.docker.com/compose/compose-file/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
official documentation
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</WebEditorForm>
|
||||||
|
);
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ export function TemplateSelector({
|
||||||
) => void;
|
) => void;
|
||||||
error?: string;
|
error?: string;
|
||||||
}) {
|
}) {
|
||||||
const { options, getTemplate } = useOptions();
|
const { options, getTemplate, selectedValue } = useOptions(value);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControl label="Template" inputId="template_selector" errors={error}>
|
<FormControl label="Template" inputId="template_selector" errors={error}>
|
||||||
|
@ -32,10 +32,8 @@ export function TemplateSelector({
|
||||||
inputId="template_selector"
|
inputId="template_selector"
|
||||||
formatGroupLabel={GroupLabel}
|
formatGroupLabel={GroupLabel}
|
||||||
placeholder="Select an Edge stack template"
|
placeholder="Select an Edge stack template"
|
||||||
value={{
|
options={options}
|
||||||
templateId: value.templateId,
|
value={selectedValue}
|
||||||
type: value.type,
|
|
||||||
}}
|
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
onChange(undefined, undefined);
|
onChange(undefined, undefined);
|
||||||
|
@ -48,14 +46,19 @@ export function TemplateSelector({
|
||||||
}
|
}
|
||||||
onChange(getTemplate({ type, id: templateId }), type);
|
onChange(getTemplate({ type, id: templateId }), type);
|
||||||
}}
|
}}
|
||||||
options={options}
|
|
||||||
data-cy="edge-stacks-create-template-selector"
|
data-cy="edge-stacks-create-template-selector"
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useOptions() {
|
interface Option {
|
||||||
|
label: string;
|
||||||
|
templateId?: number;
|
||||||
|
type: 'app' | 'custom';
|
||||||
|
}
|
||||||
|
|
||||||
|
function useOptions(value: SelectedTemplateValue) {
|
||||||
const customTemplatesQuery = useCustomTemplates({
|
const customTemplatesQuery = useCustomTemplates({
|
||||||
params: {
|
params: {
|
||||||
edge: true,
|
edge: true,
|
||||||
|
@ -71,43 +74,75 @@ function useOptions() {
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const appTemplateOptions: Array<Option> = useMemo(
|
||||||
|
() =>
|
||||||
|
appTemplatesQuery.data?.map(
|
||||||
|
(template) =>
|
||||||
|
({
|
||||||
|
label: `${template.Title} - ${template.Description}`,
|
||||||
|
|
||||||
|
templateId: template.Id,
|
||||||
|
type: 'app',
|
||||||
|
}) satisfies Option
|
||||||
|
) || [],
|
||||||
|
[appTemplatesQuery.data]
|
||||||
|
);
|
||||||
|
|
||||||
|
const customTemplateOptions: Array<Option> = useMemo(
|
||||||
|
() =>
|
||||||
|
customTemplatesQuery.data && customTemplatesQuery.data.length > 0
|
||||||
|
? customTemplatesQuery.data.map(
|
||||||
|
(template) =>
|
||||||
|
({
|
||||||
|
label: `${template.Title} - ${template.Description}`,
|
||||||
|
|
||||||
|
templateId: template.Id,
|
||||||
|
type: 'custom' as 'app' | 'custom',
|
||||||
|
}) satisfies Option
|
||||||
|
)
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
label: 'No edge custom templates available',
|
||||||
|
|
||||||
|
templateId: undefined,
|
||||||
|
type: 'custom' as 'app' | 'custom',
|
||||||
|
} satisfies Option,
|
||||||
|
],
|
||||||
|
[customTemplatesQuery.data]
|
||||||
|
);
|
||||||
|
|
||||||
const options = useMemo(
|
const options = useMemo(
|
||||||
() =>
|
() =>
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
label: 'Edge App Templates',
|
label: 'Edge App Templates',
|
||||||
options:
|
options: appTemplateOptions,
|
||||||
appTemplatesQuery.data?.map((template) => ({
|
|
||||||
label: `${template.Title} - ${template.Description}`,
|
|
||||||
|
|
||||||
templateId: template.Id,
|
|
||||||
type: 'app' as 'app' | 'custom',
|
|
||||||
})) || [],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Edge Custom Templates',
|
label: 'Edge Custom Templates',
|
||||||
options:
|
options: customTemplateOptions,
|
||||||
customTemplatesQuery.data && customTemplatesQuery.data.length > 0
|
|
||||||
? customTemplatesQuery.data.map((template) => ({
|
|
||||||
label: `${template.Title} - ${template.Description}`,
|
|
||||||
|
|
||||||
templateId: template.Id,
|
|
||||||
type: 'custom' as 'app' | 'custom',
|
|
||||||
}))
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
label: 'No edge custom templates available',
|
|
||||||
|
|
||||||
templateId: undefined,
|
|
||||||
type: undefined,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
] as const,
|
] as const,
|
||||||
[appTemplatesQuery.data, customTemplatesQuery.data]
|
[appTemplateOptions, customTemplateOptions]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { options, getTemplate };
|
const selectedValue: Option | undefined = useMemo(() => {
|
||||||
|
if (!value.templateId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.type === 'app') {
|
||||||
|
return appTemplateOptions.find(
|
||||||
|
(template) => template.templateId === value.templateId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return customTemplateOptions.find(
|
||||||
|
(template) => template.templateId === value.templateId
|
||||||
|
);
|
||||||
|
}, [value.templateId, value.type, customTemplateOptions, appTemplateOptions]);
|
||||||
|
|
||||||
|
return { options, getTemplate, selectedValue };
|
||||||
|
|
||||||
function getTemplate({ type, id }: { type: 'app' | 'custom'; id: number }) {
|
function getTemplate({ type, id }: { type: 'app' | 'custom'; id: number }) {
|
||||||
if (type === 'app') {
|
if (type === 'app') {
|
||||||
|
|
|
@ -16,13 +16,18 @@ export function useRenderTemplate(
|
||||||
templateValues: DockerFormValues['templateValues'],
|
templateValues: DockerFormValues['templateValues'],
|
||||||
setValues: (values: SetStateAction<DockerFormValues>) => void
|
setValues: (values: SetStateAction<DockerFormValues>) => void
|
||||||
) {
|
) {
|
||||||
const templateQuery = useCustomTemplate(templateValues.templateId);
|
const templateQuery = useCustomTemplate(templateValues.templateId, {
|
||||||
|
enabled: templateValues.type === 'custom',
|
||||||
|
});
|
||||||
|
|
||||||
const template = templateQuery.data;
|
const template = templateQuery.data;
|
||||||
|
|
||||||
const templateFileQuery = useCustomTemplateFile(
|
const templateFileQuery = useCustomTemplateFile(
|
||||||
templateValues.templateId,
|
templateValues.templateId,
|
||||||
!!template?.GitConfig
|
!!template?.GitConfig,
|
||||||
|
{
|
||||||
|
enabled: templateValues.type === 'custom',
|
||||||
|
}
|
||||||
);
|
);
|
||||||
const [renderedFile, setRenderedFile] = useState<string>('');
|
const [renderedFile, setRenderedFile] = useState<string>('');
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ export function useAppTemplates<T = Array<TemplateViewModel>>({
|
||||||
|
|
||||||
export function useAppTemplate(
|
export function useAppTemplate(
|
||||||
id: AppTemplate['id'] | undefined,
|
id: AppTemplate['id'] | undefined,
|
||||||
{ enabled = true }: { enabled?: boolean } = {}
|
{ enabled }: { enabled?: boolean } = {}
|
||||||
) {
|
) {
|
||||||
const templateListQuery = useAppTemplates({ enabled: !!id && enabled });
|
const templateListQuery = useAppTemplates({ enabled: !!id && enabled });
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ export function useAppTemplate(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: template,
|
data: template,
|
||||||
isLoading: templateListQuery.isLoading,
|
isLoading: templateListQuery.isInitialLoading,
|
||||||
error: templateListQuery.error,
|
error: templateListQuery.error,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ export async function getCustomTemplate(id: CustomTemplate['Id']) {
|
||||||
|
|
||||||
export function useCustomTemplate(
|
export function useCustomTemplate(
|
||||||
id?: CustomTemplate['Id'],
|
id?: CustomTemplate['Id'],
|
||||||
{ enabled = true }: { enabled?: boolean } = {}
|
{ enabled }: { enabled?: boolean } = {}
|
||||||
) {
|
) {
|
||||||
return useQuery(queryKeys.item(id!), () => getCustomTemplate(id!), {
|
return useQuery(queryKeys.item(id!), () => getCustomTemplate(id!), {
|
||||||
...withGlobalError('Unable to retrieve custom template'),
|
...withGlobalError('Unable to retrieve custom template'),
|
||||||
|
|
|
@ -12,13 +12,17 @@ type CustomTemplateFileContent = {
|
||||||
FileContent: string;
|
FileContent: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useCustomTemplateFile(id?: CustomTemplate['Id'], git = false) {
|
export function useCustomTemplateFile(
|
||||||
|
id?: CustomTemplate['Id'],
|
||||||
|
git = false,
|
||||||
|
{ enabled }: { enabled?: boolean } = {}
|
||||||
|
) {
|
||||||
return useQuery(
|
return useQuery(
|
||||||
id ? queryKeys.file(id, { git }) : [],
|
queryKeys.file(id!, { git }),
|
||||||
() => getCustomTemplateFile({ id: id!, git }),
|
() => getCustomTemplateFile({ id: id!, git }),
|
||||||
{
|
{
|
||||||
...withGlobalError('Failed to get custom template file'),
|
...withGlobalError('Failed to get custom template file'),
|
||||||
enabled: !!id,
|
enabled: !!id && enabled,
|
||||||
// there's nothing to do with a new file content, so we're disabling refetch
|
// there's nothing to do with a new file content, so we're disabling refetch
|
||||||
refetchOnReconnect: false,
|
refetchOnReconnect: false,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
|
|
Loading…
Reference in New Issue