Files
Krow-workspace/firebase/internal-launchpad/index.html
bwnyasse b7477944bc feat: update title and favicon in index.html
This commit updates the title and favicon in the index.html file
to reflect the new KROW branding. It also updates the links in
the internal launchpad to point to the correct environments.

feat: add script to patch index.html during integration

This commit adds a new script to patch the index.html file during
the integration process. This script updates the title and favicon
to reflect the new KROW branding.

style: update badge style in Dashboard.jsx

This commit updates the badge style in the Dashboard.jsx file to
use a span element with rounded corners instead of the Badge
component. This is to match the design of the new KROW branding.
2025-11-14 09:06:30 -05:00

503 lines
22 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KROW Launchpad</title>
<link rel="icon" type="image/x-icon" href="favicon.svg">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
<!-- Mermaid -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.6.1/mermaid.min.js"></script>
<!-- Custom CSS -->
<style>
body {
background-color: #f8f9fa;
}
.main-layout {
display: grid;
grid-template-columns: 280px 1fr;
min-height: 100vh;
}
.sidebar {
background-color: #ffffff;
border-right: 1px solid #dee2e6;
padding: 1.5rem;
overflow-y: auto;
}
.sidebar .nav-link {
color: #495057;
font-weight: 500;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
display: flex;
align-items: center;
gap: 0.75rem;
transition: color 0.2s, background-color 0.2s;
}
.sidebar .nav-link.active,
.sidebar .nav-link:hover {
color: #0d6efd;
background-color: #e9ecef;
}
.sidebar-heading {
font-size: 0.75rem;
font-weight: 600;
color: #6c757d;
text-transform: uppercase;
padding: 0 1rem;
margin-top: 1.5rem;
margin-bottom: 0.5rem;
}
.sidebar-subheading {
font-size: 0.7rem;
font-weight: 600;
color: #868e96;
padding: 0 1rem 0 2rem;
margin-top: 0.75rem;
margin-bottom: 0.25rem;
}
.nav-link.sub-item {
padding-left: 2.5rem;
font-size: 0.9rem;
}
.nav-link.sub-sub-item {
padding-left: 3.5rem;
font-size: 0.85rem;
}
.content-area {
padding: 2rem;
overflow-y: auto;
}
#diagram-viewer {
display: none;
height: calc(100vh - 4rem);
display: flex;
flex-direction: column;
}
#diagram-container {
cursor: grab;
overflow: hidden;
flex-grow: 1;
position: relative;
background-color: #ffffff;
border-radius: 0.5rem;
border: 1px solid #dee2e6;
display: flex;
justify-content: center;
align-items: center;
padding: 2rem;
}
#diagram-container:active {
cursor: grabbing;
}
#diagram-container:focus {
outline: none;
}
#diagram-container svg {
max-width: 100%;
height: auto;
}
.loading-spinner {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
</style>
</head>
<body>
<div class="main-layout">
<!-- Sidebar -->
<nav class="sidebar">
<div class="d-flex justify-content-center align-items-center mb-4">
<img src="logo.svg" alt="Krow Logo" style="height: 60px;" onerror="this.style.display='none'">
</div>
<div class="nav flex-column nav-pills" id="sidebar-nav">
<a class="nav-link active" href="#" id="nav-home" onclick="showView('home', this)">
<i class="bi bi-house-door"></i>Home
</a>
<div class="sidebar-heading">Static Diagrams</div>
<a class="nav-link" href="#" onclick="showView('diagram', this, './assets/diagrams/high-level-overview.svg', 'Apps High-Level Overview', 'svg')">
<i class="bi bi-diagram-3"></i>High-Level Overview
</a>
<a class="nav-link" href="#" onclick="showView('diagram', this, './assets/diagrams/shift-lifecycle-workflow.svg', 'Core Workflow - Shift Lifecycle', 'svg')">
<i class="bi bi-arrow-repeat"></i>Shift Lifecycle
</a>
<a class="nav-link" href="#" onclick="showView('diagram', this, './assets/diagrams/invoice-workflow.svg', 'Invoice Workflow - Complete', 'svg')">
<i class="bi bi-receipt"></i>Invoice Workflow
</a>
<a class="nav-link" href="#" onclick="showView('diagram', this, './assets/diagrams/complete-workflow.svg', 'Complete Workflow', 'svg')">
<i class="bi bi-infinity"></i>Complete Workflow
</a>
<!-- Dynamic Mermaid diagrams will be inserted here -->
<div id="dynamic-diagrams-section"></div>
</div>
</nav>
<!-- Main Content Area -->
<main class="content-area">
<!-- View 1: Home Content -->
<div id="home-view">
<h2 class="mb-4">Welcome to the Project Launchpad</h2>
<div class="row">
<div class="col-lg-6">
<div class="card shadow-sm mb-4">
<div class="card-header"><h3>Applications (Hosting URLs)</h3></div>
<div class="card-body">
<ul class="list-group list-group-flush">
<li class="list-group-item d-flex justify-content-between align-items-center">
<a target="_blank" href="https://krow-workforce-dev.web.app">Control Tower (Dev)</a>
<span class="badge bg-primary rounded-pill">Dev</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<a target="_blank" href="https://krow-workforce-staging.web.app">Control Tower (Staging)</a>
<span class="badge bg-warning text-dark rounded-pill">Staging</span>
</li>
</ul>
</div>
</div>
<div class="card shadow-sm mb-4">
<div class="card-header"><h3>Legacy Mobile Apps</h3></div>
<div class="card-body">
<ul class="list-group list-group-flush">
<li class="list-group-item d-flex justify-content-between align-items-center">
<a target="_blank" href="https://play.google.com/store/apps/dev?id=9163719228191263405&hl=en">Google Play Store</a>
<span class="badge bg-success rounded-pill">Live</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<a target="_blank" href="https://apps.apple.com/us/developer/thinkloops-llc/id1719034287">Apple App Store</a>
<span class="badge bg-success rounded-pill">Live</span>
</li>
</ul>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card shadow-sm mb-4">
<div class="card-header"><h3>Google Cloud & Firebase Consoles</h3></div>
<div class="card-body">
<ul class="list-group list-group-flush">
<li class="list-group-item d-flex justify-content-between align-items-center">
<a target="_blank" href="https://console.firebase.google.com/project/krow-workforce-dev/overview">Firebase Console (Dev)</a>
<span class="badge bg-primary rounded-pill">Dev</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<a target="_blank" href="https://console.firebase.google.com/project/krow-workforce-staging/overview">Firebase Console (Staging)</a>
<span class="badge bg-warning text-dark rounded-pill">Staging</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<a target="_blank" href="https://console.cloud.google.com/welcome/new?project=krow-workforce-dev">Google Cloud Console (Dev)</a>
<span class="badge bg-primary rounded-pill">Dev</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<a target="_blank" href="https://console.cloud.google.com/welcome/new?project=krow-workforce-staging">Google Cloud Console (Staging)</a>
<span class="badge bg-warning text-dark rounded-pill">Staging</span>
</li>
</ul>
</div>
</div>
<div class="card shadow-sm mb-4">
<div class="card-header"><h3>Access & Resources</h3></div>
<div class="card-body">
<div class="list-group list-group-flush">
<a href="https://github.com/Oloodi/krow-workforce" target="_blank" class="list-group-item list-group-item-action">
<div class="fw-bold">GitHub Repository</div>
</a>
<a href="https://chat.google.com/" target="_blank" class="list-group-item list-group-item-action">
<div class="fw-bold">Team Communication</div>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- View 2: Diagram Viewer -->
<div id="diagram-viewer">
<div class="d-flex justify-content-between align-items-center mb-3">
<h3 id="diagram-title" class="mb-0"></h3>
<div class="btn-group">
<button type="button" class="btn btn-outline-secondary" id="zoomInBtn" title="Zoom In"><i class="bi bi-zoom-in"></i></button>
<button type="button" class="btn btn-outline-secondary" id="zoomOutBtn" title="Zoom Out"><i class="bi bi-zoom-out"></i></button>
<button type="button" class="btn btn-outline-secondary" id="resetBtn" title="Reset View"><i class="bi bi-aspect-ratio"></i></button>
</div>
</div>
<div id="diagram-container" tabindex="-1">
<!-- SVG will be loaded here -->
</div>
</div>
</main>
</div>
<!-- JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@panzoom/panzoom@4.5.1/dist/panzoom.min.js"></script>
<script>
let mermaidDiagrams = [];
const homeView = document.getElementById('home-view');
const diagramViewer = document.getElementById('diagram-viewer');
const diagramContainer = document.getElementById('diagram-container');
const diagramTitle = document.getElementById('diagram-title');
const zoomInBtn = document.getElementById('zoomInBtn');
const zoomOutBtn = document.getElementById('zoomOutBtn');
const resetBtn = document.getElementById('resetBtn');
let panzoomInstance = null;
let currentScale = 1;
// Initialize Mermaid
mermaid.initialize({
startOnLoad: false,
theme: 'default',
flowchart: {
useMaxWidth: false,
htmlLabels: true,
curve: 'basis'
}
});
// Build hierarchical structure from paths
function buildDiagramHierarchy(diagrams) {
const hierarchy = {};
diagrams.forEach(diagram => {
const parts = diagram.path.split('/');
// Remove 'assets/diagrams/' prefix
const relevantParts = parts.slice(2, -1); // Everything except filename
const filename = parts[parts.length - 1].replace('.mermaid', '');
let current = hierarchy;
relevantParts.forEach(part => {
if (!current[part]) {
current[part] = { _items: [], _children: {} };
}
current = current[part]._children;
});
// Add the item to the last level
const lastLevel = relevantParts.length > 0 ?
relevantParts.reduce((acc, part) => acc[part]._children, hierarchy) :
hierarchy;
if (relevantParts.length > 0) {
const parentKey = relevantParts[relevantParts.length - 1];
if (!hierarchy[relevantParts[0]]) {
hierarchy[relevantParts[0]] = { _items: [], _children: {} };
}
let parent = hierarchy[relevantParts[0]];
for (let i = 1; i < relevantParts.length; i++) {
parent = parent._children[relevantParts[i]];
}
parent._items.push(diagram);
} else {
if (!hierarchy._root) {
hierarchy._root = { _items: [], _children: {} };
}
hierarchy._root._items.push(diagram);
}
});
return hierarchy;
}
// Create navigation from hierarchy
function createNavigation(hierarchy, parentElement, level = 0) {
Object.keys(hierarchy).forEach(key => {
if (key === '_items' || key === '_children' || key === '_root') return;
const section = hierarchy[key];
const heading = document.createElement('div');
heading.className = level === 0 ? 'sidebar-heading' : 'sidebar-subheading';
heading.textContent = key.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
parentElement.appendChild(heading);
// Add items in this section
if (section._items && section._items.length > 0) {
section._items.forEach(diagram => {
const link = document.createElement('a');
link.className = `nav-link ${level > 0 ? 'sub-item' : ''}`;
link.href = '#';
link.onclick = (e) => {
e.preventDefault();
showView('diagram', link, diagram.path, diagram.title, 'mermaid');
};
link.innerHTML = `<i class="bi bi-file-earmark-code"></i>${diagram.title}`;
parentElement.appendChild(link);
});
}
// Recursively add children
if (section._children && Object.keys(section._children).length > 0) {
createNavigation(section._children, parentElement, level + 1);
}
});
}
// Load and render dynamic diagrams navigation
async function loadDynamicDiagrams() {
const dynamicSection = document.getElementById('dynamic-diagrams-section');
try {
// Fetch the diagrams configuration from JSON file
const response = await fetch('./assets/diagrams/diagrams-config.json');
if (!response.ok) {
throw new Error(`Failed to load diagrams config: ${response.status}`);
}
mermaidDiagrams = await response.json();
if (mermaidDiagrams.length > 0) {
const mainHeading = document.createElement('div');
mainHeading.className = 'sidebar-heading';
mainHeading.textContent = 'Mermaid Diagrams';
dynamicSection.appendChild(mainHeading);
const hierarchy = buildDiagramHierarchy(mermaidDiagrams);
createNavigation(hierarchy, dynamicSection);
}
} catch (error) {
console.error('Error loading diagrams configuration:', error);
dynamicSection.innerHTML = `<div class="alert alert-warning m-2 small">No Mermaid diagrams configuration found</div>`;
}
}
function setActiveNav(activeLink) {
document.querySelectorAll('.sidebar .nav-link').forEach(link => {
link.classList.remove('active');
});
activeLink.classList.add('active');
}
async function showView(viewName, navLink, filePath, title, type = 'svg') {
setActiveNav(navLink);
if (panzoomInstance) {
panzoomInstance.destroy();
panzoomInstance = null;
}
diagramContainer.innerHTML = '';
currentScale = 1;
if (viewName === 'home') {
homeView.style.display = 'block';
diagramViewer.style.display = 'none';
} else if (viewName === 'diagram') {
homeView.style.display = 'none';
diagramViewer.style.display = 'flex';
diagramTitle.textContent = title;
diagramContainer.innerHTML = '<div class="loading-spinner"><div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div></div>';
try {
if (type === 'svg') {
// Load static SVG files
const response = await fetch(filePath);
if (!response.ok) throw new Error(`Network error: ${response.status}`);
const svgContent = await response.text();
const parser = new DOMParser();
const svgDoc = parser.parseFromString(svgContent, "image/svg+xml");
const svgElement = svgDoc.querySelector('svg');
if (svgElement) {
diagramContainer.innerHTML = '';
diagramContainer.appendChild(svgElement);
panzoomInstance = Panzoom(svgElement, {
canvas: true,
maxScale: 10,
minScale: 0.3,
startScale: 1
});
diagramContainer.addEventListener('wheel', panzoomInstance.zoomWithWheel);
diagramContainer.focus();
} else {
throw new Error('No SVG element found.');
}
} else if (type === 'mermaid') {
// Load and render Mermaid files
const response = await fetch(filePath);
if (!response.ok) throw new Error(`Network error: ${response.status}`);
const mermaidCode = await response.text();
const { svg } = await mermaid.render('mermaidDiagram_' + Date.now(), mermaidCode);
diagramContainer.innerHTML = svg;
const svgElement = diagramContainer.querySelector('svg');
if (svgElement) {
svgElement.style.maxWidth = 'none';
svgElement.style.height = 'auto';
panzoomInstance = Panzoom(svgElement, {
canvas: true,
maxScale: 10,
minScale: 0.3,
startScale: 1
});
diagramContainer.addEventListener('wheel', panzoomInstance.zoomWithWheel);
diagramContainer.focus();
} else {
throw new Error('Failed to render Mermaid diagram.');
}
}
} catch (error) {
diagramContainer.innerHTML = `<div class="alert alert-danger m-3">Failed to load diagram: ${error.message}</div>`;
}
}
}
zoomInBtn.addEventListener('click', () => {
if (panzoomInstance) {
panzoomInstance.zoomIn();
diagramContainer.focus();
}
});
zoomOutBtn.addEventListener('click', () => {
if (panzoomInstance) {
panzoomInstance.zoomOut();
diagramContainer.focus();
}
});
resetBtn.addEventListener('click', () => {
if (panzoomInstance) {
panzoomInstance.reset();
diagramContainer.focus();
}
});
document.addEventListener('DOMContentLoaded', () => {
loadDynamicDiagrams();
showView('home', document.getElementById('nav-home'));
});
</script>
</body>
</html>