import { Component, OnInit, inject, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Router, RouterLink } from '@angular/router';
import { ApiService } from '../../core/services/api.service';
interface EnvVar {
key: string;
value: string;
}
interface Domain {
domain: string;
dnsProvider: 'cloudflare' | 'manual' | null;
isObsolete: boolean;
}
@Component({
selector: 'app-service-create',
standalone: true,
imports: [CommonModule, FormsModule, RouterLink],
template: `
`,
})
export class ServiceCreateComponent implements OnInit {
private apiService = inject(ApiService);
private router = inject(Router);
name = '';
image = '';
port = 80;
domain = '';
autoDNS = true;
autoSSL = true;
envVars = signal([]);
loading = signal(false);
error = signal('');
// Onebox Registry
useOneboxRegistry = false;
registryImageTag = 'latest';
autoUpdateOnPush = false;
// Domain validation
availableDomains = signal([]);
domainWarning = signal(false);
domainWarningTitle = signal('');
domainWarningMessage = signal('');
ngOnInit(): void {
this.loadDomains();
}
loadDomains(): void {
this.apiService.getDomains().subscribe({
next: (response) => {
if (response.success && response.data) {
const domains: Domain[] = response.data.map((d: any) => ({
domain: d.domain.domain,
dnsProvider: d.domain.dnsProvider,
isObsolete: d.domain.isObsolete,
}));
this.availableDomains.set(domains);
}
},
error: () => {
// Silently fail - domains list not critical
},
});
}
onDomainChange(): void {
if (!this.domain) {
this.domainWarning.set(false);
return;
}
// Extract base domain from entered domain
const parts = this.domain.split('.');
if (parts.length < 2) {
// Not a valid domain format
this.domainWarning.set(false);
return;
}
const baseDomain = parts.slice(-2).join('.');
// Check if base domain exists in available domains
const matchingDomain = this.availableDomains().find(
(d) => d.domain === baseDomain
);
if (!matchingDomain) {
this.domainWarning.set(true);
this.domainWarningTitle.set('Domain not found');
this.domainWarningMessage.set(
`The base domain "${baseDomain}" is not in the Domain table. The service will deploy, but certificate management may not work. Sync your Cloudflare domains or manually add the domain first.`
);
} else if (matchingDomain.isObsolete) {
this.domainWarning.set(true);
this.domainWarningTitle.set('Domain is obsolete');
this.domainWarningMessage.set(
`The domain "${baseDomain}" is marked as obsolete (likely removed from Cloudflare). Certificate management may not work properly.`
);
} else {
this.domainWarning.set(false);
}
}
addEnvVar(): void {
this.envVars.update((vars) => [...vars, { key: '', value: '' }]);
}
removeEnvVar(index: number): void {
this.envVars.update((vars) => vars.filter((_, i) => i !== index));
}
onSubmit(): void {
this.error.set('');
this.loading.set(true);
// Convert env vars to object
const envVarsObj: Record = {};
for (const env of this.envVars()) {
if (env.key && env.value) {
envVarsObj[env.key] = env.value;
}
}
const data = {
name: this.name,
image: this.image,
port: this.port,
domain: this.domain || undefined,
envVars: envVarsObj,
autoDNS: this.autoDNS,
autoSSL: this.autoSSL,
useOneboxRegistry: this.useOneboxRegistry,
registryImageTag: this.useOneboxRegistry ? this.registryImageTag : undefined,
autoUpdateOnPush: this.useOneboxRegistry ? this.autoUpdateOnPush : undefined,
};
this.apiService.createService(data).subscribe({
next: (response) => {
this.loading.set(false);
if (response.success) {
this.router.navigate(['/services']);
} else {
this.error.set(response.error || 'Failed to deploy service');
}
},
error: (err) => {
this.loading.set(false);
this.error.set(err.error?.error || 'An error occurred');
},
});
}
cancel(): void {
this.router.navigate(['/services']);
}
}