Update
This commit is contained in:
1 parent
b7f7d7e793
commit
c01d747352
14 files changed
+987
-294
No files matched your search
@@ -47,6 +47,16 @@ import {
|
||||
} from "../api";
|
||||
import { currentDay, currentMonth, formatDate, formatMinutes } from "../format";
|
||||
import { ticketPattern } from "../timers";
|
||||
import {
|
||||
matchesZammadPriorityFilter,
|
||||
matchesZammadStateFilter,
|
||||
ZammadPriorityBadge,
|
||||
zammadPriorityFilterOptions,
|
||||
zammadPrioritySortRank,
|
||||
ZammadStateBadge,
|
||||
zammadStateFilterOptions,
|
||||
zammadStateSortRank
|
||||
} from "../zammad-meta";
|
||||
import type {
|
||||
DashboardFavorite,
|
||||
DashboardPreference,
|
||||
@@ -161,7 +171,27 @@ function widgetAllowedFilters(type: DashboardWidgetType) {
|
||||
}
|
||||
|
||||
if (type === "projectBudgets") {
|
||||
return ["budgeted", "withoutBudget", "critical90", "overBudget", "open", "closed", "openTodos", "overdueTodos", "fixedBilling", "manualBilling"];
|
||||
return [
|
||||
"budgeted",
|
||||
"withoutBudget",
|
||||
"critical90",
|
||||
"overBudget",
|
||||
"open",
|
||||
"closed",
|
||||
"zammadState:2",
|
||||
"zammadState:3",
|
||||
"zammadState:4",
|
||||
"zammadState:7",
|
||||
"zammadState:none",
|
||||
"zammadPriority:1",
|
||||
"zammadPriority:2",
|
||||
"zammadPriority:3",
|
||||
"zammadPriority:none",
|
||||
"openTodos",
|
||||
"overdueTodos",
|
||||
"fixedBilling",
|
||||
"manualBilling"
|
||||
];
|
||||
}
|
||||
|
||||
if (type === "openRatings") {
|
||||
@@ -169,7 +199,23 @@ function widgetAllowedFilters(type: DashboardWidgetType) {
|
||||
}
|
||||
|
||||
if (type === "favorites") {
|
||||
return ["projects", "openTodos", "overdueTodos", "missingMeta", "fixedBilling", "manualBilling"];
|
||||
return [
|
||||
"projects",
|
||||
"openTodos",
|
||||
"overdueTodos",
|
||||
"zammadState:2",
|
||||
"zammadState:3",
|
||||
"zammadState:4",
|
||||
"zammadState:7",
|
||||
"zammadState:none",
|
||||
"zammadPriority:1",
|
||||
"zammadPriority:2",
|
||||
"zammadPriority:3",
|
||||
"zammadPriority:none",
|
||||
"missingMeta",
|
||||
"fixedBilling",
|
||||
"manualBilling"
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
@@ -498,6 +544,14 @@ function projectFilterGroup(filter: string) {
|
||||
return "status";
|
||||
}
|
||||
|
||||
if (filter.startsWith("zammadState:")) {
|
||||
return "zammadState";
|
||||
}
|
||||
|
||||
if (filter.startsWith("zammadPriority:")) {
|
||||
return "zammadPriority";
|
||||
}
|
||||
|
||||
if (filter === "openTodos" || filter === "overdueTodos") {
|
||||
return "todos";
|
||||
}
|
||||
@@ -547,6 +601,14 @@ function matchesSingleProjectFilter(project: ProjectSummary, filterBy: string, f
|
||||
return Boolean(project.closed_at);
|
||||
}
|
||||
|
||||
if (filterBy.startsWith("zammadState:")) {
|
||||
return matchesZammadStateFilter(project.zammad_state_id, filterBy.slice("zammadState:".length) as Parameters<typeof matchesZammadStateFilter>[1]);
|
||||
}
|
||||
|
||||
if (filterBy.startsWith("zammadPriority:")) {
|
||||
return matchesZammadPriorityFilter(project.zammad_priority_id, filterBy.slice("zammadPriority:".length) as Parameters<typeof matchesZammadPriorityFilter>[1]);
|
||||
}
|
||||
|
||||
if (filterBy === "openTodos") {
|
||||
return Number(project.open_todos ?? 0) > 0;
|
||||
}
|
||||
@@ -608,11 +670,19 @@ function favoriteFilterGroup(filter: string) {
|
||||
return "todos";
|
||||
}
|
||||
|
||||
if (filter.startsWith("zammadState:")) {
|
||||
return "zammadState";
|
||||
}
|
||||
|
||||
if (filter.startsWith("zammadPriority:")) {
|
||||
return "zammadPriority";
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
function sortedFavorites(favorites: DashboardFavorite[], metas: Record<string, TicketMeta | null>, config: Record<string, unknown>) {
|
||||
const sortBy = config.sortBy === "ticket" || config.sortBy === "title" || config.sortBy === "recent" ? config.sortBy : "custom";
|
||||
const sortBy = config.sortBy === "ticket" || config.sortBy === "title" || config.sortBy === "recent" || config.sortBy === "zammadStatus" || config.sortBy === "zammadPriority" ? config.sortBy : "custom";
|
||||
const direction: DashboardSortDirection = config.sortDirection === "desc" ? "desc" : "asc";
|
||||
const factor = directionFactor(direction);
|
||||
|
||||
@@ -629,6 +699,14 @@ function sortedFavorites(favorites: DashboardFavorite[], metas: Record<string, T
|
||||
return compareOptionalTimestamp(left.addedAt, right.addedAt, direction) || compareText(left.ticketNumber, right.ticketNumber);
|
||||
}
|
||||
|
||||
if (sortBy === "zammadStatus") {
|
||||
return (compareNumber(zammadStateSortRank(metas[left.ticketNumber]?.zammad_state_id), zammadStateSortRank(metas[right.ticketNumber]?.zammad_state_id)) * factor) || compareText(left.ticketNumber, right.ticketNumber);
|
||||
}
|
||||
|
||||
if (sortBy === "zammadPriority") {
|
||||
return (compareNumber(zammadPrioritySortRank(metas[left.ticketNumber]?.zammad_priority_id), zammadPrioritySortRank(metas[right.ticketNumber]?.zammad_priority_id)) * factor) || compareText(left.ticketNumber, right.ticketNumber);
|
||||
}
|
||||
|
||||
return (compareNumber(left.sortOrder, right.sortOrder) * factor) || compareText(left.ticketNumber, right.ticketNumber);
|
||||
});
|
||||
}
|
||||
@@ -1568,12 +1646,34 @@ function WidgetSettings({
|
||||
function ProjectBudgetWidget({ widget, editing, projects, stats, onNavigate, onUpdateConfig }: WidgetContentProps) {
|
||||
const filterValues = readFilterValues(
|
||||
widget.config,
|
||||
["budgeted", "withoutBudget", "critical90", "overBudget", "open", "closed", "openTodos", "overdueTodos", "fixedBilling", "manualBilling"],
|
||||
[
|
||||
"budgeted",
|
||||
"withoutBudget",
|
||||
"critical90",
|
||||
"overBudget",
|
||||
"open",
|
||||
"closed",
|
||||
"zammadState:2",
|
||||
"zammadState:3",
|
||||
"zammadState:4",
|
||||
"zammadState:7",
|
||||
"zammadState:none",
|
||||
"zammadPriority:1",
|
||||
"zammadPriority:2",
|
||||
"zammadPriority:3",
|
||||
"zammadPriority:none",
|
||||
"openTodos",
|
||||
"overdueTodos",
|
||||
"fixedBilling",
|
||||
"manualBilling"
|
||||
],
|
||||
["budgeted"]
|
||||
);
|
||||
const sortBy =
|
||||
widget.config?.sortBy === "consumption" ||
|
||||
widget.config?.sortBy === "consumptionPercent" ||
|
||||
widget.config?.sortBy === "zammadStatus" ||
|
||||
widget.config?.sortBy === "zammadPriority" ||
|
||||
widget.config?.sortBy === "title" ||
|
||||
widget.config?.sortBy === "ticket" ||
|
||||
widget.config?.sortBy === "organization" ||
|
||||
@@ -1598,6 +1698,14 @@ function ProjectBudgetWidget({ widget, editing, projects, stats, onNavigate, onU
|
||||
return (compareText(left.organization_name || left.customer_name, right.organization_name || right.customer_name) * factor) || compareText(left.ticket_number, right.ticket_number);
|
||||
}
|
||||
|
||||
if (sortBy === "zammadStatus") {
|
||||
return (compareNumber(zammadStateSortRank(left.zammad_state_id), zammadStateSortRank(right.zammad_state_id)) * factor) || compareText(left.ticket_number, right.ticket_number);
|
||||
}
|
||||
|
||||
if (sortBy === "zammadPriority") {
|
||||
return (compareNumber(zammadPrioritySortRank(left.zammad_priority_id), zammadPrioritySortRank(right.zammad_priority_id)) * factor) || compareText(left.ticket_number, right.ticket_number);
|
||||
}
|
||||
|
||||
if (sortBy === "consumption") {
|
||||
return (compareNumber(left.consumption_minutes ?? 0, right.consumption_minutes ?? 0) * factor) || compareText(left.ticket_number, right.ticket_number);
|
||||
}
|
||||
@@ -1640,6 +1748,8 @@ function ProjectBudgetWidget({ widget, editing, projects, stats, onNavigate, onU
|
||||
{ value: "withoutBudget", label: "Ohne Kontingent" },
|
||||
{ value: "open", label: "Offene Projekte" },
|
||||
{ value: "closed", label: "Geschlossene Projekte" },
|
||||
...zammadStateFilterOptions.filter((option) => option.value !== "all").map((option) => ({ value: `zammadState:${option.value}`, label: `Status: ${option.label}` })),
|
||||
...zammadPriorityFilterOptions.filter((option) => option.value !== "all").map((option) => ({ value: `zammadPriority:${option.value}`, label: `Prio: ${option.label}` })),
|
||||
{ value: "openTodos", label: "Mit offenen ToDos" },
|
||||
{ value: "overdueTodos", label: "Mit überfälligen ToDos" },
|
||||
{ value: "fixedBilling", label: "Fixe Abrechnungen" },
|
||||
@@ -1655,7 +1765,9 @@ function ProjectBudgetWidget({ widget, editing, projects, stats, onNavigate, onU
|
||||
{ value: "todos", label: "ToDos" },
|
||||
{ value: "title", label: "Titel" },
|
||||
{ value: "ticket", label: "Ticket" },
|
||||
{ value: "organization", label: "Organisation" }
|
||||
{ value: "organization", label: "Organisation" },
|
||||
{ value: "zammadStatus", label: "Zammad-Status" },
|
||||
{ value: "zammadPriority", label: "Zammad-Prio" }
|
||||
]}
|
||||
onChange={onUpdateConfig}
|
||||
/>
|
||||
@@ -1677,6 +1789,10 @@ function ProjectBudgetWidget({ widget, editing, projects, stats, onNavigate, onU
|
||||
<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"}
|
||||
</span>
|
||||
<span className="mt-1 flex flex-wrap gap-1">
|
||||
<ZammadStateBadge stateId={project.zammad_state_id} />
|
||||
<ZammadPriorityBadge priorityId={project.zammad_priority_id} />
|
||||
</span>
|
||||
{percent !== null ? (
|
||||
<span className="mt-1 block h-1.5 overflow-hidden rounded-full bg-muted" title={`${percent}% Verbrauch`} aria-label={`${percent}% Verbrauch`}>
|
||||
<span className={cn("block h-full rounded-full", consumptionBarClass(percent))} style={{ width: `${Math.min(100, percent)}%` }} />
|
||||
@@ -2196,6 +2312,14 @@ function FavoritesWidget({
|
||||
return todos.some((todo) => todo.ticket_number === favorite.ticketNumber && todo.status === "open" && todo.ends_on && todo.ends_on < today);
|
||||
}
|
||||
|
||||
if (filter.startsWith("zammadState:")) {
|
||||
return matchesZammadStateFilter(meta?.zammad_state_id, filter.slice("zammadState:".length) as Parameters<typeof matchesZammadStateFilter>[1]);
|
||||
}
|
||||
|
||||
if (filter.startsWith("zammadPriority:")) {
|
||||
return matchesZammadPriorityFilter(meta?.zammad_priority_id, filter.slice("zammadPriority:".length) as Parameters<typeof matchesZammadPriorityFilter>[1]);
|
||||
}
|
||||
|
||||
if (filter === "missingMeta") {
|
||||
return favoriteMetas[favorite.ticketNumber] === null;
|
||||
}
|
||||
@@ -2233,6 +2357,8 @@ function FavoritesWidget({
|
||||
{ value: "projects", label: "Nur Projekte" },
|
||||
{ value: "openTodos", label: "Mit offenen ToDos" },
|
||||
{ value: "overdueTodos", label: "Mit überfälligen ToDos" },
|
||||
...zammadStateFilterOptions.filter((option) => option.value !== "all").map((option) => ({ value: `zammadState:${option.value}`, label: `Status: ${option.label}` })),
|
||||
...zammadPriorityFilterOptions.filter((option) => option.value !== "all").map((option) => ({ value: `zammadPriority:${option.value}`, label: `Prio: ${option.label}` })),
|
||||
{ value: "missingMeta", label: "Nicht gefunden" },
|
||||
{ value: "fixedBilling", label: "Fixe Abrechnungen" },
|
||||
{ value: "manualBilling", label: "Ohne fixe Abrechnung" }
|
||||
@@ -2243,7 +2369,9 @@ function FavoritesWidget({
|
||||
{ value: "custom", label: "Frei" },
|
||||
{ value: "ticket", label: "Ticket" },
|
||||
{ value: "title", label: "Titel" },
|
||||
{ value: "recent", label: "Neu" }
|
||||
{ value: "recent", label: "Neu" },
|
||||
{ value: "zammadStatus", label: "Zammad-Status" },
|
||||
{ value: "zammadPriority", label: "Zammad-Prio" }
|
||||
]}
|
||||
onChange={onUpdateConfig}
|
||||
/>
|
||||
@@ -2261,6 +2389,10 @@ function FavoritesWidget({
|
||||
<button type="button" className="min-w-0 flex-1 text-left" onClick={() => meta?.id && onNavigate(`/tickets/${meta.id}?month=${currentMonth()}`)}>
|
||||
<span className="block truncate text-xs font-medium">{favorite.ticketNumber}</span>
|
||||
<span className="block truncate text-[11px] text-muted-foreground">{meta?.title || meta?.organization_name || "Favorit"}</span>
|
||||
<span className="mt-1 flex flex-wrap gap-1">
|
||||
<ZammadStateBadge stateId={meta?.zammad_state_id} />
|
||||
<ZammadPriorityBadge priorityId={meta?.zammad_priority_id} />
|
||||
</span>
|
||||
</button>
|
||||
{editing && sortBy === "custom" ? (
|
||||
<>
|
||||
|
||||
Reference in new issue
Block a user