feat(allocations): add Excel export button to allocations toolbar
Adds an Export button that downloads visible/filtered allocation rows as an xlsx file via the existing downloadWorkbookSheets utility. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,7 @@ import { ALLOCATION_STATUS_BADGE as STATUS_BADGE } from "~/lib/status-styles.js"
|
||||
import { SuccessToast } from "~/components/ui/SuccessToast.js";
|
||||
import { EmptyState } from "~/components/ui/EmptyState.js";
|
||||
import { BatchDateShiftModal } from "./BatchDateShiftModal.js";
|
||||
import { downloadWorkbookSheets } from "~/lib/workbook-export.js";
|
||||
import {
|
||||
collapseAllAllocationGroups,
|
||||
createInitialCollapsedAllocationGroups,
|
||||
@@ -191,6 +192,22 @@ export function AllocationsClient() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [filterProjectId, filterResourceId, filterStatus, hidePastProjects, hideCompletedProjects, hideDraftProjects]);
|
||||
|
||||
function handleExportExcel() {
|
||||
const rows: (string | number | null)[][] = [
|
||||
["Resource", "Project", "Role", "Start Date", "End Date", "Hours/Day", "Status"],
|
||||
...sorted.map((a) => [
|
||||
(a.resource as { displayName?: string } | null | undefined)?.displayName ?? "Unassigned",
|
||||
(a.project as { shortCode?: string; name?: string } | null | undefined) ? `${(a.project as { shortCode: string }).shortCode} — ${(a.project as { name: string }).name}` : "",
|
||||
a.role ?? "",
|
||||
typeof a.startDate === "string" ? a.startDate : (a.startDate as Date).toISOString().slice(0, 10),
|
||||
typeof a.endDate === "string" ? a.endDate : (a.endDate as Date).toISOString().slice(0, 10),
|
||||
a.hoursPerDay,
|
||||
a.status,
|
||||
]),
|
||||
];
|
||||
void downloadWorkbookSheets("allocations.xlsx", [{ name: "Allocations", rows }]);
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
setEditingAllocation(null);
|
||||
setModalOpen(true);
|
||||
@@ -665,6 +682,20 @@ export function AllocationsClient() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{sorted.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleExportExcel}
|
||||
title="Export visible rows to Excel"
|
||||
className="inline-flex items-center gap-1.5 rounded-lg border border-gray-300 dark:border-gray-600 px-2.5 py-2 text-sm font-medium text-gray-600 dark:text-gray-300 transition hover:border-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800"
|
||||
>
|
||||
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
||||
</svg>
|
||||
Export
|
||||
</button>
|
||||
)}
|
||||
|
||||
{viewMode === "grouped" && groups.length > 1 && (
|
||||
<div className="flex items-center gap-1">
|
||||
<button type="button" onClick={expandAll} className="text-xs text-brand-600 hover:text-brand-800 dark:text-brand-400 dark:hover:text-brand-200 whitespace-nowrap">
|
||||
|
||||
Reference in New Issue
Block a user