caddy lables

This commit is contained in:
2026-05-29 22:30:35 +03:00
parent 0c8718b7bf
commit 70a6229ca6
4 changed files with 208 additions and 58 deletions
@@ -61,15 +61,15 @@
<div class="flex flex-col gap-0.5">
<span class="text-[10px] uppercase tracking-wider font-bold text-gray-500">Маршрутизация сети:</span>
<ng-container *ngIf="getContainerDomain(container.name) as domain; else noDomain">
<ng-container *ngIf="getContainerDomain(container) as domain; else noDomain">
<div class="flex items-center gap-2 mt-1">
<a [href]="'https://' + domain" target="_blank" class="text-xs font-semibold text-blue-400 hover:text-blue-300 hover:underline flex items-center gap-1 font-mono">
<mat-icon class="!w-3.5 !h-3.5 !text-sm text-blue-400 shrink-0">open_in_new</mat-icon>
<span class="truncate max-w-[200px]">{{ domain }}</span>
</a>
<span class="text-[10px] text-gray-400 font-mono bg-gray-950 px-2 py-0.5 rounded border border-gray-850 shrink-0">
порт {{ getContainerPort(container.name) }}
</span>
порт {{ getContainerPort(container) }}
</span>
</div>
</ng-container>
@@ -264,64 +264,81 @@ export class ProjectDetailsComponent implements OnInit, OnDestroy, AfterViewChec
* Безопасно извлекает имя сервиса (например, 'web') из имени Docker-контейнера.
* Проверяет префиксы как по ID, так и по Name проекта.
*/
getServiceName(containerName: string): string | null {
if (!containerName || !this.project) return null;
getServiceName(container: any): string | null {
if (!container) return null;
const prefixId = `jambotron-${this.project.id}-`;
const prefixName = `jambotron-${this.project.name}-`;
let servicePart = '';
if (containerName.startsWith(prefixId)) {
servicePart = containerName.substring(prefixId.length);
} else if (containerName.startsWith(prefixName)) {
servicePart = containerName.substring(prefixName.length);
} else {
// Резервный разбор по токенам (jambotron-проект-сервис)
const parts = containerName.split('-');
if (parts.length >= 3 && parts[0] === 'jambotron') {
servicePart = parts.slice(2).join('-');
} else {
return null;
}
// 1. Идеальный путь созидания: берем стабильный ID из меток Docker
if (container.labels && container.labels['jambotron.service.id']) {
return container.labels['jambotron.service.id'];
}
// Отрезаем индекс реплики Docker Compose (например, "-1")
if (servicePart.endsWith('-1')) {
servicePart = servicePart.substring(0, servicePart.length - 2);
// 2. Если меток нет, переходим к парсингу имени контейнера
const containerName = container.name || '';
// Проверяем базовый маркер нашей системы
if (!containerName.startsWith('jambotron-')) {
console.warn(`[Jambotron] Контейнер не принадлежит системе Jambotron: ${containerName}`);
return null;
}
return servicePart;
// Отрезаем индекс реплики (-1, -2) и префикс "jambotron-"
let cleanName = containerName.replace(/-\d+$/, '').replace(/^jambotron-/, '');
// 3. Проверяем массив известных имен сервисов из YAML
const validServices: string[] = this.config?.serviceNames || [];
if (validServices.length > 0) {
const match = validServices.find((service: string) => cleanName.endsWith(service) || cleanName.includes(service));
if (match) return match;
}
// 4. Финальный пуленепробиваемый фоллбэк для старых контейнеров (вырезаем имя проекта)
// Для "test-web" -> cleanName = "test-web" -> parts = ['test', 'web'] -> возвращает "web"
const parts = cleanName.split('-');
if (parts.length >= 2) {
return parts.slice(1).join('-');
}
// Только если вообще ничего не получилось извлечь — выводим реальное предупреждение
if (!cleanName) {
console.warn(`[Jambotron] Не удалось определить имя сервиса для: ${containerName}`);
return null;
}
return cleanName;
}
/**
* Возвращает текущий сформированный домен для вывода в UI
*/
getContainerDomain(containerName: string): string | null {
const serviceName = this.getServiceName(containerName);
if (!serviceName || !this.config?.serviceConfigs) return null;
getContainerDomain(container: any): string | null {
const serviceId = this.getServiceName(container);
if (!serviceId || !this.config?.serviceConfigs) return null;
const serviceConfig = this.config.serviceConfigs[serviceName];
// Ищем настройки в мапе по системному ID (например, srv-0)
const serviceConfig = this.config.serviceConfigs[serviceId];
return serviceConfig && serviceConfig.subdomain ? `${serviceConfig.subdomain}.jambotron.com` : null;
}
/**
* Возвращает порт сервиса из конфигурации MongoDB
*/
getContainerPort(containerName: string): number {
const serviceName = this.getServiceName(containerName);
if (!serviceName || !this.config?.serviceConfigs) return 80;
getContainerPort(container: any): number {
const serviceId = this.getServiceName(container);
if (!serviceId || !this.config?.serviceConfigs) return 80;
const serviceConfig = this.config.serviceConfigs[serviceName];
// Ищем настройки в мапе по системному ID (например, srv-0)
const serviceConfig = this.config.serviceConfigs[serviceId];
return serviceConfig && serviceConfig.port ? serviceConfig.port : 80;
}
/**
* Активация режима редактирования. Теперь полностью безопасна.
* Активация режима редактирования.
*/
startEditDomain(container: any) {
const serviceName = this.getServiceName(container.name);
// ПЕРЕДАЕМ КОНТЕЙНЕР ЦЕЛИКОМ, а не container.name
const serviceName = this.getServiceName(container);
if (!serviceName) {
console.warn(`[Jambotron] Не удалось определить имя сервиса для: ${container.name}`);
console.warn(`[Jambotron] Не удалось определить имя сервиса для:`, container);
return;
}
@@ -338,7 +355,8 @@ export class ProjectDetailsComponent implements OnInit, OnDestroy, AfterViewChec
* Сохранение изменённого поддомена и порта в MongoDB базы данных
*/
saveDomainConfig(container: any) {
const serviceName = this.getServiceName(container.name);
// ПЕРЕДАЕМ КОНТЕЙНЕР ЦЕЛИКОМ, а не container.name
const serviceName = this.getServiceName(container);
if (!serviceName || !this.project?.id || !this.config) return;
if (!this.config.serviceConfigs) {
@@ -360,7 +378,6 @@ export class ProjectDetailsComponent implements OnInit, OnDestroy, AfterViewChec
// Отправка монолитного конфига на бэкенд
this.projectService.updateProjectConfig(this.project.id, this.config).subscribe({
next: () => {
// Бэкенд возвращает void (200 OK). Нам НЕ нужно затирать config!
this.editingDomains[container.id] = false;
console.log(`[Caddy] Маршрут для сервиса ${serviceName} успешно сохранён.`);
},