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.
503 lines
22 KiB
HTML
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>
|