component {
resources {
link(rel = import, href = "service/logs.component.gv", as = ServiceLogsTab)
link(rel = import, href = "service/general.component.gv", as = ServiceGeneralTab)
link(rel = import, href = "service/connection.component.gv", as = ServiceConnectionTab)
link(rel = import, href = "service/environment.component.gv", as = ServiceEnvironmentTab)
link(rel = import, href = "service/domains.component.gv", as = ServiceDomainsTab)
link(rel = import, href = "service/migrar.component.gv", as = ServiceMigrarTab)
link(rel = import, href = "service/dados.component.gv", as = ServiceDadosTab)
link(rel = import, href = "service/databases.component.gv", as = ServiceDatabasesTab)
link(rel = import, href = "service/deployments.component.gv", as = ServiceDeploymentsTab)
link(rel = import, href = "service/healthcheck.component.gv", as = ServiceHealthcheckTab)
link(rel = import, href = "service/advanced.component.gv", as = ServiceAdvancedTab)
style """
/* Cabeçalho + ações */
.service__head { width: fill; align_y: start; }
.service__title-row { width: fill; spacing: 14; align_y: center; }
.service__title { width: fill; }
/* Título editável: um input sem borda e sem fundo próprio, que parece o
título comum (mesmo tamanho/peso de .page-head__title). Só o hover/foco
tinge o fundo, como pista de que dá para editar. */
.service__title-input { width: fill; size: 30; bold: true; color: var(--text); background: var(--bg); border_width: 0; padding: 0 6; }
.service__title-input:hover { background: var(--surface); }
.service__title-input:focus { background: var(--surface); }
/* Sub-linha de status (badge + timer) logo abaixo do nome. */
.service__substatus { spacing: 10; align_y: center; }
.service__actions { spacing: 10; align_y: center; }
.service__panels { width: fill; spacing: 14; }
.tabs__scroll { width: fill; }
.tabs__main { width: shrink; spacing: 4; }
/* Corpo: conteúdo da aba + painel lateral */
.service__body { width: fill; height: fill; spacing: 20; }
.service__main { width: fill; height: fill; spacing: 16; }
.service__aside { width: 360; height: fill; spacing: 16; }
.service__err { size: 13; color: var(--error); }
/* Deployments (lista + build log) */
.table__col-dep-id { width: 130; }
.table__col-dep-start { width: fill; }
.deployments__image { size: 11; color: var(--faint); padding: 2 0 0 0; }
.deployments__wrap { width: fill; height: fill; spacing: 8; }
.deployments__list-scroll { width: fill; height: 240; }
.deployments__actions { spacing: 8; align_y: center; }
/* Logs (aba Logs = launcher da janela isolada; painel usado só p/ layout) */
.log-panel { width: fill; height: fill; background: var(--surface); border_radius: 6; border_width: 1; border_color: var(--border); padding: 14 16; spacing: 8; }
.log-panel__body { width: fill; spacing: 2; }
.log-panel__line { width: fill; spacing: 12; }
.log-panel__time { width: 76; size: 11; color: var(--faint); }
.log-panel__text { width: fill; size: 12; color: #9DA7B3; }
/* Painel lateral (o `--fill` troca só a altura e o respiro) */
.aside-panel { width: fill; background: var(--surface); border_radius: 6; border_width: 1; border_color: var(--border); padding: 18; spacing: 8; }
.aside-panel--fill { height: fill; padding: 14 16; }
/* Responsivo: estreita o painel lateral e aperta o corpo (glacier-ui 0.9.0+). */
@media (max-width: 900) {
.service__aside { width: 240; }
.service__body { spacing: 12; }
}
@media (max-width: 560) {
.service__aside { width: 170; }
}
"""
}
column(class = content) {
row(class = service__head) {
column(class = page-head__titles) {
row(class = service__title-row) {
button(
class = "btn btn--ghost",
on_click = open_project:@service_project_id,
disabled = @busy_open_project,
text = "‹ @service_project",
)
input(
class = "service__title-input",
:value = edit_service_name,
on_change = service_title_change,
placeholder = "{t('general.service_name')}",
)
}
row(class = service__substatus) {
rp-badge(color = @service_status_color, label = @service_status_label)
rp-badge(
if = @service_pending_deploy_visible,
equals = true,
color = warn,
label = "◆ {t('service_card.change_pending_deploy')}"
)
rp-badge(
if = @service_warm_visible,
equals = true, color = @service_warm_color,
label = "◐ @service_warm_label"
)
row(class = badge, if = @service_deploy_running, equals = true) {
text("⏱", class = status-dot, color = text(
"@service_deploy_elapsed",
class = badge__label,
color = )
}
}
text(
"{t('service.cold', service_warm_reason=service_warm_reason)}",
if = @service_warm_reason,
not_equals = "",
class = u-muted,
)
text(
"@service_action_message",
if = @service_action_message,
not_equals = "",
class = u-muted,
color = @service_action_color,
)
row(class = "service__actions service__actions--compact") {
button(
class = "btn btn--primary",
on_click = service_deploy,
disabled = @busy_service_deploy,
text = "▶",
tooltip = "{t('service.deploy')}",
)
button(
class = "btn btn--blue btn--wide",
on_click = service_reload,
disabled = @busy_service_reload,
text = "⟳",
tooltip = "{t('service.reload')}",
)
button(
class = "btn btn--blue btn--wide",
on_click = service_rebuild,
disabled = @busy_service_rebuild,
text = "⚙",
tooltip = "{t('service.rebuild')}",
)
button(
class = "btn btn--danger",
on_click = service_stop,
disabled = @busy_service_stop,
text = "■",
tooltip = "{t('service.stop')}",
)
button(
if = @service_warm_visible,
equals = true,
class = "btn btn--ghost",
on_click = service_warm,
disabled = @busy_service_warm,
text = "◐",
tooltip = "{t('service.warm_builds_the_image_so')}",
)
button(
class = "btn btn--ghost",
on_click = open_export_window,
disabled = @busy_open_export_window,
text = "⇪",
tooltip = "{t('service.export_service')}",
)
}
}
row(class = "service__actions service__actions--full") {
button(
class = "btn btn--primary",
on_click = service_deploy,
disabled = @busy_service_deploy,
text = "{t('service.deploy')}"
)
button(
class = "btn btn--blue btn--wide",
on_click = service_reload,
disabled = @busy_service_reload,
text = "{t('service.reload')}"
)
button(
class = "btn btn--blue btn--wide",
on_click = service_rebuild,
disabled = @busy_service_rebuild,
text = "{t('service.rebuild')}"
)
button(
class = "btn btn--danger",
on_click = service_stop,
disabled = @busy_service_stop,
text = "{t('service.stop')}"
)
button(
if = @service_warm_visible,
equals = true,
class = "btn btn--ghost",
on_click = service_warm,
disabled = @busy_service_warm,
text = "{t('service.warm')}",
)
button(
class = "btn btn--ghost",
on_click = open_export_window,
disabled = @busy_open_export_window,
text = "{t('service.export_service')}",
)
}
}
scroll(class = tabs__scroll, direction = horizontal) {
row(class = tabs__main) {
TabButton(
label = "{t('service.general')}",
current = @tab,
target = general,
action = tab:general,
)
TabButton(
label = "{t('service.connection')}",
current = @tab,
target = connection,
action = tab:connection,
)
TabButton(
label = "{t('service.environment')}",
current = @tab,
target = environment,
action = tab:environment,
)
TabButton(
label = "{t('service.domains')}",
current = @tab,
target = domains,
action = tab:domains,
)
TabButton(
label = "{t('common.deployments')}",
current = @tab,
target = deployments,
action = tab:deployments,
)
if @service_shared == "true" {
TabButton(
label = "{t('service.databases')}",
current = @tab,
target = databases,
action = tab:databases,
)
}
if @service_can_migrate == "true" {
TabButton(
label = "{t('common.migrate')}",
current = @tab,
target = migrar,
action = tab:migrar,
)
}
TabButton(
label = "{t('dados.tab')}",
current = @tab,
target = dados,
action = tab:dados,
)
TabButton(
label = "{t('service.healthcheck')}",
current = @tab,
target = healthcheck,
action = tab:healthcheck,
)
TabButton(
label = "{t('service.logs')}",
current = @tab,
target = logs,
action = tab:logs,
)
TabButton(
label = "{t('service.advanced')}",
current = @tab,
target = advanced,
action = tab:advanced,
)
}
}
hr
row(class = service__body) {
column(class = service__main) {
text(
"@service_error",
if = @service_error,
not_equals = "",
class = service__err,
)
ServiceGeneralTab(if = @tab, equals = general)
ServiceConnectionTab(if = @tab, equals = connection)
ServiceEnvironmentTab(if = @tab, equals = environment)
ServiceDomainsTab(if = @tab, equals = domains)
ServiceMigrarTab(if = @tab, equals = migrar)
ServiceDadosTab(if = @tab, equals = dados)
ServiceDatabasesTab(if = @tab, equals = databases)
ServiceDeploymentsTab(if = @tab, equals = deployments)
ServiceHealthcheckTab(if = @tab, equals = healthcheck)
ServiceLogsTab(if = @tab, equals = logs)
ServiceAdvancedTab(if = @tab, equals = advanced)
}
column(class = service__aside) {
column(class = aside-panel) {
text("{t('common.status')}", class = u-label-cap)
rp-badge(color = @service_status_color, label = @service_status_label)
text("{t('common.uptime')}", class = u-label-cap)
text("@daemon_uptime", class = kv-list__val)
text("{t('common.services')}", class = u-label-cap)
text("@services_label", class = kv-list__val)
}
column(class = "aside-panel aside-panel--fill") {
text("{t('service.logs_2')}", class = u-label-cap)
text(
"{t('service.runtime_and_build_logs_open')}",
class = u-muted,
)
row(class = env__add) {
button(
class = tabs__tab,
on_click = open_logs_window,
disabled = @busy_open_logs_window,
text = "{t('service.runtime_logs')}",
)
}
}
}
}
}
}