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:
@@ -118,6 +118,10 @@ export function SystemSettingsClient() {
|
||||
const [vacationDefaultDays, setVacationDefaultDays] = useState(28);
|
||||
const [vacationSaved, setVacationSaved] = useState(false);
|
||||
|
||||
// Timeline
|
||||
const [undoMaxSteps, setUndoMaxSteps] = useState(50);
|
||||
const [timelineSaved, setTimelineSaved] = useState(false);
|
||||
|
||||
const { data: settings, isLoading } = trpc.settings.getSystemSettings.useQuery(undefined, {
|
||||
staleTime: 0,
|
||||
});
|
||||
@@ -152,6 +156,8 @@ export function SystemSettingsClient() {
|
||||
setAnonymizationSeed("");
|
||||
// Vacation
|
||||
setVacationDefaultDays(settings.vacationDefaultDays ?? 28);
|
||||
// Timeline
|
||||
setUndoMaxSteps(settings.timelineUndoMaxSteps ?? 50);
|
||||
}
|
||||
}, [settings]);
|
||||
|
||||
@@ -227,6 +233,13 @@ export function SystemSettingsClient() {
|
||||
},
|
||||
});
|
||||
|
||||
const saveTimelineMutation = trpc.settings.updateSystemSettings.useMutation({
|
||||
onSuccess: () => {
|
||||
setTimelineSaved(true);
|
||||
setTimeout(() => setTimelineSaved(false), 3000);
|
||||
},
|
||||
});
|
||||
|
||||
function handleSaveSmtp() {
|
||||
saveSmtpMutation.mutate({
|
||||
smtpHost: smtpHost || undefined,
|
||||
@@ -242,6 +255,10 @@ export function SystemSettingsClient() {
|
||||
saveVacationMutation.mutate({ vacationDefaultDays });
|
||||
}
|
||||
|
||||
function handleSaveTimeline() {
|
||||
saveTimelineMutation.mutate({ timelineUndoMaxSteps: undoMaxSteps });
|
||||
}
|
||||
|
||||
function handleSaveAnonymization() {
|
||||
saveAnonymizationMutation.mutate({
|
||||
anonymizationEnabled,
|
||||
@@ -1226,6 +1243,46 @@ export function SystemSettingsClient() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={PANEL_CLASS}>
|
||||
<div>
|
||||
<h2 className="text-base font-semibold text-gray-900 dark:text-gray-100 flex items-center">
|
||||
Timeline <InfoTooltip content="Settings for the timeline view, including undo history depth." />
|
||||
</h2>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
Configure timeline behavior and undo/redo history.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="max-w-xs">
|
||||
<label className={LABEL_CLASS}>Undo History Depth</label>
|
||||
<input
|
||||
type="number"
|
||||
className={INPUT_CLASS}
|
||||
value={undoMaxSteps}
|
||||
onChange={(e) => setUndoMaxSteps(parseInt(e.target.value, 10) || 50)}
|
||||
min={1}
|
||||
max={200}
|
||||
/>
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500 mt-1">
|
||||
Maximum number of undo steps for timeline operations (single moves and batch shifts). Default: 50.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSaveTimeline}
|
||||
disabled={saveTimelineMutation.isPending}
|
||||
className={PRIMARY_BUTTON_CLASS}
|
||||
>
|
||||
{saveTimelineMutation.isPending ? "Saving…" : "Save Timeline Settings"}
|
||||
</button>
|
||||
{timelineSaved && (
|
||||
<span className="text-sm text-green-600 dark:text-green-400 font-medium">Saved!</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={PANEL_CLASS}>
|
||||
<div>
|
||||
<h2 className="text-base font-semibold text-gray-900 dark:text-gray-100 flex items-center">
|
||||
|
||||
Reference in New Issue
Block a user