From c63181abac918ad6a73f95878b25151878278741 Mon Sep 17 00:00:00 2001 From: Lakehouse Admin Date: Tue, 19 May 2026 22:14:32 +0200 Subject: [PATCH] Homepage: tab layout, RSS proxy, and deploy docs - Reorganize services into OPS/DATA/FEEDS/LINKS tabs with compact DB grid - Add rss-proxy service (29 FDE feeds) and Intel feed groups - Update Palantir theme CSS/JS; Dell wordmark SVG; Proxmox API token auth - Add deploy/docker-compose.homepage.yml and config/homepage/README.md - Stop tracking runtime logs; add .gitignore --- .gitignore | 7 + config/homepage/README.md | 38 + config/homepage/custom.css | 991 ++++++++++++++++---- config/homepage/custom.js | 37 + config/homepage/dell-technologies.svg | 18 - config/homepage/docker.yaml | 3 +- config/homepage/icons/debezium.svg | 1 + config/homepage/icons/dell-technologies.svg | 20 +- config/homepage/logs/homepage.log | 7 - config/homepage/proxmox.yaml | 6 +- config/homepage/services.yaml | 554 ++++++++--- config/homepage/settings.yaml | 39 +- config/homepage/widgets.yaml | 8 +- deploy/docker-compose.homepage.yml | 32 + rss-proxy/Dockerfile | 6 + rss-proxy/server.py | 68 ++ 16 files changed, 1430 insertions(+), 405 deletions(-) create mode 100644 .gitignore create mode 100644 config/homepage/README.md delete mode 100644 config/homepage/logs/homepage.log create mode 100644 deploy/docker-compose.homepage.yml create mode 100644 rss-proxy/Dockerfile create mode 100644 rss-proxy/server.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c324aef --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Runtime logs (not config) +config/homepage/logs/ +*.log + +# OS / editor +.DS_Store +*~ diff --git a/config/homepage/README.md b/config/homepage/README.md new file mode 100644 index 0000000..c76f585 --- /dev/null +++ b/config/homepage/README.md @@ -0,0 +1,38 @@ +# ATC Lakehouse Homepage + +Palantir-style ops dashboard for Forward Deployed Engineering (Dell ATC). + +## Tabs + +| Tab | Content | +|-----|---------| +| OPS | Data pipeline, analytics, infrastructure, Docker | +| DATA | Database connection tiles (db01 + db02) | +| FEEDS | Live RSS widgets via `rss-proxy` | +| LINKS | Static docs & bookmarks (no RSS) | + +## Key files + +- `settings.yaml` — layout, tabs, theme +- `services.yaml` — service tiles, widgets, DB URIs +- `widgets.yaml` — header logo, Proxmox widget +- `proxmox.yaml` — Proxmox API token (keep private) +- `docker.yaml` — Docker socket integration +- `custom.css` / `custom.js` — Palantir theme, scanlines + +## RSS proxy + +Feeds are defined in `../../rss-proxy/server.py`. Rebuild after changes: + +```bash +cd /root/lakehouse/rss-proxy && docker build -t rss-proxy:latest . +docker restart rss-proxy +docker exec homepage wget -qO- http://127.0.0.1:3000/api/revalidate +``` + +## Deploy + +```bash +cd /root/lakehouse +docker compose -f deploy/docker-compose.homepage.yml up -d --build +``` diff --git a/config/homepage/custom.css b/config/homepage/custom.css index bc71978..56cbb0c 100644 --- a/config/homepage/custom.css +++ b/config/homepage/custom.css @@ -1,300 +1,885 @@ -/* ATC Lakehouse — Palantir dark + Dell orange */ -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap'); +/* EL-KADI OPS — Palantir blue + orange */ +@import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700&family=JetBrains+Mono:wght@400;500;600&display=swap'); :root { - --bg-deep: #06080c; - --bg-main: #0a0e14; - --bg-card: #121820; - --bg-card-hover: #181f2a; - --border: rgba(74, 158, 255, 0.12); - --border-hover: rgba(232, 117, 42, 0.45); - --text: #e8ecf1; - --text-muted: #8b9cb3; - --accent-blue: #4a9eff; - --accent-orange: #e8752a; - --accent-orange-glow: rgba(232, 117, 42, 0.25); - --dell-blue: #007db8; + --p-void: #040c18; + --p-deep: #061428; + --p-surface: #0c1a30; + --p-elevated: rgba(12, 28, 52, 0.92); + --p-border: rgba(56, 132, 220, 0.18); + --p-border-hot: rgba(251, 146, 60, 0.45); + --p-blue: #3b82f6; + --p-cyan: #22d3ee; + --p-orange: #fb923c; + --p-amber: #fbbf24; + --p-teal: #2dd4bf; + --p-text: #e8eef7; + --p-muted: #64748b; + --p-mono: 'JetBrains Mono', ui-monospace, monospace; + --p-sans: 'DM Sans', system-ui, sans-serif; + --btn-bg: #1a1e28; + --btn-hover: #242a38; + --btn-icon: #2c3344; + --color-logo-start: 59, 130, 246; + --color-logo-stop: 251, 146, 60; } -* { - font-family: 'Inter', system-ui, sans-serif !important; -} +html { color-scheme: dark; } body { - background: radial-gradient(ellipse 120% 80% at 50% -20%, rgba(0, 125, 184, 0.08), transparent), - radial-gradient(ellipse 80% 50% at 100% 0%, rgba(232, 117, 42, 0.06), transparent), - var(--bg-main) !important; - color: var(--text) !important; - min-height: 100vh; + font-family: var(--p-sans) !important; + background: var(--p-void) !important; + color: var(--p-text) !important; } -/* ── Header / widgets row ── */ +body::before { + content: ''; + position: fixed; + inset: 0; + background: + radial-gradient(ellipse 110% 75% at 5% -10%, rgba(37, 99, 235, 0.38), transparent 55%), + radial-gradient(ellipse 85% 60% at 92% 8%, rgba(34, 211, 238, 0.18), transparent 50%), + radial-gradient(ellipse 70% 55% at 85% 80%, rgba(59, 130, 246, 0.12), transparent 48%), + radial-gradient(ellipse 55% 45% at 10% 88%, rgba(251, 146, 60, 0.1), transparent 42%), + linear-gradient(165deg, #0a1e3a 0%, #040c18 42%, #051220 100%); + pointer-events: none; + z-index: 0; + animation: bg-breathe 14s ease-in-out infinite alternate; +} + +@keyframes bg-breathe { + 0% { opacity: 1; } + 100% { opacity: 0.9; } +} + +body::after { + content: ''; + position: fixed; + inset: 0; + background-image: + linear-gradient(rgba(59, 130, 246, 0.07) 1px, transparent 1px), + linear-gradient(90deg, rgba(59, 130, 246, 0.07) 1px, transparent 1px); + background-size: 56px 56px; + mask-image: radial-gradient(ellipse 90% 80% at 50% 30%, black 10%, transparent 72%); + pointer-events: none; + z-index: 0; + animation: grid-drift 40s linear infinite; +} + +@keyframes grid-drift { + from { transform: translate(0, 0); } + to { transform: translate(-56px, -56px); } +} + +.palantir-scanline { + position: fixed; + inset: 0; + pointer-events: none; + z-index: 1; + background: repeating-linear-gradient(0deg, transparent, transparent 3px, rgba(0,0,0,0.04) 3px, rgba(0,0,0,0.04) 6px); + opacity: 0.35; +} + +.palantir-noise { + position: fixed; + inset: 0; + pointer-events: none; + z-index: 1; + opacity: 0.03; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); +} + +#page_wrapper, main, #information-widgets { position: relative; z-index: 2; } + +html, body, #__next, #__next > div, main, footer, #footer, +[class*="bg-theme"], [class*="bg-slate"], [class*="bg-zinc"] { + background-color: var(--p-void) !important; + background-image: none !important; +} + +/* ── Header ── */ #information-widgets, .information-widget-container { - background: linear-gradient(180deg, #0d1219 0%, rgba(18, 24, 32, 0.98) 100%) !important; - border-bottom: 2px solid transparent !important; - border-image: linear-gradient(90deg, var(--dell-blue), var(--accent-orange), var(--dell-blue)) 1 !important; - padding: 14px 28px !important; + display: flex !important; + flex-wrap: wrap !important; + align-items: center !important; + gap: 12px 24px !important; + border: 1px solid var(--p-border) !important; + border-radius: 10px !important; + background: var(--p-elevated) !important; + backdrop-filter: blur(14px); + box-shadow: 0 4px 24px rgba(0,0,0,0.35), inset 0 1px 0 rgba(59,130,246,0.08) !important; + padding: 14px 24px !important; + margin: 12px 16px 0 !important; + border-bottom: none !important; } -header { - background: transparent !important; +header { background: transparent !important; border: none !important; } +header h1 { display: none !important; } + +.information-widget { border: none !important; + border-radius: 0 !important; + background: transparent !important; + backdrop-filter: none !important; + box-shadow: none !important; + padding: 0 !important; } -header h1 { - font-size: 1.35rem !important; - font-weight: 700 !important; - background: linear-gradient(90deg, #fff 30%, var(--accent-orange) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - +#information-widget-greeting, .information-widget-greeting { - color: var(--text) !important; -} - -.information-widget-greeting .text-theme-800 { - color: var(--accent-orange) !important; font-weight: 600 !important; + letter-spacing: 0.12em !important; + text-transform: uppercase !important; + font-size: 0.7rem !important; + color: var(--p-orange) !important; + font-family: var(--p-mono) !important; + border-left: 1px solid var(--p-border) !important; + padding-left: 18px !important; } -.information-widget-greeting .text-theme-500 { - color: var(--text-muted) !important; - font-size: 0.75rem !important; +.information-widget-greeting .text-theme-800, +.information-widget-greeting .text-theme-200 { + color: var(--p-text) !important; + font-size: 0.95rem !important; + letter-spacing: 0.04em !important; + text-transform: none !important; +} + +.information-widget-greeting .text-theme-500, +.information-widget-greeting .text-theme-400 { + color: var(--p-muted) !important; + font-size: 0.65rem !important; + text-transform: none !important; +} + +/* Dell Technologies wordmark — geen ronde D, alleen tekstlogo */ +.information-widget-logo { + order: -10 !important; + margin-right: 16px !important; + min-width: 0 !important; } .information-widget-logo img, +.information-widget-logo a img, .information-widget-logo svg { - max-height: 48px !important; width: auto !important; - filter: drop-shadow(0 0 14px var(--accent-orange-glow)); + height: 36px !important; + min-width: 180px !important; + max-width: 280px !important; + min-height: unset !important; + max-height: 36px !important; + border-radius: 0 !important; + object-fit: contain !important; + object-position: left center !important; + border: none !important; + box-shadow: none !important; + filter: none !important; + animation: none !important; + background: transparent !important; +} + +/* Verberg gradient/afkorting fallback (de "D") */ +.information-widget-logo .rounded-full, +.information-widget-logo [class*="gradient"], +.information-widget-logo > div:not(:has(img)) { + display: none !important; } .information-widget-search input { - background: var(--bg-deep) !important; - border: 1px solid var(--border) !important; - border-radius: 8px !important; - color: var(--text) !important; + background: rgba(26, 30, 40, 0.9) !important; + border: 1px solid var(--p-border) !important; + color: var(--p-text) !important; + border-radius: 6px !important; } -.information-widget-search input:focus { - border-color: var(--accent-orange) !important; - box-shadow: 0 0 0 2px var(--accent-orange-glow) !important; +.information-widget-resource .resource-icon { animation: none !important; filter: none !important; } +.information-widget-resource:nth-child(1) .resource-icon { color: #60a5fa !important; } +.information-widget-resource:nth-child(2) .resource-icon { color: #fb923c !important; } +.information-widget-resource:nth-child(3) .resource-icon { color: #4ade80 !important; } + +.resource-usage > div { + background: linear-gradient(90deg, #3b82f6, #fb923c) !important; + animation: none !important; + background-size: 100% 100% !important; +} + +/* ── Tabs (custom.js #atc-tabs) ── */ +#atc-tabs { + display: flex; + flex-wrap: wrap; + gap: 6px; + padding: 10px 20px 0; + margin: 12px 16px 0; + background: transparent !important; + border: none !important; + position: sticky; + top: 0; + z-index: 50; +} + +.atc-tab, +button[role="tab"] { + font-family: var(--p-mono) !important; + font-size: 0.68rem !important; + letter-spacing: 0.14em !important; + text-transform: uppercase !important; + border: 1px solid var(--p-border) !important; + border-radius: 6px !important; + background: rgba(26, 30, 40, 0.75) !important; + color: var(--p-muted) !important; + padding: 10px 18px !important; + cursor: pointer; + transition: all 0.25s ease; +} + +.atc-tab:hover, +button[role="tab"]:hover { + color: var(--p-text) !important; + border-color: rgba(59, 130, 246, 0.35) !important; +} + +.atc-tab.active, +button[role="tab"][aria-selected="true"] { + background: linear-gradient(135deg, rgba(59,130,246,0.2), rgba(251,146,60,0.12)) !important; + border-color: var(--p-border-hot) !important; + color: var(--p-cyan) !important; + box-shadow: 0 0 20px rgba(251,146,60,0.15); + animation: none !important; } main { - padding: 24px 28px 48px !important; + padding: 16px 20px 48px !important; max-width: 1720px !important; margin: 0 auto !important; + background: transparent !important; } +/* ── Secties ── */ .services-group { - margin-bottom: 32px !important; + margin-bottom: 24px !important; + background: transparent !important; + border: none !important; + box-shadow: none !important; } +.services-group.atc-hidden { display: none !important; } + .services-group > div:first-child, -.services-group h2 { - font-size: 0.72rem !important; - font-weight: 700 !important; +.services-group h2, +#services h2.service-group-name, +.service-group-title { + font-family: var(--p-mono) !important; + font-size: 0.62rem !important; + letter-spacing: 0.2em !important; text-transform: uppercase !important; - letter-spacing: 0.14em !important; - color: var(--accent-orange) !important; - margin-bottom: 14px !important; - padding-bottom: 8px !important; - border-bottom: 2px solid transparent !important; - border-image: linear-gradient(90deg, var(--accent-orange), var(--accent-blue), transparent) 1 !important; + color: var(--p-cyan) !important; + margin-bottom: 12px !important; + padding: 0 !important; + border: none !important; + background: transparent !important; +} + +.services-group > div:first-child::before, +.services-group h2::before { + content: ''; + display: inline-block; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--p-orange); + box-shadow: 0 0 10px var(--p-orange); + margin-right: 10px; + vertical-align: middle; } .services-group ul, -.services-group > div:last-child { +.services-list { display: grid !important; - grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)) !important; - gap: 12px !important; + grid-template-columns: repeat(4, 1fr) !important; + gap: 10px !important; list-style: none !important; padding: 0 !important; margin: 0 !important; + background: transparent !important; } -/* Database sections — wider tiles, always show connection strings */ -.services-group:has(h2) ul .service:has(.service-description) { - min-height: 168px !important; +.services-group ul > li, +.services-list > li { + background: transparent !important; + border: none !important; + box-shadow: none !important; + padding: 0 !important; } -.service { - flex-direction: column !important; - align-items: center !important; - text-align: center !important; - background: var(--bg-card) !important; - border: 1px solid var(--border) !important; - border-radius: 12px !important; - padding: 16px 12px 14px !important; - min-height: 132px !important; - transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s !important; +@media (max-width: 1280px) { + .services-group ul, .services-list { grid-template-columns: repeat(3, 1fr) !important; } +} +@media (max-width: 768px) { + .services-group ul, .services-list { grid-template-columns: repeat(2, 1fr) !important; } +} + +/* ── Service knoppen — strak kader om de knop (referentie homelab) ── */ +.services-group, +.services-group.flex-1, +.services-group.subgroup { + padding: 0 !important; + margin-bottom: 18px !important; +} + +.services-group ul, +.services-list { + gap: 6px !important; +} + +.services-group ul > li.service, +li.service { + background: transparent !important; + border: none !important; + box-shadow: none !important; + padding: 0 !important; + margin: 0 !important; + list-style: none !important; +} + +/* De knop = .service-card, strak, laag (~42px) */ +.service-card { + display: block !important; + background: rgba(22, 28, 38, 0.95) !important; + border: 1px solid rgba(255, 255, 255, 0.09) !important; + border-radius: 5px !important; + padding: 0 !important; + margin: 0 !important; + min-height: 42px !important; + max-height: 42px !important; position: relative !important; - overflow: visible !important; + cursor: pointer !important; + overflow: hidden !important; + backdrop-filter: none !important; + box-shadow: none !important; + transition: border-color 0.15s ease, background 0.15s ease !important; + animation: none !important; } -.service::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 2px; - background: linear-gradient(90deg, var(--dell-blue), var(--accent-orange)); - opacity: 0; - transition: opacity 0.2s; - border-radius: 12px 12px 0 0; +.service-card[class*="bg-theme"], +.service-card[class*="shadow-theme"], +.service-card.hover\:bg-theme-300\/20, +.service-card.dark\:hover\:bg-white\/10, +.service-card.dark\:bg-white\/5 { + background: rgba(22, 28, 38, 0.95) !important; + box-shadow: none !important; } -.service:hover { - background: var(--bg-card-hover) !important; - border-color: var(--border-hover) !important; - box-shadow: 0 8px 28px rgba(0, 0, 0, 0.4), 0 0 24px var(--accent-orange-glow) !important; - transform: translateY(-4px) !important; - z-index: 2 !important; +.service-card:hover { + background: rgba(28, 34, 46, 0.98) !important; + border-color: rgba(255, 255, 255, 0.16) !important; + transform: none !important; + box-shadow: none !important; } -.service:hover::before { - opacity: 1; -} +/* Gekleurde accent-streep links op de knop */ +.services-group ul > li.service:nth-child(6n+1) .service-card { border-left: 3px solid #3b82f6 !important; } +.services-group ul > li.service:nth-child(6n+2) .service-card { border-left: 3px solid #a855f7 !important; } +.services-group ul > li.service:nth-child(6n+3) .service-card { border-left: 3px solid #22c55e !important; } +.services-group ul > li.service:nth-child(6n+4) .service-card { border-left: 3px solid #06b6d4 !important; } +.services-group ul > li.service:nth-child(6n+5) .service-card { border-left: 3px solid #f59e0b !important; } +.services-group ul > li.service:nth-child(6n+6) .service-card { border-left: 3px solid #ec4899 !important; } -.service-icon { - width: 52px !important; - height: 52px !important; - min-width: 52px !important; - margin: 0 0 10px 0 !important; - padding: 8px !important; - border-radius: 12px !important; - background: linear-gradient(145deg, rgba(0, 125, 184, 0.12), rgba(232, 117, 42, 0.08)) !important; +.service-title { display: flex !important; + flex-direction: row !important; align-items: center !important; - justify-content: center !important; - box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07); + min-height: 42px !important; + padding: 0 !important; + margin: 0 !important; + background: transparent !important; + border: none !important; + box-shadow: none !important; } +.service-title-text, +.service-title-text a { + flex: 1 !important; + min-width: 0 !important; + padding: 2px 22px 2px 6px !important; + background: transparent !important; + border: none !important; + box-shadow: none !important; +} + +.service-name { + font-size: 0.78rem !important; + font-weight: 600 !important; + line-height: 1.25 !important; + color: var(--p-text) !important; + margin: 0 !important; +} + +.service-description { + font-size: 0.6rem !important; + line-height: 1.2 !important; + color: var(--p-muted) !important; + margin: 0 !important; + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; +} + +/* Icoon compact — geen apart groot kader */ +.service-icon, +a.service-icon, +.service-icon.w-12 { + width: 32px !important; + height: 32px !important; + min-width: 32px !important; + max-width: 32px !important; + margin: 5px 6px 5px 5px !important; + padding: 4px !important; + border: none !important; + border-radius: 4px !important; + background: transparent !important; + box-shadow: none !important; + flex-shrink: 0 !important; +} + +.service-icon::before, +.service-icon::after { display: none !important; content: none !important; } + .service-icon img, .service-icon svg { width: 100% !important; height: 100% !important; object-fit: contain !important; - filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.35)); + filter: none !important; } -.service-name { - font-size: 0.84rem !important; - font-weight: 600 !important; - color: var(--text) !important; - line-height: 1.25 !important; - margin-bottom: 6px !important; - width: 100% !important; +.service-card:hover .service-icon { + background: transparent !important; + transform: none !important; } -.service-description { - font-family: 'JetBrains Mono', monospace !important; - font-size: 0.56rem !important; - line-height: 1.5 !important; - color: #7d8fa8 !important; +li.service.atc-db-tile .service-card { + min-height: 52px !important; + max-height: none !important; +} +li.service.atc-db-tile .service-title { align-items: flex-start !important; min-height: 52px !important; } +li.service.atc-db-tile .service-description { + font-family: var(--p-mono) !important; + font-size: 0.5rem !important; white-space: pre-wrap !important; - word-break: break-word !important; - width: 100% !important; - text-align: left !important; - padding: 0 4px !important; + max-height: 2.6em !important; } +li.service.atc-db-tile:hover .service-description { max-height: 10em !important; } -/* DB / API tiles: show full connection info */ -.service:not([href]) .service-description, -.service[href=""] .service-description { - max-height: none !important; - color: #9aadc4 !important; -} - -.service:hover .service-description { - max-height: none !important; - color: #b8c8dc !important; -} - -.status-status-healthy, -.status-dot-green { - background: #3dd68c !important; - box-shadow: 0 0 8px rgba(61, 214, 140, 0.5) !important; -} - -.status-status-unhealthy, -.status-dot-red { - background: #f87171 !important; -} - -.ping { +/* Status dot — rechts in de knop */ +.service-card .ping, +.service-card .status-dot, +.service-card [class*="status-dot"], +.ping, .status-dot, [class*="status-dot"] { position: absolute !important; - top: 8px !important; - right: 8px !important; - font-size: 0.55rem !important; - margin: 0 !important; + right: 7px !important; + top: 50% !important; + transform: translateY(-50%) !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + box-shadow: none !important; } -.information-widget-resources { - font-size: 0.75rem !important; - color: var(--text-muted) !important; +.status-dot-status-green, +.status-status-healthy, +.text-green-500, +.status-dot-green { + background-color: #4ade80 !important; + box-shadow: 0 0 8px rgba(74, 222, 128, 0.55), 0 0 0 2px var(--btn-bg) !important; + animation: status-pulse-green 3s ease-out infinite; } -footer { - opacity: 0.45; - border-top: 1px solid var(--border) !important; +.status-dot-status-red, +.text-red-500, +.status-dot-red { + background-color: #f87171 !important; + animation: status-pulse-red 3s ease-out infinite; } -/* Live feed widgets */ -.services-group:has(.service-widget) ul { - grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)) !important; +@keyframes status-pulse-green { + 0% { box-shadow: 0 0 0 0 rgba(74, 222, 128, 0.5), 0 0 0 2px var(--btn-bg); } + 70% { box-shadow: 0 0 0 6px rgba(74, 222, 128, 0), 0 0 0 2px var(--btn-bg); } } - -.services-group:has(.service-widget) .service { - min-height: 220px !important; - align-items: stretch !important; +@keyframes status-pulse-red { + 0% { box-shadow: 0 0 0 0 rgba(248, 113, 113, 0.5), 0 0 0 2px var(--btn-bg); } + 70% { box-shadow: 0 0 0 6px rgba(248, 113, 113, 0), 0 0 0 2px var(--btn-bg); } } .service-widget { - background: var(--bg-deep) !important; - border-radius: 8px !important; - border: 1px solid var(--border) !important; - margin-top: 10px !important; - padding: 8px 10px !important; - max-height: 200px !important; - overflow-y: auto !important; - width: 100% !important; - text-align: left !important; + background: rgba(5, 12, 24, 0.6) !important; + border: 1px solid var(--p-border) !important; + border-radius: 6px !important; + margin-top: 8px !important; + padding: 6px 8px !important; + font-size: 0.58rem !important; + color: var(--p-muted) !important; } -.service-widget::-webkit-scrollbar { - width: 4px; +/* RSS Intel Hub — FEEDS tab */ +#atc-rss-hub.atc-hub-hidden { display: none !important; } + +#atc-rss-hub { + margin: 0 16px 24px !important; + max-width: 1720px; } -.service-widget::-webkit-scrollbar-thumb { - background: var(--accent-orange); - border-radius: 4px; +.services-group.atc-hub-active { + display: none !important; } -.service-widget a, -.service-widget li a { - color: var(--accent-blue) !important; - font-size: 0.65rem !important; - line-height: 1.4 !important; - display: block !important; - padding: 3px 0 !important; +.rss-list { list-style: none; padding: 0; margin: 0; } + +.rss-column { + max-height: 72vh; + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: var(--p-blue) transparent; } -.service-widget a:hover { - color: var(--accent-orange) !important; -} - -.service-widget li { - border-bottom: 1px solid rgba(255, 255, 255, 0.04) !important; - padding: 4px 0 !important; -} - -.information-widget-openmeteo { - color: var(--text-muted) !important; +.rss-items li { font-size: 0.8rem !important; + line-height: 1.45 !important; + padding: 0.4rem 0 !important; } + +.rss-items a { + display: block; + white-space: normal !important; + overflow: visible !important; + text-overflow: unset !important; + line-height: 1.4; + transition: color 0.15s ease; +} + +.rss-items a:hover { + color: var(--p-orange) !important; + text-shadow: 0 0 12px rgba(251, 146, 60, 0.25); +} + +.rss-items time { + font-size: 0.62rem !important; + opacity: 0.85; + min-width: 2.2rem; + text-align: right; +} + +.rss-feed-name { + font-size: 0.58rem !important; + margin-bottom: 0.45rem !important; + color: var(--p-cyan) !important; +} + +.rss-column-head { + position: sticky; + top: 0; + background: rgba(6, 14, 28, 0.95); + z-index: 2; + backdrop-filter: blur(8px); +} + +/* Live Feeds tab (legacy tiles) */ +.services-group.atc-feeds-group ul { grid-template-columns: repeat(3, 1fr) !important; } +.services-group.atc-feeds-group .service-card { + min-height: 200px !important; + padding: 12px !important; +} +.services-group.atc-feeds-group .service-title { + flex-direction: column !important; + align-items: flex-start !important; +} +.services-group.atc-feeds-group .service-icon { + width: 46px !important; + height: 46px !important; + margin: 0 0 8px 2px !important; +} +.services-group.atc-feeds-group .service-widget { + max-height: 130px !important; + overflow-y: auto !important; +} +.services-group.atc-feeds-group .service-widget a { color: var(--p-cyan) !important; } +.services-group.atc-feeds-group .service-widget a:hover { color: var(--p-orange) !important; } + +/* Native FEEDS tab — leesbare RSS-widgets in kaarten */ +.services-group .service-widget { + max-height: 220px !important; + overflow-y: auto !important; + padding: 10px 12px !important; + margin-top: 10px !important; + font-size: 0.72rem !important; + line-height: 1.5 !important; + scrollbar-width: thin; + scrollbar-color: var(--p-blue) transparent; +} + +.services-group .service-widget ul, +.services-group .service-widget ol { + list-style: none !important; + padding: 0 !important; + margin: 0 !important; +} + +.services-group .service-widget li { + padding: 0.35rem 0 !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important; +} + +.services-group .service-widget a { + color: var(--p-text) !important; + text-decoration: none !important; + display: block !important; + white-space: normal !important; + line-height: 1.4 !important; +} + +.services-group .service-widget a:hover { + color: var(--p-orange) !important; +} + +/* Homepage native tabs */ +button[role="tab"] { + font-family: var(--p-mono) !important; + font-size: 0.68rem !important; + letter-spacing: 0.12em !important; + text-transform: uppercase !important; +} + +/* Bookmarks */ +#bookmarks .bookmark-group h2, +.bookmark-group-name { + font-family: var(--p-mono) !important; + font-size: 0.62rem !important; + letter-spacing: 0.18em !important; + text-transform: uppercase !important; + color: var(--p-orange) !important; +} + +#bookmarks a { + border: 1px solid var(--p-border) !important; + transition: border-color 0.2s, box-shadow 0.2s; +} + +#bookmarks a:hover { + border-color: rgba(251,146,60,0.4) !important; + box-shadow: 0 0 16px rgba(59,130,246,0.1); +} + +.bookmark-icon { + font-weight: 600 !important; + color: #fff !important; + animation: none !important; + box-shadow: none !important; +} + +.bookmark:nth-child(4n+1) .bookmark-icon { background: linear-gradient(135deg, #2563eb, #3b82f6) !important; } +.bookmark:nth-child(4n+2) .bookmark-icon { background: linear-gradient(135deg, #ea580c, #fb923c) !important; } +.bookmark:nth-child(4n+3) .bookmark-icon { background: linear-gradient(135deg, #7c3aed, #a855f7) !important; } +.bookmark:nth-child(4n+4) .bookmark-icon { background: linear-gradient(135deg, #059669, #22c55e) !important; } + +/* RSS hub (custom.js elkadi — optioneel) */ +.rss-hub { + margin: 1rem 1.5rem 1.5rem; + padding: 1.25rem 1.5rem; + border: 1px solid var(--p-border); + border-radius: 14px; + background: linear-gradient(145deg, rgba(10,22,40,0.95), rgba(6,12,22,0.98)); + box-shadow: 0 8px 40px rgba(0,0,0,0.45), inset 0 1px 0 rgba(59,130,246,0.12); + backdrop-filter: blur(16px); + position: relative; + overflow: hidden; +} + +.rss-hub::before { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, var(--p-blue), var(--p-orange), var(--p-cyan), transparent); + animation: rss-scan 4s ease-in-out infinite; +} + +@keyframes rss-scan { + 0%, 100% { opacity: 0.5; transform: scaleX(0.6); } + 50% { opacity: 1; transform: scaleX(1); } +} + +.rss-hub-title { + display: flex; + align-items: baseline; + flex-wrap: wrap; + gap: 0.5rem 1rem; + margin-bottom: 1.25rem; + font-family: var(--p-mono); + font-size: 0.72rem; + letter-spacing: 0.28em; + text-transform: uppercase; + color: var(--p-cyan); +} + +.rss-hub-accent { + display: inline-block; + width: 8px; height: 8px; + border-radius: 50%; + background: var(--p-orange); + box-shadow: 0 0 12px var(--p-orange); + animation: pulse-dot 2s ease-in-out infinite; +} + +@keyframes pulse-dot { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.6; transform: scale(0.85); } +} + +.rss-hub-sub { + font-size: 0.58rem; + letter-spacing: 0.1em; + color: var(--p-muted); + text-transform: none; +} + +.rss-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1rem; +} + +@media (max-width: 1280px) { .rss-grid { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 640px) { .rss-grid { grid-template-columns: 1fr; } } + +.rss-column { + border: 1px solid rgba(59,130,246,0.12); + border-radius: 10px; + padding: 0.75rem; + background: rgba(5,12,24,0.6); + min-height: 160px; +} + +.rss-column-head { + display: flex; + align-items: center; + gap: 0.5rem; + font-family: var(--p-mono); + font-size: 0.58rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--p-orange); + margin-bottom: 0.65rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--p-border); +} + +.rss-pulse { + width: 6px; height: 6px; + border-radius: 50%; + background: var(--p-cyan); + animation: pulse-dot 1.8s ease-in-out infinite; +} + +.rss-feed-block { list-style: none; margin-bottom: 0.85rem; } + +.rss-feed-name { + display: block; + font-family: var(--p-mono); + font-size: 0.55rem; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--p-muted); + margin-bottom: 0.35rem; +} + +.rss-items { list-style: none; padding: 0; margin: 0; } + +.rss-items li { + display: flex; + justify-content: space-between; + gap: 0.5rem; + padding: 0.28rem 0; + border-bottom: 1px solid rgba(255,255,255,0.04); + font-size: 0.72rem; + line-height: 1.35; + animation: rss-fade-in 0.4s ease forwards; + opacity: 0; +} + +.rss-items li:nth-child(1) { animation-delay: 0.05s; } +.rss-items li:nth-child(2) { animation-delay: 0.1s; } +.rss-items li:nth-child(3) { animation-delay: 0.15s; } +.rss-items li:nth-child(4) { animation-delay: 0.2s; } +.rss-items li:nth-child(5) { animation-delay: 0.25s; } + +@keyframes rss-fade-in { to { opacity: 1; } } + +.rss-items a { + color: var(--p-text) !important; + text-decoration: none; + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.rss-items a:hover { color: var(--p-orange) !important; } + +.rss-items time { + font-family: var(--p-mono); + font-size: 0.58rem; + color: var(--p-muted); + flex-shrink: 0; +} + +.rss-loading { color: var(--p-muted); font-style: italic; } +.rss-error a { color: var(--p-orange) !important; } + +footer, #footer { + opacity: 0.35; + font-family: var(--p-mono); + font-size: 0.62rem; + background: transparent !important; +} + +::-webkit-scrollbar { width: 6px; } +::-webkit-scrollbar-track { background: var(--p-void); } +::-webkit-scrollbar-thumb { background: #2a3040; border-radius: 3px; } +::-webkit-scrollbar-thumb:hover { background: var(--p-orange); } + +.service-card { animation: none !important; } +.rss-hub { animation: none !important; } + +@media (prefers-reduced-motion: reduce) { + body::before, body::after, .rss-hub::before, .rss-pulse, .rss-hub-accent, + .service-icon, .service-icon::before, .service-icon::after, .service-card, + .bookmark-icon, .information-widget-resource .resource-icon, + button[role="tab"][aria-selected="true"], .rss-hub, #information-widgets img, + .palantir-scanline, .palantir-noise, .atc-tab, .service { + animation: none !important; + } +} + +/* DATA tab — compact 4-column database grid */ +.services-group:has(h2) h2:has(+ ul li.service.atc-db-tile), +li.service.atc-db-tile { max-width: 100%; } +.services-group ul:has(li.service.atc-db-tile) { + display: grid !important; + grid-template-columns: repeat(4, minmax(0, 1fr)) !important; + gap: 0.35rem 0.5rem !important; +} +li.service.atc-db-tile .service-card { min-height: 42px !important; max-height: 52px !important; } +li.service.atc-db-tile .service-description { + font-size: 0.62rem !important; + line-height: 1.25 !important; + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + max-height: 2.5em !important; +} +li.service.atc-db-tile:hover .service-description { + white-space: normal !important; + overflow: visible !important; + max-height: 8em !important; +} +#atc-rss-hub { display: none !important; } diff --git a/config/homepage/custom.js b/config/homepage/custom.js index e69de29..4e15838 100644 --- a/config/homepage/custom.js +++ b/config/homepage/custom.js @@ -0,0 +1,37 @@ +/* ATC Lakehouse — scanlines + noise only (tabs via settings.yaml) */ +(function () { + function injectOverlays() { + if (!document.querySelector('.palantir-scanline')) { + const scan = document.createElement('div'); + scan.className = 'palantir-scanline'; + document.body.appendChild(scan); + } + if (!document.querySelector('.palantir-noise')) { + const noise = document.createElement('div'); + noise.className = 'palantir-noise'; + document.body.appendChild(noise); + } + } + + function applyServiceColors() { + document.querySelectorAll('li.service').forEach(function (card) { + const desc = card.querySelector('.service-description'); + const text = desc ? desc.textContent : ''; + const link = card.querySelector('a[href^="http"]'); + if (text.indexOf('Host:') >= 0 || text.indexOf('Port:') >= 0 || !link) { + card.classList.add('atc-db-tile'); + } + }); + } + + function init() { + injectOverlays(); + applyServiceColors(); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); diff --git a/config/homepage/dell-technologies.svg b/config/homepage/dell-technologies.svg index 3e41b32..e69de29 100644 --- a/config/homepage/dell-technologies.svg +++ b/config/homepage/dell-technologies.svg @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - D - DELL - Technologies - diff --git a/config/homepage/docker.yaml b/config/homepage/docker.yaml index 4125cb3..05c8b2d 100644 --- a/config/homepage/docker.yaml +++ b/config/homepage/docker.yaml @@ -1,4 +1,3 @@ --- -# Docker integration — socket on atc-docker01 -local: +my-docker: socket: /var/run/docker.sock diff --git a/config/homepage/icons/debezium.svg b/config/homepage/icons/debezium.svg index e69de29..602632d 100644 --- a/config/homepage/icons/debezium.svg +++ b/config/homepage/icons/debezium.svg @@ -0,0 +1 @@ +Apache Kafka \ No newline at end of file diff --git a/config/homepage/icons/dell-technologies.svg b/config/homepage/icons/dell-technologies.svg index 3e41b32..d70179c 100644 --- a/config/homepage/icons/dell-technologies.svg +++ b/config/homepage/icons/dell-technologies.svg @@ -1,18 +1,4 @@ - - - - - - - - - - - - - - - D - DELL - Technologies + + DELL + Technologies diff --git a/config/homepage/logs/homepage.log b/config/homepage/logs/homepage.log deleted file mode 100644 index c275b37..0000000 --- a/config/homepage/logs/homepage.log +++ /dev/null @@ -1,7 +0,0 @@ -[2026-05-19T15:50:52.333Z] info: kubernetes.yaml was copied to the config folder -[2026-05-19T15:51:22.251Z] error: Host validation failed for: atc-docker01.dell-atc.lan. Hint: Set the HOMEPAGE_ALLOWED_HOSTS environment variable to allow requests from this host / port. -[2026-05-19T15:52:02.580Z] info: docker.yaml was copied to the config folder -[2026-05-19T15:52:22.162Z] info: bookmarks.yaml was copied to the config folder -[2026-05-19T15:52:22.162Z] info: widgets.yaml was copied to the config folder -[2026-05-19T15:52:22.164Z] info: custom.js was copied to the config folder -[2026-05-19T16:55:57.843Z] error: HTTP Error 401 calling https://10.0.10.65:8006/api2/json/cluster/resources diff --git a/config/homepage/proxmox.yaml b/config/homepage/proxmox.yaml index 653a4f7..218195a 100644 --- a/config/homepage/proxmox.yaml +++ b/config/homepage/proxmox.yaml @@ -1,5 +1,5 @@ --- -pve: +pve01: url: https://10.0.10.65:8006 - username: root@pam - password: Dell2026! + token: "root@pam!homepage" + secret: "8890185b-0850-42b7-bab2-a690ea4dc3f1" diff --git a/config/homepage/services.yaml b/config/homepage/services.yaml index c18f24a..638f932 100644 --- a/config/homepage/services.yaml +++ b/config/homepage/services.yaml @@ -5,290 +5,562 @@ - Kafka UI: icon: http://atc-docker01.dell-atc.lan:8080/apachekafka.svg href: http://atc-kafka01.dell-atc.lan:9000/ - description: Kafka cluster UI + description: atc-kafka01.dell-atc.lan:9000 siteMonitor: http://atc-kafka01.dell-atc.lan:9000/ color: "#E02014" - Debezium: icon: http://atc-docker01.dell-atc.lan:8080/debezium.png href: http://atc-lake01.dell-atc.lan:8083/ - description: CDC connectors + description: atc-lake01.dell-atc.lan:8083 siteMonitor: http://atc-lake01.dell-atc.lan:8083/ color: "#4ECDC4" - Spark: icon: http://atc-docker01.dell-atc.lan:8080/apachespark.svg href: http://atc-lake01.dell-atc.lan:8080/ - description: Spark master UI + description: atc-lake01.dell-atc.lan:8080 siteMonitor: http://atc-lake01.dell-atc.lan:8080/ color: "#E25A1C" - Trino: icon: http://atc-docker01.dell-atc.lan:8080/trino.svg - href: http://atc-lake01.dell-atc.lan:8089/ - description: Distributed SQL + href: http://atc-lake01.dell-atc.lan:8089/ui/ + description: atc-lake01.dell-atc.lan:8089/ui/ siteMonitor: http://atc-lake01.dell-atc.lan:8089/ui/ color: "#DD00A1" - Airflow: icon: http://atc-docker01.dell-atc.lan:8080/apacheairflow.svg href: http://10.0.21.55:8080/ - description: Workflow orchestration - siteMonitor: http://10.0.21.55:8080/ + description: 10.0.21.55:8080 + siteMonitor: http://10.0.21.55:8080/health color: "#017CEE" - Analytics: - Superset: icon: http://atc-docker01.dell-atc.lan:8080/apachesuperset.svg href: http://atc-docker01.dell-atc.lan:8088/ - description: BI dashboards + description: atc-docker01.dell-atc.lan:8088 siteMonitor: http://atc-docker01.dell-atc.lan:8088/health color: "#6c5ce7" - Kibana: icon: http://atc-docker01.dell-atc.lan:8080/kibana.svg href: http://atc-elastic01.dell-atc.lan:5601/ - description: Elasticsearch UI + description: atc-elastic01.dell-atc.lan:5601 siteMonitor: http://atc-elastic01.dell-atc.lan:5601/ color: "#F04E98" - - Elasticsearch API: + - Elasticsearch: icon: http://atc-docker01.dell-atc.lan:8080/elasticsearch.svg ping: atc-elastic01.dell-atc.lan description: | Host: atc-elastic01.dell-atc.lan - Port: 9200 (internal/VLAN) + Port: 9200 (no public HTTP) curl: curl http://atc-elastic01.dell-atc.lan:9200 - Note: use Kibana for browser access + Use Kibana for browser UI color: "#005571" - Grafana: icon: http://atc-docker01.dell-atc.lan:8080/grafana.svg + href: http://atc-grafana.dell-atc.lan:3000/ ping: atc-grafana.dell-atc.lan description: | - Host: atc-grafana.dell-atc.lan (10.0.20.103) + Host: atc-grafana.dell-atc.lan + IP: 10.0.20.103 Port: 3000 - Status: service stopped - Start: systemctl start grafana-server + Note: start with systemctl start grafana-server + siteMonitor: http://atc-grafana.dell-atc.lan:3000/ color: "#F46800" - Infrastructure: - ObjectScale: icon: http://atc-docker01.dell-atc.lan:8080/dell.svg href: https://10.0.20.111/ - description: Dell ObjectScale S3 + description: 10.0.20.111 siteMonitor: https://10.0.20.111/ color: "#007DB8" + - iDRAC: + icon: http://atc-docker01.dell-atc.lan:8080/dell.svg + href: https://10.0.41.102/ + description: Dell iDRAC · 10.0.41.102 + siteMonitor: https://10.0.41.102/ + color: "#007DB8" - Proxmox: icon: http://atc-docker01.dell-atc.lan:8080/proxmox.svg href: https://10.0.10.65:8006/ - description: pve01 virtualization + description: 10.0.10.65:8006 siteMonitor: https://10.0.10.65:8006/ color: "#E57000" widget: type: proxmox url: https://10.0.10.65:8006 + username: "root@pam!homepage" + password: "8890185b-0850-42b7-bab2-a690ea4dc3f1" node: pve01 fields: ["vms", "lxc", "resources.cpu", "resources.mem"] - Forgejo: icon: http://atc-docker01.dell-atc.lan:8080/git.svg href: http://atc-mgt01.dell-atc.lan:3001/ - description: Git — Lakehouse repo + description: atc-mgt01.dell-atc.lan:3001 siteMonitor: http://atc-mgt01.dell-atc.lan:3001/ color: "#F05032" - LDAP Admin: icon: http://atc-docker01.dell-atc.lan:8080/ldap.png href: http://atc-mgt01.dell-atc.lan/lam/ - description: LDAP Account Manager + description: atc-mgt01.dell-atc.lan/lam/ siteMonitor: http://atc-mgt01.dell-atc.lan/lam/ color: "#0984e3" -- Databases (atc-db01 — 10.0.20.112): - - PostgreSQL: +- Databases: + - PostgreSQL · db01: icon: http://atc-docker01.dell-atc.lan:8080/postgresql.svg ping: atc-db01.dell-atc.lan - description: | - Host: atc-db01.dell-atc.lan - Port: 5432 - URI: postgresql://USER:PASS@atc-db01.dell-atc.lan:5432/DBNAME - psql: psql -h atc-db01.dell-atc.lan -U USER -d DBNAME + description: atc-db01:5432 · postgresql://USER@atc-db01.dell-atc.lan:5432/DB · psql -h atc-db01 color: "#4169E1" - - MySQL: + - MySQL · db01: icon: http://atc-docker01.dell-atc.lan:8080/mysql.svg ping: atc-db01.dell-atc.lan - description: | - Host: atc-db01.dell-atc.lan - Port: 3306 - URI: mysql://USER:PASS@atc-db01.dell-atc.lan:3306/DBNAME - CLI: mysql -h atc-db01.dell-atc.lan -u USER -p + description: atc-db01:3306 · mysql://USER@atc-db01.dell-atc.lan:3306/DB · mysql -h atc-db01 color: "#4479A1" - -- Databases (atc-db02 — 10.0.21.51): - - MongoDB: + - MongoDB · db02: icon: http://atc-docker01.dell-atc.lan:8080/mongodb.svg ping: atc-db02.dell-atc.lan - description: | - Host: atc-db02.dell-atc.lan - Port: 27017 - URI: mongodb://USER:PASS@atc-db02.dell-atc.lan:27017/DBNAME - CLI: mongosh "mongodb://atc-db02.dell-atc.lan:27017" + description: atc-db02:27017 · mongodb://USER@atc-db02.dell-atc.lan:27017/DB · mongosh color: "#47A248" - - PostgreSQL: + - PostgreSQL · db02: icon: http://atc-docker01.dell-atc.lan:8080/postgresql.svg ping: atc-db02.dell-atc.lan - description: | - Host: atc-db02.dell-atc.lan - Port: 5432 - URI: postgresql://USER:PASS@atc-db02.dell-atc.lan:5432/DBNAME - psql: psql -h atc-db02.dell-atc.lan -U USER -d DBNAME + description: atc-db02:5432 · postgresql://USER@atc-db02.dell-atc.lan:5432/DB · psql -h atc-db02 color: "#336791" - - MySQL: + - MySQL · db02: icon: http://atc-docker01.dell-atc.lan:8080/mysql.svg ping: atc-db02.dell-atc.lan - description: | - Host: atc-db02.dell-atc.lan - Port: 3306 - URI: mysql://USER:PASS@atc-db02.dell-atc.lan:3306/DBNAME - CLI: mysql -h atc-db02.dell-atc.lan -u USER -p + description: atc-db02:3306 · mysql://USER@atc-db02.dell-atc.lan:3306/DB · mysql -h atc-db02 color: "#00758F" - - Cassandra: + - Cassandra · db02: icon: http://atc-docker01.dell-atc.lan:8080/apachecassandra.svg ping: atc-db02.dell-atc.lan - description: | - Host: atc-db02.dell-atc.lan - Port: 9042 - cqlsh: cqlsh atc-db02.dell-atc.lan 9042 - URI: cassandra://atc-db02.dell-atc.lan:9042 + description: atc-db02:9042 · cqlsh atc-db02.dell-atc.lan 9042 · cassandra://atc-db02:9042 color: "#1287B1" - - Neo4j: + - Neo4j · db02: icon: http://atc-docker01.dell-atc.lan:8080/neo4j.svg href: http://atc-db02.dell-atc.lan:7474/ - description: | - Browser: http://atc-db02.dell-atc.lan:7474 - Bolt: bolt://atc-db02.dell-atc.lan:7687 - URI: neo4j://atc-db02.dell-atc.lan:7687 + ping: atc-db02.dell-atc.lan + description: HTTP :7474 · bolt://atc-db02:7687 · neo4j://atc-db02.dell-atc.lan:7687 siteMonitor: http://atc-db02.dell-atc.lan:7474/ color: "#008CC1" -- Live Feeds: - - Hacker News DE: - icon: mdi-newspaper-variant-outline - href: https://hn.algolia.com/?q=data%20engineering - description: Data engineering on HN +- Intel · Hacker News: + - HN Front Page: + icon: mdi-newspaper + href: https://news.ycombinator.com/ + description: Hacker News — front page color: "#E8752A" widget: type: customapi - url: https://hn.algolia.com/api/v1/search?query=data+engineering&tags=story&hitsPerPage=8 + url: http://atc-docker01.dell-atc.lan:8090/feed/hn-front refreshInterval: 300000 display: dynamic-list mappings: - items: hits + items: items name: title - label: points - href: url - target: url - - Hacker News Kafka: - icon: mdi-lightning-bolt + href: link + target: _blank + - HN Data Engineering: + icon: mdi-database-search + href: https://hn.algolia.com/?q=data%20engineering + description: Hacker News — data engineering + color: "#3b82f6" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/hn-de + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - HN Kafka: + icon: http://atc-docker01.dell-atc.lan:8080/apachekafka.svg href: https://hn.algolia.com/?q=kafka - description: Kafka & streaming + description: Hacker News — Kafka & streaming color: "#E02014" widget: type: customapi - url: https://hn.algolia.com/api/v1/search?query=apache+kafka&tags=story&hitsPerPage=8 + url: http://atc-docker01.dell-atc.lan:8090/feed/hn-kafka refreshInterval: 300000 display: dynamic-list mappings: - items: hits + items: items name: title - label: points - href: url - target: url + href: link + target: _blank + - HN Spark: + icon: http://atc-docker01.dell-atc.lan:8080/apachespark.svg + href: https://hn.algolia.com/?q=apache+spark + description: Hacker News — Apache Spark + color: "#E25A1C" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/hn-spark + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Lobsters: + icon: mdi-lobster + href: https://lobste.rs/ + description: Computing & infra — curated links + color: "#ef4444" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/lobsters + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + +- Intel · Data Architecture: + - Data Eng Weekly: + icon: mdi-calendar-week + href: https://www.dataengineeringweekly.com/ + description: Weekly newsletter — pipelines & platforms + color: "#22d3ee" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/de-weekly + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Pragmatic Engineer: + icon: mdi-account-tie + href: https://blog.pragmaticengineer.com/ + description: Big tech engineering & architecture + color: "#a855f7" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/pragmatic + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Martin Fowler: + icon: mdi-arch + href: https://martinfowler.com/ + description: Software architecture & design + color: "#64748b" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/martinfowler + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - InfoQ: + icon: mdi-information-outline + href: https://www.infoq.com/ + description: Architecture, data & dev practices + color: "#94a3b8" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/infoq + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - ByteByteGo: + icon: mdi-school + href: https://blog.bytebytego.com/ + description: System design — scalable architectures + color: "#f59e0b" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/bytebytego + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - TLDR Data Eng: + icon: mdi-lightning-bolt + href: https://tldr.tech/dataengineering/ + description: Daily data engineering digest + color: "#E8752A" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/tldr-de + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + + + - Seattle Data Guy: + icon: mdi-chart-bar + href: https://www.seattledataguy.com/ + description: Practical data engineering tutorials + color: "#0ea5e9" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/seattle-de + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - RedMonk: + icon: mdi-chart-line + href: https://redmonk.com/ + description: Developer-focused industry analysis + color: "#dc2626" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/redmonk + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + +- Intel · Platforms & Blogs: - Confluent Blog: icon: http://atc-docker01.dell-atc.lan:8080/apachekafka.svg href: https://www.confluent.io/blog/ - description: Confluent RSS - color: "#E02014" + description: Kafka & event streaming + color: "#007DB8" widget: - type: rss - url: https://www.confluent.io/blog/rss.xml - limit: 8 - format: rss + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/confluent + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Databricks Blog: + icon: mdi-layers-triple + href: https://www.databricks.com/blog + description: Lakehouse & Spark platform + color: "#fb923c" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/databricks + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Debezium CDC: + icon: http://atc-docker01.dell-atc.lan:8080/debezium.png + href: https://debezium.io/blog/ + description: Change data capture patterns + color: "#4ECDC4" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/debezium + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - AWS Big Data: + icon: mdi-aws + href: https://aws.amazon.com/blogs/big-data/ + description: AWS analytics & data lakes + color: "#FF9900" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/aws-bigdata + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Google Cloud Blog: + icon: mdi-google-cloud + href: https://cloud.google.com/blog + description: GCP data & analytics + color: "#4285F4" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/google-cloud + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Cloudflare Eng: + icon: mdi-cloud + href: https://blog.cloudflare.com/ + description: Edge, networking & scale + color: "#F38020" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/cloudflare + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Meta Engineering: + icon: mdi-facebook + href: https://engineering.fb.com/ + description: Large-scale infra & data + color: "#1877F2" + widget: + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/fb-engineering + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Airflow Blog: icon: http://atc-docker01.dell-atc.lan:8080/apacheairflow.svg href: https://airflow.apache.org/blog/ - description: Apache Airflow news + description: Workflow orchestration & DAGs color: "#017CEE" widget: - type: rss + type: customapi url: http://atc-docker01.dell-atc.lan:8090/feed/airflow - limit: 8 - format: rss - - KDnuggets: - icon: mdi-chart-timeline-variant - href: https://www.kdnuggets.com/ - description: Data science news - color: "#f59e0b" + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - Elastic Blog: + icon: http://atc-docker01.dell-atc.lan:8080/elasticsearch.svg + href: https://www.elastic.co/blog/ + description: Search, observability & security + color: "#005571" widget: - type: rss - url: http://atc-docker01.dell-atc.lan:8090/feed/kdnuggets - limit: 8 - format: rss - - Towards Data Science: - icon: mdi-brain - href: https://towardsdatascience.com/ - description: ML & data articles - color: "#007DB8" + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/elastic + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank + - The New Stack: + icon: mdi-newspaper-variant-multiple + href: https://thenewstack.io/ + description: Cloud native & platform engineering + color: "#22c55e" widget: - type: rss - url: http://atc-docker01.dell-atc.lan:8090/feed/towardsds - limit: 8 - format: rss - - Debezium Blog: - icon: http://atc-docker01.dell-atc.lan:8080/debezium.png - href: https://debezium.io/blog/ - description: CDC & streaming blog - color: "#4ECDC4" - widget: - type: rss - url: https://debezium.io/blog.atom - limit: 8 - format: atom + type: customapi + url: http://atc-docker01.dell-atc.lan:8090/feed/thenewstack + refreshInterval: 300000 + display: dynamic-list + mappings: + items: items + name: title + href: link + target: _blank - News & Resources: - - TLDR Data Eng: - icon: mdi-rss - href: https://tldr.tech/dataengineering/ - description: Daily DE digest - color: "#E8752A" - - TLDR AI: - icon: mdi-robot - href: https://tldr.tech/ai/ - description: Daily AI digest - color: "#ff8c2a" - - Dell Newsroom: - icon: http://atc-docker01.dell-atc.lan:8080/dell.svg - href: https://www.dell.com/en-us/dt/corporate/newsroom.htm - description: Dell Technologies news + - Dell Technologies: + icon: http://atc-docker01.dell-atc.lan:8080/dell-technologies.svg + href: https://www.delltechnologies.com/ + description: Corporate site & solutions color: "#007DB8" + - Dell Blog · Data: + icon: mdi-post-outline + href: https://www.dell.com/en-us/blog/categories/products-solutions-analytics + description: Analytics & data solutions + color: "#007DB8" + - Apache Spark: + icon: http://atc-docker01.dell-atc.lan:8080/apachespark.svg + href: https://spark.apache.org/docs/latest/ + description: Spark documentation + color: "#E25A1C" + - Trino: + icon: http://atc-docker01.dell-atc.lan:8080/trino.svg + href: https://trino.io/docs/current/ + description: Distributed SQL engine docs + color: "#DD00A1" + - Apache Iceberg: + icon: mdi-snowflake + href: https://iceberg.apache.org/docs/latest/ + description: Open table format for lakes + color: "#38bdf8" - Real Python: icon: mdi-language-python href: https://realpython.com/ - description: Python tutorials + description: Python tutorials & patterns color: "#3776AB" + - MinIO Docs: + icon: http://atc-docker01.dell-atc.lan:8080/minio.svg + href: https://min.io/docs/minio/linux/index.html + description: S3-compatible object storage + color: "#C72C48" + - TLDR Tech: + icon: mdi-lightning-bolt-outline + href: https://tldr.tech/ + description: Daily tech newsletter (web) + color: "#E8752A" -- Docker (atc-docker01): +- Docker · atc-docker01: - Homepage: icon: mdi-view-dashboard href: http://atc-docker01.dell-atc.lan/ - description: This dashboard - server: local + description: atc-docker01.dell-atc.lan + server: my-docker container: homepage color: "#E8752A" - Superset: icon: http://atc-docker01.dell-atc.lan:8080/apachesuperset.svg href: http://atc-docker01.dell-atc.lan:8088/ - description: BI platform - server: local + description: atc-docker01.dell-atc.lan:8088 + server: my-docker container: superset color: "#6c5ce7" - Forgejo Local: icon: http://atc-docker01.dell-atc.lan:8080/git.svg href: http://atc-docker01.dell-atc.lan:4002/ - description: Local Git :4002 + description: atc-docker01.dell-atc.lan:4002 siteMonitor: http://atc-docker01.dell-atc.lan:4002/ - server: local + server: my-docker container: forgejo color: "#F05032" diff --git a/config/homepage/settings.yaml b/config/homepage/settings.yaml index 66dd907..780f943 100644 --- a/config/homepage/settings.yaml +++ b/config/homepage/settings.yaml @@ -2,33 +2,52 @@ title: ATC Lakehouse description: Forward Deployed Engineering — Dell Technologies · Bart & Mo theme: dark -color: slate +color: zinc +iconStyle: gradient headerStyle: underlined +useEqualHeights: true statusStyle: dot +fullWidth: true target: _blank showStats: true +background: + opacity: 0 + brightness: 0 + saturate: 0 layout: Data Pipeline: + tab: OPS style: row columns: 5 Analytics: + tab: OPS style: row columns: 4 Infrastructure: + tab: OPS style: row - columns: 4 - Databases (atc-db01 — 10.0.20.112): - style: row - columns: 2 - Databases (atc-db02 — 10.0.21.51): + columns: 5 + Docker · atc-docker01: + tab: OPS style: row columns: 3 - Live Feeds: + Databases: + tab: DATA style: row columns: 4 + Intel · Hacker News: + tab: FEEDS + style: row + columns: 5 + Intel · Data Architecture: + tab: FEEDS + style: row + columns: 7 + Intel · Platforms & Blogs: + tab: FEEDS + style: row + columns: 6 News & Resources: + tab: LINKS style: row columns: 4 - Docker (atc-docker01): - style: row - columns: 3 diff --git a/config/homepage/widgets.yaml b/config/homepage/widgets.yaml index 081401f..a99fec4 100644 --- a/config/homepage/widgets.yaml +++ b/config/homepage/widgets.yaml @@ -4,11 +4,11 @@ href: https://www.delltechnologies.com target: _blank - greeting: - text_size: xl - text: "Forward Deployed Engineering" - subtext: "Bart & Mo · Dell Technologies · ATC Lakehouse" -- datetime: text_size: lg + text: ATC Lakehouse + subtext: "Forward Deployed Engineering · Bart & Mo" +- datetime: + text_size: md format: timeStyle: short dateStyle: medium diff --git a/deploy/docker-compose.homepage.yml b/deploy/docker-compose.homepage.yml new file mode 100644 index 0000000..30d0f80 --- /dev/null +++ b/deploy/docker-compose.homepage.yml @@ -0,0 +1,32 @@ +# ATC Lakehouse dashboard stack (atc-docker01) +# Usage: docker compose -f deploy/docker-compose.homepage.yml up -d --build + +services: + homepage: + image: ghcr.io/gethomepage/homepage:latest + container_name: homepage + restart: unless-stopped + ports: + - "80:3000" + volumes: + - ../config/homepage:/app/config + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + HOMEPAGE_ALLOWED_HOSTS: "*" + + rss-proxy: + build: ../rss-proxy + image: rss-proxy:latest + container_name: rss-proxy + restart: unless-stopped + ports: + - "8090:8090" + + icons-server: + image: nginx:alpine + container_name: icons-server + restart: unless-stopped + ports: + - "8080:80" + volumes: + - ../config/homepage/icons:/usr/share/nginx/html:ro diff --git a/rss-proxy/Dockerfile b/rss-proxy/Dockerfile new file mode 100644 index 0000000..b85ec3f --- /dev/null +++ b/rss-proxy/Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir flask gunicorn feedparser +COPY server.py . +EXPOSE 8090 +CMD ["gunicorn", "-b", "0.0.0.0:8090", "-w", "1", "server:app"] diff --git a/rss-proxy/server.py b/rss-proxy/server.py new file mode 100644 index 0000000..108fccf --- /dev/null +++ b/rss-proxy/server.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +"""RSS proxy for ATC Lakehouse — normalized JSON for homepage widgets.""" +from flask import Flask, jsonify +import feedparser + +app = Flask(__name__) + +FEEDS = { + # Hacker News & community + "hn-front": "https://hnrss.org/frontpage", + "hn-de": "https://hnrss.org/newest?q=data+engineering", + "hn-kafka": "https://hnrss.org/newest?q=kafka", + "hn-spark": "https://hnrss.org/newest?q=apache+spark", + "hn-lakehouse": "https://hnrss.org/newest?q=lakehouse", + "lobsters": "https://lobste.rs/rss", + # Data architecture & FDE reading + "de-weekly": "https://www.dataengineeringweekly.com/feed", + "de-central": "https://dataengineeringcentral.substack.com/feed", + "pragmatic": "https://blog.pragmaticengineer.com/rss/", + "martinfowler": "https://martinfowler.com/feed.atom", + "infoq": "https://www.infoq.com/feed/", + "oreilly-radar": "https://feeds.feedburner.com/oreilly/radar/atom", + "bytebytego": "https://blog.bytebytego.com/feed", + "seattle-de": "https://www.seattledataguy.com/feed/", + # Platforms & lakehouse stack + "confluent": "https://www.confluent.io/rss.xml", + "databricks": "https://www.databricks.com/blog/feed.xml", + "airflow": "https://airflow.apache.org/blog/index.xml", + "debezium": "https://debezium.io/blog.atom", + "elastic": "https://www.elastic.co/blog/feed", + "minio": "https://blog.min.io/rss.xml", + "aws-bigdata": "https://aws.amazon.com/blogs/big-data/feed/", + "google-cloud": "https://cloudblog.withgoogle.com/rss/", + "cloudflare": "https://blog.cloudflare.com/rss/", + "fb-engineering": "https://engineering.fb.com/feed/", + # Newsletters + "tldr-de": "https://tldr.tech/rss/dataengineering", + "thenewstack": "https://thenewstack.io/feed/", + "kdnuggets": "https://www.kdnuggets.com/feed", + "towardsds": "https://medium.com/feed/towards-data-science", + "redmonk": "https://redmonk.com/feed/", +} + + +@app.get("/health") +def health(): + return jsonify({"status": "ok", "count": len(FEEDS), "feeds": sorted(FEEDS.keys())}) + + +@app.get("/feed/") +def feed(name): + url = FEEDS.get(name) + if not url: + return jsonify({"error": f"unknown feed: {name}", "feeds": sorted(FEEDS.keys())}), 404 + parsed = feedparser.parse(url) + items = [ + { + "title": e.get("title", "Untitled"), + "link": e.get("link", ""), + "published": e.get("published", e.get("updated", "")), + } + for e in parsed.entries[:10] + ] + return jsonify({"title": parsed.feed.get("title", name), "items": items}) + + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=8090)