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:
2026-03-18 11:31:56 +01:00
parent 21af720f90
commit 093e13b88f
86 changed files with 5623 additions and 744 deletions
@@ -9,6 +9,7 @@ import { trpc } from "~/lib/trpc/client.js";
import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js";
import { DateInput } from "~/components/ui/DateInput.js";
import { RecurrenceEditor } from "./RecurrenceEditor.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
const ALLOCATION_STATUSES = Object.values(AllocationStatus);
type EntryKind = "demand" | "assignment";
@@ -308,7 +309,7 @@ export function AllocationModal({ allocation, onClose, onSuccess }: AllocationMo
{!isDemandEntry && (
<div>
<label htmlFor="modal-resource" className={labelClass}>
Resource <span className="text-red-500">*</span>
Resource <span className="text-red-500">*</span><InfoTooltip content="The person to assign. Their LCR determines the daily cost of this allocation." />
</label>
<select
id="modal-resource"
@@ -330,7 +331,7 @@ export function AllocationModal({ allocation, onClose, onSuccess }: AllocationMo
{/* Project */}
<div>
<label htmlFor="modal-project" className={labelClass}>
Project <span className="text-red-500">*</span>
Project <span className="text-red-500">*</span><InfoTooltip content="The project this time block is allocated to. Costs roll up to the project budget." />
</label>
<select
id="modal-project"
@@ -350,7 +351,7 @@ export function AllocationModal({ allocation, onClose, onSuccess }: AllocationMo
{/* Role */}
<div>
<label htmlFor="modal-role" className={labelClass}>Role</label>
<label htmlFor="modal-role" className={labelClass}>Role<InfoTooltip content="Role for this allocation. Pick a predefined role or type a custom one." /></label>
<select
id="modal-role"
value={roleId}
@@ -380,7 +381,7 @@ export function AllocationModal({ allocation, onClose, onSuccess }: AllocationMo
<div className="grid grid-cols-2 gap-4">
<div>
<label htmlFor="modal-start" className={labelClass}>
Start Date <span className="text-red-500">*</span>
Start Date <span className="text-red-500">*</span><InfoTooltip content="First day of this allocation period (inclusive)." />
</label>
<DateInput
id="modal-start"
@@ -392,7 +393,7 @@ export function AllocationModal({ allocation, onClose, onSuccess }: AllocationMo
</div>
<div>
<label htmlFor="modal-end" className={labelClass}>
End Date <span className="text-red-500">*</span>
End Date <span className="text-red-500">*</span><InfoTooltip content="Last day of this allocation period (inclusive)." />
</label>
<DateInput
id="modal-end"
@@ -409,7 +410,7 @@ export function AllocationModal({ allocation, onClose, onSuccess }: AllocationMo
<div className="grid grid-cols-2 gap-4">
<div>
<label htmlFor="modal-hours" className={labelClass}>
Hours / Day
Hours / Day<InfoTooltip content="Working hours per day. Total cost = LCR x hours/day x working days. Vacation days are excluded." />
</label>
<input
id="modal-hours"
@@ -424,7 +425,7 @@ export function AllocationModal({ allocation, onClose, onSuccess }: AllocationMo
</div>
<div>
<label htmlFor="modal-status" className={labelClass}>
Status
Status<InfoTooltip content="PROPOSED = draft/request · CONFIRMED = approved · ACTIVE = in progress · COMPLETED = done · CANCELLED = removed." />
</label>
<select
id="modal-status"
@@ -453,7 +454,7 @@ export function AllocationModal({ allocation, onClose, onSuccess }: AllocationMo
}}
className="rounded border-gray-300 dark:border-gray-600"
/>
<span className="font-medium text-gray-700 dark:text-gray-300">Recurring schedule</span>
<span className="font-medium text-gray-700 dark:text-gray-300">Recurring schedule</span><InfoTooltip content="Enable to repeat this allocation on specific days (e.g. every Monday/Wednesday). Hours per day applies on active days only." />
</label>
{isRecurring && (
<div className="mt-2">