feat: Add comprehensive study management system to dashboard

Added full study configuration UI:
- Create studies with isolated folder structure (sim/, results/, config.json)
- File management: users drop .sim/.prt files into study's sim folder
- NX expression extraction: journal script to explore .sim file
- Configuration UI for design variables, objectives, and constraints
- Save/load study configurations through API
- Step-by-step workflow: create → add files → explore → configure → run

Backend API (app.py):
- POST /api/study/create - Create new study with folder structure
- GET /api/study/<name>/sim/files - List files in sim folder
- POST /api/study/<name>/explore - Extract expressions from .sim file
- GET/POST /api/study/<name>/config - Load/save study configuration

Frontend:
- New study configuration view with 5-step wizard
- Modal for creating new studies
- Expression explorer with clickable selection
- Dynamic forms for variables/objectives/constraints
- Professional styling with config cards

NX Integration:
- extract_expressions.py journal script
- Scans .sim and all loaded .prt files
- Identifies potential design variable candidates
- Exports expressions with values, formulas, units

Each study is self-contained with its own geometry files and config.
This commit is contained in:
2025-11-15 14:00:00 -05:00
parent c1fad3bd37
commit 9ddc065d31
5 changed files with 1216 additions and 3 deletions

View File

@@ -528,6 +528,157 @@ tbody tr:hover {
color: var(--text-light);
}
/* Study Configuration */
.study-config {
display: none;
}
.config-steps {
display: flex;
flex-direction: column;
gap: 2rem;
}
.config-step {
background: var(--bg);
border-radius: 12px;
padding: 1.5rem;
border-left: 4px solid var(--primary);
}
.config-step h3 {
color: var(--text);
margin-bottom: 1rem;
}
.step-description {
color: var(--text-light);
margin-bottom: 1rem;
font-size: 0.95rem;
}
.step-content {
margin-top: 1rem;
}
.file-info {
background: white;
padding: 1rem;
border-radius: 8px;
margin-bottom: 1rem;
border: 1px solid var(--border);
}
.files-list {
margin: 1rem 0;
max-height: 200px;
overflow-y: auto;
}
.file-item {
padding: 0.75rem;
background: white;
border-radius: 6px;
margin-bottom: 0.5rem;
border: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: center;
}
.file-item .file-name {
font-weight: 600;
}
.file-item .file-meta {
font-size: 0.85rem;
color: var(--text-light);
}
.expressions-list {
margin-top: 1rem;
padding: 1rem;
background: white;
border-radius: 8px;
border: 1px solid var(--border);
max-height: 300px;
overflow-y: auto;
}
.expression-item {
padding: 0.75rem;
background: var(--bg);
border-radius: 6px;
margin-bottom: 0.5rem;
cursor: pointer;
border: 2px solid transparent;
transition: all 0.2s;
}
.expression-item:hover {
border-color: var(--primary);
transform: translateX(4px);
}
.expression-item.selected {
background: linear-gradient(135deg, #667eea20 0%, #764ba220 100%);
border-color: var(--primary);
}
.expression-name {
font-weight: 600;
margin-bottom: 0.25rem;
}
.expression-meta {
font-size: 0.85rem;
color: var(--text-light);
}
.variables-config, .objectives-config, .constraints-config {
margin: 1rem 0;
}
.config-item {
background: white;
padding: 1rem;
border-radius: 8px;
margin-bottom: 1rem;
border: 1px solid var(--border);
}
.config-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.75rem;
}
.config-item-title {
font-weight: 600;
color: var(--text);
}
.config-item-remove {
background: none;
border: none;
color: var(--danger);
cursor: pointer;
font-size: 1.2rem;
}
.config-item-fields {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.field-inline {
display: flex;
gap: 1rem;
align-items: flex-end;
}
/* Responsive */
@media (max-width: 1024px) {
.main-content {
@@ -541,4 +692,8 @@ tbody tr:hover {
.charts-container {
grid-template-columns: 1fr;
}
.config-item-fields {
grid-template-columns: 1fr;
}
}