@burdenoff/microfe-planmagnet 2026.928.4 → 2026.928.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +130 -97
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +256 -156
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/automation/AutomationExecutionsPanel.d.ts +5 -0
- package/dist/planmagnet/automation/AutomationExecutionsPanel.d.ts.map +1 -0
- package/dist/planmagnet/automation/AutomationExecutionsPanel.js +107 -0
- package/dist/planmagnet/automation/AutomationExecutionsPanel.js.map +1 -0
- package/dist/planmagnet/automation/AutomationRuleFields.d.ts +29 -0
- package/dist/planmagnet/automation/AutomationRuleFields.d.ts.map +1 -0
- package/dist/planmagnet/automation/AutomationRuleFields.js +308 -0
- package/dist/planmagnet/automation/AutomationRuleFields.js.map +1 -0
- package/dist/planmagnet/automation/automationRuleTypes.d.ts +60 -0
- package/dist/planmagnet/automation/automationRuleTypes.d.ts.map +1 -0
- package/dist/planmagnet/automation/automationRuleTypes.js +113 -0
- package/dist/planmagnet/automation/automationRuleTypes.js.map +1 -0
- package/dist/planmagnet/board/BulkActions.d.ts +11 -0
- package/dist/planmagnet/board/BulkActions.d.ts.map +1 -0
- package/dist/planmagnet/board/BulkActions.js +182 -0
- package/dist/planmagnet/board/BulkActions.js.map +1 -0
- package/dist/planmagnet/board/ProjectBoard.d.ts.map +1 -1
- package/dist/planmagnet/board/ProjectBoard.js +289 -254
- package/dist/planmagnet/board/ProjectBoard.js.map +1 -1
- package/dist/planmagnet/budgets/BudgetControls.d.ts +30 -0
- package/dist/planmagnet/budgets/BudgetControls.d.ts.map +1 -0
- package/dist/planmagnet/budgets/BudgetControls.js +470 -0
- package/dist/planmagnet/budgets/BudgetControls.js.map +1 -0
- package/dist/planmagnet/budgets/ExpenseControls.d.ts +27 -0
- package/dist/planmagnet/budgets/ExpenseControls.d.ts.map +1 -0
- package/dist/planmagnet/budgets/ExpenseControls.js +366 -0
- package/dist/planmagnet/budgets/ExpenseControls.js.map +1 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.d.ts +5 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.d.ts.map +1 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.js +112 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.js.map +1 -0
- package/dist/planmagnet/budgets/budgetMath.d.ts +26 -0
- package/dist/planmagnet/budgets/budgetMath.d.ts.map +1 -0
- package/dist/planmagnet/budgets/budgetMath.js +49 -0
- package/dist/planmagnet/budgets/budgetMath.js.map +1 -0
- package/dist/planmagnet/controls/AutomationRuleControls.d.ts +23 -0
- package/dist/planmagnet/controls/AutomationRuleControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/AutomationRuleControls.js +172 -0
- package/dist/planmagnet/controls/AutomationRuleControls.js.map +1 -0
- package/dist/planmagnet/controls/CompetitorControls.js +15 -15
- package/dist/planmagnet/controls/CustomFieldControls.d.ts +42 -0
- package/dist/planmagnet/controls/CustomFieldControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/CustomFieldControls.js +84 -0
- package/dist/planmagnet/controls/CustomFieldControls.js.map +1 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts +8 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts.map +1 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.js +315 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.js.map +1 -0
- package/dist/planmagnet/controls/FeatureControls.js +54 -54
- package/dist/planmagnet/controls/ObjectiveControls.js +15 -15
- package/dist/planmagnet/controls/Pickers.d.ts +7 -0
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
- package/dist/planmagnet/controls/Pickers.js +58 -20
- package/dist/planmagnet/controls/Pickers.js.map +1 -1
- package/dist/planmagnet/controls/PortfolioControls.js +7 -7
- package/dist/planmagnet/controls/ProgramControls.js +19 -19
- package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/ProjectControls.js +54 -47
- package/dist/planmagnet/controls/ProjectControls.js.map +1 -1
- package/dist/planmagnet/controls/ReleaseControls.js +7 -7
- package/dist/planmagnet/controls/RiskControls.d.ts +27 -0
- package/dist/planmagnet/controls/RiskControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/RiskControls.js +346 -0
- package/dist/planmagnet/controls/RiskControls.js.map +1 -0
- package/dist/planmagnet/controls/TemplateControls.d.ts +15 -0
- package/dist/planmagnet/controls/TemplateControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/TemplateControls.js +55 -0
- package/dist/planmagnet/controls/TemplateControls.js.map +1 -0
- package/dist/planmagnet/controls/WorkItemControls.d.ts +6 -2
- package/dist/planmagnet/controls/WorkItemControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/WorkItemControls.js +9 -9
- package/dist/planmagnet/controls/WorkItemControls.js.map +1 -1
- package/dist/planmagnet/create/CreateDialogs.d.ts +20 -0
- package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
- package/dist/planmagnet/create/CreateDialogs.js +455 -116
- package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
- package/dist/planmagnet/dependency/DependencyPanel.d.ts +6 -0
- package/dist/planmagnet/dependency/DependencyPanel.d.ts.map +1 -0
- package/dist/planmagnet/dependency/DependencyPanel.js +310 -0
- package/dist/planmagnet/dependency/DependencyPanel.js.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js +171 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js +232 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts +2 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +93 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js.map +1 -0
- package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js +11 -3
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js +5 -5
- package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js +9 -9
- package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js +6 -6
- package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js +4 -4
- package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js +6 -6
- package/dist/planmagnet/pages/ProgramsProgramsPagePage.js +5 -5
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js +315 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +186 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js +164 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js +348 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +10 -10
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +4 -4
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +20 -10
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +13 -8
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js +76 -56
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +372 -203
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +81 -72
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.js +278 -0
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js +191 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js.map +1 -0
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +168 -122
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +5 -5
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js +4 -4
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +161 -137
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.js +124 -113
- package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js +263 -0
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js +254 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.js +165 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.js +288 -91
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.js +217 -0
- package/dist/planmagnet/pages/TeamTeamDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TeamTeamEditPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TeamTeamEditPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TeamTeamEditPagePage.js +211 -0
- package/dist/planmagnet/pages/TeamTeamEditPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TeamTeamsListPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TeamTeamsListPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TeamTeamsListPagePage.js +118 -0
- package/dist/planmagnet/pages/TeamTeamsListPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js +316 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js.map +1 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js +208 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts +0 -5
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +47 -89
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js.map +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.js +24 -24
- package/dist/planmagnet/sprints/SprintControls.d.ts +15 -3
- package/dist/planmagnet/sprints/SprintControls.d.ts.map +1 -1
- package/dist/planmagnet/sprints/SprintControls.js +293 -190
- package/dist/planmagnet/sprints/SprintControls.js.map +1 -1
- package/dist/planmagnet/team/TeamControls.d.ts +31 -0
- package/dist/planmagnet/team/TeamControls.d.ts.map +1 -0
- package/dist/planmagnet/team/TeamControls.js +407 -0
- package/dist/planmagnet/team/TeamControls.js.map +1 -0
- package/dist/planmagnet/time/TaskTimePanel.d.ts +7 -0
- package/dist/planmagnet/time/TaskTimePanel.d.ts.map +1 -0
- package/dist/planmagnet/time/TaskTimePanel.js +104 -0
- package/dist/planmagnet/time/TaskTimePanel.js.map +1 -0
- package/dist/planmagnet/time/TimeEntryControls.d.ts +37 -0
- package/dist/planmagnet/time/TimeEntryControls.d.ts.map +1 -0
- package/dist/planmagnet/time/TimeEntryControls.js +338 -0
- package/dist/planmagnet/time/TimeEntryControls.js.map +1 -0
- package/dist/planmagnet/time/TimesheetControls.d.ts +18 -0
- package/dist/planmagnet/time/TimesheetControls.d.ts.map +1 -0
- package/dist/planmagnet/time/TimesheetControls.js +244 -0
- package/dist/planmagnet/time/TimesheetControls.js.map +1 -0
- package/dist/planmagnet/time/timeShared.d.ts +29 -0
- package/dist/planmagnet/time/timeShared.d.ts.map +1 -0
- package/dist/planmagnet/time/timeShared.js +34 -0
- package/dist/planmagnet/time/timeShared.js.map +1 -0
- package/dist/planmagnet/utils/rowNavigation.js +5 -2
- package/dist/planmagnet/utils/rowNavigation.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { LEAVES_PAGE_CONTEXT as t, throwOnError as n } from "../utils/mutationResult.js";
|
|
3
|
+
import { ConfirmButton as r, ErrorLine as i } from "../controls/ConfirmButton.js";
|
|
4
|
+
import { ProjectSelect as a } from "../controls/Pickers.js";
|
|
5
|
+
import { enumLabel as o } from "../controls/WorkItemControls.js";
|
|
6
|
+
import { toDateInputValue as s } from "../time/timeShared.js";
|
|
7
|
+
import { useState as c } from "react";
|
|
8
|
+
import { CheckCircle2 as l, Pencil as u, Plus as d, Trash2 as f } from "lucide-react";
|
|
9
|
+
import { gql as p } from "@apollo/client";
|
|
10
|
+
import { useMutation as m } from "@apollo/client/react";
|
|
11
|
+
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
12
|
+
import { Button as _, Input as v, ResponsiveDialog as y, ResponsiveDialogContent as b, ResponsiveDialogDescription as x, ResponsiveDialogFooter as S, ResponsiveDialogHeader as C, ResponsiveDialogTitle as w, ResponsiveDialogTrigger as T } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
//#region src/planmagnet/budgets/BudgetControls.tsx
|
|
14
|
+
var E = [
|
|
15
|
+
"DRAFT",
|
|
16
|
+
"ACTIVE",
|
|
17
|
+
"APPROVED",
|
|
18
|
+
"EXCEEDED",
|
|
19
|
+
"CLOSED"
|
|
20
|
+
], D = E.filter((e) => e !== "APPROVED"), O = [
|
|
21
|
+
"BudgetsList",
|
|
22
|
+
"GetBudget",
|
|
23
|
+
"GetBudgetPerformance",
|
|
24
|
+
"ProjectBudgetsSummary"
|
|
25
|
+
], k = p`
|
|
26
|
+
mutation BudgetControlsCreate($input: PlanmagnetCreateBudgetInput!) {
|
|
27
|
+
planmagnetCreateBudget(input: $input) {
|
|
28
|
+
id
|
|
29
|
+
name
|
|
30
|
+
status
|
|
31
|
+
plannedAmount
|
|
32
|
+
currency
|
|
33
|
+
createdAt
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`, A = p`
|
|
37
|
+
mutation BudgetControlsUpdate($id: ID!, $input: PlanmagnetUpdateBudgetInput!) {
|
|
38
|
+
planmagnetUpdateBudget(id: $id, input: $input) {
|
|
39
|
+
id
|
|
40
|
+
name
|
|
41
|
+
description
|
|
42
|
+
status
|
|
43
|
+
plannedAmount
|
|
44
|
+
currency
|
|
45
|
+
periodStart
|
|
46
|
+
periodEnd
|
|
47
|
+
updatedAt
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`, j = p`
|
|
51
|
+
mutation BudgetControlsApprove($id: ID!) {
|
|
52
|
+
planmagnetApproveBudget(id: $id) {
|
|
53
|
+
id
|
|
54
|
+
status
|
|
55
|
+
approverId
|
|
56
|
+
approvedAt
|
|
57
|
+
updatedAt
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
`, M = p`
|
|
61
|
+
mutation BudgetControlsDelete($id: ID!) {
|
|
62
|
+
planmagnetDeleteBudget(id: $id)
|
|
63
|
+
}
|
|
64
|
+
`, N = "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60", P = (e, t) => e instanceof Error ? e.message : t;
|
|
65
|
+
function F({ presetProjectId: e, onCreated: t, triggerSize: r = "sm" }) {
|
|
66
|
+
let o = {
|
|
67
|
+
projectId: e ?? "",
|
|
68
|
+
name: "",
|
|
69
|
+
description: "",
|
|
70
|
+
plannedAmount: "",
|
|
71
|
+
currency: "USD",
|
|
72
|
+
periodStart: "",
|
|
73
|
+
periodEnd: ""
|
|
74
|
+
}, [s, l] = c(!1), [u, f] = c(o), [p, E] = c(null), [D, { loading: A }] = m(k, {
|
|
75
|
+
refetchQueries: O,
|
|
76
|
+
awaitRefetchQueries: !0
|
|
77
|
+
}), j = u.periodStart && u.periodEnd && u.periodEnd < u.periodStart, M = Number(u.plannedAmount), F = !A && u.name.trim() !== "" && !!u.projectId && Number.isFinite(M) && M >= 0 && u.currency.trim() !== "" && !j, I = async () => {
|
|
78
|
+
E(null);
|
|
79
|
+
try {
|
|
80
|
+
let e = (await n(D({ variables: { input: {
|
|
81
|
+
projectId: u.projectId,
|
|
82
|
+
name: u.name.trim(),
|
|
83
|
+
...u.description.trim() ? { description: u.description.trim() } : {},
|
|
84
|
+
plannedAmount: M,
|
|
85
|
+
currency: u.currency.trim().toUpperCase(),
|
|
86
|
+
...u.periodStart ? { periodStart: u.periodStart } : {},
|
|
87
|
+
...u.periodEnd ? { periodEnd: u.periodEnd } : {}
|
|
88
|
+
} } }))).data?.planmagnetCreateBudget.id;
|
|
89
|
+
l(!1), f(o), e && t?.(e);
|
|
90
|
+
} catch (e) {
|
|
91
|
+
E(P(e, "The budget could not be created."));
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
return /* @__PURE__ */ g(y, {
|
|
95
|
+
open: s,
|
|
96
|
+
onOpenChange: (e) => {
|
|
97
|
+
l(e), e ? f(o) : E(null);
|
|
98
|
+
},
|
|
99
|
+
children: [/* @__PURE__ */ h(T, {
|
|
100
|
+
asChild: !0,
|
|
101
|
+
children: /* @__PURE__ */ g(_, {
|
|
102
|
+
size: r,
|
|
103
|
+
"data-testid": "new-budget-open",
|
|
104
|
+
children: [/* @__PURE__ */ h(d, { className: "mr-1 h-4 w-4" }), "New budget"]
|
|
105
|
+
})
|
|
106
|
+
}), /* @__PURE__ */ g(b, {
|
|
107
|
+
className: "max-w-lg",
|
|
108
|
+
children: [
|
|
109
|
+
/* @__PURE__ */ g(C, { children: [/* @__PURE__ */ h(w, { children: "New budget" }), /* @__PURE__ */ h(x, { children: "The budget starts in Draft." })] }),
|
|
110
|
+
/* @__PURE__ */ g("div", {
|
|
111
|
+
className: "space-y-3",
|
|
112
|
+
children: [
|
|
113
|
+
!e && /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
114
|
+
htmlFor: "new-budget-project",
|
|
115
|
+
className: "text-sm font-medium",
|
|
116
|
+
children: "Project"
|
|
117
|
+
}), /* @__PURE__ */ h("div", {
|
|
118
|
+
className: "mt-1",
|
|
119
|
+
children: /* @__PURE__ */ h(a, {
|
|
120
|
+
id: "new-budget-project",
|
|
121
|
+
value: u.projectId,
|
|
122
|
+
onChange: (e) => f({
|
|
123
|
+
...u,
|
|
124
|
+
projectId: e
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
})] }),
|
|
128
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
129
|
+
htmlFor: "new-budget-name",
|
|
130
|
+
className: "text-sm font-medium",
|
|
131
|
+
children: "Name"
|
|
132
|
+
}), /* @__PURE__ */ h(v, {
|
|
133
|
+
id: "new-budget-name",
|
|
134
|
+
className: "mt-1",
|
|
135
|
+
value: u.name,
|
|
136
|
+
onChange: (e) => f({
|
|
137
|
+
...u,
|
|
138
|
+
name: e.target.value
|
|
139
|
+
})
|
|
140
|
+
})] }),
|
|
141
|
+
/* @__PURE__ */ g("div", {
|
|
142
|
+
className: "grid grid-cols-2 gap-3",
|
|
143
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
144
|
+
htmlFor: "new-budget-amount",
|
|
145
|
+
className: "text-sm font-medium",
|
|
146
|
+
children: "Planned amount"
|
|
147
|
+
}), /* @__PURE__ */ h(v, {
|
|
148
|
+
id: "new-budget-amount",
|
|
149
|
+
className: "mt-1",
|
|
150
|
+
type: "number",
|
|
151
|
+
min: "0",
|
|
152
|
+
step: "0.01",
|
|
153
|
+
inputMode: "decimal",
|
|
154
|
+
value: u.plannedAmount,
|
|
155
|
+
onChange: (e) => f({
|
|
156
|
+
...u,
|
|
157
|
+
plannedAmount: e.target.value
|
|
158
|
+
})
|
|
159
|
+
})] }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
160
|
+
htmlFor: "new-budget-currency",
|
|
161
|
+
className: "text-sm font-medium",
|
|
162
|
+
children: "Currency"
|
|
163
|
+
}), /* @__PURE__ */ h(v, {
|
|
164
|
+
id: "new-budget-currency",
|
|
165
|
+
className: "mt-1",
|
|
166
|
+
placeholder: "USD",
|
|
167
|
+
maxLength: 3,
|
|
168
|
+
value: u.currency,
|
|
169
|
+
onChange: (e) => f({
|
|
170
|
+
...u,
|
|
171
|
+
currency: e.target.value.toUpperCase()
|
|
172
|
+
})
|
|
173
|
+
})] })]
|
|
174
|
+
}),
|
|
175
|
+
/* @__PURE__ */ g("div", {
|
|
176
|
+
className: "grid grid-cols-2 gap-3",
|
|
177
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
178
|
+
htmlFor: "new-budget-start",
|
|
179
|
+
className: "text-sm font-medium",
|
|
180
|
+
children: "Period start (optional)"
|
|
181
|
+
}), /* @__PURE__ */ h(v, {
|
|
182
|
+
id: "new-budget-start",
|
|
183
|
+
className: "mt-1",
|
|
184
|
+
type: "date",
|
|
185
|
+
value: u.periodStart,
|
|
186
|
+
onChange: (e) => f({
|
|
187
|
+
...u,
|
|
188
|
+
periodStart: e.target.value
|
|
189
|
+
})
|
|
190
|
+
})] }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
191
|
+
htmlFor: "new-budget-end",
|
|
192
|
+
className: "text-sm font-medium",
|
|
193
|
+
children: "Period end (optional)"
|
|
194
|
+
}), /* @__PURE__ */ h(v, {
|
|
195
|
+
id: "new-budget-end",
|
|
196
|
+
className: "mt-1",
|
|
197
|
+
type: "date",
|
|
198
|
+
value: u.periodEnd,
|
|
199
|
+
onChange: (e) => f({
|
|
200
|
+
...u,
|
|
201
|
+
periodEnd: e.target.value
|
|
202
|
+
})
|
|
203
|
+
})] })]
|
|
204
|
+
}),
|
|
205
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
206
|
+
htmlFor: "new-budget-description",
|
|
207
|
+
className: "text-sm font-medium",
|
|
208
|
+
children: "Description"
|
|
209
|
+
}), /* @__PURE__ */ h("textarea", {
|
|
210
|
+
id: "new-budget-description",
|
|
211
|
+
className: `${N} min-h-[64px]`,
|
|
212
|
+
value: u.description,
|
|
213
|
+
onChange: (e) => f({
|
|
214
|
+
...u,
|
|
215
|
+
description: e.target.value
|
|
216
|
+
})
|
|
217
|
+
})] }),
|
|
218
|
+
j && /* @__PURE__ */ h(i, { message: "The period end cannot be before the period start." }),
|
|
219
|
+
p && /* @__PURE__ */ h(i, { message: p })
|
|
220
|
+
]
|
|
221
|
+
}),
|
|
222
|
+
/* @__PURE__ */ g(S, { children: [/* @__PURE__ */ h(_, {
|
|
223
|
+
variant: "outline",
|
|
224
|
+
onClick: () => l(!1),
|
|
225
|
+
children: "Cancel"
|
|
226
|
+
}), /* @__PURE__ */ h(_, {
|
|
227
|
+
onClick: () => void I(),
|
|
228
|
+
disabled: !F,
|
|
229
|
+
"data-testid": "new-budget-submit",
|
|
230
|
+
children: A ? "Creating…" : "Create budget"
|
|
231
|
+
})] })
|
|
232
|
+
]
|
|
233
|
+
})]
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function I({ budget: a }) {
|
|
237
|
+
let s = e(), [u, d] = m(A, {
|
|
238
|
+
refetchQueries: O,
|
|
239
|
+
awaitRefetchQueries: !0
|
|
240
|
+
}), [p, v] = m(j, {
|
|
241
|
+
refetchQueries: O,
|
|
242
|
+
awaitRefetchQueries: !0
|
|
243
|
+
}), [y, b] = m(M, {
|
|
244
|
+
refetchQueries: ["BudgetsList", "ProjectBudgetsSummary"],
|
|
245
|
+
context: t
|
|
246
|
+
}), [x, S] = c(null), C = d.loading || v.loading || b.loading, w = D.includes(a.status) ? D : [a.status, ...D], T = async (e) => {
|
|
247
|
+
S(null);
|
|
248
|
+
try {
|
|
249
|
+
await n(u({ variables: {
|
|
250
|
+
id: a.id,
|
|
251
|
+
input: { status: e }
|
|
252
|
+
} }));
|
|
253
|
+
} catch (e) {
|
|
254
|
+
S(P(e, "The status could not be changed."));
|
|
255
|
+
}
|
|
256
|
+
}, E = async () => {
|
|
257
|
+
S(null);
|
|
258
|
+
try {
|
|
259
|
+
await n(p({ variables: { id: a.id } }));
|
|
260
|
+
} catch (e) {
|
|
261
|
+
S(P(e, "The budget could not be approved."));
|
|
262
|
+
}
|
|
263
|
+
}, k = async () => {
|
|
264
|
+
S(null);
|
|
265
|
+
try {
|
|
266
|
+
await n(y({ variables: { id: a.id } })), s("/projects/budgets-page");
|
|
267
|
+
} catch (e) {
|
|
268
|
+
S(P(e, "The budget could not be deleted."));
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
return /* @__PURE__ */ g("div", {
|
|
272
|
+
className: "flex flex-col items-end gap-2",
|
|
273
|
+
children: [/* @__PURE__ */ g("div", {
|
|
274
|
+
className: "flex flex-wrap items-center justify-end gap-2",
|
|
275
|
+
children: [
|
|
276
|
+
/* @__PURE__ */ h("select", {
|
|
277
|
+
"aria-label": "Status",
|
|
278
|
+
"data-testid": "budget-status",
|
|
279
|
+
className: "rounded-md border border-input bg-background px-2 py-1 text-sm disabled:opacity-60",
|
|
280
|
+
value: a.status,
|
|
281
|
+
disabled: C,
|
|
282
|
+
onChange: (e) => {
|
|
283
|
+
e.target.value !== a.status && T(e.target.value);
|
|
284
|
+
},
|
|
285
|
+
children: w.map((e) => /* @__PURE__ */ h("option", {
|
|
286
|
+
value: e,
|
|
287
|
+
children: o(e)
|
|
288
|
+
}, e))
|
|
289
|
+
}),
|
|
290
|
+
a.status !== "APPROVED" && a.status !== "CLOSED" && /* @__PURE__ */ g(_, {
|
|
291
|
+
size: "sm",
|
|
292
|
+
variant: "outline",
|
|
293
|
+
disabled: C,
|
|
294
|
+
onClick: () => void E(),
|
|
295
|
+
children: [/* @__PURE__ */ h(l, { className: "mr-1 h-4 w-4" }), "Approve"]
|
|
296
|
+
}),
|
|
297
|
+
/* @__PURE__ */ h(L, { budget: a }),
|
|
298
|
+
/* @__PURE__ */ h(r, {
|
|
299
|
+
label: "Delete",
|
|
300
|
+
variant: "outline",
|
|
301
|
+
icon: /* @__PURE__ */ h(f, { className: "mr-1 h-4 w-4" }),
|
|
302
|
+
title: `Delete "${a.name}"?`,
|
|
303
|
+
description: "The budget and its logged expenses are removed. This cannot be undone here.",
|
|
304
|
+
confirmLabel: "Delete budget",
|
|
305
|
+
destructive: !0,
|
|
306
|
+
disabled: C,
|
|
307
|
+
onConfirm: () => void k()
|
|
308
|
+
})
|
|
309
|
+
]
|
|
310
|
+
}), x && /* @__PURE__ */ h(i, { message: x })]
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
function L({ budget: e }) {
|
|
314
|
+
let t = {
|
|
315
|
+
name: e.name,
|
|
316
|
+
description: e.description ?? "",
|
|
317
|
+
plannedAmount: String(e.plannedAmount),
|
|
318
|
+
currency: e.currency,
|
|
319
|
+
periodStart: s(e.periodStart),
|
|
320
|
+
periodEnd: s(e.periodEnd)
|
|
321
|
+
}, [r, a] = c(!1), [o, l] = c(t), [d, f] = c(null), [p, E] = m(A, {
|
|
322
|
+
refetchQueries: O,
|
|
323
|
+
awaitRefetchQueries: !0
|
|
324
|
+
}), D = Number(o.plannedAmount), k = o.periodStart && o.periodEnd && o.periodEnd < o.periodStart, j = !E.loading && o.name.trim() !== "" && Number.isFinite(D) && D >= 0 && !k, M = async () => {
|
|
325
|
+
f(null);
|
|
326
|
+
let r = {};
|
|
327
|
+
if (o.name.trim() !== t.name && (r.name = o.name.trim()), o.description.trim() !== t.description.trim() && (r.description = o.description.trim() || null), D !== e.plannedAmount && (r.plannedAmount = D), o.currency.trim().toUpperCase() !== t.currency && (r.currency = o.currency.trim().toUpperCase()), o.periodStart !== t.periodStart && (r.periodStart = o.periodStart || null), o.periodEnd !== t.periodEnd && (r.periodEnd = o.periodEnd || null), Object.keys(r).length === 0) {
|
|
328
|
+
a(!1);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
await n(p({ variables: {
|
|
333
|
+
id: e.id,
|
|
334
|
+
input: r
|
|
335
|
+
} })), a(!1);
|
|
336
|
+
} catch (e) {
|
|
337
|
+
f(P(e, "The budget could not be saved."));
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
return /* @__PURE__ */ g(y, {
|
|
341
|
+
open: r,
|
|
342
|
+
onOpenChange: (e) => {
|
|
343
|
+
a(e), e ? l(t) : f(null);
|
|
344
|
+
},
|
|
345
|
+
children: [/* @__PURE__ */ h(T, {
|
|
346
|
+
asChild: !0,
|
|
347
|
+
children: /* @__PURE__ */ g(_, {
|
|
348
|
+
size: "sm",
|
|
349
|
+
variant: "outline",
|
|
350
|
+
"data-testid": "budget-edit",
|
|
351
|
+
children: [/* @__PURE__ */ h(u, { className: "mr-1 h-4 w-4" }), "Edit"]
|
|
352
|
+
})
|
|
353
|
+
}), /* @__PURE__ */ g(b, {
|
|
354
|
+
className: "max-w-lg",
|
|
355
|
+
children: [
|
|
356
|
+
/* @__PURE__ */ g(C, { children: [/* @__PURE__ */ h(w, { children: "Edit budget" }), /* @__PURE__ */ h(x, { children: "Change the name, amount, currency, period or description." })] }),
|
|
357
|
+
/* @__PURE__ */ g("div", {
|
|
358
|
+
className: "space-y-3",
|
|
359
|
+
children: [
|
|
360
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
361
|
+
htmlFor: "edit-budget-name",
|
|
362
|
+
className: "text-sm font-medium",
|
|
363
|
+
children: "Name"
|
|
364
|
+
}), /* @__PURE__ */ h(v, {
|
|
365
|
+
id: "edit-budget-name",
|
|
366
|
+
className: "mt-1",
|
|
367
|
+
value: o.name,
|
|
368
|
+
onChange: (e) => l({
|
|
369
|
+
...o,
|
|
370
|
+
name: e.target.value
|
|
371
|
+
})
|
|
372
|
+
})] }),
|
|
373
|
+
/* @__PURE__ */ g("div", {
|
|
374
|
+
className: "grid grid-cols-2 gap-3",
|
|
375
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
376
|
+
htmlFor: "edit-budget-amount",
|
|
377
|
+
className: "text-sm font-medium",
|
|
378
|
+
children: "Planned amount"
|
|
379
|
+
}), /* @__PURE__ */ h(v, {
|
|
380
|
+
id: "edit-budget-amount",
|
|
381
|
+
className: "mt-1",
|
|
382
|
+
type: "number",
|
|
383
|
+
min: "0",
|
|
384
|
+
step: "0.01",
|
|
385
|
+
inputMode: "decimal",
|
|
386
|
+
value: o.plannedAmount,
|
|
387
|
+
onChange: (e) => l({
|
|
388
|
+
...o,
|
|
389
|
+
plannedAmount: e.target.value
|
|
390
|
+
})
|
|
391
|
+
})] }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
392
|
+
htmlFor: "edit-budget-currency",
|
|
393
|
+
className: "text-sm font-medium",
|
|
394
|
+
children: "Currency"
|
|
395
|
+
}), /* @__PURE__ */ h(v, {
|
|
396
|
+
id: "edit-budget-currency",
|
|
397
|
+
className: "mt-1",
|
|
398
|
+
maxLength: 3,
|
|
399
|
+
value: o.currency,
|
|
400
|
+
onChange: (e) => l({
|
|
401
|
+
...o,
|
|
402
|
+
currency: e.target.value.toUpperCase()
|
|
403
|
+
})
|
|
404
|
+
})] })]
|
|
405
|
+
}),
|
|
406
|
+
/* @__PURE__ */ g("div", {
|
|
407
|
+
className: "grid grid-cols-2 gap-3",
|
|
408
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
409
|
+
htmlFor: "edit-budget-start",
|
|
410
|
+
className: "text-sm font-medium",
|
|
411
|
+
children: "Period start"
|
|
412
|
+
}), /* @__PURE__ */ h(v, {
|
|
413
|
+
id: "edit-budget-start",
|
|
414
|
+
className: "mt-1",
|
|
415
|
+
type: "date",
|
|
416
|
+
value: o.periodStart,
|
|
417
|
+
onChange: (e) => l({
|
|
418
|
+
...o,
|
|
419
|
+
periodStart: e.target.value
|
|
420
|
+
})
|
|
421
|
+
})] }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
422
|
+
htmlFor: "edit-budget-end",
|
|
423
|
+
className: "text-sm font-medium",
|
|
424
|
+
children: "Period end"
|
|
425
|
+
}), /* @__PURE__ */ h(v, {
|
|
426
|
+
id: "edit-budget-end",
|
|
427
|
+
className: "mt-1",
|
|
428
|
+
type: "date",
|
|
429
|
+
value: o.periodEnd,
|
|
430
|
+
onChange: (e) => l({
|
|
431
|
+
...o,
|
|
432
|
+
periodEnd: e.target.value
|
|
433
|
+
})
|
|
434
|
+
})] })]
|
|
435
|
+
}),
|
|
436
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
437
|
+
htmlFor: "edit-budget-description",
|
|
438
|
+
className: "text-sm font-medium",
|
|
439
|
+
children: "Description"
|
|
440
|
+
}), /* @__PURE__ */ h("textarea", {
|
|
441
|
+
id: "edit-budget-description",
|
|
442
|
+
className: `${N} min-h-[64px]`,
|
|
443
|
+
value: o.description,
|
|
444
|
+
onChange: (e) => l({
|
|
445
|
+
...o,
|
|
446
|
+
description: e.target.value
|
|
447
|
+
})
|
|
448
|
+
})] }),
|
|
449
|
+
k && /* @__PURE__ */ h(i, { message: "The period end cannot be before the period start." }),
|
|
450
|
+
d && /* @__PURE__ */ h(i, { message: d })
|
|
451
|
+
]
|
|
452
|
+
}),
|
|
453
|
+
/* @__PURE__ */ g(S, { children: [/* @__PURE__ */ h(_, {
|
|
454
|
+
variant: "outline",
|
|
455
|
+
onClick: () => a(!1),
|
|
456
|
+
children: "Cancel"
|
|
457
|
+
}), /* @__PURE__ */ h(_, {
|
|
458
|
+
onClick: () => void M(),
|
|
459
|
+
disabled: !j,
|
|
460
|
+
"data-testid": "edit-budget-save",
|
|
461
|
+
children: E.loading ? "Saving…" : "Save"
|
|
462
|
+
})] })
|
|
463
|
+
]
|
|
464
|
+
})]
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
//#endregion
|
|
468
|
+
export { E as BUDGET_STATUSES, I as BudgetHeaderActions, F as CreateBudgetDialog };
|
|
469
|
+
|
|
470
|
+
//# sourceMappingURL=BudgetControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BudgetControls.js","names":[],"sources":["../../../src/planmagnet/budgets/BudgetControls.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n Button,\n Input,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { CheckCircle2, Pencil, Plus, Trash2 } from 'lucide-react';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport { ProjectSelect } from '../controls/Pickers';\nimport { throwOnError, LEAVES_PAGE_CONTEXT } from '../utils/mutationResult';\nimport { ConfirmButton, ErrorLine } from '../controls/ConfirmButton';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { toDateInputValue } from '../time/timeShared';\n\n/**\n * Budget controls (BOFF-8047): create a budget, edit it, approve it, delete it.\n *\n * Approval is its own mutation (`planmagnetApproveBudget`), not a plain status change: it is the only write\n * that records who approved a budget and when (`approverId`/`approvedAt` — the service's `approve()`, unlike\n * `update()`, sets both). The status select below therefore never offers APPROVED as a target; moving to it\n * goes through the Approve button so that audit trail is never silently skipped.\n */\n\nexport const BUDGET_STATUSES = ['DRAFT', 'ACTIVE', 'APPROVED', 'EXCEEDED', 'CLOSED'] as const;\n/** Selectable directly. APPROVED is reached only through the dedicated Approve action (see above). */\nconst SELECTABLE_STATUSES = BUDGET_STATUSES.filter((s) => s !== 'APPROVED');\n\nconst BUDGET_QUERIES = [\n 'BudgetsList',\n 'GetBudget',\n 'GetBudgetPerformance',\n 'ProjectBudgetsSummary',\n];\n\nconst CREATE_BUDGET = gql`\n mutation BudgetControlsCreate($input: PlanmagnetCreateBudgetInput!) {\n planmagnetCreateBudget(input: $input) {\n id\n name\n status\n plannedAmount\n currency\n createdAt\n }\n }\n`;\n\nconst UPDATE_BUDGET = gql`\n mutation BudgetControlsUpdate($id: ID!, $input: PlanmagnetUpdateBudgetInput!) {\n planmagnetUpdateBudget(id: $id, input: $input) {\n id\n name\n description\n status\n plannedAmount\n currency\n periodStart\n periodEnd\n updatedAt\n }\n }\n`;\n\nconst APPROVE_BUDGET = gql`\n mutation BudgetControlsApprove($id: ID!) {\n planmagnetApproveBudget(id: $id) {\n id\n status\n approverId\n approvedAt\n updatedAt\n }\n }\n`;\n\nconst DELETE_BUDGET = gql`\n mutation BudgetControlsDelete($id: ID!) {\n planmagnetDeleteBudget(id: $id)\n }\n`;\n\nconst FIELD =\n 'mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60';\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\n\n/** Create a budget. With `presetProjectId` (the Project Detail entry point) the project picker is skipped. */\nexport function CreateBudgetDialog({\n presetProjectId,\n onCreated,\n triggerSize = 'sm',\n}: {\n presetProjectId?: string;\n onCreated?: (id: string) => void;\n triggerSize?: 'sm' | 'default';\n}) {\n const empty = {\n projectId: presetProjectId ?? '',\n name: '',\n description: '',\n plannedAmount: '',\n currency: 'USD',\n periodStart: '',\n periodEnd: '',\n };\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(empty);\n const [error, setError] = useState<string | null>(null);\n const [create, { loading }] = useMutation<{ planmagnetCreateBudget: { id: string } }>(\n CREATE_BUDGET,\n { refetchQueries: BUDGET_QUERIES, awaitRefetchQueries: true }\n );\n\n const invertedLocally = form.periodStart && form.periodEnd && form.periodEnd < form.periodStart;\n const amount = Number(form.plannedAmount);\n const canSubmit =\n !loading &&\n form.name.trim() !== '' &&\n !!form.projectId &&\n Number.isFinite(amount) &&\n amount >= 0 &&\n form.currency.trim() !== '' &&\n !invertedLocally;\n\n const submit = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n create({\n variables: {\n input: {\n projectId: form.projectId,\n name: form.name.trim(),\n ...(form.description.trim() ? { description: form.description.trim() } : {}),\n plannedAmount: amount,\n currency: form.currency.trim().toUpperCase(),\n ...(form.periodStart ? { periodStart: form.periodStart } : {}),\n ...(form.periodEnd ? { periodEnd: form.periodEnd } : {}),\n },\n },\n })\n );\n const id = result.data?.planmagnetCreateBudget.id;\n setOpen(false);\n setForm(empty);\n if (id) onCreated?.(id);\n } catch (e) {\n setError(messageOf(e, 'The budget could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) setForm(empty);\n else setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size={triggerSize} data-testid=\"new-budget-open\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New budget\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New budget</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>The budget starts in Draft.</ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n {!presetProjectId && (\n <div>\n <label htmlFor=\"new-budget-project\" className=\"text-sm font-medium\">\n Project\n </label>\n <div className=\"mt-1\">\n <ProjectSelect\n id=\"new-budget-project\"\n value={form.projectId}\n onChange={(projectId) => setForm({ ...form, projectId })}\n />\n </div>\n </div>\n )}\n <div>\n <label htmlFor=\"new-budget-name\" className=\"text-sm font-medium\">\n Name\n </label>\n <Input\n id=\"new-budget-name\"\n className=\"mt-1\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n />\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"new-budget-amount\" className=\"text-sm font-medium\">\n Planned amount\n </label>\n <Input\n id=\"new-budget-amount\"\n className=\"mt-1\"\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n inputMode=\"decimal\"\n value={form.plannedAmount}\n onChange={(e) => setForm({ ...form, plannedAmount: e.target.value })}\n />\n </div>\n <div>\n <label htmlFor=\"new-budget-currency\" className=\"text-sm font-medium\">\n Currency\n </label>\n <Input\n id=\"new-budget-currency\"\n className=\"mt-1\"\n placeholder=\"USD\"\n maxLength={3}\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value.toUpperCase() })}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"new-budget-start\" className=\"text-sm font-medium\">\n Period start (optional)\n </label>\n <Input\n id=\"new-budget-start\"\n className=\"mt-1\"\n type=\"date\"\n value={form.periodStart}\n onChange={(e) => setForm({ ...form, periodStart: e.target.value })}\n />\n </div>\n <div>\n <label htmlFor=\"new-budget-end\" className=\"text-sm font-medium\">\n Period end (optional)\n </label>\n <Input\n id=\"new-budget-end\"\n className=\"mt-1\"\n type=\"date\"\n value={form.periodEnd}\n onChange={(e) => setForm({ ...form, periodEnd: e.target.value })}\n />\n </div>\n </div>\n <div>\n <label htmlFor=\"new-budget-description\" className=\"text-sm font-medium\">\n Description\n </label>\n <textarea\n id=\"new-budget-description\"\n className={`${FIELD} min-h-[64px]`}\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n {invertedLocally && (\n <ErrorLine message=\"The period end cannot be before the period start.\" />\n )}\n {error && <ErrorLine message={error} />}\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button\n onClick={() => void submit()}\n disabled={!canSubmit}\n data-testid=\"new-budget-submit\"\n >\n {loading ? 'Creating…' : 'Create budget'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport interface BudgetValues {\n id: string;\n name: string;\n description: string | null;\n status: string;\n plannedAmount: number;\n currency: string;\n periodStart: string | null;\n periodEnd: string | null;\n}\n\n/** Status select, Edit, Approve and Delete for the budget detail header. */\nexport function BudgetHeaderActions({ budget }: { budget: BudgetValues }) {\n const navigate = usePlanMagnetNavigate();\n const [update, updateState] = useMutation(UPDATE_BUDGET, {\n refetchQueries: BUDGET_QUERIES,\n awaitRefetchQueries: true,\n });\n const [approveMutation, approveState] = useMutation(APPROVE_BUDGET, {\n refetchQueries: BUDGET_QUERIES,\n awaitRefetchQueries: true,\n });\n const [remove, removeState] = useMutation(DELETE_BUDGET, {\n refetchQueries: ['BudgetsList', 'ProjectBudgetsSummary'],\n context: LEAVES_PAGE_CONTEXT,\n });\n const [error, setError] = useState<string | null>(null);\n const busy = updateState.loading || approveState.loading || removeState.loading;\n const statusOptions = SELECTABLE_STATUSES.includes(\n budget.status as (typeof SELECTABLE_STATUSES)[number]\n )\n ? SELECTABLE_STATUSES\n : [budget.status, ...SELECTABLE_STATUSES];\n\n const onStatus = async (status: string) => {\n setError(null);\n try {\n await throwOnError(update({ variables: { id: budget.id, input: { status } } }));\n } catch (e) {\n setError(messageOf(e, 'The status could not be changed.'));\n }\n };\n const onApprove = async () => {\n setError(null);\n try {\n await throwOnError(approveMutation({ variables: { id: budget.id } }));\n } catch (e) {\n setError(messageOf(e, 'The budget could not be approved.'));\n }\n };\n const onDelete = async () => {\n setError(null);\n try {\n await throwOnError(remove({ variables: { id: budget.id } }));\n navigate('/projects/budgets-page');\n } catch (e) {\n setError(messageOf(e, 'The budget could not be deleted.'));\n }\n };\n\n return (\n <div className=\"flex flex-col items-end gap-2\">\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n <select\n aria-label=\"Status\"\n data-testid=\"budget-status\"\n className=\"rounded-md border border-input bg-background px-2 py-1 text-sm disabled:opacity-60\"\n value={budget.status}\n disabled={busy}\n onChange={(e) => {\n if (e.target.value !== budget.status) void onStatus(e.target.value);\n }}\n >\n {statusOptions.map((s) => (\n <option key={s} value={s}>\n {enumLabel(s)}\n </option>\n ))}\n </select>\n {budget.status !== 'APPROVED' && budget.status !== 'CLOSED' && (\n <Button size=\"sm\" variant=\"outline\" disabled={busy} onClick={() => void onApprove()}>\n <CheckCircle2 className=\"mr-1 h-4 w-4\" />\n Approve\n </Button>\n )}\n <BudgetEditDialog budget={budget} />\n <ConfirmButton\n label=\"Delete\"\n variant=\"outline\"\n icon={<Trash2 className=\"mr-1 h-4 w-4\" />}\n title={`Delete \"${budget.name}\"?`}\n description=\"The budget and its logged expenses are removed. This cannot be undone here.\"\n confirmLabel=\"Delete budget\"\n destructive\n disabled={busy}\n onConfirm={() => void onDelete()}\n />\n </div>\n {error && <ErrorLine message={error} />}\n </div>\n );\n}\n\n/** Name, description, planned amount, currency and period. Only changed fields are sent. */\nfunction BudgetEditDialog({ budget }: { budget: BudgetValues }) {\n const initial = {\n name: budget.name,\n description: budget.description ?? '',\n plannedAmount: String(budget.plannedAmount),\n currency: budget.currency,\n periodStart: toDateInputValue(budget.periodStart),\n periodEnd: toDateInputValue(budget.periodEnd),\n };\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(initial);\n const [error, setError] = useState<string | null>(null);\n const [update, state] = useMutation(UPDATE_BUDGET, {\n refetchQueries: BUDGET_QUERIES,\n awaitRefetchQueries: true,\n });\n\n const amount = Number(form.plannedAmount);\n const invertedLocally = form.periodStart && form.periodEnd && form.periodEnd < form.periodStart;\n const canSubmit =\n !state.loading &&\n form.name.trim() !== '' &&\n Number.isFinite(amount) &&\n amount >= 0 &&\n !invertedLocally;\n\n const save = async () => {\n setError(null);\n const input: Record<string, unknown> = {};\n if (form.name.trim() !== initial.name) input.name = form.name.trim();\n if (form.description.trim() !== initial.description.trim())\n input.description = form.description.trim() || null;\n if (amount !== budget.plannedAmount) input.plannedAmount = amount;\n if (form.currency.trim().toUpperCase() !== initial.currency)\n input.currency = form.currency.trim().toUpperCase();\n if (form.periodStart !== initial.periodStart) input.periodStart = form.periodStart || null;\n if (form.periodEnd !== initial.periodEnd) input.periodEnd = form.periodEnd || null;\n if (Object.keys(input).length === 0) {\n setOpen(false);\n return;\n }\n try {\n await throwOnError(update({ variables: { id: budget.id, input } }));\n setOpen(false);\n } catch (e) {\n setError(messageOf(e, 'The budget could not be saved.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) setForm(initial);\n else setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\" variant=\"outline\" data-testid=\"budget-edit\">\n <Pencil className=\"mr-1 h-4 w-4\" />\n Edit\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Edit budget</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Change the name, amount, currency, period or description.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <div>\n <label htmlFor=\"edit-budget-name\" className=\"text-sm font-medium\">\n Name\n </label>\n <Input\n id=\"edit-budget-name\"\n className=\"mt-1\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n />\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"edit-budget-amount\" className=\"text-sm font-medium\">\n Planned amount\n </label>\n <Input\n id=\"edit-budget-amount\"\n className=\"mt-1\"\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n inputMode=\"decimal\"\n value={form.plannedAmount}\n onChange={(e) => setForm({ ...form, plannedAmount: e.target.value })}\n />\n </div>\n <div>\n <label htmlFor=\"edit-budget-currency\" className=\"text-sm font-medium\">\n Currency\n </label>\n <Input\n id=\"edit-budget-currency\"\n className=\"mt-1\"\n maxLength={3}\n value={form.currency}\n onChange={(e) => setForm({ ...form, currency: e.target.value.toUpperCase() })}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"edit-budget-start\" className=\"text-sm font-medium\">\n Period start\n </label>\n <Input\n id=\"edit-budget-start\"\n className=\"mt-1\"\n type=\"date\"\n value={form.periodStart}\n onChange={(e) => setForm({ ...form, periodStart: e.target.value })}\n />\n </div>\n <div>\n <label htmlFor=\"edit-budget-end\" className=\"text-sm font-medium\">\n Period end\n </label>\n <Input\n id=\"edit-budget-end\"\n className=\"mt-1\"\n type=\"date\"\n value={form.periodEnd}\n onChange={(e) => setForm({ ...form, periodEnd: e.target.value })}\n />\n </div>\n </div>\n <div>\n <label htmlFor=\"edit-budget-description\" className=\"text-sm font-medium\">\n Description\n </label>\n <textarea\n id=\"edit-budget-description\"\n className={`${FIELD} min-h-[64px]`}\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n {invertedLocally && (\n <ErrorLine message=\"The period end cannot be before the period start.\" />\n )}\n {error && <ErrorLine message={error} />}\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button onClick={() => void save()} disabled={!canSubmit} data-testid=\"edit-budget-save\">\n {state.loading ? 'Saving…' : 'Save'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AA+BA,IAAa,IAAkB;CAAC;CAAS;CAAU;CAAY;CAAY;CAAS,EAE9E,IAAsB,EAAgB,QAAQ,MAAM,MAAM,WAAW,EAErE,IAAiB;CACrB;CACA;CACA;CACA;CACD,EAEK,IAAgB,CAAG;;;;;;;;;;;GAanB,IAAgB,CAAG;;;;;;;;;;;;;;GAgBnB,IAAiB,CAAG;;;;;;;;;;GAYpB,IAAgB,CAAG;;;;GAMnB,IACJ,kGAEI,KAAa,GAAY,MAAsB,aAAa,QAAQ,EAAE,UAAU;AAGtF,SAAgB,EAAmB,EACjC,oBACA,cACA,iBAAc,QAKb;CACD,IAAM,IAAQ;EACZ,WAAW,KAAmB;EAC9B,MAAM;EACN,aAAa;EACb,eAAe;EACf,UAAU;EACV,aAAa;EACb,WAAW;EACZ,EACK,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,CAAC,GAAM,KAAW,EAAS,EAAM,EACjC,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAQ,EAAE,gBAAa,EAC5B,GACA;EAAE,gBAAgB;EAAgB,qBAAqB;EAAM,CAC9D,EAEK,IAAkB,EAAK,eAAe,EAAK,aAAa,EAAK,YAAY,EAAK,aAC9E,IAAS,OAAO,EAAK,cAAc,EACnC,IACJ,CAAC,KACD,EAAK,KAAK,MAAM,KAAK,MACrB,CAAC,CAAC,EAAK,aACP,OAAO,SAAS,EAAO,IACvB,KAAU,KACV,EAAK,SAAS,MAAM,KAAK,MACzB,CAAC,GAEG,IAAS,YAAY;AACzB,IAAS,KAAK;AACd,MAAI;GAgBF,IAAM,KAfS,MAAM,EACnB,EAAO,EACL,WAAW,EACT,OAAO;IACL,WAAW,EAAK;IAChB,MAAM,EAAK,KAAK,MAAM;IACtB,GAAI,EAAK,YAAY,MAAM,GAAG,EAAE,aAAa,EAAK,YAAY,MAAM,EAAE,GAAG,EAAE;IAC3E,eAAe;IACf,UAAU,EAAK,SAAS,MAAM,CAAC,aAAa;IAC5C,GAAI,EAAK,cAAc,EAAE,aAAa,EAAK,aAAa,GAAG,EAAE;IAC7D,GAAI,EAAK,YAAY,EAAE,WAAW,EAAK,WAAW,GAAG,EAAE;IACxD,EACF,EACF,CAAC,CACH,EACiB,MAAM,uBAAuB;AAG/C,GAFA,EAAQ,GAAM,EACd,EAAQ,EAAM,EACV,KAAI,IAAY,EAAG;WAChB,GAAG;AACV,KAAS,EAAU,GAAG,mCAAmC,CAAC;;;AAI9D,QACE,kBAAC,GAAD;EACQ;EACN,eAAe,MAAS;AAEtB,GADA,EAAQ,EAAK,EACT,IAAM,EAAQ,EAAM,GACnB,EAAS,KAAK;;YALvB,CAQE,kBAAC,GAAD;GAAyB,SAAA;aACvB,kBAAC,GAAD;IAAQ,MAAM;IAAa,eAAY;cAAvC,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,aAE1B;;GACe,CAAA,EAC1B,kBAAC,GAAD;GAAyB,WAAU;aAAnC;IACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,cAAkC,CAAA,EACzD,kBAAC,GAAD,EAAA,UAA6B,+BAAyD,CAAA,CAC/D,EAAA,CAAA;IACzB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,CAAC,KACA,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,SAAQ;OAAqB,WAAU;iBAAsB;OAE5D,CAAA,EACR,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QACE,IAAG;QACH,OAAO,EAAK;QACZ,WAAW,MAAc,EAAQ;SAAE,GAAG;SAAM;SAAW,CAAC;QACxD,CAAA;OACE,CAAA,CACF,EAAA,CAAA;MAER,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,SAAQ;OAAkB,WAAU;iBAAsB;OAEzD,CAAA,EACR,kBAAC,GAAD;OACE,IAAG;OACH,WAAU;OACV,OAAO,EAAK;OACZ,WAAW,MAAM,EAAQ;QAAE,GAAG;QAAM,MAAM,EAAE,OAAO;QAAO,CAAC;OAC3D,CAAA,CACE,EAAA,CAAA;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAoB,WAAU;kBAAsB;QAE3D,CAAA,EACR,kBAAC,GAAD;QACE,IAAG;QACH,WAAU;QACV,MAAK;QACL,KAAI;QACJ,MAAK;QACL,WAAU;QACV,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,eAAe,EAAE,OAAO;SAAO,CAAC;QACpE,CAAA,CACE,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAsB,WAAU;kBAAsB;QAE7D,CAAA,EACR,kBAAC,GAAD;QACE,IAAG;QACH,WAAU;QACV,aAAY;QACZ,WAAW;QACX,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,UAAU,EAAE,OAAO,MAAM,aAAa;SAAE,CAAC;QAC7E,CAAA,CACE,EAAA,CAAA,CACF;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAmB,WAAU;kBAAsB;QAE1D,CAAA,EACR,kBAAC,GAAD;QACE,IAAG;QACH,WAAU;QACV,MAAK;QACL,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,aAAa,EAAE,OAAO;SAAO,CAAC;QAClE,CAAA,CACE,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAiB,WAAU;kBAAsB;QAExD,CAAA,EACR,kBAAC,GAAD;QACE,IAAG;QACH,WAAU;QACV,MAAK;QACL,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,WAAW,EAAE,OAAO;SAAO,CAAC;QAChE,CAAA,CACE,EAAA,CAAA,CACF;;MACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,SAAQ;OAAyB,WAAU;iBAAsB;OAEhE,CAAA,EACR,kBAAC,YAAD;OACE,IAAG;OACH,WAAW,GAAG,EAAM;OACpB,OAAO,EAAK;OACZ,WAAW,MAAM,EAAQ;QAAE,GAAG;QAAM,aAAa,EAAE,OAAO;QAAO,CAAC;OAClE,CAAA,CACE,EAAA,CAAA;MACL,KACC,kBAAC,GAAD,EAAW,SAAQ,qDAAsD,CAAA;MAE1E,KAAS,kBAAC,GAAD,EAAW,SAAS,GAAS,CAAA;MACnC;;IACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAQ,SAAQ;KAAU,eAAe,EAAQ,GAAM;eAAE;KAEhD,CAAA,EACT,kBAAC,GAAD;KACE,eAAe,KAAK,GAAQ;KAC5B,UAAU,CAAC;KACX,eAAY;eAEX,IAAU,cAAc;KAClB,CAAA,CACc,EAAA,CAAA;IACD;KACT;;;AAgBvB,SAAgB,EAAoB,EAAE,aAAoC;CACxE,IAAM,IAAW,GAAuB,EAClC,CAAC,GAAQ,KAAe,EAAY,GAAe;EACvD,gBAAgB;EAChB,qBAAqB;EACtB,CAAC,EACI,CAAC,GAAiB,KAAgB,EAAY,GAAgB;EAClE,gBAAgB;EAChB,qBAAqB;EACtB,CAAC,EACI,CAAC,GAAQ,KAAe,EAAY,GAAe;EACvD,gBAAgB,CAAC,eAAe,wBAAwB;EACxD,SAAS;EACV,CAAC,EACI,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,IAAO,EAAY,WAAW,EAAa,WAAW,EAAY,SAClE,IAAgB,EAAoB,SACxC,EAAO,OACR,GACG,IACA,CAAC,EAAO,QAAQ,GAAG,EAAoB,EAErC,IAAW,OAAO,MAAmB;AACzC,IAAS,KAAK;AACd,MAAI;AACF,SAAM,EAAa,EAAO,EAAE,WAAW;IAAE,IAAI,EAAO;IAAI,OAAO,EAAE,WAAQ;IAAE,EAAE,CAAC,CAAC;WACxE,GAAG;AACV,KAAS,EAAU,GAAG,mCAAmC,CAAC;;IAGxD,IAAY,YAAY;AAC5B,IAAS,KAAK;AACd,MAAI;AACF,SAAM,EAAa,EAAgB,EAAE,WAAW,EAAE,IAAI,EAAO,IAAI,EAAE,CAAC,CAAC;WAC9D,GAAG;AACV,KAAS,EAAU,GAAG,oCAAoC,CAAC;;IAGzD,IAAW,YAAY;AAC3B,IAAS,KAAK;AACd,MAAI;AAEF,GADA,MAAM,EAAa,EAAO,EAAE,WAAW,EAAE,IAAI,EAAO,IAAI,EAAE,CAAC,CAAC,EAC5D,EAAS,yBAAyB;WAC3B,GAAG;AACV,KAAS,EAAU,GAAG,mCAAmC,CAAC;;;AAI9D,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,UAAD;KACE,cAAW;KACX,eAAY;KACZ,WAAU;KACV,OAAO,EAAO;KACd,UAAU;KACV,WAAW,MAAM;AACf,MAAI,EAAE,OAAO,UAAU,EAAO,UAAa,EAAS,EAAE,OAAO,MAAM;;eAGpE,EAAc,KAAK,MAClB,kBAAC,UAAD;MAAgB,OAAO;gBACpB,EAAU,EAAE;MACN,EAFI,EAEJ,CACT;KACK,CAAA;IACR,EAAO,WAAW,cAAc,EAAO,WAAW,YACjD,kBAAC,GAAD;KAAQ,MAAK;KAAK,SAAQ;KAAU,UAAU;KAAM,eAAe,KAAK,GAAW;eAAnF,CACE,kBAAC,GAAD,EAAc,WAAU,gBAAiB,CAAA,EAAA,UAElC;;IAEX,kBAAC,GAAD,EAA0B,WAAU,CAAA;IACpC,kBAAC,GAAD;KACE,OAAM;KACN,SAAQ;KACR,MAAM,kBAAC,GAAD,EAAQ,WAAU,gBAAiB,CAAA;KACzC,OAAO,WAAW,EAAO,KAAK;KAC9B,aAAY;KACZ,cAAa;KACb,aAAA;KACA,UAAU;KACV,iBAAiB,KAAK,GAAU;KAChC,CAAA;IACE;MACL,KAAS,kBAAC,GAAD,EAAW,SAAS,GAAS,CAAA,CACnC;;;AAKV,SAAS,EAAiB,EAAE,aAAoC;CAC9D,IAAM,IAAU;EACd,MAAM,EAAO;EACb,aAAa,EAAO,eAAe;EACnC,eAAe,OAAO,EAAO,cAAc;EAC3C,UAAU,EAAO;EACjB,aAAa,EAAiB,EAAO,YAAY;EACjD,WAAW,EAAiB,EAAO,UAAU;EAC9C,EACK,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,CAAC,GAAM,KAAW,EAAS,EAAQ,EACnC,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAQ,KAAS,EAAY,GAAe;EACjD,gBAAgB;EAChB,qBAAqB;EACtB,CAAC,EAEI,IAAS,OAAO,EAAK,cAAc,EACnC,IAAkB,EAAK,eAAe,EAAK,aAAa,EAAK,YAAY,EAAK,aAC9E,IACJ,CAAC,EAAM,WACP,EAAK,KAAK,MAAM,KAAK,MACrB,OAAO,SAAS,EAAO,IACvB,KAAU,KACV,CAAC,GAEG,IAAO,YAAY;AACvB,IAAS,KAAK;EACd,IAAM,IAAiC,EAAE;AASzC,MARI,EAAK,KAAK,MAAM,KAAK,EAAQ,SAAM,EAAM,OAAO,EAAK,KAAK,MAAM,GAChE,EAAK,YAAY,MAAM,KAAK,EAAQ,YAAY,MAAM,KACxD,EAAM,cAAc,EAAK,YAAY,MAAM,IAAI,OAC7C,MAAW,EAAO,kBAAe,EAAM,gBAAgB,IACvD,EAAK,SAAS,MAAM,CAAC,aAAa,KAAK,EAAQ,aACjD,EAAM,WAAW,EAAK,SAAS,MAAM,CAAC,aAAa,GACjD,EAAK,gBAAgB,EAAQ,gBAAa,EAAM,cAAc,EAAK,eAAe,OAClF,EAAK,cAAc,EAAQ,cAAW,EAAM,YAAY,EAAK,aAAa,OAC1E,OAAO,KAAK,EAAM,CAAC,WAAW,GAAG;AACnC,KAAQ,GAAM;AACd;;AAEF,MAAI;AAEF,GADA,MAAM,EAAa,EAAO,EAAE,WAAW;IAAE,IAAI,EAAO;IAAI;IAAO,EAAE,CAAC,CAAC,EACnE,EAAQ,GAAM;WACP,GAAG;AACV,KAAS,EAAU,GAAG,iCAAiC,CAAC;;;AAI5D,QACE,kBAAC,GAAD;EACQ;EACN,eAAe,MAAS;AAEtB,GADA,EAAQ,EAAK,EACT,IAAM,EAAQ,EAAQ,GACrB,EAAS,KAAK;;YALvB,CAQE,kBAAC,GAAD;GAAyB,SAAA;aACvB,kBAAC,GAAD;IAAQ,MAAK;IAAK,SAAQ;IAAU,eAAY;cAAhD,CACE,kBAAC,GAAD,EAAQ,WAAU,gBAAiB,CAAA,EAAA,OAE5B;;GACe,CAAA,EAC1B,kBAAC,GAAD;GAAyB,WAAU;aAAnC;IACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,eAAmC,CAAA,EAC1D,kBAAC,GAAD,EAAA,UAA6B,6DAEC,CAAA,CACP,EAAA,CAAA;IACzB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,SAAQ;OAAmB,WAAU;iBAAsB;OAE1D,CAAA,EACR,kBAAC,GAAD;OACE,IAAG;OACH,WAAU;OACV,OAAO,EAAK;OACZ,WAAW,MAAM,EAAQ;QAAE,GAAG;QAAM,MAAM,EAAE,OAAO;QAAO,CAAC;OAC3D,CAAA,CACE,EAAA,CAAA;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAqB,WAAU;kBAAsB;QAE5D,CAAA,EACR,kBAAC,GAAD;QACE,IAAG;QACH,WAAU;QACV,MAAK;QACL,KAAI;QACJ,MAAK;QACL,WAAU;QACV,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,eAAe,EAAE,OAAO;SAAO,CAAC;QACpE,CAAA,CACE,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAuB,WAAU;kBAAsB;QAE9D,CAAA,EACR,kBAAC,GAAD;QACE,IAAG;QACH,WAAU;QACV,WAAW;QACX,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,UAAU,EAAE,OAAO,MAAM,aAAa;SAAE,CAAC;QAC7E,CAAA,CACE,EAAA,CAAA,CACF;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAoB,WAAU;kBAAsB;QAE3D,CAAA,EACR,kBAAC,GAAD;QACE,IAAG;QACH,WAAU;QACV,MAAK;QACL,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,aAAa,EAAE,OAAO;SAAO,CAAC;QAClE,CAAA,CACE,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAkB,WAAU;kBAAsB;QAEzD,CAAA,EACR,kBAAC,GAAD;QACE,IAAG;QACH,WAAU;QACV,MAAK;QACL,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,WAAW,EAAE,OAAO;SAAO,CAAC;QAChE,CAAA,CACE,EAAA,CAAA,CACF;;MACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,SAAQ;OAA0B,WAAU;iBAAsB;OAEjE,CAAA,EACR,kBAAC,YAAD;OACE,IAAG;OACH,WAAW,GAAG,EAAM;OACpB,OAAO,EAAK;OACZ,WAAW,MAAM,EAAQ;QAAE,GAAG;QAAM,aAAa,EAAE,OAAO;QAAO,CAAC;OAClE,CAAA,CACE,EAAA,CAAA;MACL,KACC,kBAAC,GAAD,EAAW,SAAQ,qDAAsD,CAAA;MAE1E,KAAS,kBAAC,GAAD,EAAW,SAAS,GAAS,CAAA;MACnC;;IACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAQ,SAAQ;KAAU,eAAe,EAAQ,GAAM;eAAE;KAEhD,CAAA,EACT,kBAAC,GAAD;KAAQ,eAAe,KAAK,GAAM;KAAE,UAAU,CAAC;KAAW,eAAY;eACnE,EAAM,UAAU,YAAY;KACtB,CAAA,CACc,EAAA,CAAA;IACD;KACT"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Log an expense against a budget. */
|
|
2
|
+
export declare function LogExpenseDialog({ budgetId, projectId, refetchQueries, }: {
|
|
3
|
+
budgetId: string;
|
|
4
|
+
/** Narrows the optional "work item" search to the budget's own project, when known. */
|
|
5
|
+
projectId?: string;
|
|
6
|
+
refetchQueries: string[];
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export interface ExpenseValues {
|
|
9
|
+
id: string;
|
|
10
|
+
description: string;
|
|
11
|
+
amount: number;
|
|
12
|
+
category: string | null;
|
|
13
|
+
date: string;
|
|
14
|
+
referenceUrl: string | null;
|
|
15
|
+
}
|
|
16
|
+
/** Edit an expense's description, amount, category, date or reference URL. Only changed fields are sent. */
|
|
17
|
+
export declare function EditExpenseDialog({ expense, refetchQueries, }: {
|
|
18
|
+
expense: ExpenseValues;
|
|
19
|
+
refetchQueries: string[];
|
|
20
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
/** Delete an expense, with confirmation. */
|
|
22
|
+
export declare function DeleteExpenseButton({ id, description, refetchQueries, }: {
|
|
23
|
+
id: string;
|
|
24
|
+
description: string;
|
|
25
|
+
refetchQueries: string[];
|
|
26
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
//# sourceMappingURL=ExpenseControls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpenseControls.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/budgets/ExpenseControls.tsx"],"names":[],"mappings":"AAoEA,uCAAuC;AACvC,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,SAAS,EACT,cAAc,GACf,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,2CAwKA;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,4GAA4G;AAC5G,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,cAAc,GACf,EAAE;IACD,OAAO,EAAE,aAAa,CAAC;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,2CA+IA;AAED,4CAA4C;AAC5C,wBAAgB,mBAAmB,CAAC,EAClC,EAAE,EACF,WAAW,EACX,cAAc,GACf,EAAE;IACD,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,2CAiCA"}
|