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:
@@ -5,6 +5,7 @@ import { useFocusTrap } from "~/hooks/useFocusTrap.js";
|
||||
import type { Resource, SkillEntry } from "@planarchy/shared";
|
||||
import { GERMAN_FEDERAL_STATES, inferStateFromPostalCode, ResourceType } from "@planarchy/shared";
|
||||
import { trpc } from "~/lib/trpc/client.js";
|
||||
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
|
||||
|
||||
interface RoleAssignment {
|
||||
roleId: string;
|
||||
@@ -372,7 +373,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-eid">
|
||||
Employee ID <span className="text-red-500">*</span>
|
||||
Employee ID <span className="text-red-500">*</span><InfoTooltip content="Unique employee identifier (e.g. EMP-042). Used for imports and cross-referencing." />
|
||||
</label>
|
||||
<input
|
||||
id="rm-eid"
|
||||
@@ -386,7 +387,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
</div>
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-displayName">
|
||||
Display Name <span className="text-red-500">*</span>
|
||||
Display Name <span className="text-red-500">*</span><InfoTooltip content="Full name shown in the timeline, reports, and staffing views." />
|
||||
</label>
|
||||
<input
|
||||
id="rm-displayName"
|
||||
@@ -444,7 +445,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
</div>
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-roleId">
|
||||
Area of Expertise <span className="text-gray-400 dark:text-gray-500 font-normal">(optional)</span>
|
||||
Area of Expertise <span className="text-gray-400 dark:text-gray-500 font-normal">(optional)</span><InfoTooltip content="The resource's primary area role. Used for skill matrix grouping and AI summary generation." />
|
||||
</label>
|
||||
<select
|
||||
id="rm-roleId"
|
||||
@@ -464,7 +465,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
<div className="grid grid-cols-2 gap-4 mt-4">
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-postalCode">
|
||||
Postal Code (PLZ) <span className="text-gray-400 dark:text-gray-500 font-normal">(optional)</span>
|
||||
Postal Code (PLZ) <span className="text-gray-400 dark:text-gray-500 font-normal">(optional)</span><InfoTooltip content="German postal code. Used to auto-derive the federal state for public holiday calculations." />
|
||||
</label>
|
||||
<input
|
||||
id="rm-postalCode"
|
||||
@@ -487,7 +488,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
</div>
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-federalState">
|
||||
Federal State <span className="text-gray-400 dark:text-gray-500 font-normal">(optional)</span>
|
||||
Federal State <span className="text-gray-400 dark:text-gray-500 font-normal">(optional)</span><InfoTooltip content="Determines which public holidays apply (e.g. Bavaria has extra holidays). Auto-derived from postal code." />
|
||||
</label>
|
||||
<select
|
||||
id="rm-federalState"
|
||||
@@ -509,7 +510,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-enterpriseId">
|
||||
Enterprise ID <span className="text-gray-400 dark:text-gray-500 font-normal">(optional)</span>
|
||||
Enterprise ID <span className="text-gray-400 dark:text-gray-500 font-normal">(optional)</span><InfoTooltip content="Corporate directory ID for cross-system integration (e.g. a.kasperovich)." />
|
||||
</label>
|
||||
<input
|
||||
id="rm-enterpriseId"
|
||||
@@ -522,7 +523,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
</div>
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-fte">
|
||||
FTE
|
||||
FTE<InfoTooltip content="Full-Time Equivalent (0.01-1.0). A value of 0.5 means the resource works 50% of standard hours." />
|
||||
</label>
|
||||
<input
|
||||
id="rm-fte"
|
||||
@@ -608,7 +609,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 mt-4">
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-mgmtGroupId">Management Level Group</label>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-mgmtGroupId">Management Level Group<InfoTooltip content="Seniority grouping (e.g. Associate, Manager, Director). Determines the available management levels." /></label>
|
||||
<select
|
||||
id="rm-mgmtGroupId"
|
||||
className={INPUT_CLASS}
|
||||
@@ -625,7 +626,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-mgmtLevelId">Management Level</label>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-mgmtLevelId">Management Level<InfoTooltip content="Specific seniority level within the group. Used in chargeability reports and cost analysis." /></label>
|
||||
<select
|
||||
id="rm-mgmtLevelId"
|
||||
className={INPUT_CLASS}
|
||||
@@ -643,7 +644,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
|
||||
<div className="grid grid-cols-4 gap-4 mt-4">
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-resourceType">Resource Type</label>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-resourceType">Resource Type<InfoTooltip content="Employee, contractor, or freelancer. Affects cost attribution rules." /></label>
|
||||
<select
|
||||
id="rm-resourceType"
|
||||
className={INPUT_CLASS}
|
||||
@@ -696,7 +697,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-lcr">
|
||||
LCR €/h <span className="text-red-500">*</span>
|
||||
LCR €/h <span className="text-red-500">*</span><InfoTooltip content="Loaded Cost Rate in EUR per hour. E.g. 85 = 85.00 EUR/h. Stored internally as integer cents (8500)." />
|
||||
</label>
|
||||
<input
|
||||
id="rm-lcr"
|
||||
@@ -712,7 +713,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
</div>
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-ucr">
|
||||
UCR €/h <span className="text-red-500">*</span>
|
||||
UCR €/h <span className="text-red-500">*</span><InfoTooltip content="Unit Cost Rate in EUR per hour. The rate billed to the project or client." />
|
||||
</label>
|
||||
<input
|
||||
id="rm-ucr"
|
||||
@@ -743,7 +744,7 @@ export function ResourceModal({ mode, resource, onClose }: ResourceModalProps) {
|
||||
</div>
|
||||
<div>
|
||||
<label className={LABEL_CLASS} htmlFor="rm-chargeability">
|
||||
Chargeability Target %
|
||||
Chargeability Target %<InfoTooltip content="Target % of working time on chargeable projects. E.g. 80 means 80% of hours should be billable." />
|
||||
</label>
|
||||
<input
|
||||
id="rm-chargeability"
|
||||
|
||||
Reference in New Issue
Block a user