@ -4,6 +4,10 @@ const loginForm = document.querySelector('[data-admin-login-form="true"]');
const reviewBoard = document . querySelector ( '[data-admin-tool-review-board="true"]' ) ;
const toolIntakePage = document . querySelector ( '[data-admin-tool-intake="true"]' ) ;
const collaboratorBoard = document . querySelector ( '[data-admin-collaborator-board="true"]' ) ;
const systemConfigurationPage = document . querySelector ( '[data-admin-system-configuration="true"]' ) ;
const salesRevenueReportsPage = document . querySelector ( '[data-admin-sales-revenue-reports="true"]' ) ;
const rentalReportsPage = document . querySelector ( '[data-admin-rental-reports="true"]' ) ;
const botMonitoringPage = document . querySelector ( '[data-admin-bot-monitoring="true"]' ) ;
if ( loginForm ) {
mountLoginForm ( loginForm ) ;
@ -21,6 +25,22 @@ if (collaboratorBoard) {
mountCollaboratorBoard ( collaboratorBoard ) ;
}
if ( systemConfigurationPage ) {
mountSystemConfigurationPage ( systemConfigurationPage ) ;
}
if ( salesRevenueReportsPage ) {
mountSalesRevenueReportsPage ( salesRevenueReportsPage ) ;
}
if ( rentalReportsPage ) {
mountRentalReportsPage ( rentalReportsPage ) ;
}
if ( botMonitoringPage ) {
mountBotMonitoringPage ( botMonitoringPage ) ;
}
function mountLoginForm ( form ) {
const feedback = document . getElementById ( "admin-login-feedback" ) ;
const submitButton = form . querySelector ( 'button[type="submit"]' ) ;
@ -554,6 +574,672 @@ function mountCollaboratorBoard(board) {
}
}
function mountSystemConfigurationPage ( page ) {
const refreshButton = page . querySelector ( "[data-admin-system-refresh]" ) ;
const refreshLabel = page . querySelector ( "[data-system-refresh-label]" ) ;
const refreshSpinner = page . querySelector ( "[data-system-refresh-spinner]" ) ;
const feedback = document . getElementById ( "admin-system-configuration-feedback" ) ;
const functionalList = page . querySelector ( "[data-system-functional-list]" ) ;
const parentKeys = page . querySelector ( "[data-system-parent-keys]" ) ;
const botSettingsList = page . querySelector ( "[data-system-bot-settings-list]" ) ;
const runtimeSummary = page . querySelector ( "[data-system-runtime-summary]" ) ;
const securitySummary = page . querySelector ( "[data-system-security-summary]" ) ;
const modelRuntimeSummary = page . querySelector ( "[data-system-model-runtime-summary]" ) ;
const sourceList = page . querySelector ( "[data-system-source-list]" ) ;
if ( ! refreshButton || ! refreshLabel || ! refreshSpinner || ! feedback || ! functionalList || ! parentKeys || ! botSettingsList || ! runtimeSummary || ! securitySummary || ! modelRuntimeSummary || ! sourceList ) {
return ;
}
refreshButton . addEventListener ( "click" , ( ) => {
void loadConfiguration ( ) ;
} ) ;
void loadConfiguration ( ) ;
async function loadConfiguration ( ) {
toggleRefreshing ( true ) ;
clearFeedback ( ) ;
const [ overviewResult , runtimeResult , securityResult , modelRuntimesResult , functionalResult , botGovernanceResult ] = await Promise . all ( [
fetchPanelJson ( page . dataset . overviewEndpoint ) ,
fetchPanelJson ( page . dataset . runtimeEndpoint ) ,
fetchPanelJson ( page . dataset . securityEndpoint ) ,
fetchPanelJson ( page . dataset . modelRuntimesEndpoint ) ,
fetchPanelJson ( page . dataset . functionalEndpoint ) ,
fetchPanelJson ( page . dataset . botGovernanceEndpoint ) ,
] ) ;
if ( functionalResult . ok ) {
renderFunctionalCatalog ( functionalResult . body ) ;
} else {
renderLockedState ( functionalList , "Catalogo funcional indisponivel" , functionalResult . message || "Nao foi possivel carregar o catalogo funcional." ) ;
setText ( "[data-system-config-count]" , "0" ) ;
setText ( "[data-system-functional-mode]" , "Bloqueado" ) ;
}
if ( botGovernanceResult . ok ) {
renderBotGovernance ( botGovernanceResult . body ) ;
} else {
parentKeys . innerHTML = '<span class="badge rounded-pill bg-body-tertiary text-secondary border">Bloqueado</span>' ;
renderLockedState ( botSettingsList , "Governanca do bot indisponivel" , botGovernanceResult . message || "Nao foi possivel carregar os campos governados pelo bot." ) ;
setText ( "[data-system-bot-setting-count]" , "0" ) ;
}
if ( runtimeResult . ok ) {
renderRuntime ( runtimeResult . body ) ;
} else {
renderLockedState ( runtimeSummary , "Runtime protegido" , runtimeResult . message || "A sessao atual nao pode ler o runtime administrativo." ) ;
}
if ( securityResult . ok ) {
renderSecurity ( securityResult . body ) ;
} else {
renderLockedState ( securitySummary , "Seguranca protegida" , securityResult . message || "A sessao atual nao pode ler o snapshot de seguranca." ) ;
}
if ( modelRuntimesResult . ok ) {
renderModelRuntimes ( modelRuntimesResult . body ) ;
} else {
renderLockedState ( modelRuntimeSummary , "Separacao tecnica protegida" , modelRuntimesResult . message || "A sessao atual nao pode ler os perfis de runtime." ) ;
setText ( "[data-system-runtime-profile-count]" , "0" ) ;
}
if ( overviewResult . ok ) {
renderSources ( overviewResult . body ) ;
} else {
renderLockedState ( sourceList , "Overview tecnico protegido" , overviewResult . message || "A sessao atual nao pode ler as fontes do snapshot." ) ;
setText ( "[data-system-source-count]" , "0" ) ;
}
const directorOnlyLocked = [ overviewResult , runtimeResult , securityResult , modelRuntimesResult ] . some ( ( result ) => ! result . ok ) ;
if ( functionalResult . ok && botGovernanceResult . ok && directorOnlyLocked ) {
showFeedback ( "info" , "A sessao atual consegue consultar a configuracao funcional do sistema. Blocos de runtime, seguranca e separacao tecnica exigem manage_settings." ) ;
} else if ( functionalResult . ok && botGovernanceResult . ok ) {
showFeedback ( "success" , "Snapshot de configuracoes do sistema carregado com sucesso." ) ;
} else {
showFeedback ( "warning" , "A tela nao conseguiu carregar todas as superficies de configuracao com a sessao atual." ) ;
}
setText ( "[data-system-last-sync]" , formatNow ( ) ) ;
toggleRefreshing ( false ) ;
}
function renderFunctionalCatalog ( payload ) {
const configurations = Array . isArray ( payload ? . configurations ) ? payload . configurations : [ ] ;
setText ( "[data-system-config-count]" , String ( configurations . length ) ) ;
setText ( "[data-system-functional-mode]" , formatModeLabel ( payload ? . mode ) ) ;
functionalList . innerHTML = configurations . length > 0
? configurations . map ( ( item ) => {
const writableCount = Array . isArray ( item ? . fields )
? item . fields . filter ( ( field ) => field ? . writable ) . length
: 0 ;
const editingLabel = writableCount > 0 ? ` ${ writableCount } campo(s) ajustavel(is) ` : "Somente leitura" ;
const impactLabel = item ? . affects _product _runtime ? "Impacta o atendimento" : "Uso interno do admin" ;
return ` <article class="admin-system-item rounded-4 p-4"><div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-3"><div><div class="small text-uppercase fw-semibold text-secondary mb-2"> ${ escapeHtml ( formatDomainLabel ( item ? . domain || "sistema" ) ) } </div><h4 class="h5 fw-semibold mb-1"> ${ escapeHtml ( formatConfigTitle ( item ? . config _key || "configuracao" ) ) } </h4><div class="small text-secondary"> ${ escapeHtml ( item ? . description || "" ) } </div></div><span class="badge rounded-pill bg-body-tertiary text-secondary border"> ${ escapeHtml ( formatMutabilityLabel ( item ? . mutability || "readonly" ) ) } </span></div><div class="admin-system-meta small text-secondary"><div><strong>Campos visiveis:</strong> ${ escapeHtml ( String ( Array . isArray ( item ? . fields ) ? item . fields . length : 0 ) ) } </div><div><strong>Ajustes nesta fase:</strong> ${ escapeHtml ( editingLabel ) } </div><div><strong>Impacto:</strong> ${ escapeHtml ( impactLabel ) } </div></div></article> ` ;
} ) . join ( "" )
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Nenhuma configuracao encontrada</h4><p class="text-secondary mb-0">O catalogo funcional nao retornou itens nesta leitura.</p></div> ` ;
}
function renderBotGovernance ( payload ) {
const settings = Array . isArray ( payload ? . settings ) ? payload . settings : [ ] ;
const parentConfigKeys = Array . isArray ( payload ? . parent _config _keys ) ? payload . parent _config _keys : [ ] ;
setText ( "[data-system-bot-setting-count]" , String ( settings . length ) ) ;
parentKeys . innerHTML = parentConfigKeys . length > 0
? parentConfigKeys . map ( ( item ) => ` <span class="badge rounded-pill bg-body-tertiary text-secondary border"> ${ escapeHtml ( item ) } </span> ` ) . join ( "" )
: '<span class="badge rounded-pill bg-body-tertiary text-secondary border">Sem parent keys</span>' ;
botSettingsList . innerHTML = settings . length > 0
? settings . slice ( 0 , 12 ) . map ( ( item ) => ` <article class="admin-system-item rounded-4 p-4"><div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-3"><div><div class="small text-uppercase fw-semibold text-secondary mb-2"> ${ escapeHtml ( formatDomainLabel ( item ? . area || "bot" ) ) } </div><h4 class="h5 fw-semibold mb-1"> ${ escapeHtml ( humanizeKey ( item ? . setting _key || "setting" ) ) } </h4><div class="small text-secondary"> ${ escapeHtml ( item ? . description || "" ) } </div></div><span class="badge rounded-pill bg-body-tertiary text-secondary border"> ${ escapeHtml ( formatMutabilityLabel ( item ? . mutability || "versioned" ) ) } </span></div><div class="admin-system-meta small text-secondary"><div><strong>Grupo:</strong> ${ escapeHtml ( formatConfigTitle ( item ? . parent _config _key || "-" ) ) } </div><div><strong>Escrita direta:</strong> ${ item ? . direct _product _write _allowed ? 'Permitida' : 'Bloqueada' } </div></div></article> ` ) . join ( "" )
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Nenhum campo governado encontrado</h4><p class="text-secondary mb-0">A governanca do bot nao retornou itens nesta leitura.</p></div> ` ;
}
function renderRuntime ( payload ) {
const runtime = payload ? . runtime ;
if ( ! runtime ) {
renderLockedState ( runtimeSummary , "Runtime indisponivel" , "Nao foi possivel interpretar a resposta do runtime." ) ;
return ;
}
runtimeSummary . innerHTML = ` <div class="admin-system-stack"><div class="admin-system-item rounded-4 p-4"><div class="small text-uppercase fw-semibold text-secondary mb-2">Aplicacao</div><div class="admin-system-meta small text-secondary"><div><strong>Nome:</strong> ${ escapeHtml ( runtime ? . application ? . app _name || "-" ) } </div><div><strong>Ambiente:</strong> ${ escapeHtml ( runtime ? . application ? . environment || "-" ) } </div><div><strong>Versao:</strong> ${ escapeHtml ( runtime ? . application ? . version || "-" ) } </div><div><strong>Modo debug:</strong> ${ runtime ? . application ? . debug ? 'Ativo' : 'Desligado' } </div></div><p class="small text-secondary mb-0 mt-3">Detalhes internos de infraestrutura e cookies nao aparecem aqui para manter a tela mais limpa.</p></div></div> ` ;
}
function renderSecurity ( payload ) {
const security = payload ? . security ;
if ( ! security ) {
renderLockedState ( securitySummary , "Seguranca indisponivel" , "Nao foi possivel interpretar a resposta de seguranca." ) ;
return ;
}
securitySummary . innerHTML = ` <div class="admin-system-stack"><div class="admin-system-item rounded-4 p-4"><div class="small text-uppercase fw-semibold text-secondary mb-2">Senha e sessao</div><div class="admin-system-meta small text-secondary"><div><strong>Tamanho minimo:</strong> ${ escapeHtml ( String ( security ? . password ? . min _length || 0 ) ) } caracteres</div><div><strong>Requisitos:</strong> ${ renderPasswordRequirements ( security ? . password ) } </div><div><strong>Acesso expira em:</strong> ${ escapeHtml ( String ( security ? . tokens ? . access _token _ttl _minutes || 0 ) ) } min</div><div><strong>Renovacao disponivel por:</strong> ${ escapeHtml ( String ( security ? . tokens ? . refresh _token _ttl _days || 0 ) ) } dias</div></div><p class="small text-secondary mb-0 mt-3">Informacoes internas de assinatura e bootstrap ficam fora desta tela para reduzir ruido.</p></div></div> ` ;
}
function renderModelRuntimes ( payload ) {
const modelRuntimes = payload ? . model _runtimes ;
const profiles = Array . isArray ( modelRuntimes ? . runtime _profiles ) ? modelRuntimes . runtime _profiles : [ ] ;
const separationRules = Array . isArray ( modelRuntimes ? . separation _rules ) ? modelRuntimes . separation _rules : [ ] ;
setText ( "[data-system-runtime-profile-count]" , String ( profiles . length ) ) ;
modelRuntimeSummary . innerHTML = profiles . length > 0
? ` <div class="admin-system-stack"><div class="admin-system-item rounded-4 p-4"><div class="small text-uppercase fw-semibold text-secondary mb-3">Regras principais</div><ul class="small text-secondary ps-3 mb-0"> ${ separationRules . map ( ( rule ) => ` <li class="mb-2"> ${ escapeHtml ( rule ) } </li> ` ) . join ( "" ) } </ul></div> ${ profiles . map ( ( profile ) => ` <article class="admin-system-item rounded-4 p-4"><div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-3"><div><div class="small text-uppercase fw-semibold text-secondary mb-2"> ${ escapeHtml ( formatRuntimeTargetLabel ( profile ? . runtime _target || "runtime" ) ) } </div><h4 class="h5 fw-semibold mb-1"> ${ escapeHtml ( formatConfigTitle ( profile ? . config _key || "perfil" ) ) } </h4><div class="small text-secondary"> ${ escapeHtml ( profile ? . description || "" ) } </div></div><span class="badge rounded-pill bg-body-tertiary text-secondary border"> ${ profile ? . affects _customer _response ? 'Atendimento' : 'Interno' } </span></div><div class="admin-system-meta small text-secondary"><div><strong>Servico:</strong> ${ escapeHtml ( humanizeKey ( profile ? . consumed _by _service || "-" ) ) } </div><div><strong>Uso principal:</strong> ${ escapeHtml ( formatPurposeLabel ( profile ? . purpose || "-" ) ) } </div><div><strong>Gera tools:</strong> ${ profile ? . can _generate _code ? 'Sim' : 'Nao' } </div><div><strong>Rollback separado:</strong> ${ profile ? . rollback _independently ? 'Sim' : 'Nao' } </div></div></article> ` ) . join ( "" ) } </div> `
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Nenhum perfil retornado</h4><p class="text-secondary mb-0">A separacao de runtime nao retornou perfis nesta leitura.</p></div> ` ;
}
function renderSources ( payload ) {
const sources = Array . isArray ( payload ? . sources ) ? payload . sources : [ ] ;
setText ( "[data-system-source-count]" , String ( sources . length ) ) ;
sourceList . innerHTML = sources . length > 0
? sources . map ( ( item ) => ` <article class="admin-system-item rounded-4 p-4"><div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-3"><div><div class="small text-uppercase fw-semibold text-secondary mb-2"> ${ escapeHtml ( formatSourceLabel ( item ? . source || "origem" ) ) } </div><h4 class="h5 fw-semibold mb-1"> ${ escapeHtml ( formatConfigTitle ( item ? . key || "configuracao" ) ) } </h4><div class="small text-secondary"> ${ escapeHtml ( item ? . description || "" ) } </div></div><span class="badge rounded-pill ${ item ? . mutable ? 'bg-warning-subtle text-warning-emphasis border border-warning-subtle' : 'bg-success-subtle text-success-emphasis border border-success-subtle' } "> ${ item ? . mutable ? 'Pode mudar' : 'Base fixa' } </span></div></article> ` ) . join ( "" )
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Nenhuma fonte encontrada</h4><p class="text-secondary mb-0">O overview tecnico nao retornou fontes nesta leitura.</p></div> ` ;
}
function renderPasswordRequirements ( passwordPolicy ) {
const requirements = [ ] ;
if ( passwordPolicy ? . require _uppercase ) requirements . push ( "letra maiuscula" ) ;
if ( passwordPolicy ? . require _lowercase ) requirements . push ( "letra minuscula" ) ;
if ( passwordPolicy ? . require _digit ) requirements . push ( "numero" ) ;
if ( passwordPolicy ? . require _symbol ) requirements . push ( "simbolo" ) ;
return requirements . length > 0 ? escapeHtml ( requirements . join ( ", " ) ) : "nenhum requisito adicional" ;
}
function renderLockedState ( container , title , message ) {
container . innerHTML = ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2"> ${ escapeHtml ( title ) } </h4><p class="text-secondary mb-0"> ${ escapeHtml ( message ) } </p></div> ` ;
}
function toggleRefreshing ( isLoading ) {
refreshButton . disabled = isLoading ;
refreshSpinner . classList . toggle ( "d-none" , ! isLoading ) ;
refreshLabel . textContent = isLoading ? "Atualizando..." : "Atualizar leitura" ;
}
function clearFeedback ( ) {
feedback . className = "alert d-none rounded-4 mb-4" ;
feedback . textContent = "" ;
}
function showFeedback ( variant , message ) {
feedback . className = ` alert alert- ${ variant } rounded-4 mb-4 ` ;
feedback . textContent = message ;
}
}
function mountSalesRevenueReportsPage ( page ) {
const refreshButton = page . querySelector ( "[data-admin-commercial-refresh]" ) ;
const refreshLabel = page . querySelector ( "[data-commercial-refresh-label]" ) ;
const refreshSpinner = page . querySelector ( "[data-commercial-refresh-spinner]" ) ;
const feedback = document . getElementById ( "admin-commercial-feedback" ) ;
const salesMetrics = page . querySelector ( "[data-sales-overview-metrics]" ) ;
const salesMaterialization = page . querySelector ( "[data-sales-materialization]" ) ;
const salesReportList = page . querySelector ( "[data-sales-report-list]" ) ;
const salesNextSteps = page . querySelector ( "[data-sales-next-steps]" ) ;
const revenueMetrics = page . querySelector ( "[data-revenue-overview-metrics]" ) ;
const revenueMaterialization = page . querySelector ( "[data-revenue-materialization]" ) ;
const revenueReportList = page . querySelector ( "[data-revenue-report-list]" ) ;
const revenueNextSteps = page . querySelector ( "[data-revenue-next-steps]" ) ;
if ( ! refreshButton || ! refreshLabel || ! refreshSpinner || ! feedback || ! salesMetrics || ! salesMaterialization || ! salesReportList || ! salesNextSteps || ! revenueMetrics || ! revenueMaterialization || ! revenueReportList || ! revenueNextSteps ) {
return ;
}
refreshButton . addEventListener ( "click" , ( ) => {
void loadReports ( ) ;
} ) ;
void loadReports ( ) ;
async function loadReports ( ) {
toggleRefreshing ( true ) ;
clearFeedback ( ) ;
const [ salesResult , revenueResult ] = await Promise . all ( [
fetchPanelJson ( page . dataset . salesOverviewEndpoint ) ,
fetchPanelJson ( page . dataset . revenueOverviewEndpoint ) ,
] ) ;
if ( salesResult . ok ) {
renderDomainOverview ( { kind : "sales" , payload : salesResult . body , metricsTarget : salesMetrics , materializationTarget : salesMaterialization , reportsTarget : salesReportList , nextStepsTarget : salesNextSteps } ) ;
} else {
renderLockedState ( salesMetrics , "Vendas indisponivel" , salesResult . message || "Nao foi possivel carregar o overview de vendas." ) ;
salesMaterialization . innerHTML = "" ;
salesReportList . innerHTML = "" ;
salesNextSteps . innerHTML = "" ;
setText ( "[data-sales-report-count]" , "0" ) ;
}
if ( revenueResult . ok ) {
renderDomainOverview ( { kind : "revenue" , payload : revenueResult . body , metricsTarget : revenueMetrics , materializationTarget : revenueMaterialization , reportsTarget : revenueReportList , nextStepsTarget : revenueNextSteps } ) ;
} else {
renderLockedState ( revenueMetrics , "Arrecadacao indisponivel" , revenueResult . message || "Nao foi possivel carregar o overview de arrecadacao." ) ;
revenueMaterialization . innerHTML = "" ;
revenueReportList . innerHTML = "" ;
revenueNextSteps . innerHTML = "" ;
setText ( "[data-revenue-report-count]" , "0" ) ;
}
if ( salesResult . ok && revenueResult . ok ) {
const salesPayload = salesResult . body ;
const revenuePayload = revenueResult . body ;
const datasetCount = uniqueCount ( salesPayload ? . source _dataset _keys , revenuePayload ? . source _dataset _keys ) ;
const syncStrategy = salesPayload ? . materialization ? . sync _strategy === revenuePayload ? . materialization ? . sync _strategy
? salesPayload ? . materialization ? . sync _strategy
: "mixed" ;
setText ( "[data-commercial-dataset-count]" , String ( datasetCount ) ) ;
setText ( "[data-commercial-sync-strategy]" , formatSyncStrategyLabel ( syncStrategy || "--" ) ) ;
showFeedback ( "success" , "Relatorios de vendas e arrecadacao carregados com sucesso na sessao do painel." ) ;
} else if ( salesResult . ok || revenueResult . ok ) {
const onlyLoaded = salesResult . ok ? "vendas" : "arrecadacao" ;
const datasetCount = salesResult . ok
? ( Array . isArray ( salesResult . body ? . source _dataset _keys ) ? salesResult . body . source _dataset _keys . length : 0 )
: ( Array . isArray ( revenueResult . body ? . source _dataset _keys ) ? revenueResult . body . source _dataset _keys . length : 0 ) ;
const syncStrategy = salesResult . ok ? salesResult . body ? . materialization ? . sync _strategy : revenueResult . body ? . materialization ? . sync _strategy ;
setText ( "[data-commercial-dataset-count]" , String ( datasetCount ) ) ;
setText ( "[data-commercial-sync-strategy]" , formatSyncStrategyLabel ( syncStrategy || "--" ) ) ;
showFeedback ( "warning" , ` A tela carregou apenas o overview de ${ onlyLoaded } com a sessao atual. ` ) ;
} else {
setText ( "[data-commercial-dataset-count]" , "0" ) ;
setText ( "[data-commercial-sync-strategy]" , "--" ) ;
showFeedback ( "warning" , "Nao foi possivel carregar os relatorios comerciais na sessao atual." ) ;
}
setText ( "[data-commercial-last-sync]" , formatNow ( ) ) ;
toggleRefreshing ( false ) ;
}
function renderDomainOverview ( { kind , payload , metricsTarget , materializationTarget , reportsTarget , nextStepsTarget } ) {
const reports = Array . isArray ( payload ? . reports ) ? payload . reports : [ ] ;
const metrics = Array . isArray ( payload ? . metrics ) ? payload . metrics : [ ] ;
const nextSteps = Array . isArray ( payload ? . next _steps ) ? payload . next _steps : [ ] ;
const reportCountSelector = kind === "sales" ? "[data-sales-report-count]" : "[data-revenue-report-count]" ;
setText ( reportCountSelector , String ( reports . length ) ) ;
metricsTarget . innerHTML = metrics . length > 0
? ` <div class="admin-commercial-grid"> ${ metrics . map ( ( item ) => ` <article class="admin-commercial-item rounded-4 p-4"><div class="small text-uppercase fw-semibold text-secondary mb-2"> ${ escapeHtml ( item ? . label || item ? . key || "metrica" ) } </div><div class="h3 fw-semibold mb-2"> ${ escapeHtml ( item ? . value || "0" ) } </div><div class="small text-secondary"> ${ escapeHtml ( item ? . description || "" ) } </div></article> ` ) . join ( "" ) } </div> `
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Metricas nao disponiveis</h4><p class="text-secondary mb-0">O overview nao retornou metricas nesta leitura.</p></div> ` ;
materializationTarget . innerHTML = payload ? . materialization
? ` <article class="admin-commercial-item rounded-4 p-4"><div class="small text-uppercase fw-semibold text-secondary mb-3">Atualizacao da tela</div><div class="admin-commercial-meta small text-secondary"><div><strong>Ritmo:</strong> ${ escapeHtml ( formatSyncStrategyLabel ( payload ? . materialization ? . sync _strategy || "-" ) ) } </div><div><strong>Camada:</strong> ${ escapeHtml ( formatStorageLabel ( payload ? . materialization ? . storage _shape || "-" ) ) } </div><div><strong>Consulta:</strong> ${ escapeHtml ( formatQuerySurfaceLabel ( payload ? . materialization ? . query _surface || "-" ) ) } </div></div></article> `
: "" ;
reportsTarget . innerHTML = reports . length > 0
? reports . map ( ( item ) => ` <article class="admin-commercial-item rounded-4 p-4"><div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-3"><div><h4 class="h5 fw-semibold mb-1"> ${ escapeHtml ( item ? . label || humanizeKey ( item ? . report _key || "relatorio" ) ) } </h4><div class="small text-secondary"> ${ escapeHtml ( item ? . description || "" ) } </div></div><span class="badge rounded-pill bg-body-tertiary text-secondary border"> ${ escapeHtml ( formatGranularityLabel ( item ? . default _granularity || "aggregate" ) ) } </span></div><div class="admin-commercial-chip-group"><span class="badge rounded-pill bg-body-tertiary text-secondary border">Indicadores: ${ escapeHtml ( String ( ( item ? . supported _metric _keys || [ ] ) . length ) ) } </span><span class="badge rounded-pill bg-body-tertiary text-secondary border">Recortes: ${ escapeHtml ( String ( ( item ? . supported _dimension _fields || [ ] ) . length ) ) } </span></div></article> ` ) . join ( "" )
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Nenhum relatorio previsto</h4><p class="text-secondary mb-0">O overview nao retornou relatorios para este dominio.</p></div> ` ;
nextStepsTarget . innerHTML = nextSteps . length > 0
? nextSteps . map ( ( item ) => ` <div class="admin-commercial-item rounded-4 p-3 small text-secondary"> ${ escapeHtml ( item ) } </div> ` ) . join ( "" )
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Sem proximos passos</h4><p class="text-secondary mb-0">Nenhuma orientacao adicional foi retornada para este overview.</p></div> ` ;
}
function renderLockedState ( container , title , message ) {
container . innerHTML = ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2"> ${ escapeHtml ( title ) } </h4><p class="text-secondary mb-0"> ${ escapeHtml ( message ) } </p></div> ` ;
}
function toggleRefreshing ( isLoading ) {
refreshButton . disabled = isLoading ;
refreshSpinner . classList . toggle ( "d-none" , ! isLoading ) ;
refreshLabel . textContent = isLoading ? "Atualizando..." : "Atualizar leitura" ;
}
function clearFeedback ( ) {
feedback . className = "alert d-none rounded-4 mb-4" ;
feedback . textContent = "" ;
}
function showFeedback ( variant , message ) {
feedback . className = ` alert alert- ${ variant } rounded-4 mb-4 ` ;
feedback . textContent = message ;
}
}
function mountRentalReportsPage ( page ) {
const refreshButton = page . querySelector ( "[data-admin-rental-refresh]" ) ;
const refreshLabel = page . querySelector ( "[data-rental-refresh-label]" ) ;
const refreshSpinner = page . querySelector ( "[data-rental-refresh-spinner]" ) ;
const feedback = document . getElementById ( "admin-rental-feedback" ) ;
const overviewMetrics = page . querySelector ( "[data-rental-overview-metrics]" ) ;
const materialization = page . querySelector ( "[data-rental-materialization]" ) ;
const reportList = page . querySelector ( "[data-rental-report-list]" ) ;
const nextSteps = page . querySelector ( "[data-rental-next-steps]" ) ;
if ( ! refreshButton || ! refreshLabel || ! refreshSpinner || ! feedback || ! overviewMetrics || ! materialization || ! reportList || ! nextSteps ) {
return ;
}
refreshButton . addEventListener ( "click" , ( ) => {
void loadOverview ( ) ;
} ) ;
void loadOverview ( ) ;
async function loadOverview ( ) {
toggleRefreshing ( true ) ;
clearFeedback ( ) ;
const result = await fetchPanelJson ( page . dataset . rentalOverviewEndpoint ) ;
if ( result . ok ) {
const payload = result . body ;
const metrics = Array . isArray ( payload ? . metrics ) ? payload . metrics : [ ] ;
const reports = Array . isArray ( payload ? . reports ) ? payload . reports : [ ] ;
const datasets = Array . isArray ( payload ? . source _dataset _keys ) ? payload . source _dataset _keys : [ ] ;
const plannedSteps = Array . isArray ( payload ? . next _steps ) ? payload . next _steps : [ ] ;
setText ( "[data-rental-report-count]" , String ( reports . length ) ) ;
setText ( "[data-rental-dataset-count]" , String ( datasets . length ) ) ;
setText ( "[data-rental-sync-strategy]" , formatSyncStrategyLabel ( payload ? . materialization ? . sync _strategy || "--" ) ) ;
setText ( "[data-rental-source-domain]" , formatDomainLabel ( payload ? . source _domain || "--" ) ) ;
overviewMetrics . innerHTML = metrics . length > 0
? ` <div class="admin-rental-grid"> ${ metrics . map ( ( item ) => ` <article class="admin-rental-item rounded-4 p-4"><div class="small text-uppercase fw-semibold text-secondary mb-2"> ${ escapeHtml ( item ? . label || item ? . key || "metrica" ) } </div><div class="h3 fw-semibold mb-2"> ${ escapeHtml ( item ? . value || "0" ) } </div><div class="small text-secondary"> ${ escapeHtml ( item ? . description || "" ) } </div></article> ` ) . join ( "" ) } </div> `
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Metricas nao disponiveis</h4><p class="text-secondary mb-0">O overview de locacao nao retornou metricas nesta leitura.</p></div> ` ;
materialization . innerHTML = payload ? . materialization
? ` <article class="admin-rental-item rounded-4 p-4"><div class="small text-uppercase fw-semibold text-secondary mb-3">Atualizacao da tela</div><div class="admin-rental-meta small text-secondary"><div><strong>Ritmo:</strong> ${ escapeHtml ( formatSyncStrategyLabel ( payload ? . materialization ? . sync _strategy || "-" ) ) } </div><div><strong>Camada:</strong> ${ escapeHtml ( formatStorageLabel ( payload ? . materialization ? . storage _shape || "-" ) ) } </div><div><strong>Consulta:</strong> ${ escapeHtml ( formatQuerySurfaceLabel ( payload ? . materialization ? . query _surface || "-" ) ) } </div></div></article> `
: "" ;
reportList . innerHTML = reports . length > 0
? reports . map ( ( item ) => ` <article class="admin-rental-item rounded-4 p-4"><div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-3"><div><h4 class="h5 fw-semibold mb-1"> ${ escapeHtml ( item ? . label || humanizeKey ( item ? . report _key || "relatorio" ) ) } </h4><div class="small text-secondary"> ${ escapeHtml ( item ? . description || "" ) } </div></div><span class="badge rounded-pill bg-body-tertiary text-secondary border"> ${ escapeHtml ( formatGranularityLabel ( item ? . default _granularity || "aggregate" ) ) } </span></div><div class="admin-rental-chip-group"><span class="badge rounded-pill bg-body-tertiary text-secondary border">Indicadores: ${ escapeHtml ( String ( ( item ? . supported _metric _keys || [ ] ) . length ) ) } </span><span class="badge rounded-pill bg-body-tertiary text-secondary border">Recortes: ${ escapeHtml ( String ( ( item ? . supported _dimension _fields || [ ] ) . length ) ) } </span><span class="badge rounded-pill bg-body-tertiary text-secondary border">Filtros: ${ escapeHtml ( String ( ( item ? . supported _filter _fields || [ ] ) . length ) ) } </span></div></article> ` ) . join ( "" )
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Nenhum relatorio previsto</h4><p class="text-secondary mb-0">O overview nao retornou relatorios de locacao nesta leitura.</p></div> ` ;
nextSteps . innerHTML = plannedSteps . length > 0
? plannedSteps . map ( ( item ) => ` <div class="admin-rental-item rounded-4 p-3 small text-secondary"> ${ escapeHtml ( item ) } </div> ` ) . join ( "" )
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Sem proximos passos</h4><p class="text-secondary mb-0">Nenhuma orientacao adicional foi retornada para locacao.</p></div> ` ;
showFeedback ( "success" , "Relatorios de locacao carregados com sucesso na sessao do painel." ) ;
} else {
setText ( "[data-rental-report-count]" , "0" ) ;
setText ( "[data-rental-dataset-count]" , "0" ) ;
setText ( "[data-rental-sync-strategy]" , "--" ) ;
setText ( "[data-rental-source-domain]" , "--" ) ;
overviewMetrics . innerHTML = ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Locacao indisponivel</h4><p class="text-secondary mb-0"> ${ escapeHtml ( result . message || "Nao foi possivel carregar o overview de locacao." ) } </p></div> ` ;
materialization . innerHTML = "" ;
reportList . innerHTML = "" ;
nextSteps . innerHTML = "" ;
showFeedback ( "warning" , result . message || "Nao foi possivel carregar os relatorios de locacao na sessao atual." ) ;
}
setText ( "[data-rental-last-sync]" , formatNow ( ) ) ;
toggleRefreshing ( false ) ;
}
function toggleRefreshing ( isLoading ) {
refreshButton . disabled = isLoading ;
refreshSpinner . classList . toggle ( "d-none" , ! isLoading ) ;
refreshLabel . textContent = isLoading ? "Atualizando..." : "Atualizar leitura" ;
}
function clearFeedback ( ) {
feedback . className = "alert d-none rounded-4 mb-4" ;
feedback . textContent = "" ;
}
function showFeedback ( variant , message ) {
feedback . className = ` alert alert- ${ variant } rounded-4 mb-4 ` ;
feedback . textContent = message ;
}
}
function mountBotMonitoringPage ( page ) {
const refreshButton = page . querySelector ( "[data-admin-bot-monitoring-refresh]" ) ;
const refreshLabel = page . querySelector ( "[data-bot-monitoring-refresh-label]" ) ;
const refreshSpinner = page . querySelector ( "[data-bot-monitoring-refresh-spinner]" ) ;
const feedback = document . getElementById ( "admin-bot-monitoring-feedback" ) ;
const botFlowMetrics = page . querySelector ( "[data-bot-flow-overview-metrics]" ) ;
const botFlowMaterialization = page . querySelector ( "[data-bot-flow-materialization]" ) ;
const botFlowReportList = page . querySelector ( "[data-bot-flow-report-list]" ) ;
const botFlowNextSteps = page . querySelector ( "[data-bot-flow-next-steps]" ) ;
const telemetryMetrics = page . querySelector ( "[data-bot-telemetry-overview-metrics]" ) ;
const telemetryMaterialization = page . querySelector ( "[data-bot-telemetry-materialization]" ) ;
const telemetryReportList = page . querySelector ( "[data-bot-telemetry-report-list]" ) ;
const telemetryNextSteps = page . querySelector ( "[data-bot-telemetry-next-steps]" ) ;
if ( ! refreshButton || ! refreshLabel || ! refreshSpinner || ! feedback || ! botFlowMetrics || ! botFlowMaterialization || ! botFlowReportList || ! botFlowNextSteps || ! telemetryMetrics || ! telemetryMaterialization || ! telemetryReportList || ! telemetryNextSteps ) {
return ;
}
refreshButton . addEventListener ( "click" , ( ) => {
void loadMonitoring ( ) ;
} ) ;
void loadMonitoring ( ) ;
async function loadMonitoring ( ) {
toggleRefreshing ( true ) ;
clearFeedback ( ) ;
const [ botFlowResult , telemetryResult ] = await Promise . all ( [
fetchPanelJson ( page . dataset . botFlowOverviewEndpoint ) ,
fetchPanelJson ( page . dataset . telemetryOverviewEndpoint ) ,
] ) ;
if ( botFlowResult . ok ) {
renderDomainOverview ( { kind : "flow" , payload : botFlowResult . body , metricsTarget : botFlowMetrics , materializationTarget : botFlowMaterialization , reportsTarget : botFlowReportList , nextStepsTarget : botFlowNextSteps } ) ;
} else {
renderLockedState ( botFlowMetrics , "Fluxo do bot indisponivel" , botFlowResult . message || "Nao foi possivel carregar o overview operacional do bot." ) ;
botFlowMaterialization . innerHTML = "" ;
botFlowReportList . innerHTML = "" ;
botFlowNextSteps . innerHTML = "" ;
setText ( "[data-bot-flow-report-count]" , "0" ) ;
}
if ( telemetryResult . ok ) {
renderDomainOverview ( { kind : "telemetry" , payload : telemetryResult . body , metricsTarget : telemetryMetrics , materializationTarget : telemetryMaterialization , reportsTarget : telemetryReportList , nextStepsTarget : telemetryNextSteps } ) ;
} else {
renderLockedState ( telemetryMetrics , "Telemetria indisponivel" , telemetryResult . message || "Nao foi possivel carregar o overview de telemetria conversacional." ) ;
telemetryMaterialization . innerHTML = "" ;
telemetryReportList . innerHTML = "" ;
telemetryNextSteps . innerHTML = "" ;
setText ( "[data-bot-telemetry-report-count]" , "0" ) ;
}
if ( botFlowResult . ok && telemetryResult . ok ) {
const botFlowPayload = botFlowResult . body ;
const telemetryPayload = telemetryResult . body ;
const datasetCount = uniqueCount ( botFlowPayload ? . source _dataset _keys , telemetryPayload ? . source _dataset _keys ) ;
const syncStrategy = botFlowPayload ? . materialization ? . sync _strategy === telemetryPayload ? . materialization ? . sync _strategy
? botFlowPayload ? . materialization ? . sync _strategy
: "mixed" ;
setText ( "[data-bot-monitoring-dataset-count]" , String ( datasetCount ) ) ;
setText ( "[data-bot-monitoring-sync-strategy]" , formatSyncStrategyLabel ( syncStrategy || "--" ) ) ;
showFeedback ( "success" , "Fluxo operacional do bot e telemetria conversacional carregados com sucesso na sessao do painel." ) ;
} else if ( botFlowResult . ok || telemetryResult . ok ) {
const onlyLoaded = botFlowResult . ok ? "fluxo do bot" : "telemetria conversacional" ;
const datasetCount = botFlowResult . ok
? ( Array . isArray ( botFlowResult . body ? . source _dataset _keys ) ? botFlowResult . body . source _dataset _keys . length : 0 )
: ( Array . isArray ( telemetryResult . body ? . source _dataset _keys ) ? telemetryResult . body . source _dataset _keys . length : 0 ) ;
const syncStrategy = botFlowResult . ok ? botFlowResult . body ? . materialization ? . sync _strategy : telemetryResult . body ? . materialization ? . sync _strategy ;
setText ( "[data-bot-monitoring-dataset-count]" , String ( datasetCount ) ) ;
setText ( "[data-bot-monitoring-sync-strategy]" , formatSyncStrategyLabel ( syncStrategy || "--" ) ) ;
showFeedback ( "warning" , ` A tela carregou apenas ${ onlyLoaded } com a sessao atual. ` ) ;
} else {
setText ( "[data-bot-monitoring-dataset-count]" , "0" ) ;
setText ( "[data-bot-monitoring-sync-strategy]" , "--" ) ;
showFeedback ( "warning" , "Nao foi possivel carregar o monitoramento operacional do bot na sessao atual." ) ;
}
setText ( "[data-bot-monitoring-last-sync]" , formatNow ( ) ) ;
toggleRefreshing ( false ) ;
}
function renderDomainOverview ( { kind , payload , metricsTarget , materializationTarget , reportsTarget , nextStepsTarget } ) {
const reports = Array . isArray ( payload ? . reports ) ? payload . reports : [ ] ;
const metrics = Array . isArray ( payload ? . metrics ) ? payload . metrics : [ ] ;
const nextSteps = Array . isArray ( payload ? . next _steps ) ? payload . next _steps : [ ] ;
const reportCountSelector = kind === "flow" ? "[data-bot-flow-report-count]" : "[data-bot-telemetry-report-count]" ;
setText ( reportCountSelector , String ( reports . length ) ) ;
metricsTarget . innerHTML = metrics . length > 0
? ` <div class="admin-bot-monitoring-grid"> ${ metrics . map ( ( item ) => ` <article class="admin-bot-monitoring-item rounded-4 p-4"><div class="small text-uppercase fw-semibold text-secondary mb-2"> ${ escapeHtml ( item ? . label || item ? . key || "metrica" ) } </div><div class="h3 fw-semibold mb-2"> ${ escapeHtml ( item ? . value || "0" ) } </div><div class="small text-secondary"> ${ escapeHtml ( item ? . description || "" ) } </div></article> ` ) . join ( "" ) } </div> `
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Metricas nao disponiveis</h4><p class="text-secondary mb-0">O overview nao retornou metricas nesta leitura.</p></div> ` ;
materializationTarget . innerHTML = payload ? . materialization
? ` <article class="admin-bot-monitoring-item rounded-4 p-4"><div class="small text-uppercase fw-semibold text-secondary mb-3">Atualizacao da tela</div><div class="admin-bot-monitoring-meta small text-secondary"><div><strong>Ritmo:</strong> ${ escapeHtml ( formatSyncStrategyLabel ( payload ? . materialization ? . sync _strategy || "-" ) ) } </div><div><strong>Camada:</strong> ${ escapeHtml ( formatStorageLabel ( payload ? . materialization ? . storage _shape || "-" ) ) } </div><div><strong>Consulta:</strong> ${ escapeHtml ( formatQuerySurfaceLabel ( payload ? . materialization ? . query _surface || "-" ) ) } </div></div></article> `
: "" ;
reportsTarget . innerHTML = reports . length > 0
? reports . map ( ( item ) => ` <article class="admin-bot-monitoring-item rounded-4 p-4"><div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-3"><div><h4 class="h5 fw-semibold mb-1"> ${ escapeHtml ( item ? . label || humanizeKey ( item ? . report _key || "relatorio" ) ) } </h4><div class="small text-secondary"> ${ escapeHtml ( item ? . description || "" ) } </div></div><span class="badge rounded-pill bg-body-tertiary text-secondary border"> ${ escapeHtml ( formatGranularityLabel ( item ? . default _granularity || "aggregate" ) ) } </span></div><div class="admin-bot-monitoring-chip-group"><span class="badge rounded-pill bg-body-tertiary text-secondary border">Indicadores: ${ escapeHtml ( String ( ( item ? . supported _metric _keys || [ ] ) . length ) ) } </span><span class="badge rounded-pill bg-body-tertiary text-secondary border">Recortes: ${ escapeHtml ( String ( ( item ? . supported _dimension _fields || [ ] ) . length ) ) } </span></div></article> ` ) . join ( "" )
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Nenhum relatorio previsto</h4><p class="text-secondary mb-0">O overview nao retornou relatorios para este dominio.</p></div> ` ;
nextStepsTarget . innerHTML = nextSteps . length > 0
? nextSteps . map ( ( item ) => ` <div class="admin-bot-monitoring-item rounded-4 p-3 small text-secondary"> ${ escapeHtml ( item ) } </div> ` ) . join ( "" )
: ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2">Sem proximos passos</h4><p class="text-secondary mb-0">Nenhuma orientacao adicional foi retornada para este overview.</p></div> ` ;
}
function renderLockedState ( container , title , message ) {
container . innerHTML = ` <div class="admin-tool-empty-state rounded-4 p-4"><h4 class="h5 fw-semibold mb-2"> ${ escapeHtml ( title ) } </h4><p class="text-secondary mb-0"> ${ escapeHtml ( message ) } </p></div> ` ;
}
function toggleRefreshing ( isLoading ) {
refreshButton . disabled = isLoading ;
refreshSpinner . classList . toggle ( "d-none" , ! isLoading ) ;
refreshLabel . textContent = isLoading ? "Atualizando..." : "Atualizar leitura" ;
}
function clearFeedback ( ) {
feedback . className = "alert d-none rounded-4 mb-4" ;
feedback . textContent = "" ;
}
function showFeedback ( variant , message ) {
feedback . className = ` alert alert- ${ variant } rounded-4 mb-4 ` ;
feedback . textContent = message ;
}
}
function humanizeKey ( value ) {
const raw = String ( value || "" ) . trim ( ) ;
if ( ! raw ) {
return "-" ;
}
return raw
. replace ( /[_-]+/g , " " )
. replace ( /\b\w/g , ( char ) => char . toUpperCase ( ) ) ;
}
function formatFriendlyLabel ( value , mapping , fallback = "-" ) {
const normalized = String ( value || "" ) . trim ( ) . toLowerCase ( ) ;
if ( ! normalized ) {
return fallback ;
}
return mapping [ normalized ] || humanizeKey ( normalized ) ;
}
function formatConfigTitle ( value ) {
return formatFriendlyLabel ( value , {
application : "Aplicacao" ,
database : "Banco administrativo" ,
security : "Politicas de acesso" ,
panel _session : "Sessao do painel" ,
functional _configuration _contracts : "Catalogo funcional" ,
bot _governed _configuration _contracts : "Ajustes do atendimento" ,
model _runtime _separation : "Separacao de modelos" ,
write _governance : "Protecao de escrita" ,
atendimento _runtime _profile : "Modelo do atendimento" ,
tool _generation _runtime _profile : "Geracao de tools" ,
published _runtime _state : "Estado publicado"
} , "Configuracao" ) ;
}
function formatModeLabel ( value ) {
return formatFriendlyLabel ( value , {
shared _contract _bootstrap : "Contrato base" ,
sales _contract _bootstrap : "Estrutura inicial" ,
revenue _contract _bootstrap : "Estrutura inicial" ,
rental _contract _bootstrap : "Estrutura inicial" ,
bot _flow _contract _bootstrap : "Estrutura inicial" ,
conversation _telemetry _contract _bootstrap : "Estrutura inicial" ,
mixed : "Leituras combinadas"
} , "Leitura base" ) ;
}
function formatMutabilityLabel ( value ) {
return formatFriendlyLabel ( value , {
readonly : "Somente leitura" ,
read _only : "Somente leitura" ,
versioned : "Versionado" ,
mutable : "Editavel" ,
governed : "Governado"
} , "Somente leitura" ) ;
}
function formatGranularityLabel ( value ) {
return formatFriendlyLabel ( value , {
aggregate : "Visao consolidada" ,
daily : "Por dia" ,
weekly : "Por semana" ,
monthly : "Por mes"
} , "Visao consolidada" ) ;
}
function formatSyncStrategyLabel ( value ) {
return formatFriendlyLabel ( value , {
etl _incremental : "Atualizacao em lote" ,
snapshot _refresh : "Atualizacao por snapshot" ,
mixed : "Leituras combinadas"
} , "Nao informado" ) ;
}
function formatStorageLabel ( value ) {
return formatFriendlyLabel ( value , {
snapshot _table : "Snapshot consolidado" ,
dedicated _view : "Visao preparada"
} , "Nao informado" ) ;
}
function formatQuerySurfaceLabel ( value ) {
return formatFriendlyLabel ( value , {
dedicated _view : "Consulta preparada" ,
analytical _view : "Consulta analitica" ,
report _endpoint : "Consulta do painel"
} , "Nao informado" ) ;
}
function formatDomainLabel ( value ) {
return formatFriendlyLabel ( value , {
sistema : "Sistema" ,
sales : "Vendas" ,
arrecadacao : "Arrecadacao" ,
rental : "Locacao" ,
fluxo _bot : "Fluxo do bot" ,
telemetria _conversacional : "Telemetria conversacional" ,
bot : "Atendimento"
} , "-" ) ;
}
function formatSourceLabel ( value ) {
return formatFriendlyLabel ( value , {
env : "Ambiente" ,
runtime : "Aplicacao" ,
shared _contract : "Contrato compartilhado" ,
runtime _guard : "Protecao ativa"
} , "Origem" ) ;
}
function formatRuntimeTargetLabel ( value ) {
return formatFriendlyLabel ( value , {
atendimento : "Atendimento" ,
tool _generation : "Geracao de tools"
} , "Runtime" ) ;
}
function formatPurposeLabel ( value ) {
return formatFriendlyLabel ( value , {
customer _response : "Resposta ao cliente" ,
tool _generation : "Geracao de tools" ,
decision _support : "Apoio a decisao"
} , "Uso interno" ) ;
}
function uniqueCount ( ... collections ) {
return new Set (
collections . flatMap ( ( items ) => Array . isArray ( items ) ? items : [ ] ) . filter ( Boolean )
) . size ;
}
async function fetchPanelJson ( url ) {
const response = await fetch ( url , {
credentials : "same-origin" ,