209 lines
No EOL
6 KiB
Markdown
209 lines
No EOL
6 KiB
Markdown
# Chunk 8: Graph Analysis
|
|
|
|
**Parent:** [Build Graph Dashboard](../build-graph-dashboard.md)
|
|
**Previous:** [Chunk 7: Jobs Pages](./chunk-7-jobs-pages.md)
|
|
**Next:** [Chunk 9: Polish](./chunk-9-polish.md)
|
|
|
|
## Overview
|
|
|
|
Implement interactive build graph analysis with partition input forms, Mermaid.js visualization, and execution plan display.
|
|
|
|
## Scope
|
|
|
|
### In Scope
|
|
- Partition input form for analysis requests
|
|
- Mermaid.js visualization of job graphs
|
|
- Execution plan table with job details
|
|
- Interactive graph exploration
|
|
- Error handling for invalid partition references
|
|
|
|
### Out of Scope
|
|
- Complex graph editing capabilities
|
|
- Advanced graph algorithms or analysis
|
|
- Performance optimization for large graphs
|
|
- Real-time graph updates
|
|
|
|
## Technical Approach
|
|
|
|
### Data Sources
|
|
From Build Graph Service API:
|
|
- `/api/v1/analyze` - Analyze build graph for partitions
|
|
- Returns `JobGraph` with tasks and dependencies
|
|
|
|
### Component Structure
|
|
```typescript
|
|
const GraphAnalysis = {
|
|
oninit: () => {
|
|
this.partitions = [''];
|
|
this.jobGraph = null;
|
|
this.loading = false;
|
|
this.error = null;
|
|
this.mermaidRendered = false;
|
|
},
|
|
|
|
view: () => [
|
|
m('.analysis-header', [
|
|
m('h1', 'Graph Analysis'),
|
|
m('p', 'Analyze the build graph for specific partitions')
|
|
]),
|
|
|
|
m('.analysis-form', [
|
|
m('h2', 'Partition References'),
|
|
m('.partition-inputs', [
|
|
this.partitions.map((partition, index) =>
|
|
m('.input-group', [
|
|
m('input', {
|
|
value: partition,
|
|
placeholder: 'Enter partition reference...',
|
|
oninput: (e) => this.partitions[index] = e.target.value,
|
|
}),
|
|
m('button.btn.btn-outline', {
|
|
onclick: () => this.removePartition(index),
|
|
disabled: this.partitions.length <= 1
|
|
}, 'Remove')
|
|
])
|
|
),
|
|
m('button.btn.btn-outline', {
|
|
onclick: () => this.addPartition()
|
|
}, 'Add Partition')
|
|
]),
|
|
|
|
m('.form-actions', [
|
|
m('button.btn.btn-primary', {
|
|
onclick: () => this.analyzeGraph(),
|
|
disabled: this.loading || !this.hasValidPartitions()
|
|
}, this.loading ? 'Analyzing...' : 'Analyze Graph')
|
|
])
|
|
]),
|
|
|
|
this.error ? m('.error-message', [
|
|
m('.alert.alert-error', this.error)
|
|
]) : null,
|
|
|
|
this.jobGraph ? m('.analysis-results', [
|
|
m('.graph-visualization', [
|
|
m('h2', 'Job Graph'),
|
|
m('#mermaid-graph', {
|
|
oncreate: () => this.renderMermaid(),
|
|
onupdate: () => this.renderMermaid()
|
|
})
|
|
]),
|
|
|
|
m('.execution-plan', [
|
|
m('h2', 'Execution Plan'),
|
|
m('table.table', [
|
|
m('thead', [
|
|
m('tr', [
|
|
m('th', 'Job'),
|
|
m('th', 'Outputs'),
|
|
m('th', 'Inputs'),
|
|
m('th', 'Arguments'),
|
|
])
|
|
]),
|
|
m('tbody', this.jobGraph.nodes.map(task =>
|
|
m('tr', [
|
|
m('td', m('a', {
|
|
href: `/jobs/${encodeJobLabel(task.job.label)}`
|
|
}, task.job.label)),
|
|
m('td', m('ul', task.config.outputs.map(output =>
|
|
m('li', m('a', {
|
|
href: `/partitions/${encodePartitionRef(output.str)}`
|
|
}, output.str))
|
|
))),
|
|
m('td', m('ul', task.config.inputs.map(input =>
|
|
m('li', input.partition_ref.str)
|
|
))),
|
|
m('td', m('code', task.config.args.join(' '))),
|
|
])
|
|
))
|
|
])
|
|
])
|
|
]) : null
|
|
]
|
|
};
|
|
```
|
|
|
|
### Mermaid.js Integration
|
|
```typescript
|
|
// Generate Mermaid diagram from JobGraph
|
|
function generateMermaidDiagram(jobGraph: JobGraph): string {
|
|
const nodes = jobGraph.nodes.map(task =>
|
|
`${task.job.label}["${task.job.label}"]`
|
|
).join('\n ');
|
|
|
|
const edges = jobGraph.nodes.flatMap(task =>
|
|
task.config.inputs.map(input => {
|
|
const sourceJob = findJobForPartition(input.partition_ref.str);
|
|
return sourceJob ? `${sourceJob} --> ${task.job.label}` : null;
|
|
}).filter(Boolean)
|
|
).join('\n ');
|
|
|
|
return `graph TD\n ${nodes}\n ${edges}`;
|
|
}
|
|
|
|
// Render with Mermaid
|
|
function renderMermaid() {
|
|
if (!this.jobGraph || this.mermaidRendered) return;
|
|
|
|
const diagram = generateMermaidDiagram(this.jobGraph);
|
|
mermaid.render('graph', diagram, (svgCode) => {
|
|
document.getElementById('mermaid-graph').innerHTML = svgCode;
|
|
this.mermaidRendered = true;
|
|
});
|
|
}
|
|
```
|
|
|
|
### Form Management
|
|
- Dynamic partition input fields
|
|
- Add/remove partition functionality
|
|
- Input validation
|
|
- Error handling for invalid references
|
|
|
|
## Implementation Strategy
|
|
|
|
1. **Create Form Interface**
|
|
- Dynamic partition input management
|
|
- Form validation and submission
|
|
- Loading states and error handling
|
|
|
|
2. **Integrate Graph Analysis API**
|
|
- API calls to analyze endpoint
|
|
- Error handling for analysis failures
|
|
- JobGraph data processing
|
|
|
|
3. **Add Mermaid.js Visualization**
|
|
- Include Mermaid.js library
|
|
- Generate diagrams from JobGraph
|
|
- Handle rendering lifecycle
|
|
|
|
4. **Build Execution Plan Display**
|
|
- Table layout for job details
|
|
- Links to job and partition pages
|
|
- Clear display of dependencies
|
|
|
|
## Deliverables
|
|
|
|
- [ ] Interactive partition input form
|
|
- [ ] Mermaid.js graph visualization
|
|
- [ ] Execution plan table with job details
|
|
- [ ] Error handling for invalid inputs
|
|
- [ ] Links to related job and partition pages
|
|
|
|
## Success Criteria
|
|
|
|
- Form allows adding/removing partition inputs
|
|
- Graph analysis API integration works correctly
|
|
- Mermaid diagrams render accurately
|
|
- Execution plan shows complete job details
|
|
- Error handling provides useful feedback
|
|
- Links navigate to appropriate detail pages
|
|
|
|
## Testing
|
|
|
|
- Test form with various partition combinations
|
|
- Verify graph analysis API calls work correctly
|
|
- Test Mermaid diagram generation and rendering
|
|
- Validate execution plan accuracy
|
|
- Test error handling with invalid partitions
|
|
- Check links to job and partition detail pages
|
|
- Test with complex multi-job graphs |