feat: resolve app template env placeholders
This commit is contained in:
+31
-2
@@ -112,9 +112,15 @@ export class OneboxServicesManager {
|
|||||||
|
|
||||||
// Merge platform env vars with user-specified env vars (user vars take precedence)
|
// Merge platform env vars with user-specified env vars (user vars take precedence)
|
||||||
const mergedEnvVars = { ...platformEnvVars, ...(options.envVars || {}) };
|
const mergedEnvVars = { ...platformEnvVars, ...(options.envVars || {}) };
|
||||||
|
this.resolveEnvVarTemplates(mergedEnvVars, {
|
||||||
|
...platformEnvVars,
|
||||||
|
SERVICE_NAME: options.name,
|
||||||
|
SERVICE_DOMAIN: options.domain || '',
|
||||||
|
SERVICE_PORT: String(options.port),
|
||||||
|
});
|
||||||
|
|
||||||
// Update service with merged env vars
|
// Update service with merged and resolved env vars.
|
||||||
if (Object.keys(platformEnvVars).length > 0) {
|
if (Object.keys(mergedEnvVars).length > 0) {
|
||||||
this.database.updateService(service.id!, { envVars: mergedEnvVars });
|
this.database.updateService(service.id!, { envVars: mergedEnvVars });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -697,6 +703,29 @@ export class OneboxServicesManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private resolveEnvVarTemplates(
|
||||||
|
envVarsArg: Record<string, string>,
|
||||||
|
valuesArg: Record<string, string>,
|
||||||
|
): void {
|
||||||
|
for (const [key, value] of Object.entries(envVarsArg)) {
|
||||||
|
const missingValues = new Set<string>();
|
||||||
|
const resolvedValue = value.replace(/\$\{([A-Z0-9_]+)\}/g, (match, placeholderName) => {
|
||||||
|
const replacement = valuesArg[placeholderName];
|
||||||
|
if (replacement === undefined || replacement === '') {
|
||||||
|
missingValues.add(placeholderName);
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
return replacement;
|
||||||
|
});
|
||||||
|
if (missingValues.size > 0) {
|
||||||
|
throw new Error(
|
||||||
|
`Missing template value(s) for ${key}: ${Array.from(missingValues).join(', ')}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
envVarsArg[key] = resolvedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start auto-update monitoring for registry services
|
* Start auto-update monitoring for registry services
|
||||||
* Polls every 30 seconds for digest changes and restarts services if needed
|
* Polls every 30 seconds for digest changes and restarts services if needed
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -42,6 +42,9 @@ export class ObViewAppStore extends DeesElement {
|
|||||||
@state()
|
@state()
|
||||||
accessor serviceName: string = '';
|
accessor serviceName: string = '';
|
||||||
|
|
||||||
|
@state()
|
||||||
|
accessor serviceDomain: string = '';
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor loading: boolean = false;
|
accessor loading: boolean = false;
|
||||||
|
|
||||||
@@ -474,6 +477,18 @@ export class ObViewAppStore extends DeesElement {
|
|||||||
Lowercase letters, numbers, and hyphens only.
|
Lowercase letters, numbers, and hyphens only.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="section-label" style="margin-top: 18px;">Domain</div>
|
||||||
|
<input
|
||||||
|
class="name-input"
|
||||||
|
type="text"
|
||||||
|
.value=${this.serviceDomain}
|
||||||
|
placeholder="e.g. cloudly.example.com"
|
||||||
|
@input=${(e: Event) => this.handleServiceDomainChange((e.target as HTMLInputElement).value)}
|
||||||
|
/>
|
||||||
|
<div style="font-size: 12px; color: var(--ci-shade-4, #71717a); margin-top: 6px;">
|
||||||
|
Optional. When configured, Onebox routes this domain to the deployed app.
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="actions-row">
|
<div class="actions-row">
|
||||||
<button class="btn btn-secondary" @click=${() => { this.currentView = 'grid'; }}>Cancel</button>
|
<button class="btn btn-secondary" @click=${() => { this.currentView = 'grid'; }}>Cancel</button>
|
||||||
<button class="btn btn-primary" @click=${() => this.handleDeploy()}>
|
<button class="btn btn-primary" @click=${() => this.handleDeploy()}>
|
||||||
@@ -560,6 +575,7 @@ export class ObViewAppStore extends DeesElement {
|
|||||||
required: ev.required,
|
required: ev.required,
|
||||||
platformInjected: ev.value?.includes('${') || false,
|
platformInjected: ev.value?.includes('${') || false,
|
||||||
}));
|
}));
|
||||||
|
this.serviceDomain = '';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to fetch app config:', err);
|
console.error('Failed to fetch app config:', err);
|
||||||
}
|
}
|
||||||
@@ -571,14 +587,29 @@ export class ObViewAppStore extends DeesElement {
|
|||||||
this.editableEnvVars = updated;
|
this.editableEnvVars = updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleServiceDomainChange(valueArg: string) {
|
||||||
|
this.serviceDomain = this.normalizeDomain(valueArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private normalizeDomain(valueArg: string) {
|
||||||
|
return valueArg.trim().replace(/^https?:\/\//, '').replace(/\/$/, '');
|
||||||
|
}
|
||||||
|
|
||||||
private async handleDeploy() {
|
private async handleDeploy() {
|
||||||
const app = this.selectedApp;
|
const app = this.selectedApp;
|
||||||
const config = this.selectedAppConfig;
|
const config = this.selectedAppConfig;
|
||||||
if (!app || !config) return;
|
if (!app || !config) return;
|
||||||
|
const needsServiceDomain = (config.envVars || []).some((envVarArg) => {
|
||||||
|
return envVarArg.value?.includes('${SERVICE_DOMAIN}');
|
||||||
|
});
|
||||||
|
if (needsServiceDomain && !this.serviceDomain) {
|
||||||
|
console.error('A domain is required for this app.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const envVars: Record<string, string> = {};
|
const envVars: Record<string, string> = {};
|
||||||
for (const ev of this.editableEnvVars) {
|
for (const ev of this.editableEnvVars) {
|
||||||
if (ev.key && ev.value && !ev.platformInjected) {
|
if (ev.key && ev.value) {
|
||||||
envVars[ev.key] = ev.value;
|
envVars[ev.key] = ev.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -588,6 +619,7 @@ export class ObViewAppStore extends DeesElement {
|
|||||||
name: this.serviceName || app.id,
|
name: this.serviceName || app.id,
|
||||||
image: config.image,
|
image: config.image,
|
||||||
port: config.port || 80,
|
port: config.port || 80,
|
||||||
|
domain: this.serviceDomain || undefined,
|
||||||
envVars,
|
envVars,
|
||||||
enableMongoDB: platformReqs.mongodb || false,
|
enableMongoDB: platformReqs.mongodb || false,
|
||||||
enableS3: platformReqs.s3 || false,
|
enableS3: platformReqs.s3 || false,
|
||||||
|
|||||||
Reference in New Issue
Block a user