Spaces:
Running
Running
| from __future__ import annotations | |
| import html | |
| from typing import Any, Iterable, Mapping, Sequence | |
| # Placeholder for models.EmployeeTrainingPlan if not provided | |
| class EmployeeTrainingPlan: | |
| def __init__(self): | |
| pass | |
| def _as_mapping(member: EmployeeTrainingPlan | Mapping[str, Any]) -> Mapping[str, Any]: | |
| if isinstance(member, Mapping): | |
| return member | |
| # Assuming the actual EmployeeTrainingPlan model has these attributes or model_dump | |
| if hasattr(member, "model_dump"): | |
| return member.model_dump() | |
| return { | |
| "employee_name": getattr(member, "employee_name", "Unknown employee"), | |
| "role": getattr(member, "role", "Unknown role"), | |
| "skills_gaps": getattr(member, "skills_gaps", []), | |
| "training_plan": getattr(member, "training_plan", []), | |
| } | |
| def _render_skill_gaps(gaps: Sequence[Mapping[str, Any]] | None) -> str: | |
| if not gaps: | |
| return "<p>No notable skill gaps.</p>" | |
| items = [] | |
| for gap in gaps: | |
| skill = html.escape(str(gap.get("skill", "Unknown skill"))) | |
| raw_magnitude = gap.get("gap") | |
| try: | |
| magnitude_value = max(0.0, min(10.0, float(raw_magnitude))) | |
| magnitude = f"{magnitude_value:.1f}" | |
| except (TypeError, ValueError): | |
| magnitude_value = None | |
| magnitude = html.escape(str(raw_magnitude or "N/A")) | |
| severity = "High" | |
| if magnitude_value is not None: | |
| if magnitude_value < 4: | |
| severity = "Low" | |
| elif magnitude_value < 7: | |
| severity = "Medium" | |
| # progress_pct is not used in the current HTML but kept for context if needed | |
| # progress_pct = ( | |
| # f"{(magnitude_value or 0) / 10 * 100:.0f}" | |
| # if magnitude_value is not None | |
| # else "0" | |
| # ) | |
| items.append( | |
| "<li>" | |
| f'<div class="skill-gap-item">' | |
| f'<span class="skill-name">{skill}</span>' | |
| f'<span class="gap-pill" data-severity="{severity.lower()}">Gap {magnitude}</span>' | |
| "</div>" | |
| "</li>" | |
| ) | |
| return f'<ul class="skill-gap-list" role="list">{"".join(items)}</ul>' | |
| def _render_training_plan(resources: Iterable[Mapping[str, Any]] | None) -> str: | |
| if not resources: | |
| return "<p>No training plan yet.</p>" | |
| cards = [] | |
| for resource in resources: | |
| title = html.escape(str(resource.get("title", "Training resource"))) | |
| url = resource.get("url") | |
| provider = resource.get("provider") or resource.get("platform") | |
| duration = resource.get("duration_hours") or resource.get("duration") | |
| cost = resource.get("cost") | |
| cost_text = "Free" if cost in (None, "", 0) else f"${cost}" | |
| skills = resource.get("skills_covered") or resource.get("skills") or [] | |
| link = ( | |
| f'<a href="{html.escape(url)}" target="_blank" rel="noreferrer">{title}</a>' | |
| if url | |
| else title | |
| ) | |
| rows = [f'<div class="resource-title">{link}</div>'] | |
| meta_bits = [] | |
| if provider: | |
| meta_bits.append(html.escape(str(provider))) | |
| if duration: | |
| meta_bits.append(html.escape(str(duration))) | |
| if cost_text: | |
| meta_bits.append(html.escape(cost_text)) | |
| if meta_bits: | |
| rows.append(f'<div class="resource-meta">{" · ".join(meta_bits)}</div>') | |
| if skills: | |
| chips = "".join( | |
| f'<span class="skill-chip">{html.escape(str(skill))}</span>' | |
| for skill in skills | |
| ) | |
| rows.append(f'<div class="resource-skills">{chips}</div>') | |
| cards.append(f'<li>{"".join(rows)}</li>') | |
| return f'<ul class="training-plan-list" role="list">{"".join(cards)}</ul>' | |
| def render_employee_card(member: EmployeeTrainingPlan | Mapping[str, Any]) -> str: | |
| data = _as_mapping(member) | |
| name = html.escape(str(data.get("employee_name", "Unknown employee"))) | |
| role = html.escape(str(data.get("role") or "Not provided")) | |
| skill_gap_html = _render_skill_gaps(data.get("skills_gaps")) | |
| training_plan_html = _render_training_plan(data.get("training_plan")) | |
| return f""" | |
| <div class="employee-card"> | |
| <div class="employee-title">{name}</div> | |
| <div class="employee-meta">{role}</div> | |
| <div class="employee-section"> | |
| <span class="section-label">Skill Gap</span> | |
| {skill_gap_html} | |
| </div> | |
| <div class="employee-section"> | |
| <span class="section-label">Training Plan</span> | |
| {training_plan_html} | |
| </div> | |
| </div> | |
| """ |