fixes, dev templates, etc
This commit is contained in:
2201
apps/api/devTemplates.yaml
Normal file
2201
apps/api/devTemplates.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@ import { verifyRemoteDockerEngineFn } from './routes/api/v1/destinations/handler
|
|||||||
import { checkContainer } from './lib/docker';
|
import { checkContainer } from './lib/docker';
|
||||||
import { migrateServicesToNewTemplate } from './lib';
|
import { migrateServicesToNewTemplate } from './lib';
|
||||||
import { getTemplates } from './lib/services';
|
import { getTemplates } from './lib/services';
|
||||||
|
import { refreshTemplates } from './routes/api/v1/handlers';
|
||||||
declare module 'fastify' {
|
declare module 'fastify' {
|
||||||
interface FastifyInstance {
|
interface FastifyInstance {
|
||||||
config: {
|
config: {
|
||||||
@@ -129,22 +130,21 @@ const host = '0.0.0.0';
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { default: got } = await import('got')
|
const { default: got } = await import('got')
|
||||||
let templates = {}
|
|
||||||
try {
|
try {
|
||||||
|
if (isDev) {
|
||||||
|
const response = await fs.readFile('./devTemplates.yaml', 'utf8')
|
||||||
|
await fs.writeFile('./template.json', JSON.stringify(yaml.load(response), null, 2))
|
||||||
|
} else {
|
||||||
const response = await got.get('https://get.coollabs.io/coolify/service-templates.yaml').text()
|
const response = await got.get('https://get.coollabs.io/coolify/service-templates.yaml').text()
|
||||||
templates = yaml.load(response)
|
await fs.writeFile('/app/template.json', JSON.stringify(yaml.load(response), null, 2))
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Couldn't get latest templates.")
|
console.log("Couldn't get latest templates.")
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDev) {
|
await migrateServicesToNewTemplate()
|
||||||
await fs.writeFile('./template.json', JSON.stringify(templates, null, 2))
|
|
||||||
} else {
|
|
||||||
await fs.writeFile('/app/template.json', JSON.stringify(templates, null, 2))
|
|
||||||
}
|
|
||||||
const templateJson = await getTemplates()
|
|
||||||
await migrateServicesToNewTemplate(templateJson)
|
|
||||||
|
|
||||||
await fastify.listen({ port, host })
|
await fastify.listen({ port, host })
|
||||||
console.log(`Coolify's API is listening on ${host}:${port}`);
|
console.log(`Coolify's API is listening on ${host}:${port}`);
|
||||||
@@ -169,10 +169,11 @@ const host = '0.0.0.0';
|
|||||||
await cleanupStorage()
|
await cleanupStorage()
|
||||||
}, 60000 * 10)
|
}, 60000 * 10)
|
||||||
|
|
||||||
// checkProxies and checkFluentBit
|
// checkProxies, checkFluentBit & refresh templates
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
await checkProxies();
|
await checkProxies();
|
||||||
await checkFluentBit();
|
await checkFluentBit();
|
||||||
|
await refreshTemplates()
|
||||||
}, 10000)
|
}, 10000)
|
||||||
|
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
import cuid from "cuid";
|
import cuid from "cuid";
|
||||||
import { decrypt, encrypt, generatePassword, getDomain, prisma } from "./lib/common";
|
import { decrypt, encrypt, generatePassword, getDomain, prisma } from "./lib/common";
|
||||||
|
import { getTemplates } from "./lib/services";
|
||||||
import { includeServices } from "./lib/services/common";
|
import { includeServices } from "./lib/services/common";
|
||||||
|
|
||||||
export async function migrateServicesToNewTemplate(templates: any) {
|
export async function migrateServicesToNewTemplate() {
|
||||||
// This function migrates old hardcoded services to the new template based services
|
// This function migrates old hardcoded services to the new template based services
|
||||||
try {
|
try {
|
||||||
|
let templates = await getTemplates()
|
||||||
const services: any = await prisma.service.findMany({ include: includeServices })
|
const services: any = await prisma.service.findMany({ include: includeServices })
|
||||||
for (const service of services) {
|
for (const service of services) {
|
||||||
const { id } = service
|
const { id } = service
|
||||||
|
@@ -244,7 +244,11 @@ export async function isDNSValid(hostname: any, domain: string): Promise<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getDomain(domain: string): string {
|
export function getDomain(domain: string): string {
|
||||||
|
if (domain) {
|
||||||
return domain?.replace('https://', '').replace('http://', '');
|
return domain?.replace('https://', '').replace('http://', '');
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function isDomainConfigured({
|
export async function isDomainConfigured({
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@ export async function cleanupManually(request: FastifyRequest) {
|
|||||||
return errorHandler({ status, message });
|
return errorHandler({ status, message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function refreshTemplates(request: FastifyRequest) {
|
export async function refreshTemplates() {
|
||||||
try {
|
try {
|
||||||
const { default: got } = await import('got')
|
const { default: got } = await import('got')
|
||||||
let templates = {}
|
let templates = {}
|
||||||
|
@@ -58,7 +58,7 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
|
|
||||||
fastify.post('/internal/refreshTemplates', {
|
fastify.post('/internal/refreshTemplates', {
|
||||||
onRequest: [fastify.authenticate]
|
onRequest: [fastify.authenticate]
|
||||||
}, async (request) => await refreshTemplates(request));
|
}, async () => await refreshTemplates());
|
||||||
};
|
};
|
||||||
|
|
||||||
export default root;
|
export default root;
|
||||||
|
@@ -136,13 +136,12 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
|
|||||||
const description = variable?.description
|
const description = variable?.description
|
||||||
const defaultValue = variable?.defaultValue
|
const defaultValue = variable?.defaultValue
|
||||||
const main = variable?.main || '$$id'
|
const main = variable?.main || '$$id'
|
||||||
const extras = variable?.extras
|
if (envValue.startsWith('$$config') || variable?.showOnUI) {
|
||||||
if (envValue.startsWith('$$config') || extras?.isVisibleOnUI) {
|
|
||||||
if (envValue.startsWith('$$config_coolify')) {
|
if (envValue.startsWith('$$config_coolify')) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
parsedTemplate[realKey].environment.push(
|
parsedTemplate[realKey].environment.push(
|
||||||
{ name: envKey, value: envValue, main, label, description, defaultValue, extras }
|
{ name: envKey, value: envValue, main, label, description, defaultValue }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,10 +152,10 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
|
|||||||
if (proxyValue.domain) {
|
if (proxyValue.domain) {
|
||||||
const variable = foundTemplate.variables.find(v => v.id === proxyValue.domain)
|
const variable = foundTemplate.variables.find(v => v.id === proxyValue.domain)
|
||||||
if (variable) {
|
if (variable) {
|
||||||
const { id, name, label, description, defaultValue, extras } = variable
|
const { id, name, label, description, defaultValue, required = false } = variable
|
||||||
const found = await prisma.serviceSetting.findFirst({ where: { variableName: proxyValue.domain } })
|
const found = await prisma.serviceSetting.findFirst({ where: { variableName: proxyValue.domain } })
|
||||||
parsedTemplate[realKey].fqdns.push(
|
parsedTemplate[realKey].fqdns.push(
|
||||||
{ id, name, value: found?.value || '', label, description, defaultValue, extras }
|
{ id, name, value: found?.value || '', label, description, defaultValue, required }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,9 +185,9 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
|
|||||||
if (variableName.startsWith('$$config_coolify')) {
|
if (variableName.startsWith('$$config_coolify')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (service.fqdn && value === '$$generate_fqdn') {
|
if (value === '$$generate_fqdn') {
|
||||||
strParsedTemplate = strParsedTemplate.replaceAll(variableName, service.fqdn)
|
strParsedTemplate = strParsedTemplate.replaceAll(variableName, service.fqdn || '')
|
||||||
} else if (service.fqdn && value === '$$generate_domain') {
|
} else if (value === '$$generate_domain') {
|
||||||
strParsedTemplate = strParsedTemplate.replaceAll(variableName, getDomain(service.fqdn))
|
strParsedTemplate = strParsedTemplate.replaceAll(variableName, getDomain(service.fqdn))
|
||||||
} else if (service.destinationDocker?.network && value === '$$generate_network') {
|
} else if (service.destinationDocker?.network && value === '$$generate_network') {
|
||||||
strParsedTemplate = strParsedTemplate.replaceAll(variableName, service.destinationDocker.network)
|
strParsedTemplate = strParsedTemplate.replaceAll(variableName, service.destinationDocker.network)
|
||||||
@@ -260,7 +259,9 @@ export async function saveServiceType(request: FastifyRequest<SaveServiceType>,
|
|||||||
const regex = /^\$\$.*\((\d+)\)$/g;
|
const regex = /^\$\$.*\((\d+)\)$/g;
|
||||||
const length = Number(regex.exec(defaultValue)?.[1]) || undefined
|
const length = Number(regex.exec(defaultValue)?.[1]) || undefined
|
||||||
if (variable.defaultValue.startsWith('$$generate_password')) {
|
if (variable.defaultValue.startsWith('$$generate_password')) {
|
||||||
|
console.log(variable)
|
||||||
variable.value = generatePassword({ length });
|
variable.value = generatePassword({ length });
|
||||||
|
console.log(variable.value)
|
||||||
} else if (variable.defaultValue.startsWith('$$generate_hex')) {
|
} else if (variable.defaultValue.startsWith('$$generate_hex')) {
|
||||||
variable.value = generatePassword({ length, isHex: true });
|
variable.value = generatePassword({ length, isHex: true });
|
||||||
} else if (variable.defaultValue.startsWith('$$generate_username')) {
|
} else if (variable.defaultValue.startsWith('$$generate_username')) {
|
||||||
|
@@ -374,6 +374,7 @@ export async function traefikConfiguration(request, reply) {
|
|||||||
type,
|
type,
|
||||||
destinationDockerId,
|
destinationDockerId,
|
||||||
dualCerts,
|
dualCerts,
|
||||||
|
serviceSetting
|
||||||
} = service;
|
} = service;
|
||||||
if (destinationDockerId) {
|
if (destinationDockerId) {
|
||||||
const templates = await getTemplates();
|
const templates = await getTemplates();
|
||||||
@@ -387,13 +388,17 @@ export async function traefikConfiguration(request, reply) {
|
|||||||
const { proxy } = found.services[oneService];
|
const { proxy } = found.services[oneService];
|
||||||
for (const configuration of proxy) {
|
for (const configuration of proxy) {
|
||||||
const publicPort = service[type]?.publicPort;
|
const publicPort = service[type]?.publicPort;
|
||||||
|
if (configuration.domain) {
|
||||||
|
const setting = serviceSetting.find((a) => a.variableName === configuration.domain);
|
||||||
|
configuration.domain = configuration.domain.replace(configuration.domain, setting.value);
|
||||||
|
}
|
||||||
if (fqdn) {
|
if (fqdn) {
|
||||||
data.services.push({
|
data.services.push({
|
||||||
id: oneService,
|
id: oneService,
|
||||||
publicPort,
|
publicPort,
|
||||||
fqdn,
|
fqdn,
|
||||||
dualCerts,
|
dualCerts,
|
||||||
configuration
|
configuration,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,17 +409,20 @@ export async function traefikConfiguration(request, reply) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const service of data.services) {
|
for (const service of data.services) {
|
||||||
const { id, fqdn, dualCerts, configuration: { port, pathPrefix = '/' }, isCustomSSL = false } = service
|
let { id, fqdn, dualCerts, configuration: { port, pathPrefix = '/', domain: customDomain }, isCustomSSL = false } = service
|
||||||
|
if (customDomain) {
|
||||||
|
fqdn = customDomain
|
||||||
|
}
|
||||||
const domain = getDomain(fqdn);
|
const domain = getDomain(fqdn);
|
||||||
const nakedDomain = domain.replace(/^www\./, '');
|
const nakedDomain = domain.replace(/^www\./, '');
|
||||||
const isHttps = fqdn.startsWith('https://');
|
const isHttps = fqdn.startsWith('https://');
|
||||||
const isWWW = fqdn.includes('www.');
|
const isWWW = fqdn.includes('www.');
|
||||||
if (isHttps) {
|
if (isHttps) {
|
||||||
traefik.http.routers[id] = generateHttpRouter(id, nakedDomain, pathPrefix)
|
traefik.http.routers[`${id}-${port || 'default'}`] = generateHttpRouter(`${id}-${port || 'default'}`, nakedDomain, pathPrefix)
|
||||||
traefik.http.routers[`${id}-secure`] = generateProtocolRedirectRouter(id, nakedDomain, pathPrefix, 'http-to-https')
|
traefik.http.routers[`${id}-${port || 'default'}-secure`] = generateProtocolRedirectRouter(`${id}-${port || 'default'}-secure`, nakedDomain, pathPrefix, 'http-to-https')
|
||||||
traefik.http.services[id] = generateLoadBalancerService(id, port)
|
traefik.http.services[`${id}-${port || 'default'}`] = generateLoadBalancerService(id, port)
|
||||||
if (dualCerts) {
|
if (dualCerts) {
|
||||||
traefik.http.routers[`${id}-secure`] = {
|
traefik.http.routers[`${id}-${port || 'default'}-secure`] = {
|
||||||
entrypoints: ['websecure'],
|
entrypoints: ['websecure'],
|
||||||
rule: `(Host(\`${nakedDomain}\`) || Host(\`www.${nakedDomain}\`)) && PathPrefix(\`${pathPrefix}\`)`,
|
rule: `(Host(\`${nakedDomain}\`) || Host(\`www.${nakedDomain}\`)) && PathPrefix(\`${pathPrefix}\`)`,
|
||||||
service: `${id}`,
|
service: `${id}`,
|
||||||
@@ -425,7 +433,7 @@ export async function traefikConfiguration(request, reply) {
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if (isWWW) {
|
if (isWWW) {
|
||||||
traefik.http.routers[`${id}-secure-www`] = {
|
traefik.http.routers[`${id}-${port || 'default'}-secure-www`] = {
|
||||||
entrypoints: ['websecure'],
|
entrypoints: ['websecure'],
|
||||||
rule: `Host(\`www.${nakedDomain}\`) && PathPrefix(\`${pathPrefix}\`)`,
|
rule: `Host(\`www.${nakedDomain}\`) && PathPrefix(\`${pathPrefix}\`)`,
|
||||||
service: `${id}`,
|
service: `${id}`,
|
||||||
@@ -434,7 +442,7 @@ export async function traefikConfiguration(request, reply) {
|
|||||||
},
|
},
|
||||||
middlewares: []
|
middlewares: []
|
||||||
};
|
};
|
||||||
traefik.http.routers[`${id}-secure`] = {
|
traefik.http.routers[`${id}-${port || 'default'}-secure`] = {
|
||||||
entrypoints: ['websecure'],
|
entrypoints: ['websecure'],
|
||||||
rule: `Host(\`${nakedDomain}\`) && PathPrefix(\`${pathPrefix}\`)`,
|
rule: `Host(\`${nakedDomain}\`) && PathPrefix(\`${pathPrefix}\`)`,
|
||||||
service: `${id}`,
|
service: `${id}`,
|
||||||
@@ -445,9 +453,9 @@ export async function traefikConfiguration(request, reply) {
|
|||||||
},
|
},
|
||||||
middlewares: ['redirect-to-www']
|
middlewares: ['redirect-to-www']
|
||||||
};
|
};
|
||||||
traefik.http.routers[`${id}`].middlewares.push('redirect-to-www');
|
traefik.http.routers[`${id}-${port || 'default'}`].middlewares.push('redirect-to-www');
|
||||||
} else {
|
} else {
|
||||||
traefik.http.routers[`${id}-secure-www`] = {
|
traefik.http.routers[`${id}-${port || 'default'}-secure-www`] = {
|
||||||
entrypoints: ['websecure'],
|
entrypoints: ['websecure'],
|
||||||
rule: `Host(\`www.${nakedDomain}\`) && PathPrefix(\`${pathPrefix}\`)`,
|
rule: `Host(\`www.${nakedDomain}\`) && PathPrefix(\`${pathPrefix}\`)`,
|
||||||
service: `${id}`,
|
service: `${id}`,
|
||||||
@@ -458,7 +466,7 @@ export async function traefikConfiguration(request, reply) {
|
|||||||
},
|
},
|
||||||
middlewares: ['redirect-to-non-www']
|
middlewares: ['redirect-to-non-www']
|
||||||
};
|
};
|
||||||
traefik.http.routers[`${id}-secure`] = {
|
traefik.http.routers[`${id}-${port || 'default'}-secure`] = {
|
||||||
entrypoints: ['websecure'],
|
entrypoints: ['websecure'],
|
||||||
rule: `Host(\`${domain}\`) && PathPrefix(\`${pathPrefix}\`)`,
|
rule: `Host(\`${domain}\`) && PathPrefix(\`${pathPrefix}\`)`,
|
||||||
service: `${id}`,
|
service: `${id}`,
|
||||||
@@ -467,21 +475,21 @@ export async function traefikConfiguration(request, reply) {
|
|||||||
},
|
},
|
||||||
middlewares: []
|
middlewares: []
|
||||||
};
|
};
|
||||||
traefik.http.routers[`${id}`].middlewares.push('redirect-to-non-www');
|
traefik.http.routers[`${id}-${port || 'default'}`].middlewares.push('redirect-to-non-www');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
traefik.http.routers[id] = generateHttpRouter(id, nakedDomain, pathPrefix)
|
traefik.http.routers[`${id}-${port || 'default'}`] = generateHttpRouter(`${id}-${port || 'default'}`, nakedDomain, pathPrefix)
|
||||||
traefik.http.routers[`${id}-secure`] = generateProtocolRedirectRouter(id, nakedDomain, pathPrefix, 'https-to-http')
|
traefik.http.routers[`${id}-${port || 'default'}-secure`] = generateProtocolRedirectRouter(`${id}-${port || 'default'}-secure`, nakedDomain, pathPrefix, 'https-to-http')
|
||||||
traefik.http.services[id] = generateLoadBalancerService(id, port)
|
traefik.http.services[`${id}-${port || 'default'}`] = generateLoadBalancerService(id, port)
|
||||||
|
|
||||||
if (!dualCerts) {
|
if (!dualCerts) {
|
||||||
if (isWWW) {
|
if (isWWW) {
|
||||||
traefik.http.routers[`${id}`].middlewares.push('redirect-to-www');
|
traefik.http.routers[`${id}-${port || 'default'}`].middlewares.push('redirect-to-www');
|
||||||
traefik.http.routers[`${id}-secure`].middlewares.push('redirect-to-www');
|
traefik.http.routers[`${id}-${port || 'default'}-secure`].middlewares.push('redirect-to-www');
|
||||||
} else {
|
} else {
|
||||||
traefik.http.routers[`${id}`].middlewares.push('redirect-to-non-www');
|
traefik.http.routers[`${id}-${port || 'default'}`].middlewares.push('redirect-to-non-www');
|
||||||
traefik.http.routers[`${id}-secure`].middlewares.push('redirect-to-non-www');
|
traefik.http.routers[`${id}-${port || 'default'}-secure`].middlewares.push('redirect-to-non-www');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
import DocLink from '$lib/components/DocLink.svelte';
|
import DocLink from '$lib/components/DocLink.svelte';
|
||||||
export let service: any;
|
export let service: any;
|
||||||
export let linkToDocs: boolean = false;
|
export let linkToDocs: boolean = false;
|
||||||
import ExternalLink from '$lib/components/ExternalLink.svelte';
|
|
||||||
import * as Icons from '$lib/components/svg/services';
|
import * as Icons from '$lib/components/svg/services';
|
||||||
const name: any = service.type && service.type[0].toUpperCase() + service.type.substring(1);
|
const name: any = service.type && service.type[0].toUpperCase() + service.type.substring(1);
|
||||||
|
|
||||||
@@ -31,15 +30,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if linkToDocs}
|
{#if linkToDocs}
|
||||||
<DocLink url={links[service.type]} text={`Open documentation`} isExternal={true} />
|
<DocLink url={links[service.type]} text={`Documentation`} isExternal={true} />
|
||||||
{:else}
|
{:else}
|
||||||
<svelte:component this={Icons[name]} />
|
<svelte:component this={Icons[name]} />
|
||||||
{/if}
|
{/if}
|
||||||
<!-- <a href={links[service.type]} target="_blank" class="no-underline">
|
|
||||||
{#if linkToDocs}
|
|
||||||
Open Documentation
|
|
||||||
<ExternalLink />
|
|
||||||
{:else}
|
|
||||||
|
|
||||||
{/if}
|
|
||||||
</a> -->
|
|
||||||
|
@@ -293,7 +293,7 @@
|
|||||||
<Explainer explanation={$t('application.https_explainer')} />
|
<Explainer explanation={$t('application.https_explainer')} />
|
||||||
</label>
|
</label>
|
||||||
<CopyPasswordField
|
<CopyPasswordField
|
||||||
placeholder="eg: https://analytics.coollabs.io"
|
placeholder="eg: https://coollabs.io"
|
||||||
readonly={!$appSession.isAdmin && !$status.service.isRunning}
|
readonly={!$appSession.isAdmin && !$status.service.isRunning}
|
||||||
disabled={!$appSession.isAdmin ||
|
disabled={!$appSession.isAdmin ||
|
||||||
$status.service.isRunning ||
|
$status.service.isRunning ||
|
||||||
@@ -309,7 +309,13 @@
|
|||||||
{#each template[oneService].fqdns as fqdn}
|
{#each template[oneService].fqdns as fqdn}
|
||||||
<div class="grid grid-cols-2 items-center py-1">
|
<div class="grid grid-cols-2 items-center py-1">
|
||||||
<label for={fqdn.name}>{fqdn.label || fqdn.name}</label>
|
<label for={fqdn.name}>{fqdn.label || fqdn.name}</label>
|
||||||
<input class="w-full" name={fqdn.name} id={fqdn.name} bind:value={fqdn.value} />
|
<CopyPasswordField
|
||||||
|
placeholder="eg: https://coolify.io"
|
||||||
|
required={fqdn.required}
|
||||||
|
name={fqdn.name}
|
||||||
|
id={fqdn.name}
|
||||||
|
bind:value={fqdn.value}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{/each}
|
{/each}
|
||||||
@@ -416,7 +422,7 @@
|
|||||||
readonly
|
readonly
|
||||||
name={variable.name}
|
name={variable.name}
|
||||||
id={variable.name}
|
id={variable.name}
|
||||||
value={getDomain(service.fqdn)}
|
value={getDomain(service.fqdn) || ''}
|
||||||
/>
|
/>
|
||||||
{:else if variable.defaultValue === '$$generate_network'}
|
{:else if variable.defaultValue === '$$generate_network'}
|
||||||
<input
|
<input
|
||||||
@@ -466,7 +472,7 @@
|
|||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<CopyPasswordField
|
<CopyPasswordField
|
||||||
required={variable?.extras?.required}
|
required={variable?.required}
|
||||||
readonly={isDisabled}
|
readonly={isDisabled}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
name={variable.name}
|
name={variable.name}
|
||||||
|
Reference in New Issue
Block a user