Skip to content

Commit edf9f92

Browse files
committed
Convert NIST viewer to multi-page architecture
Replace single-page viewer with multi-page web application for better organization and navigation. Changes: - Create templates/ directory with 6 HTML page templates and 2 shared components - index.html: Dashboard with overview stats and charts - controls.html: Controls browser with advanced filtering - control-detail.html: Individual control details with OSCAL metadata and TODO management - gaps.html: Gap analysis by priority and family - statistics.html: Detailed metrics and cross-product comparison - family.html: Control family breakdown and family-specific views - _shared_styles.html: Common CSS for all pages - _shared_header.html: Navigation header and product selector - Update generate_nist_viewer.py to generate multiple HTML files instead of single file - Embed data in all pages for offline access (no CORS issues) - Pages communicate via URL parameters and localStorage - Update VIEWER_README.md with multi-page architecture documentation Benefits: - Better separation of concerns (each page has focused functionality) - Easier to maintain and extend (modify individual pages without affecting others) - Clearer navigation with dedicated pages for each view - Improved user experience with logical page organization
1 parent c96a4a5 commit edf9f92

11 files changed

Lines changed: 2711 additions & 67 deletions

docs/README_nist_800_53_viewer.md

Lines changed: 122 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,77 @@
11
# NIST 800-53 Control Viewer & Gap Analysis
22

3-
Interactive web-based viewer for NIST 800-53 control files with comprehensive gap analysis and backlog management features.
3+
Interactive multi-page web-based viewer for NIST 800-53 control files with comprehensive gap analysis and backlog management features.
4+
5+
## Architecture
6+
7+
The viewer is a multi-page web application with the following pages:
8+
9+
- **index.html** - Dashboard with overview statistics and charts
10+
- **controls.html** - Controls list with advanced filtering
11+
- **control-detail.html** - Individual control details with OSCAL metadata and TODO management
12+
- **gaps.html** - Gap analysis showing controls without rules
13+
- **statistics.html** - Detailed statistics and metrics
14+
- **family.html** - Control family breakdown and family-specific views
15+
16+
All pages share:
17+
- Common navigation header for seamless page transitions
18+
- Shared CSS styling for consistent look and feel
19+
- Embedded JSON data for offline access (no external API calls)
20+
- Product selector that persists across pages via localStorage
421

522
## Features
623

7-
### Dashboard View
24+
### Dashboard (index.html)
825
- **Overall Coverage Statistics**: Total controls, automated, manual, and pending counts with percentages
9-
- **Gap Analysis**: Visual representation of controls without rules
10-
- **Product Comparison**: Side-by-side comparison of rhel8, rhel9, and rhel10 coverage
26+
- **Gap Analysis Summary**: Total controls without rules
27+
- **Product Comparison Table**: Side-by-side comparison of rhel8, rhel9, and rhel10 coverage
1128
- **Family Coverage Chart**: Bar chart showing automation coverage by control family
12-
- **Baseline Level Breakdown**: Distribution across LOW, MODERATE, and HIGH baselines
13-
- **Top Gaps List**: Quick view of controls that need rule implementation
29+
- **Top Gaps List**: Quick view of controls that need rule implementation (links to detailed gap analysis)
1430

15-
### Controls View
31+
### Controls Browser (controls.html)
1632
- **Advanced Filtering**:
1733
- Filter by control family (AC, AU, CM, IA, SC, SI, etc.)
1834
- Filter by baseline level (Low, Moderate, High)
1935
- Filter by status (Automated, Manual, Pending)
2036
- Filter by gap status (With Rules, Without Rules)
2137
- Full-text search across control IDs, titles, and descriptions
38+
- Select All / Deselect All checkboxes for each filter category
39+
40+
- **Controls List**:
41+
- Clickable control cards showing ID, title, status, and metadata
42+
- Visual gap indicators (red dots for controls without rules)
43+
- Rule count and baseline level badges
2244

