|
405 | 405 | } |
406 | 406 | } |
407 | 407 |
|
408 | | - function normalizedPlatformBanner(data) { |
409 | | - const banner = data?.banner && typeof data.banner === "object" ? data.banner : {}; |
| 408 | + function normalizedPlatformBanner(data, fallbackSource) { |
| 409 | + const banner = data && typeof data === "object" ? data : {}; |
410 | 410 | const tone = ["info", "warning", "danger"].includes(banner.tone) ? banner.tone : "info"; |
411 | 411 | return { |
412 | 412 | active: banner.active === true, |
413 | 413 | message: typeof banner.message === "string" ? banner.message.trim() : "", |
414 | | - sourceTable: typeof banner.sourceTable === "string" ? banner.sourceTable : data?.sourceTable || "", |
| 414 | + source: typeof banner.source === "string" ? banner.source : fallbackSource || "platform-settings", |
| 415 | + sourceTable: typeof banner.sourceTable === "string" ? banner.sourceTable : "", |
415 | 416 | sourceTableRowKey: typeof banner.sourceTableRowKey === "string" ? banner.sourceTableRowKey : "", |
416 | 417 | tone |
417 | 418 | }; |
|
428 | 429 | if (!response.ok || payload?.ok === false) { |
429 | 430 | throw new Error(payload?.error || "Platform banner settings are unavailable."); |
430 | 431 | } |
431 | | - return normalizedPlatformBanner(payload?.data); |
| 432 | + const data = payload?.data || {}; |
| 433 | + return { |
| 434 | + banner: normalizedPlatformBanner({ |
| 435 | + ...(data.banner || {}), |
| 436 | + sourceTable: data.banner?.sourceTable || data.sourceTable || "", |
| 437 | + }, "platform-settings"), |
| 438 | + diagnostics: data.diagnostics || data.banner || {} |
| 439 | + }; |
| 440 | + } |
| 441 | + |
| 442 | + async function requestEnvironmentBanner() { |
| 443 | + const response = await fetch("/api/public/config", { |
| 444 | + headers: { "Accept": "application/json" }, |
| 445 | + method: "GET" |
| 446 | + }); |
| 447 | + const payload = await response.json().catch(function () { |
| 448 | + return null; |
| 449 | + }); |
| 450 | + if (!response.ok || payload?.ok === false) { |
| 451 | + throw new Error(payload?.error || "Public configuration is unavailable."); |
| 452 | + } |
| 453 | + const data = payload?.data || {}; |
| 454 | + return { |
| 455 | + banner: normalizedPlatformBanner(data.environmentBanner || {}, "environment-config"), |
| 456 | + diagnostics: data.diagnostics || {} |
| 457 | + }; |
432 | 458 | } |
433 | 459 |
|
434 | 460 | function removePlatformBanner() { |
|
442 | 468 | section.className = "platform-banner platform-banner--" + banner.tone; |
443 | 469 | section.dataset.platformBanner = ""; |
444 | 470 | section.dataset.platformBannerPlacement = placement; |
| 471 | + section.dataset.platformBannerSource = banner.source || "platform-settings"; |
445 | 472 | section.setAttribute("aria-label", "Platform notice"); |
446 | 473 | const inner = document.createElement("div"); |
447 | 474 | inner.className = "platform-banner__inner"; |
|
453 | 480 | return section; |
454 | 481 | } |
455 | 482 |
|
456 | | - async function renderPlatformBanner() { |
457 | | - try { |
458 | | - const banner = await requestPlatformBanner(); |
459 | | - window.GameFoundryPlatformBannerDiagnostics = { |
460 | | - active: banner.active, |
461 | | - message: banner.message, |
462 | | - sourceTable: banner.sourceTable, |
463 | | - sourceTableRowKey: banner.sourceTableRowKey |
464 | | - }; |
465 | | - removePlatformBanner(); |
466 | | - if (!banner.active || !banner.message) { |
467 | | - return; |
468 | | - } |
469 | | - const header = document.querySelector("header.site-header"); |
470 | | - if (header) { |
471 | | - header.after(createPlatformBanner(banner, "header")); |
| 483 | + function platformBannerDiagnostics(banner) { |
| 484 | + return { |
| 485 | + active: banner.active, |
| 486 | + message: banner.message, |
| 487 | + sourceTable: banner.sourceTable, |
| 488 | + sourceTableRowKey: banner.sourceTableRowKey |
| 489 | + }; |
| 490 | + } |
| 491 | + |
| 492 | + function renderBannerPlacement(banners, placement) { |
| 493 | + const nodes = banners.map((banner) => createPlatformBanner(banner, placement)); |
| 494 | + const header = document.querySelector("header.site-header"); |
| 495 | + if (placement === "header" && header) { |
| 496 | + header.after(...nodes); |
| 497 | + return; |
| 498 | + } |
| 499 | + const footer = document.querySelector("footer.footer"); |
| 500 | + if (placement === "footer" && footer?.parentNode) { |
| 501 | + footer.before(...nodes); |
| 502 | + return; |
| 503 | + } |
| 504 | + if (placement === "header") { |
| 505 | + const main = document.querySelector("main"); |
| 506 | + if (main) { |
| 507 | + main.before(...nodes); |
472 | 508 | } |
473 | | - const footer = document.querySelector("footer.footer"); |
474 | | - if (footer?.parentNode) { |
475 | | - footer.parentNode.insertBefore(createPlatformBanner(banner, "footer"), footer); |
| 509 | + } |
| 510 | + } |
| 511 | + |
| 512 | + async function renderPlatformBanner() { |
| 513 | + const [environmentResponse, platformResponse] = await Promise.allSettled([ |
| 514 | + requestEnvironmentBanner(), |
| 515 | + requestPlatformBanner() |
| 516 | + ]); |
| 517 | + const banners = []; |
| 518 | + removePlatformBanner(); |
| 519 | + if (environmentResponse.status === "fulfilled") { |
| 520 | + const banner = environmentResponse.value.banner; |
| 521 | + window.GameFoundryEnvironmentBannerDiagnostics = environmentResponse.value.diagnostics || {}; |
| 522 | + if (banner.active && banner.message) { |
| 523 | + banners.push(banner); |
476 | 524 | } |
477 | | - if (!header) { |
478 | | - const main = document.querySelector("main"); |
479 | | - if (main?.parentNode) { |
480 | | - main.parentNode.insertBefore(createPlatformBanner(banner, "header"), main); |
481 | | - } |
| 525 | + } else { |
| 526 | + window.GameFoundryEnvironmentBannerDiagnostics = { |
| 527 | + environmentBannerActive: false, |
| 528 | + environmentLabelConfigured: false, |
| 529 | + secretsExposed: false |
| 530 | + }; |
| 531 | + console.warn("[platform-settings/operator] Public configuration unavailable:", environmentResponse.reason instanceof Error ? environmentResponse.reason.message : String(environmentResponse.reason || "")); |
| 532 | + } |
| 533 | + if (platformResponse.status === "fulfilled") { |
| 534 | + const banner = platformResponse.value.banner; |
| 535 | + window.GameFoundryPlatformBannerDiagnostics = platformResponse.value.diagnostics || platformBannerDiagnostics(banner); |
| 536 | + if (banner.active && banner.message) { |
| 537 | + banners.push(banner); |
482 | 538 | } |
483 | | - } catch (error) { |
484 | | - removePlatformBanner(); |
| 539 | + } else { |
485 | 540 | window.GameFoundryPlatformBannerDiagnostics = { |
486 | 541 | active: false, |
487 | 542 | message: "", |
488 | 543 | sourceTable: "", |
489 | 544 | sourceTableRowKey: "" |
490 | 545 | }; |
491 | | - console.warn("[platform-settings/operator] Platform banner unavailable:", error instanceof Error ? error.message : String(error || "")); |
| 546 | + console.warn("[platform-settings/operator] Platform banner unavailable:", platformResponse.reason instanceof Error ? platformResponse.reason.message : String(platformResponse.reason || "")); |
| 547 | + } |
| 548 | + if (banners.length) { |
| 549 | + renderBannerPlacement(banners, "header"); |
| 550 | + renderBannerPlacement(banners, "footer"); |
492 | 551 | } |
493 | 552 | } |
494 | 553 |
|
|
0 commit comments