This commit is contained in:
michael committed 2026-09-15 11:49:47 +00:00
1 parent 235c19e51b
commit 227644cfeb
8 files changed
+1041 -309

No files matched your search

+17 -5
View File
@@ -585,6 +585,12 @@ function matchesSingleProjectFilter(project: ProjectSummary, filterBy: string, f
return budgetMinutes <= 0;
}
if (filterBy === "standardBudgetOnly") {
const budgetedEntries = budgetedProjectTeamspaceEntries(project);
return budgetedEntries.length > 0 && budgetedEntries.every((entry) => entry.is_default);
}
if (filterBy === "critical90") {
return budgetMinutes > 0 && percent >= 0.9;
}
@@ -653,6 +659,10 @@ function projectTeamspaceEntries(project: ProjectSummary): ProjectTeamspaceEntry
];
}
function budgetedProjectTeamspaceEntries(project: ProjectSummary) {
return projectTeamspaceEntries(project).filter((entry) => Number(entry.hour_budget_minutes ?? 0) > 0);
}
function openRatingFilterGroup(filter: string) {
if (filter === "fixedBilling" || filter === "manualBilling") {
return "source";
@@ -1649,6 +1659,7 @@ function ProjectBudgetWidget({ widget, editing, projects, stats, onNavigate, onU
[
"budgeted",
"withoutBudget",
"standardBudgetOnly",
"critical90",
"overBudget",
"open",
@@ -1746,6 +1757,7 @@ function ProjectBudgetWidget({ widget, editing, projects, stats, onNavigate, onU
{ value: "critical90", label: "Ab 90%" },
{ value: "overBudget", label: "Ab 100%" },
{ value: "withoutBudget", label: "Ohne Kontingent" },
{ value: "standardBudgetOnly", label: "Nur Std.-Budget" },
{ value: "open", label: "TT Offen" },
{ value: "closed", label: "TT Geschl." },
...zammadStateFilterOptions.filter((option) => option.value !== "all").map((option) => ({ value: `zammadState:${option.value}`, label: `ZA ${option.label}` })),
@@ -1780,14 +1792,14 @@ function ProjectBudgetWidget({ widget, editing, projects, stats, onNavigate, onU
const consumptionMinutes = project.consumption_minutes ?? 0;
const budgetMinutes = project.hour_budget_minutes ?? 0;
const percent = projectConsumptionPercent(project);
const entries = projectTeamspaceEntries(project);
const hasMultipleTeamspaceEntries = entries.length > 1;
const budgetedEntries = budgetedProjectTeamspaceEntries(project);
const showBudgetedTeamspaceEntries = budgetedEntries.length > 1;
return (
<button key={project.id} type="button" className="block w-full min-w-0 rounded-md px-2 py-1.5 text-left hover:bg-muted" onClick={() => onNavigate(`/tickets/${project.ticket_id}?month=${currentMonth()}`)}>
<span className="block truncate text-xs font-medium">{project.title || project.ticket_number}</span>
<span className="block truncate text-[11px] text-muted-foreground">
{project.ticket_number} · {hasMultipleTeamspaceEntries ? `${entries.length} Teamspace · ` : ""}{budgetMinutes > 0 ? `${decimalHours(consumptionMinutes)} / ${decimalHours(budgetMinutes)} · ${percent ?? 0}%` : "ohne Kontingent"}
{project.ticket_number} · {showBudgetedTeamspaceEntries ? `${budgetedEntries.length} Budgets · ` : ""}{budgetMinutes > 0 ? `${decimalHours(consumptionMinutes)} / ${decimalHours(budgetMinutes)} · ${percent ?? 0}%` : "ohne Kontingent"}
</span>
<span className="mt-1 flex flex-wrap gap-1">
<ZammadStateBadge stateId={project.zammad_state_id} />
@@ -1798,9 +1810,9 @@ function ProjectBudgetWidget({ widget, editing, projects, stats, onNavigate, onU
<span className={cn("block h-full rounded-full", consumptionBarClass(percent))} style={{ width: `${Math.min(100, percent)}%` }} />
</span>
) : null}
{hasMultipleTeamspaceEntries ? (
{showBudgetedTeamspaceEntries ? (
<span className="mt-1 grid gap-1">
{entries.map((entry) => {
{budgetedEntries.map((entry) => {
const entryBudgetMinutes = entry.hour_budget_minutes ?? 0;
const entryConsumptionMinutes = entry.consumption_minutes ?? 0;
const entryPercent = entryBudgetMinutes > 0 ? Math.round((entryConsumptionMinutes / entryBudgetMinutes) * 100) : null;