23-
- **Control Details**:
24-
- OSCAL metadata (description, guidance, parameters)
25-
- Implementation status
26-
- Rule listings
27-
- Related controls with clickable links
28-
- Baseline level applicability
45+
### Control Details (control-detail.html)
46+
- **OSCAL Metadata**: Full description, supplemental guidance, and parameters (ODPs)
47+
- **Implementation Status**: Automated, manual, or pending
48+
- **Rule Listings**: All rules mapped to this control
49+
- **Related Controls**: Clickable links to related controls
50+
- **Baseline Level Applicability**: Which baselines (low, moderate, high) include this control
2951

3052
- **Backlog Management**:
3153
- Add TODO items per control
3254
- Mark items as complete
3355
- Delete completed items
34-
- Persistent storage in browser localStorage
56+
- Persistent storage in browser localStorage (per-control)
57+
58+
### Gap Analysis (gaps.html)
59+
- **Gap Summary**: Total gaps broken down by baseline level (high, moderate, low)
60+
- **Priority Sections**: Gaps organized by baseline priority
61+
- **Family Breakdown**: Which control families have the most gaps
62+
- **Quick Navigation**: Click any gap to view control details
63+
64+
### Statistics (statistics.html)
65+
- **Product Overview**: Comprehensive metrics for current product
66+
- **Baseline Breakdown**: Coverage statistics for each baseline level (low, moderate, high)
67+
- **Cross-Product Comparison**: Table comparing all products side-by-side
68+
- **Family Statistics**: Detailed metrics for each control family
69+
70+
### Control Families (family.html)
71+
- **Family Grid View**: All control families with coverage stats
72+
- **Family Detail View**: Click any family to see all controls in that family
73+
- **Family-Specific Stats**: Automated, manual, pending, and gap counts per family
74+
- **Quick Control Access**: Jump to any control within a family
3575

3676
## Building the Viewer
3777

@@ -44,7 +84,14 @@ cmake .. -G Ninja
4484
ninja nist-viewer
4585

4686
# The viewer will be generated at:
47-
# build/nist-controls-viewer/nist-controls-viewer.html
87+
# build/nist-controls-viewer/
88+
# ├── index.html (Dashboard - start here)
89+
# ├── controls.html (Controls browser)
90+
# ├── control-detail.html (Individual control details)
91+
# ├── gaps.html (Gap analysis)
92+
# ├── statistics.html (Detailed statistics)
93+
# ├── family.html (Control families)
94+
# └── nist-controls-data.json (Reference data file)
4895
```
4996

5097
### Manual Generation
@@ -58,21 +105,23 @@ python3 generate_nist_viewer.py \
58105
--output-dir ../../build/nist-controls-viewer \
59106
--repo-root ../..
60107

61-
# Open the viewer
62-
open ../../build/nist-controls-viewer/nist-controls-viewer.html
108+
# Open the viewer (starts at dashboard)
109+
open ../../build/nist-controls-viewer/index.html
63110
```
64111

65112
## Published Version
66113

67114
The viewer is automatically published to GitHub Pages via the `gh-pages` workflow:
68115

69-
**URL**: https://complianceascode.github.io/content-pages/nist-viewer/nist-controls-viewer.html
116+
**URL**: https://complianceascode.github.io/content-pages/nist-viewer/
70117

71-
The published version updates automatically when changes are pushed to the master branch.
118+
The published version updates automatically when changes are pushed to the master branch. Navigate to the dashboard (index.html) to start browsing.
72119

73120
## Data Structure
74121

75-
The viewer has all control data embedded directly in the HTML file (as `EMBEDDED_DATA` JavaScript constant). This allows the viewer to work when opened directly as a local file without CORS issues.
122+
The viewer embeds all control data directly in each HTML file (as `EMBEDDED_DATA` JavaScript constant). This allows the viewer to work when opened directly as local files without CORS issues or requiring a web server.
123+
124+
Data is embedded in all pages identically, allowing each page to function independently. Pages communicate via URL parameters (e.g., `control-detail.html?id=ac-2`) and localStorage (for product selection and TODOs).
76125

77126
A separate `nist-controls-data.json` file is also generated for reference and debugging purposes.
78127

@@ -150,11 +199,18 @@ TODOs are stored in browser localStorage, so they persist across sessions but ar
150199

151200
## Customization
152201

