feat: timeline multi-select, demand popover, resource hover card, merged tooltips, dark mode fixes
Major timeline enhancements: - Right-click drag multi-selection with floating action bar (batch delete/assign) - DemandPopover for demand strip details (replaces broken "Loading" modal) - ResourceHoverCard on name hover showing skills, rates, role, chapter - Merged heatmap+vacation tooltips into unified TimelineTooltip component - Fixed overbooking blink animation (date normalization, z-index ordering) - Fixed dark mode sticky column bleed-through in project view - System roles admin page, notification task management, performance review docs Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -12,11 +12,11 @@ import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
|
||||
import { formatDateLong, formatMoney } from "~/lib/format.js";
|
||||
|
||||
const VERSION_STYLES: Record<EstimateVersionStatus, string> = {
|
||||
WORKING: "bg-sky-100 text-sky-700",
|
||||
BASELINE: "bg-violet-100 text-violet-700",
|
||||
SUBMITTED: "bg-amber-100 text-amber-700",
|
||||
APPROVED: "bg-emerald-100 text-emerald-700",
|
||||
SUPERSEDED: "bg-zinc-200 text-zinc-700",
|
||||
WORKING: "bg-sky-100 text-sky-700 dark:bg-sky-900/30 dark:text-sky-300",
|
||||
BASELINE: "bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300",
|
||||
SUBMITTED: "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300",
|
||||
APPROVED: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300",
|
||||
SUPERSEDED: "bg-zinc-200 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300",
|
||||
};
|
||||
|
||||
function formatMetricValue(metric: EstimateMetricView) {
|
||||
@@ -31,7 +31,7 @@ function formatMetricValue(metric: EstimateMetricView) {
|
||||
|
||||
function EmptyState({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="rounded-3xl border border-dashed border-gray-200 bg-white px-5 py-10 text-center text-sm text-gray-400">
|
||||
<div className="rounded-3xl border border-dashed border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 px-5 py-10 text-center text-sm text-gray-400">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -75,24 +75,24 @@ export function VersionsTab({
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2 text-sm text-gray-500">
|
||||
<div className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
|
||||
<span>Versions are immutable snapshots of the estimate for comparison and audit.</span>
|
||||
<InfoTooltip content="Each version captures a full copy of scope, assumptions, demand lines, and metrics. WORKING versions can be edited; SUBMITTED and APPROVED versions are locked." />
|
||||
</div>
|
||||
{versions.map((version) => (
|
||||
<div key={version.id} className="rounded-3xl border border-gray-200 bg-white p-5 shadow-sm">
|
||||
<div key={version.id} className="rounded-3xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-5 shadow-sm">
|
||||
<div className="flex flex-wrap items-start justify-between gap-4">
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-lg font-semibold text-gray-900">v{version.versionNumber}</span>
|
||||
<span className="text-lg font-semibold text-gray-900 dark:text-gray-100">v{version.versionNumber}</span>
|
||||
<span className={clsx("rounded-full px-2.5 py-1 text-xs font-medium", VERSION_STYLES[version.status])}>
|
||||
{version.status}
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-2 text-sm text-gray-600">{version.label ?? "Unlabeled version"}</p>
|
||||
{version.notes && <p className="mt-2 text-sm text-gray-500">{version.notes}</p>}
|
||||
<p className="mt-2 text-sm text-gray-600 dark:text-gray-400">{version.label ?? "Unlabeled version"}</p>
|
||||
{version.notes && <p className="mt-2 text-sm text-gray-500 dark:text-gray-400">{version.notes}</p>}
|
||||
</div>
|
||||
<div className="text-right text-sm text-gray-500">
|
||||
<div className="text-right text-sm text-gray-500 dark:text-gray-400">
|
||||
<p>Updated {formatDateLong(version.updatedAt)}</p>
|
||||
{version.lockedAt && (
|
||||
<p className="mt-1">Locked {formatDateLong(version.lockedAt)}</p>
|
||||
@@ -130,7 +130,7 @@ export function VersionsTab({
|
||||
type="button"
|
||||
onClick={() => onCreateRevision(version.id)}
|
||||
disabled={isSubmitting || isApproving || isCreatingRevision || isCreatingPlanningHandoff}
|
||||
className="rounded-2xl border border-brand-200 bg-white px-3 py-2 text-sm font-semibold text-brand-700 transition hover:border-brand-300 hover:bg-brand-50 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
className="rounded-2xl border border-brand-200 bg-white dark:bg-gray-800 px-3 py-2 text-sm font-semibold text-brand-700 transition hover:border-brand-300 hover:bg-brand-50 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
{isCreatingRevision ? "Creating revision..." : "Create working revision"}
|
||||
</button>
|
||||
@@ -160,7 +160,7 @@ export function VersionsTab({
|
||||
)}
|
||||
|
||||
{version.status === EstimateVersionStatus.APPROVED && !hasLinkedProject && (
|
||||
<p className="mt-3 text-sm text-amber-700">
|
||||
<p className="mt-3 text-sm text-amber-700 dark:text-amber-300">
|
||||
Link this estimate to a project before handing approved demand into planning.
|
||||
</p>
|
||||
)}
|
||||
@@ -168,9 +168,9 @@ export function VersionsTab({
|
||||
{version.metrics.length > 0 && (
|
||||
<div className="mt-4 grid gap-3 md:grid-cols-2 xl:grid-cols-5">
|
||||
{version.metrics.map((metric) => (
|
||||
<div key={metric.id} className="rounded-2xl bg-gray-50 px-4 py-3">
|
||||
<div key={metric.id} className="rounded-2xl bg-gray-50 dark:bg-gray-900 px-4 py-3">
|
||||
<p className="text-xs uppercase tracking-wide text-gray-400">{metric.label}</p>
|
||||
<p className="mt-1 text-sm font-semibold text-gray-900">{formatMetricValue(metric)}</p>
|
||||
<p className="mt-1 text-sm font-semibold text-gray-900 dark:text-gray-100">{formatMetricValue(metric)}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user