refactor(insights): share workbook export and ai defaults
This commit is contained in:
@@ -70,6 +70,12 @@ function entityLink(type: string, entityId: string): string {
|
||||
return `/projects/${entityId}`;
|
||||
}
|
||||
|
||||
type ProjectOption = {
|
||||
id: string;
|
||||
name: string;
|
||||
shortCode: string | null;
|
||||
};
|
||||
|
||||
// ─── Main component ──────────────────────────────────────────────────────────
|
||||
|
||||
export function InsightsPanel() {
|
||||
@@ -111,7 +117,7 @@ export function InsightsPanel() {
|
||||
});
|
||||
|
||||
const anomalies = anomaliesQuery.data ?? [];
|
||||
const projects = projectsQuery.data?.projects ?? [];
|
||||
const projects: ProjectOption[] = (projectsQuery.data?.projects ?? []) as ProjectOption[];
|
||||
|
||||
// Filter anomalies
|
||||
const filteredAnomalies = narrativeFilter
|
||||
|
||||
@@ -6,7 +6,7 @@ import { PROFICIENCY_LABELS, proficiencyClasses, ProficiencyBadge } from "~/comp
|
||||
import { SortableColumnHeader } from "~/components/ui/SortableColumnHeader.js";
|
||||
import { useTableSort } from "~/hooks/useTableSort.js";
|
||||
import { trpc } from "~/lib/trpc/client.js";
|
||||
import * as XLSX from "xlsx";
|
||||
import { downloadWorkbook } from "~/lib/workbook-export.js";
|
||||
|
||||
const SkillDistributionChart = dynamic(
|
||||
() => import("~/components/analytics/SkillDistributionChart.js"),
|
||||
@@ -60,18 +60,17 @@ export function SkillsAnalytics() {
|
||||
|
||||
async function exportXlsx() {
|
||||
if (!data) return;
|
||||
const XLSX = await import("xlsx");
|
||||
const rows = data.aggregated.map((e) => ({
|
||||
Skill: e.skill,
|
||||
Category: e.category,
|
||||
"# Resources": e.count,
|
||||
"Avg Proficiency": e.avgProficiency,
|
||||
Chapters: e.chapters.join(", "),
|
||||
}));
|
||||
const ws = XLSX.utils.json_to_sheet(rows);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Skills");
|
||||
XLSX.writeFile(wb, `skills-analytics-${Date.now()}.xlsx`);
|
||||
const rows = [
|
||||
["Skill", "Category", "# Resources", "Avg Proficiency", "Chapters"],
|
||||
...data.aggregated.map((entry) => [
|
||||
entry.skill,
|
||||
entry.category,
|
||||
entry.count,
|
||||
entry.avgProficiency,
|
||||
entry.chapters.join(", "),
|
||||
]),
|
||||
];
|
||||
await downloadWorkbook(`skills-analytics-${Date.now()}.xlsx`, "Skills", rows);
|
||||
}
|
||||
|
||||
const allSkillNames = (data?.aggregated ?? []).map((e) => e.skill);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useState } from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { SortableColumnHeader } from "~/components/ui/SortableColumnHeader.js";
|
||||
import { useTableSort } from "~/hooks/useTableSort.js";
|
||||
import { downloadWorkbook } from "~/lib/workbook-export.js";
|
||||
import { ProficiencyBadge } from "./shared.js";
|
||||
|
||||
const SkillDistributionChart = dynamic(
|
||||
@@ -44,18 +45,17 @@ export function OverviewTab({ aggregated, categories, totalResources, totalSkill
|
||||
const gapCount = aggregated.filter((e) => e.count < 3 && e.avgProficiency >= 3).length;
|
||||
|
||||
async function exportXlsx() {
|
||||
const XLSX = await import("xlsx");
|
||||
const rows = sorted.map((e) => ({
|
||||
Skill: e.skill,
|
||||
Category: e.category,
|
||||
"# Resources": e.count,
|
||||
"Avg Proficiency": e.avgProficiency,
|
||||
Chapters: e.chapters.join(", "),
|
||||
}));
|
||||
const ws = XLSX.utils.json_to_sheet(rows);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Skills Overview");
|
||||
XLSX.writeFile(wb, `skills-overview-${Date.now()}.xlsx`);
|
||||
const rows = [
|
||||
["Skill", "Category", "# Resources", "Avg Proficiency", "Chapters"],
|
||||
...sorted.map((entry) => [
|
||||
entry.skill,
|
||||
entry.category,
|
||||
entry.count,
|
||||
entry.avgProficiency,
|
||||
entry.chapters.join(", "),
|
||||
]),
|
||||
];
|
||||
await downloadWorkbook(`skills-overview-${Date.now()}.xlsx`, "Skills Overview", rows);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useState, useId } from "react";
|
||||
import Link from "next/link";
|
||||
import { trpc } from "~/lib/trpc/client.js";
|
||||
import { downloadWorkbook } from "~/lib/workbook-export.js";
|
||||
import { ProficiencyBadge, PROFICIENCY_LABELS, proficiencyClasses } from "./shared.js";
|
||||
|
||||
type SkillRule = { skill: string; minProficiency: number };
|
||||
@@ -32,17 +33,16 @@ export function PeopleFinderTab({ allSkillNames, allChapters }: PeopleFinderTabP
|
||||
|
||||
async function exportXlsx() {
|
||||
if (!results || results.length === 0) return;
|
||||
const XLSX = await import("xlsx");
|
||||
const rows = results.map((p) => ({
|
||||
Name: p.displayName,
|
||||
EID: p.eid ?? "",
|
||||
Chapter: p.chapter ?? "",
|
||||
"Matched Skills": p.matchedSkills.map((s) => `${s.skill} (${s.proficiency})`).join(", "),
|
||||
}));
|
||||
const ws = XLSX.utils.json_to_sheet(rows);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "People Finder");
|
||||
XLSX.writeFile(wb, `people-finder-${Date.now()}.xlsx`);
|
||||
const rows = [
|
||||
["Name", "EID", "Chapter", "Matched Skills"],
|
||||
...results.map((person) => [
|
||||
person.displayName,
|
||||
person.eid ?? "",
|
||||
person.chapter ?? "",
|
||||
person.matchedSkills.map((skill) => `${skill.skill} (${skill.proficiency})`).join(", "),
|
||||
]),
|
||||
];
|
||||
await downloadWorkbook(`people-finder-${Date.now()}.xlsx`, "People Finder", rows);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user