153-
### Modifying the Template
154-
Edit `utils/nist_sync/nist_viewer_template.html` to customize:
155-
- Styling (CSS in `<style>` section)
156-
- Layout (HTML structure)
157-
- Behavior (JavaScript functions)
202+
### Modifying the Templates
203+
Edit files in `utils/nist_sync/templates/` to customize:
204+
- **_shared_styles.html** - Common CSS used across all pages
205+
- **_shared_header.html** - Navigation header and product selector
206+
- **index.html** - Dashboard page
207+
- **controls.html** - Controls browser page
208+
- **control-detail.html** - Individual control detail page
209+
- **gaps.html** - Gap analysis page
210+
- **statistics.html** - Statistics page
211+
- **family.html** - Control families page
212+
213+
Each template can have its own page-specific styles and JavaScript in addition to the shared components.
158214

159215
### Adding New Statistics
160216
Modify `generate_nist_viewer.py`:
@@ -192,33 +248,62 @@ No external dependencies - all functionality is self-contained in a single HTML
192248
## Troubleshooting
193249

194250
### "Error loading data"
195-
- The data should be embedded in the HTML file - regenerate the viewer with `ninja nist-viewer`
196-
- If you modified the template, ensure the `/* DATA_PLACEHOLDER */` comment exists in the script section
251+
- The data should be embedded in each HTML file - regenerate the viewer with `ninja nist-viewer`
252+
- If you modified a template, ensure the `/* DATA_PLACEHOLDER */` comment exists in the script section
197253
- Check browser console for specific error messages
198-
- The HTML file should be around 7MB - if it's much smaller, the data wasn't embedded properly
254+
- Each HTML file should be several MB in size - if much smaller, the data wasn't embedded properly
199255

200256
### Controls not showing
201-
- Check filter settings - try resetting all filters
202-
- Verify the data file contains controls for the selected product
257+
- Check filter settings on controls.html - try resetting all filters
258+
- Verify the data is embedded (open browser console and check for `EMBEDDED_DATA`)
259+
- Try switching products using the product selector
203260

204261
### TODOs not persisting
205262
- localStorage must be enabled in your browser
206263
- Check browser privacy settings
207-
- TODOs are per-browser and per-domain
264+
- TODOs are per-browser, per-domain, and per-control
265+
- Clearing browser data will erase TODOs
208266

209-
### Dashboard not rendering
267+
### Dashboard not rendering / Page not loading
210268
- Check browser console for JavaScript errors
211-
- Ensure the JSON data loaded successfully
269+
- Ensure the EMBEDDED_DATA constant is defined
212270
- Try refreshing the page
271+
- Verify you're using a modern browser (Chrome 90+, Firefox 88+, Safari 14+, Edge 90+)
272+
273+
### Navigation not working
274+
- Ensure all 6 HTML files are in the same directory
275+
- Check that file paths are relative (not absolute)
276+
- If hosting on a web server, verify all files are accessible
277+
278+
### Product selection not persisting
279+
- Check that localStorage is enabled
280+
- The product selection is stored in localStorage key `selected-product`
281+
- Clearing browser data will reset to default (rhel9)
213282

214283
## Development
215284

216285
To develop new features:
217286

218-
1. Edit `nist_viewer_template.html`
219-
2. Test locally by opening the generated HTML file
220-
3. Regenerate after changes: `ninja nist-viewer`
221-
4. Commit both the template and updated CMake files
287+
1. Edit templates in `utils/nist_sync/templates/`:
288+
- For styling changes: edit `_shared_styles.html`
289+
- For navigation changes: edit `_shared_header.html`
290+
- For page-specific changes: edit the corresponding page template
291+
2. Test locally by opening the generated HTML files in a browser
292+
3. Regenerate after changes: `ninja nist-viewer` (from build directory)
293+
4. Commit template changes
294+
295+
### Adding a New Page
296+
297+
1. Create a new template file in `utils/nist_sync/templates/` (e.g., `new-page.html`)
298+
2. Include placeholders for shared components:
299+
```html
300+
<!-- SHARED_STYLES_PLACEHOLDER -->
301+
<!-- SHARED_HEADER_PLACEHOLDER -->
302+
/* DATA_PLACEHOLDER */
303+
```
304+
3. Add the page to the `pages` list in `generate_nist_viewer.py`
305+
4. Add navigation link to `_shared_header.html`
306+
5. Regenerate and test
222307

