feat: project cover art with AI generation, branding rename, RBAC fix, computation graph
- Add DALL-E cover art generation for projects (Azure OpenAI + standard OpenAI)
- CoverArtSection component with generate/upload/remove/focus-point controls
- Client-side image compression (10MB input → WebP/JPEG, max 1920px)
- DALL-E settings in admin panel (deployment, endpoint, API key)
- MCP assistant tools for cover art (generate_project_cover, remove_project_cover)
- Rename "Planarchy" → "plANARCHY" across all UI-facing text (13 files)
- Fix hardcoded canEdit={true} on project detail page — now checks user role
- Computation graph visualization (2D/3D) for calculation rules
- OG image and OpenGraph metadata
Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import React, { useState, useMemo, useCallback } from "react";
|
||||
import { trpc } from "~/lib/trpc/client.js";
|
||||
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
|
||||
|
||||
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -333,13 +334,13 @@ export function ChargeabilityReportClient() {
|
||||
<div className="space-y-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
<div>Mgmt: {r.mgmtGroup ?? "—"} / {r.mgmtLevel ?? "—"}</div>
|
||||
<div className="mt-2 grid grid-cols-7 gap-1 text-[10px] uppercase tracking-[0.16em] text-gray-400 dark:text-gray-500">
|
||||
<span className="font-medium">Chg</span>
|
||||
<span className="font-medium">BD</span>
|
||||
<span className="font-medium">MD&I</span>
|
||||
<span className="font-medium">M&O</span>
|
||||
<span className="font-medium">PD&R</span>
|
||||
<span className="font-medium">Abs</span>
|
||||
<span className="font-medium">Free</span>
|
||||
<span className="font-medium inline-flex items-center gap-0.5">Chg<InfoTooltip content="Chargeability: % of available hours on chargeable work." /></span>
|
||||
<span className="font-medium inline-flex items-center gap-0.5">BD<InfoTooltip content="Business Development hours as % of available time." /></span>
|
||||
<span className="font-medium inline-flex items-center gap-0.5">MD&I<InfoTooltip content="Market Development & Innovation hours %." /></span>
|
||||
<span className="font-medium inline-flex items-center gap-0.5">M&O<InfoTooltip content="Management & Overhead hours %." /></span>
|
||||
<span className="font-medium inline-flex items-center gap-0.5">PD&R<InfoTooltip content="People Development & Recruiting hours %." /></span>
|
||||
<span className="font-medium inline-flex items-center gap-0.5">Abs<InfoTooltip content="Absence (vacation, sick) as % of working time." /></span>
|
||||
<span className="font-medium inline-flex items-center gap-0.5">Free<InfoTooltip content="Unassigned / free capacity as % of available hours." /></span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
@@ -438,22 +439,22 @@ export function ChargeabilityReportClient() {
|
||||
{data ? (
|
||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||||
<div className="app-surface p-4">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500">Resources</div>
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500 inline-flex items-center gap-0.5">Resources<InfoTooltip content="Number of active resources matching the current filters." /></div>
|
||||
<div className="mt-2 text-3xl font-semibold text-gray-900 dark:text-gray-100">{filteredResources.length}</div>
|
||||
<div className="mt-1 text-sm text-gray-500">People in the current filter scope</div>
|
||||
</div>
|
||||
<div className="app-surface p-4">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500">Average Chargeability</div>
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500 inline-flex items-center gap-0.5">Average Chargeability<InfoTooltip content="FTE-weighted average chargeability across all visible resources. Formula: sum(FTE x Chg%) / sum(FTE)." /></div>
|
||||
<div className={`mt-2 text-3xl font-semibold ${chgColor(averageChargeability, averageTarget)}`}>{pct(averageChargeability)}</div>
|
||||
<div className="mt-1 text-sm text-gray-500">Weighted across visible resources</div>
|
||||
</div>
|
||||
<div className="app-surface p-4">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500">Average Target</div>
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500 inline-flex items-center gap-0.5">Average Target<InfoTooltip content="FTE-weighted average chargeability target set per resource. The benchmark for actual performance." /></div>
|
||||
<div className="mt-2 text-3xl font-semibold text-gray-900 dark:text-gray-100">{pct(averageTarget)}</div>
|
||||
<div className="mt-1 text-sm text-gray-500">Planning target for the same population</div>
|
||||
</div>
|
||||
<div className="app-surface p-4">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500">Average Gap</div>
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-gray-500 inline-flex items-center gap-0.5">Average Gap<InfoTooltip content="Chargeability minus target. Green = above target, red = below target." /></div>
|
||||
<div className={`mt-2 text-3xl font-semibold ${averageGap >= 0 ? "text-green-700 dark:text-green-400" : "text-red-700 dark:text-red-400"}`}>
|
||||
{averageGap > 0 ? "+" : ""}{pct(averageGap)}
|
||||
</div>
|
||||
@@ -585,8 +586,8 @@ export function ChargeabilityReportClient() {
|
||||
<th className="sticky left-0 z-10 min-w-[240px] bg-gray-50/95 px-4 py-3 text-left backdrop-blur dark:bg-gray-800/95">
|
||||
Resource
|
||||
</th>
|
||||
<th className="w-20 px-3 py-3 text-center">FTE</th>
|
||||
<th className="w-24 px-3 py-3 text-center">Target</th>
|
||||
<th className="w-20 px-3 py-3 text-center"><span className="inline-flex items-center justify-center gap-0.5">FTE<InfoTooltip content="Full-Time Equivalent. 1.0 = full-time, 0.5 = half-time. Used to weight chargeability averages." /></span></th>
|
||||
<th className="w-24 px-3 py-3 text-center"><span className="inline-flex items-center justify-center gap-0.5">Target<InfoTooltip content="Chargeability target for this resource. Cells are green/yellow/red relative to this target." /></span></th>
|
||||
{data.monthKeys.map((key) => (
|
||||
<th key={key} className="min-w-[96px] px-3 py-3 text-center">
|
||||
{formatMonth(key)}
|
||||
|
||||
Reference in New Issue
Block a user