223308
## License
224309

utils/nist_sync/generate_nist_viewer.py

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -223,24 +223,50 @@ def generate_viewer_data(products: List[str], repo_root: Path) -> Dict[str, Any]
223223
}
224224

225225

226-
def generate_html_viewer(output_file: Path, template_file: Path, viewer_data: Dict[str, Any]):
227-
"""Generate HTML viewer from template with embedded data."""
228-
with open(template_file, 'r') as f:
229-
html_content = f.read()
226+
def generate_html_viewer(output_dir: Path, templates_dir: Path, viewer_data: Dict[str, Any]):
227+
"""Generate multi-page HTML viewer from templates with embedded data."""
230228

231-
# Embed the JSON data directly in the HTML
229+
# Read shared components
230+
shared_styles = (templates_dir / '_shared_styles.html').read_text()
231+
shared_header = (templates_dir / '_shared_header.html').read_text()
232+
233+
# Embed the JSON data
232234
json_data = json.dumps(viewer_data, indent=2)
235+
embedded_data_script = f'const EMBEDDED_DATA = {json_data};'
236+
237+
# List of page templates to generate
238+
pages = [
239+
'index.html',
240+
'controls.html',
241+
'control-detail.html',
242+
'gaps.html',
243+
'statistics.html',
244+
'family.html'
245+
]
246+
247+
# Generate each page
248+
for page in pages:
249+
template_file = templates_dir / page
250+
251+
if not template_file.exists():
252+
print(f"Warning: Template not found: {template_file}")
253+
continue
254+
255+
# Read template
256+
html_content = template_file.read_text()
233257

234-
# Replace the placeholder with embedded data
235-
html_content = html_content.replace(
236-
'/* DATA_PLACEHOLDER */',
237-
f'const EMBEDDED_DATA = {json_data};'
238-
)
258+
# Replace placeholders
259+
html_content = html_content.replace('<!-- SHARED_STYLES_PLACEHOLDER -->', f'<style>{shared_styles}</style>')
260+
html_content = html_content.replace('<!-- SHARED_HEADER_PLACEHOLDER -->', shared_header)
261+
html_content = html_content.replace('/* DATA_PLACEHOLDER */', embedded_data_script)
239262

240-
with open(output_file, 'w') as f:
241-
f.write(html_content)
263+
# Write output file
264+
output_file = output_dir / page
265+
output_file.write_text(html_content)
266+
print(f"Generated: {output_file}")
242267

243-
print(f"Generated HTML viewer: {output_file}")
268+
print(f"\nMulti-page viewer generated in: {output_dir}")
269+
print(f"Open {output_dir / 'index.html'} in a web browser to view.")
244270

245271

246272
def main():
@@ -267,18 +293,16 @@ def main():
267293
json.dump(viewer_data, f, indent=2)
268294
print(f"Generated data file: {data_file}")
269295

270-
# Generate HTML with embedded data
271-
template_file = Path(__file__).parent / 'nist_viewer_template.html'
272-
output_html = args.output_dir / 'nist-controls-viewer.html'
296+
# Generate multi-page HTML viewer
297+
templates_dir = Path(__file__).parent / 'templates'
273298

274-
if template_file.exists():
275-
generate_html_viewer(output_html, template_file, viewer_data)
299+
if templates_dir.exists():
300+
generate_html_viewer(args.output_dir, templates_dir, viewer_data)
276301
else:
277-
print(f"Warning: Template file not found: {template_file}")
278-
print("HTML viewer not generated. Run the template creation step first.")
302+
print(f"Warning: Templates directory not found: {templates_dir}")
303+
print("HTML viewer not generated. Ensure templates directory exists.")
279304

280305
print("\nViewer generation complete!")
281-
print(f"Open {output_html} in a web browser to view.")
282306

283307

284308
if __name__ == '__main__':

0 commit comments

Comments
 (0)