@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,217 @@
|
|
|
1
|
+
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { PersonName as n } from "../people/People.js";
|
|
3
|
+
import { useEntityId as r } from "../hooks/useEntityId.js";
|
|
4
|
+
import { ROW_LINK_CLASS as i, detailPath as a, rowLinkProps as o } from "../utils/rowNavigation.js";
|
|
5
|
+
import { PlanMagnetNotFoundPage as s } from "./NotFoundPage.js";
|
|
6
|
+
import { NewSprintDialog as c } from "../sprints/SprintControls.js";
|
|
7
|
+
import { TeamHeaderActions as l, TeamMembersPanel as u, TeamProjectsPanel as d } from "../team/TeamControls.js";
|
|
8
|
+
import { Gauge as f, UserRound as p, Users as m, Zap as h } from "lucide-react";
|
|
9
|
+
import { gql as g } from "@apollo/client";
|
|
10
|
+
import { useQuery as _ } from "@apollo/client/react";
|
|
11
|
+
import { jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
12
|
+
import { Badge as b, Card as x, CardContent as S, CardHeader as C, CardTitle as w } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
//#region src/planmagnet/pages/TeamTeamDetailPagePage.tsx
|
|
14
|
+
var T = g`
|
|
15
|
+
query GetTeamDetail($id: ID!) {
|
|
16
|
+
planmagnetTeam(id: $id) {
|
|
17
|
+
id
|
|
18
|
+
name
|
|
19
|
+
description
|
|
20
|
+
leadId
|
|
21
|
+
capacity
|
|
22
|
+
createdAt
|
|
23
|
+
members {
|
|
24
|
+
id
|
|
25
|
+
actorId
|
|
26
|
+
}
|
|
27
|
+
projects {
|
|
28
|
+
id
|
|
29
|
+
name
|
|
30
|
+
key
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
`, E = g`
|
|
35
|
+
query GetTeamSprints($workspaceId: ID!, $filter: PlanmagnetSprintFilter) {
|
|
36
|
+
planmagnetSprints(workspaceId: $workspaceId, filter: $filter, pagination: { first: 50 }) {
|
|
37
|
+
items {
|
|
38
|
+
id
|
|
39
|
+
name
|
|
40
|
+
status
|
|
41
|
+
goal
|
|
42
|
+
velocity
|
|
43
|
+
startDate
|
|
44
|
+
endDate
|
|
45
|
+
workItems {
|
|
46
|
+
id
|
|
47
|
+
status
|
|
48
|
+
storyPoints
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
totalCount
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
`, D = {
|
|
55
|
+
PLANNING: "bg-blue-100 text-blue-800",
|
|
56
|
+
ACTIVE: "bg-green-100 text-green-800",
|
|
57
|
+
REVIEW: "bg-purple-100 text-purple-800",
|
|
58
|
+
COMPLETED: "bg-gray-100 text-gray-800",
|
|
59
|
+
CANCELLED: "bg-red-100 text-red-800"
|
|
60
|
+
};
|
|
61
|
+
function O() {
|
|
62
|
+
let g = r("teamId"), { workspaceId: O } = e(), k = t(), { data: A, loading: j, error: M } = _(T, {
|
|
63
|
+
variables: { id: g },
|
|
64
|
+
skip: !g
|
|
65
|
+
}), { data: N, loading: P } = _(E, {
|
|
66
|
+
variables: {
|
|
67
|
+
workspaceId: O ?? "",
|
|
68
|
+
filter: { teamId: g }
|
|
69
|
+
},
|
|
70
|
+
skip: !g || !O
|
|
71
|
+
});
|
|
72
|
+
if (!g) return /* @__PURE__ */ v("div", {
|
|
73
|
+
className: "p-6 text-muted-foreground",
|
|
74
|
+
children: "No team selected. Open one from the list."
|
|
75
|
+
});
|
|
76
|
+
if (j && !A) return /* @__PURE__ */ v("div", {
|
|
77
|
+
className: "flex items-center justify-center p-12",
|
|
78
|
+
children: /* @__PURE__ */ v("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
79
|
+
});
|
|
80
|
+
if (M) return /* @__PURE__ */ y("div", {
|
|
81
|
+
className: "p-6 text-destructive",
|
|
82
|
+
children: ["Error loading team: ", M.message]
|
|
83
|
+
});
|
|
84
|
+
let F = A?.planmagnetTeam;
|
|
85
|
+
if (!F) return /* @__PURE__ */ v(s, {});
|
|
86
|
+
let I = N?.planmagnetSprints.items ?? [];
|
|
87
|
+
return /* @__PURE__ */ y("div", {
|
|
88
|
+
className: "space-y-6 p-6",
|
|
89
|
+
children: [
|
|
90
|
+
/* @__PURE__ */ y("div", {
|
|
91
|
+
className: "flex items-start justify-between gap-4",
|
|
92
|
+
children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ y("div", {
|
|
93
|
+
className: "flex items-center gap-2",
|
|
94
|
+
children: [/* @__PURE__ */ v(m, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ v("h1", {
|
|
95
|
+
className: "text-2xl font-semibold",
|
|
96
|
+
children: F.name
|
|
97
|
+
})]
|
|
98
|
+
}), /* @__PURE__ */ v("p", {
|
|
99
|
+
className: "text-sm text-muted-foreground mt-1",
|
|
100
|
+
children: F.description ?? "No description"
|
|
101
|
+
})] }), /* @__PURE__ */ v(l, {
|
|
102
|
+
teamId: F.id,
|
|
103
|
+
name: F.name
|
|
104
|
+
})]
|
|
105
|
+
}),
|
|
106
|
+
/* @__PURE__ */ y("div", {
|
|
107
|
+
className: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
|
108
|
+
children: [
|
|
109
|
+
/* @__PURE__ */ v(x, { children: /* @__PURE__ */ y(S, {
|
|
110
|
+
className: "pt-4",
|
|
111
|
+
children: [/* @__PURE__ */ y("div", {
|
|
112
|
+
className: "flex items-center gap-2 text-muted-foreground text-xs",
|
|
113
|
+
children: [/* @__PURE__ */ v(p, { className: "h-4 w-4" }), "Lead"]
|
|
114
|
+
}), /* @__PURE__ */ v("p", {
|
|
115
|
+
className: "text-sm font-bold mt-1 truncate",
|
|
116
|
+
children: F.leadId ? /* @__PURE__ */ v(n, { id: F.leadId }) : "No lead"
|
|
117
|
+
})]
|
|
118
|
+
}) }),
|
|
119
|
+
/* @__PURE__ */ v(x, { children: /* @__PURE__ */ y(S, {
|
|
120
|
+
className: "pt-4",
|
|
121
|
+
children: [/* @__PURE__ */ y("div", {
|
|
122
|
+
className: "flex items-center gap-2 text-muted-foreground text-xs",
|
|
123
|
+
children: [/* @__PURE__ */ v(f, { className: "h-4 w-4" }), "Capacity"]
|
|
124
|
+
}), /* @__PURE__ */ v("p", {
|
|
125
|
+
className: "text-xl font-bold mt-1",
|
|
126
|
+
children: F.capacity ?? "—"
|
|
127
|
+
})]
|
|
128
|
+
}) }),
|
|
129
|
+
/* @__PURE__ */ v(x, { children: /* @__PURE__ */ y(S, {
|
|
130
|
+
className: "pt-4",
|
|
131
|
+
children: [/* @__PURE__ */ y("div", {
|
|
132
|
+
className: "flex items-center gap-2 text-muted-foreground text-xs",
|
|
133
|
+
children: [/* @__PURE__ */ v(m, { className: "h-4 w-4" }), "Members"]
|
|
134
|
+
}), /* @__PURE__ */ v("p", {
|
|
135
|
+
className: "text-xl font-bold mt-1",
|
|
136
|
+
children: F.members.length
|
|
137
|
+
})]
|
|
138
|
+
}) }),
|
|
139
|
+
/* @__PURE__ */ v(x, { children: /* @__PURE__ */ y(S, {
|
|
140
|
+
className: "pt-4",
|
|
141
|
+
children: [/* @__PURE__ */ y("div", {
|
|
142
|
+
className: "flex items-center gap-2 text-muted-foreground text-xs",
|
|
143
|
+
children: [/* @__PURE__ */ v(h, { className: "h-4 w-4" }), "Team sprints"]
|
|
144
|
+
}), /* @__PURE__ */ v("p", {
|
|
145
|
+
className: "text-xl font-bold mt-1",
|
|
146
|
+
children: N?.planmagnetSprints.totalCount ?? (P ? "—" : I.length)
|
|
147
|
+
})]
|
|
148
|
+
}) })
|
|
149
|
+
]
|
|
150
|
+
}),
|
|
151
|
+
/* @__PURE__ */ y("div", {
|
|
152
|
+
className: "grid grid-cols-1 lg:grid-cols-2 gap-6",
|
|
153
|
+
children: [/* @__PURE__ */ y(x, { children: [/* @__PURE__ */ v(C, { children: /* @__PURE__ */ v(w, { children: "Members" }) }), /* @__PURE__ */ v(S, { children: /* @__PURE__ */ v(u, {
|
|
154
|
+
teamId: F.id,
|
|
155
|
+
members: F.members
|
|
156
|
+
}) })] }), /* @__PURE__ */ y(x, { children: [/* @__PURE__ */ v(C, { children: /* @__PURE__ */ v(w, { children: "Projects" }) }), /* @__PURE__ */ v(S, { children: /* @__PURE__ */ v(d, {
|
|
157
|
+
teamId: F.id,
|
|
158
|
+
projects: F.projects
|
|
159
|
+
}) })] })]
|
|
160
|
+
}),
|
|
161
|
+
/* @__PURE__ */ y(x, { children: [/* @__PURE__ */ y(C, {
|
|
162
|
+
className: "flex flex-row items-center justify-between space-y-0",
|
|
163
|
+
children: [/* @__PURE__ */ v(w, { children: "Sprints" }), /* @__PURE__ */ v(c, {
|
|
164
|
+
initialScope: "team",
|
|
165
|
+
initialTeamId: F.id,
|
|
166
|
+
onCreated: (e) => k(a("/projects/planning-detail-page", e))
|
|
167
|
+
})]
|
|
168
|
+
}), /* @__PURE__ */ y(S, {
|
|
169
|
+
className: "space-y-2",
|
|
170
|
+
children: [
|
|
171
|
+
P && I.length === 0 && /* @__PURE__ */ v("p", {
|
|
172
|
+
className: "text-sm text-muted-foreground text-center py-4",
|
|
173
|
+
children: "Loading sprints…"
|
|
174
|
+
}),
|
|
175
|
+
!P && I.length === 0 && /* @__PURE__ */ v("p", {
|
|
176
|
+
className: "text-sm text-muted-foreground text-center py-4",
|
|
177
|
+
children: "No sprints yet. A team sprint can only include work items from this team's projects."
|
|
178
|
+
}),
|
|
179
|
+
I.map((e) => {
|
|
180
|
+
let t = e.workItems.reduce((e, t) => e + (t.storyPoints ?? 0), 0), n = e.workItems.filter((e) => e.status === "DONE").reduce((e, t) => e + (t.storyPoints ?? 0), 0);
|
|
181
|
+
return /* @__PURE__ */ y("div", {
|
|
182
|
+
...o(() => k(a("/projects/planning-detail-page", e.id)), e.name),
|
|
183
|
+
className: `flex items-center justify-between border rounded-md p-2.5 ${i}`,
|
|
184
|
+
children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
|
|
185
|
+
className: "text-sm font-medium",
|
|
186
|
+
children: e.name
|
|
187
|
+
}), e.goal && /* @__PURE__ */ v("p", {
|
|
188
|
+
className: "text-xs text-muted-foreground",
|
|
189
|
+
children: e.goal
|
|
190
|
+
})] }), /* @__PURE__ */ y("div", {
|
|
191
|
+
className: "flex items-center gap-2",
|
|
192
|
+
children: [/* @__PURE__ */ v("span", {
|
|
193
|
+
className: "text-xs text-muted-foreground",
|
|
194
|
+
children: e.status === "COMPLETED" && e.velocity != null ? `${e.velocity} pts velocity` : `${n}/${t} pts`
|
|
195
|
+
}), /* @__PURE__ */ v("span", {
|
|
196
|
+
className: `text-xs px-2 py-0.5 rounded-full capitalize ${D[e.status] ?? "bg-gray-100"}`,
|
|
197
|
+
children: e.status.toLowerCase().replace("_", " ")
|
|
198
|
+
})]
|
|
199
|
+
})]
|
|
200
|
+
}, e.id);
|
|
201
|
+
})
|
|
202
|
+
]
|
|
203
|
+
})] }),
|
|
204
|
+
/* @__PURE__ */ y("p", {
|
|
205
|
+
className: "text-xs text-muted-foreground",
|
|
206
|
+
children: ["Created ", /* @__PURE__ */ v(b, {
|
|
207
|
+
variant: "outline",
|
|
208
|
+
children: new Date(F.createdAt).toLocaleDateString()
|
|
209
|
+
})]
|
|
210
|
+
})
|
|
211
|
+
]
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
export { O as TeamTeamDetailPagePage };
|
|
216
|
+
|
|
217
|
+
//# sourceMappingURL=TeamTeamDetailPagePage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamTeamDetailPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamTeamDetailPagePage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Badge, Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { Users, UserRound, Gauge, Zap } from 'lucide-react';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { ROW_LINK_CLASS, detailPath, rowLinkProps } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\nimport { TeamHeaderActions, TeamMembersPanel, TeamProjectsPanel } from '../team/TeamControls';\nimport { NewSprintDialog } from '../sprints/SprintControls';\nimport { PlanMagnetNotFoundPage } from './NotFoundPage';\n\n/**\n * Team detail (BOFF-8044): members, lead, capacity, projects, and the team's own sprints\n * (sprints whose scope is this team, never a project — sprint scope is PROJECT xor TEAM).\n */\n\nconst GET_TEAM_DETAIL = gql`\n query GetTeamDetail($id: ID!) {\n planmagnetTeam(id: $id) {\n id\n name\n description\n leadId\n capacity\n createdAt\n members {\n id\n actorId\n }\n projects {\n id\n name\n key\n }\n }\n }\n`;\n\nconst GET_TEAM_SPRINTS = gql`\n query GetTeamSprints($workspaceId: ID!, $filter: PlanmagnetSprintFilter) {\n planmagnetSprints(workspaceId: $workspaceId, filter: $filter, pagination: { first: 50 }) {\n items {\n id\n name\n status\n goal\n velocity\n startDate\n endDate\n workItems {\n id\n status\n storyPoints\n }\n }\n totalCount\n }\n }\n`;\n\ninterface TeamDetail {\n id: string;\n name: string;\n description: string | null;\n leadId: string | null;\n capacity: number | null;\n createdAt: string;\n members: { id: string; actorId: string }[];\n projects: { id: string; name: string; key: string }[];\n}\n\ninterface TeamSprintNode {\n id: string;\n name: string;\n status: string;\n goal: string | null;\n velocity: number | null;\n startDate: string | null;\n endDate: string | null;\n workItems: { id: string; status: string; storyPoints: number | null }[];\n}\n\nconst statusColor: Record<string, string> = {\n PLANNING: 'bg-blue-100 text-blue-800',\n ACTIVE: 'bg-green-100 text-green-800',\n REVIEW: 'bg-purple-100 text-purple-800',\n COMPLETED: 'bg-gray-100 text-gray-800',\n CANCELLED: 'bg-red-100 text-red-800',\n};\n\nexport function TeamTeamDetailPagePage() {\n const teamId = useEntityId('teamId');\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const { data, loading, error } = useQuery<{ planmagnetTeam: TeamDetail | null }>(\n GET_TEAM_DETAIL,\n { variables: { id: teamId }, skip: !teamId }\n );\n const { data: sprintData, loading: sprintsLoading } = useQuery<{\n planmagnetSprints: { items: TeamSprintNode[]; totalCount: number };\n }>(GET_TEAM_SPRINTS, {\n variables: { workspaceId: workspaceId ?? '', filter: { teamId } },\n skip: !teamId || !workspaceId,\n });\n\n if (!teamId) {\n return (\n <div className=\"p-6 text-muted-foreground\">No team selected. Open one from the list.</div>\n );\n }\n // Only before the first load: a refetch must not blank the page (it\n // unmounts every component on it and loses their state).\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n }\n if (error) {\n return <div className=\"p-6 text-destructive\">Error loading team: {error.message}</div>;\n }\n\n const team = data?.planmagnetTeam;\n // Deleted, unauthorized or an unknown id all read back the same way (no cross-tenant existence\n // leak) — the real 404 page, not an inline message and not a same-URL redirect (H5).\n if (!team) return <PlanMagnetNotFoundPage />;\n\n const sprints = sprintData?.planmagnetSprints.items ?? [];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <div className=\"flex items-center gap-2\">\n <Users className=\"h-5 w-5 text-primary\" />\n <h1 className=\"text-2xl font-semibold\">{team.name}</h1>\n </div>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {team.description ?? 'No description'}\n </p>\n </div>\n <TeamHeaderActions teamId={team.id} name={team.name} />\n </div>\n\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <UserRound className=\"h-4 w-4\" />\n Lead\n </div>\n <p className=\"text-sm font-bold mt-1 truncate\">\n {team.leadId ? <PersonName id={team.leadId} /> : 'No lead'}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Gauge className=\"h-4 w-4\" />\n Capacity\n </div>\n <p className=\"text-xl font-bold mt-1\">{team.capacity ?? '—'}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Users className=\"h-4 w-4\" />\n Members\n </div>\n <p className=\"text-xl font-bold mt-1\">{team.members.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-muted-foreground text-xs\">\n <Zap className=\"h-4 w-4\" />\n Team sprints\n </div>\n <p className=\"text-xl font-bold mt-1\">\n {sprintData?.planmagnetSprints.totalCount ?? (sprintsLoading ? '—' : sprints.length)}\n </p>\n </CardContent>\n </Card>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>Members</CardTitle>\n </CardHeader>\n <CardContent>\n <TeamMembersPanel teamId={team.id} members={team.members} />\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Projects</CardTitle>\n </CardHeader>\n <CardContent>\n <TeamProjectsPanel teamId={team.id} projects={team.projects} />\n </CardContent>\n </Card>\n </div>\n\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle>Sprints</CardTitle>\n <NewSprintDialog\n initialScope=\"team\"\n initialTeamId={team.id}\n onCreated={(id) => navigate(detailPath('/projects/planning-detail-page', id))}\n />\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {sprintsLoading && sprints.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">Loading sprints…</p>\n )}\n {!sprintsLoading && sprints.length === 0 && (\n <p className=\"text-sm text-muted-foreground text-center py-4\">\n No sprints yet. A team sprint can only include work items from this team's\n projects.\n </p>\n )}\n {sprints.map((sprint) => {\n const totalPoints = sprint.workItems.reduce(\n (sum, wi) => sum + (wi.storyPoints ?? 0),\n 0\n );\n const donePoints = sprint.workItems\n .filter((wi) => wi.status === 'DONE')\n .reduce((sum, wi) => sum + (wi.storyPoints ?? 0), 0);\n return (\n <div\n key={sprint.id}\n {...rowLinkProps(\n () => navigate(detailPath('/projects/planning-detail-page', sprint.id)),\n sprint.name\n )}\n className={`flex items-center justify-between border rounded-md p-2.5 ${ROW_LINK_CLASS}`}\n >\n <div>\n <p className=\"text-sm font-medium\">{sprint.name}</p>\n {sprint.goal && <p className=\"text-xs text-muted-foreground\">{sprint.goal}</p>}\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">\n {sprint.status === 'COMPLETED' && sprint.velocity != null\n ? `${sprint.velocity} pts velocity`\n : `${donePoints}/${totalPoints} pts`}\n </span>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${statusColor[sprint.status] ?? 'bg-gray-100'}`}\n >\n {sprint.status.toLowerCase().replace('_', ' ')}\n </span>\n </div>\n </div>\n );\n })}\n </CardContent>\n </Card>\n\n <p className=\"text-xs text-muted-foreground\">\n Created <Badge variant=\"outline\">{new Date(team.createdAt).toLocaleDateString()}</Badge>\n </p>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamTeamEditPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TeamTeamEditPagePage.tsx"],"names":[],"mappings":"AA+CA,wBAAgB,oBAAoB,4CA8LnC"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { throwOnError as t } from "../utils/mutationResult.js";
|
|
3
|
+
import { useEntityId as n } from "../hooks/useEntityId.js";
|
|
4
|
+
import { AssigneeSelect as r } from "../controls/WorkItemControls.js";
|
|
5
|
+
import { detailPath as i } from "../utils/rowNavigation.js";
|
|
6
|
+
import { parseIntField as a } from "../utils/formValidation.js";
|
|
7
|
+
import { PlanMagnetNotFoundPage as o } from "./NotFoundPage.js";
|
|
8
|
+
import { useMemo as s, useState as c } from "react";
|
|
9
|
+
import { ArrowLeft as l, Save as u } from "lucide-react";
|
|
10
|
+
import { gql as d } from "@apollo/client";
|
|
11
|
+
import { useMutation as f, useQuery as p } from "@apollo/client/react";
|
|
12
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
13
|
+
import { Button as g, Card as _, CardContent as v, CardHeader as y, CardTitle as b, Input as x } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
//#region src/planmagnet/pages/TeamTeamEditPagePage.tsx
|
|
15
|
+
var S = d`
|
|
16
|
+
query GetTeamForEdit($id: ID!) {
|
|
17
|
+
planmagnetTeam(id: $id) {
|
|
18
|
+
id
|
|
19
|
+
name
|
|
20
|
+
description
|
|
21
|
+
leadId
|
|
22
|
+
capacity
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
`, C = d`
|
|
26
|
+
mutation UpdateTeam($id: ID!, $input: PlanmagnetUpdateTeamInput!) {
|
|
27
|
+
planmagnetUpdateTeam(id: $id, input: $input) {
|
|
28
|
+
id
|
|
29
|
+
name
|
|
30
|
+
description
|
|
31
|
+
leadId
|
|
32
|
+
capacity
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
function w() {
|
|
37
|
+
let d = n("teamId"), w = e(), { data: T, loading: E, error: D } = p(S, {
|
|
38
|
+
variables: { id: d },
|
|
39
|
+
skip: !d
|
|
40
|
+
}), O = T?.planmagnetTeam, k = s(() => ({
|
|
41
|
+
name: O?.name ?? "",
|
|
42
|
+
description: O?.description ?? "",
|
|
43
|
+
leadId: O?.leadId ?? "",
|
|
44
|
+
capacity: O?.capacity?.toString() ?? ""
|
|
45
|
+
}), [O]), [A, j] = c({}), M = {
|
|
46
|
+
...k,
|
|
47
|
+
...A
|
|
48
|
+
}, N = (e) => j((t) => {
|
|
49
|
+
let n = { ...t };
|
|
50
|
+
for (let [t, r] of Object.entries(e)) r !== M[t] && (n[t] = r);
|
|
51
|
+
return n;
|
|
52
|
+
}), [P, F] = c(null), [I, L] = c(null), R = a(M.capacity, { min: 0 }), z = M.name.trim() === "", [B, { loading: V }] = f(C, { refetchQueries: [
|
|
53
|
+
"GetTeams",
|
|
54
|
+
"GetTeamDetail",
|
|
55
|
+
"GetTeamForEdit"
|
|
56
|
+
] });
|
|
57
|
+
return d ? E && !T ? /* @__PURE__ */ m("div", {
|
|
58
|
+
className: "flex items-center justify-center p-12",
|
|
59
|
+
children: /* @__PURE__ */ m("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
60
|
+
}) : D ? /* @__PURE__ */ h("div", {
|
|
61
|
+
className: "p-6 text-destructive",
|
|
62
|
+
children: ["Error loading team: ", D.message]
|
|
63
|
+
}) : O ? /* @__PURE__ */ h("div", {
|
|
64
|
+
className: "space-y-6 p-6 max-w-4xl",
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ h("div", {
|
|
67
|
+
className: "flex items-center justify-between",
|
|
68
|
+
children: [/* @__PURE__ */ h("div", {
|
|
69
|
+
className: "flex items-center gap-3",
|
|
70
|
+
children: [/* @__PURE__ */ m(g, {
|
|
71
|
+
variant: "ghost",
|
|
72
|
+
size: "sm",
|
|
73
|
+
"aria-label": "Back to the team",
|
|
74
|
+
onClick: () => w(i("/team/team-detail-page", d)),
|
|
75
|
+
children: /* @__PURE__ */ m(l, { className: "h-4 w-4" })
|
|
76
|
+
}), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h1", {
|
|
77
|
+
className: "text-2xl font-semibold",
|
|
78
|
+
children: "Edit Team"
|
|
79
|
+
}), /* @__PURE__ */ m("p", {
|
|
80
|
+
className: "text-sm text-muted-foreground",
|
|
81
|
+
children: O.name
|
|
82
|
+
})] })]
|
|
83
|
+
}), /* @__PURE__ */ h(g, {
|
|
84
|
+
size: "sm",
|
|
85
|
+
onClick: async () => {
|
|
86
|
+
if (!(!O || z || R.invalid)) {
|
|
87
|
+
F(null), L(null);
|
|
88
|
+
try {
|
|
89
|
+
await t(B({ variables: {
|
|
90
|
+
id: O.id,
|
|
91
|
+
input: {
|
|
92
|
+
name: M.name.trim(),
|
|
93
|
+
description: M.description.trim() || void 0,
|
|
94
|
+
leadId: M.leadId || void 0,
|
|
95
|
+
capacity: R.value
|
|
96
|
+
}
|
|
97
|
+
} })), L("Team updated successfully."), j({});
|
|
98
|
+
} catch (e) {
|
|
99
|
+
F(e instanceof Error ? e.message : "The team could not be saved.");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
disabled: V || z || R.invalid,
|
|
104
|
+
children: [/* @__PURE__ */ m(u, { className: "mr-1 h-4 w-4" }), V ? "Saving..." : "Save Changes"]
|
|
105
|
+
})]
|
|
106
|
+
}),
|
|
107
|
+
I && /* @__PURE__ */ m("div", {
|
|
108
|
+
role: "status",
|
|
109
|
+
className: "p-3 rounded-md text-sm bg-muted text-status-success-text",
|
|
110
|
+
children: I
|
|
111
|
+
}),
|
|
112
|
+
P && /* @__PURE__ */ h("div", {
|
|
113
|
+
role: "alert",
|
|
114
|
+
className: "p-3 rounded-md text-sm bg-destructive/10 text-destructive",
|
|
115
|
+
children: ["Error: ", P]
|
|
116
|
+
}),
|
|
117
|
+
/* @__PURE__ */ h(_, { children: [/* @__PURE__ */ m(y, { children: /* @__PURE__ */ m(b, { children: "Team Details" }) }), /* @__PURE__ */ h(v, {
|
|
118
|
+
className: "space-y-4",
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ h("div", { children: [
|
|
121
|
+
/* @__PURE__ */ m("label", {
|
|
122
|
+
htmlFor: "team-name",
|
|
123
|
+
className: "text-sm font-medium",
|
|
124
|
+
children: "Team Name"
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ m(x, {
|
|
127
|
+
id: "team-name",
|
|
128
|
+
value: M.name,
|
|
129
|
+
onChange: (e) => N({
|
|
130
|
+
...M,
|
|
131
|
+
name: e.target.value
|
|
132
|
+
}),
|
|
133
|
+
"aria-invalid": z,
|
|
134
|
+
className: "mt-1"
|
|
135
|
+
}),
|
|
136
|
+
z && /* @__PURE__ */ m("p", {
|
|
137
|
+
role: "alert",
|
|
138
|
+
className: "mt-1 text-xs text-destructive",
|
|
139
|
+
children: "Choose a name for the team."
|
|
140
|
+
})
|
|
141
|
+
] }),
|
|
142
|
+
/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
|
|
143
|
+
htmlFor: "team-description",
|
|
144
|
+
className: "text-sm font-medium",
|
|
145
|
+
children: "Description"
|
|
146
|
+
}), /* @__PURE__ */ m("textarea", {
|
|
147
|
+
id: "team-description",
|
|
148
|
+
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]",
|
|
149
|
+
value: M.description,
|
|
150
|
+
onChange: (e) => N({
|
|
151
|
+
...M,
|
|
152
|
+
description: e.target.value
|
|
153
|
+
}),
|
|
154
|
+
placeholder: "Describe the team's mission and responsibilities..."
|
|
155
|
+
})] }),
|
|
156
|
+
/* @__PURE__ */ h("div", {
|
|
157
|
+
className: "grid grid-cols-2 gap-4",
|
|
158
|
+
children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
|
|
159
|
+
htmlFor: "team-lead",
|
|
160
|
+
className: "text-sm font-medium",
|
|
161
|
+
children: "Team Lead"
|
|
162
|
+
}), /* @__PURE__ */ m("div", {
|
|
163
|
+
className: "mt-1",
|
|
164
|
+
children: /* @__PURE__ */ m(r, {
|
|
165
|
+
id: "team-lead",
|
|
166
|
+
value: M.leadId,
|
|
167
|
+
onChange: (e) => N({
|
|
168
|
+
...M,
|
|
169
|
+
leadId: e
|
|
170
|
+
}),
|
|
171
|
+
noneLabel: "No lead"
|
|
172
|
+
})
|
|
173
|
+
})] }), /* @__PURE__ */ h("div", { children: [
|
|
174
|
+
/* @__PURE__ */ m("label", {
|
|
175
|
+
htmlFor: "team-capacity",
|
|
176
|
+
className: "text-sm font-medium",
|
|
177
|
+
children: "Capacity (story points)"
|
|
178
|
+
}),
|
|
179
|
+
/* @__PURE__ */ m(x, {
|
|
180
|
+
id: "team-capacity",
|
|
181
|
+
type: "number",
|
|
182
|
+
min: 0,
|
|
183
|
+
step: 1,
|
|
184
|
+
value: M.capacity,
|
|
185
|
+
onChange: (e) => N({
|
|
186
|
+
...M,
|
|
187
|
+
capacity: e.target.value
|
|
188
|
+
}),
|
|
189
|
+
"aria-invalid": R.invalid,
|
|
190
|
+
className: "mt-1",
|
|
191
|
+
placeholder: "e.g. 60"
|
|
192
|
+
}),
|
|
193
|
+
R.invalid && /* @__PURE__ */ m("p", {
|
|
194
|
+
role: "alert",
|
|
195
|
+
className: "mt-1 text-xs text-destructive",
|
|
196
|
+
children: "Capacity must be a whole number, 0 or more."
|
|
197
|
+
})
|
|
198
|
+
] })]
|
|
199
|
+
})
|
|
200
|
+
]
|
|
201
|
+
})] })
|
|
202
|
+
]
|
|
203
|
+
}) : /* @__PURE__ */ m(o, {}) : /* @__PURE__ */ m("div", {
|
|
204
|
+
className: "p-6 text-muted-foreground",
|
|
205
|
+
children: "No team selected. Open one from the list."
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
export { w as TeamTeamEditPagePage };
|
|
210
|
+
|
|
211
|
+
//# sourceMappingURL=TeamTeamEditPagePage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamTeamEditPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamTeamEditPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, ArrowLeft } from 'lucide-react';\nimport { useEntityId } from '../hooks/useEntityId';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError } from '../utils/mutationResult';\nimport { parseIntField } from '../utils/formValidation';\nimport { AssigneeSelect } from '../controls/WorkItemControls';\nimport { PlanMagnetNotFoundPage } from './NotFoundPage';\n\n/** Edit a team's own fields (BOFF-8044). Members and projects are managed from the detail page. */\n\nconst GET_TEAM_FOR_EDIT = gql`\n query GetTeamForEdit($id: ID!) {\n planmagnetTeam(id: $id) {\n id\n name\n description\n leadId\n capacity\n }\n }\n`;\n\nconst UPDATE_TEAM = gql`\n mutation UpdateTeam($id: ID!, $input: PlanmagnetUpdateTeamInput!) {\n planmagnetUpdateTeam(id: $id, input: $input) {\n id\n name\n description\n leadId\n capacity\n }\n }\n`;\n\ninterface TeamForEdit {\n id: string;\n name: string;\n description: string | null;\n leadId: string | null;\n capacity: number | null;\n}\n\nexport function TeamTeamEditPagePage() {\n const teamId = useEntityId('teamId');\n const navigate = usePlanMagnetNavigate();\n\n const { data, loading, error } = useQuery<{ planmagnetTeam: TeamForEdit | null }>(\n GET_TEAM_FOR_EDIT,\n { variables: { id: teamId }, skip: !teamId }\n );\n const team = data?.planmagnetTeam;\n\n const defaultForm = useMemo(\n () => ({\n name: team?.name ?? '',\n description: team?.description ?? '',\n leadId: team?.leadId ?? '',\n capacity: team?.capacity?.toString() ?? '',\n }),\n [team]\n );\n const [formOverrides, setFormOverrides] = useState<Record<string, string>>({});\n const form = { ...defaultForm, ...formOverrides };\n const setForm = (updates: Record<string, string>) =>\n setFormOverrides((prev) => {\n const next = { ...prev };\n for (const [key, value] of Object.entries(updates)) {\n if (value !== form[key as keyof typeof form]) next[key] = value;\n }\n return next;\n });\n\n const [saveError, setSaveError] = useState<string | null>(null);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const capacity = parseIntField(form.capacity, { min: 0 });\n const nameInvalid = form.name.trim() === '';\n const [updateTeam, { loading: saving }] = useMutation(UPDATE_TEAM, {\n refetchQueries: ['GetTeams', 'GetTeamDetail', 'GetTeamForEdit'],\n });\n\n const handleSave = async () => {\n if (!team || nameInvalid || capacity.invalid) return;\n setSaveError(null);\n setSuccessMessage(null);\n try {\n await throwOnError(\n updateTeam({\n variables: {\n id: team.id,\n input: {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n leadId: form.leadId || undefined,\n capacity: capacity.value,\n },\n },\n })\n );\n setSuccessMessage('Team updated successfully.');\n setFormOverrides({});\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The team could not be saved.');\n }\n };\n\n if (!teamId) {\n return (\n <div className=\"p-6 text-muted-foreground\">No team selected. Open one from the list.</div>\n );\n }\n // Only before the first load: a refetch must not blank the page (it\n // unmounts every component on it and loses their state).\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n }\n if (error) {\n return <div className=\"p-6 text-destructive\">Error loading team: {error.message}</div>;\n }\n if (!team) return <PlanMagnetNotFoundPage />;\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Back to the team\"\n onClick={() => navigate(detailPath('/team/team-detail-page', teamId))}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Edit Team</h1>\n <p className=\"text-sm text-muted-foreground\">{team.name}</p>\n </div>\n </div>\n <Button size=\"sm\" onClick={handleSave} disabled={saving || nameInvalid || capacity.invalid}>\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Saving...' : 'Save Changes'}\n </Button>\n </div>\n\n {successMessage && (\n <div role=\"status\" className=\"p-3 rounded-md text-sm bg-muted text-status-success-text\">\n {successMessage}\n </div>\n )}\n {saveError && (\n <div role=\"alert\" className=\"p-3 rounded-md text-sm bg-destructive/10 text-destructive\">\n Error: {saveError}\n </div>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Team Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label htmlFor=\"team-name\" className=\"text-sm font-medium\">\n Team Name\n </label>\n <Input\n id=\"team-name\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n aria-invalid={nameInvalid}\n className=\"mt-1\"\n />\n {nameInvalid && (\n <p role=\"alert\" className=\"mt-1 text-xs text-destructive\">\n Choose a name for the team.\n </p>\n )}\n </div>\n <div>\n <label htmlFor=\"team-description\" className=\"text-sm font-medium\">\n Description\n </label>\n <textarea\n id=\"team-description\"\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Describe the team's mission and responsibilities...\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label htmlFor=\"team-lead\" className=\"text-sm font-medium\">\n Team Lead\n </label>\n <div className=\"mt-1\">\n <AssigneeSelect\n id=\"team-lead\"\n value={form.leadId}\n onChange={(next) => setForm({ ...form, leadId: next })}\n noneLabel=\"No lead\"\n />\n </div>\n </div>\n <div>\n <label htmlFor=\"team-capacity\" className=\"text-sm font-medium\">\n Capacity (story points)\n </label>\n <Input\n id=\"team-capacity\"\n type=\"number\"\n min={0}\n step={1}\n value={form.capacity}\n onChange={(e) => setForm({ ...form, capacity: e.target.value })}\n aria-invalid={capacity.invalid}\n className=\"mt-1\"\n placeholder=\"e.g. 60\"\n />\n {capacity.invalid && (\n <p role=\"alert\" className=\"mt-1 text-xs text-destructive\">\n Capacity must be a whole number, 0 or more.\n </p>\n )}\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamTeamsListPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TeamTeamsListPagePage.tsx"],"names":[],"mappings":"AA6CA,wBAAgB,qBAAqB,4CA4FpC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { PersonName as n } from "../people/People.js";
|
|
3
|
+
import { detailPath as r, rowLinkProps as i } from "../utils/rowNavigation.js";
|
|
4
|
+
import { FolderKanban as a, Plus as o, UserRound as s, Users as c } from "lucide-react";
|
|
5
|
+
import { gql as l } from "@apollo/client";
|
|
6
|
+
import { useQuery as u } from "@apollo/client/react";
|
|
7
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
8
|
+
import { Button as p, Card as m, CardContent as h, CardHeader as g, CardTitle as _ } from "@burdenoff/fe-libs/ui";
|
|
9
|
+
//#region src/planmagnet/pages/TeamTeamsListPagePage.tsx
|
|
10
|
+
var v = l`
|
|
11
|
+
query GetTeams($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {
|
|
12
|
+
planmagnetTeams(workspaceId: $workspaceId, pagination: $pagination) {
|
|
13
|
+
items {
|
|
14
|
+
id
|
|
15
|
+
name
|
|
16
|
+
description
|
|
17
|
+
leadId
|
|
18
|
+
capacity
|
|
19
|
+
members {
|
|
20
|
+
id
|
|
21
|
+
}
|
|
22
|
+
projects {
|
|
23
|
+
id
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
totalCount
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
function y() {
|
|
31
|
+
let { workspaceId: l } = e(), y = t(), { data: b, loading: x, error: S } = u(v, {
|
|
32
|
+
variables: {
|
|
33
|
+
workspaceId: l ?? "",
|
|
34
|
+
pagination: { first: 100 }
|
|
35
|
+
},
|
|
36
|
+
skip: !l
|
|
37
|
+
}), C = b?.planmagnetTeams.items ?? [];
|
|
38
|
+
return x && !b ? /* @__PURE__ */ d("div", {
|
|
39
|
+
className: "flex items-center justify-center p-12",
|
|
40
|
+
children: /* @__PURE__ */ d("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
41
|
+
}) : S ? /* @__PURE__ */ f("div", {
|
|
42
|
+
className: "p-6 text-destructive",
|
|
43
|
+
children: ["Error loading teams: ", S.message]
|
|
44
|
+
}) : /* @__PURE__ */ f("div", {
|
|
45
|
+
className: "space-y-6 p-6",
|
|
46
|
+
children: [/* @__PURE__ */ f("div", {
|
|
47
|
+
className: "flex items-center justify-between",
|
|
48
|
+
children: [/* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("h1", {
|
|
49
|
+
className: "text-2xl font-semibold",
|
|
50
|
+
children: "Teams"
|
|
51
|
+
}), /* @__PURE__ */ f("p", {
|
|
52
|
+
className: "text-sm text-muted-foreground",
|
|
53
|
+
children: [
|
|
54
|
+
b?.planmagnetTeams.totalCount ?? C.length,
|
|
55
|
+
" team",
|
|
56
|
+
(b?.planmagnetTeams.totalCount ?? C.length) === 1 ? "" : "s"
|
|
57
|
+
]
|
|
58
|
+
})] }), /* @__PURE__ */ f(p, {
|
|
59
|
+
size: "sm",
|
|
60
|
+
"data-testid": "team-create",
|
|
61
|
+
onClick: () => y("/team/create-team-page"),
|
|
62
|
+
children: [/* @__PURE__ */ d(o, { className: "mr-1 h-4 w-4" }), "New team"]
|
|
63
|
+
})]
|
|
64
|
+
}), C.length === 0 ? /* @__PURE__ */ d("p", {
|
|
65
|
+
className: "text-sm text-muted-foreground text-center py-12",
|
|
66
|
+
children: "No teams yet — create one to group projects and track cross-project sprints."
|
|
67
|
+
}) : /* @__PURE__ */ d("div", {
|
|
68
|
+
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
|
|
69
|
+
children: C.map((e) => /* @__PURE__ */ f(m, {
|
|
70
|
+
"data-testid": "team-row",
|
|
71
|
+
...i(() => y(r("/team/team-detail-page", e.id)), e.name),
|
|
72
|
+
children: [/* @__PURE__ */ d(g, {
|
|
73
|
+
className: "pb-2",
|
|
74
|
+
children: /* @__PURE__ */ f(_, {
|
|
75
|
+
className: "text-base flex items-center gap-2",
|
|
76
|
+
children: [/* @__PURE__ */ d(c, { className: "h-4 w-4 text-primary" }), e.name]
|
|
77
|
+
})
|
|
78
|
+
}), /* @__PURE__ */ f(h, {
|
|
79
|
+
className: "space-y-2",
|
|
80
|
+
children: [/* @__PURE__ */ d("p", {
|
|
81
|
+
className: "text-sm text-muted-foreground line-clamp-2",
|
|
82
|
+
children: e.description ?? "No description"
|
|
83
|
+
}), /* @__PURE__ */ f("div", {
|
|
84
|
+
className: "flex items-center gap-4 text-xs text-muted-foreground",
|
|
85
|
+
children: [
|
|
86
|
+
/* @__PURE__ */ f("span", {
|
|
87
|
+
className: "flex items-center gap-1",
|
|
88
|
+
children: [/* @__PURE__ */ d(s, { className: "h-3 w-3" }), e.leadId ? /* @__PURE__ */ d(n, { id: e.leadId }) : "No lead"]
|
|
89
|
+
}),
|
|
90
|
+
/* @__PURE__ */ f("span", {
|
|
91
|
+
className: "flex items-center gap-1",
|
|
92
|
+
children: [
|
|
93
|
+
/* @__PURE__ */ d(c, { className: "h-3 w-3" }),
|
|
94
|
+
e.members.length,
|
|
95
|
+
" member",
|
|
96
|
+
e.members.length === 1 ? "" : "s"
|
|
97
|
+
]
|
|
98
|
+
}),
|
|
99
|
+
/* @__PURE__ */ f("span", {
|
|
100
|
+
className: "flex items-center gap-1",
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ d(a, { className: "h-3 w-3" }),
|
|
103
|
+
e.projects.length,
|
|
104
|
+
" project",
|
|
105
|
+
e.projects.length === 1 ? "" : "s"
|
|
106
|
+
]
|
|
107
|
+
})
|
|
108
|
+
]
|
|
109
|
+
})]
|
|
110
|
+
})]
|
|
111
|
+
}, e.id))
|
|
112
|
+
})]
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
export { y as TeamTeamsListPagePage };
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=TeamTeamsListPagePage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TeamTeamsListPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamTeamsListPagePage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Button, Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { Plus, Users, FolderKanban, UserRound } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps, detailPath } from '../utils/rowNavigation';\nimport { PersonName } from '../people/People';\n\n/**\n * Teams list (BOFF-8044). A Team is a first-class, cross-project entity — members, a lead, capacity, and the\n * projects it can draw team-sprint work from. This replaces the old mislabelled \"Team\" nav entry, which was\n * really the workspace roster (kept, relabelled \"Members\" — see PlanMagnetRoot.tsx).\n */\n\nconst GET_TEAMS = gql`\n query GetTeams($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetTeams(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n description\n leadId\n capacity\n members {\n id\n }\n projects {\n id\n }\n }\n totalCount\n }\n }\n`;\n\ninterface TeamListItem {\n id: string;\n name: string;\n description: string | null;\n leadId: string | null;\n capacity: number | null;\n members: { id: string }[];\n projects: { id: string }[];\n}\n\nexport function TeamTeamsListPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const { data, loading, error } = useQuery<{\n planmagnetTeams: { items: TeamListItem[]; totalCount: number };\n }>(GET_TEAMS, {\n variables: { workspaceId: workspaceId ?? '', pagination: { first: 100 } },\n skip: !workspaceId,\n });\n\n const teams = data?.planmagnetTeams.items ?? [];\n\n // Only before the first load: a refetch must not blank the page (it\n // unmounts every component on it and loses their state).\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full\" />\n </div>\n );\n }\n if (error) {\n return <div className=\"p-6 text-destructive\">Error loading teams: {error.message}</div>;\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Teams</h1>\n <p className=\"text-sm text-muted-foreground\">\n {data?.planmagnetTeams.totalCount ?? teams.length} team\n {(data?.planmagnetTeams.totalCount ?? teams.length) === 1 ? '' : 's'}\n </p>\n </div>\n <Button\n size=\"sm\"\n data-testid=\"team-create\"\n onClick={() => navigate('/team/create-team-page')}\n >\n <Plus className=\"mr-1 h-4 w-4\" />\n New team\n </Button>\n </div>\n\n {teams.length === 0 ? (\n <p className=\"text-sm text-muted-foreground text-center py-12\">\n No teams yet — create one to group projects and track cross-project sprints.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {teams.map((team) => (\n <Card\n key={team.id}\n data-testid=\"team-row\"\n {...rowLinkProps(\n () => navigate(detailPath('/team/team-detail-page', team.id)),\n team.name\n )}\n >\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-base flex items-center gap-2\">\n <Users className=\"h-4 w-4 text-primary\" />\n {team.name}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground line-clamp-2\">\n {team.description ?? 'No description'}\n </p>\n <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n <span className=\"flex items-center gap-1\">\n <UserRound className=\"h-3 w-3\" />\n {team.leadId ? <PersonName id={team.leadId} /> : 'No lead'}\n </span>\n <span className=\"flex items-center gap-1\">\n <Users className=\"h-3 w-3\" />\n {team.members.length} member{team.members.length === 1 ? '' : 's'}\n </span>\n <span className=\"flex items-center gap-1\">\n <FolderKanban className=\"h-3 w-3\" />\n {team.projects.length} project{team.projects.length === 1 ? '' : 's'}\n </span>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAcA,IAAM,IAAY,CAAG;;;;;;;;;;;;;;;;;;;;AA+BrB,SAAgB,IAAwB;CACtC,IAAM,EAAE,mBAAgB,GAAe,EACjC,IAAW,GAAuB,EAElC,EAAE,SAAM,YAAS,aAAU,EAE9B,GAAW;EACZ,WAAW;GAAE,aAAa,KAAe;GAAI,YAAY,EAAE,OAAO,KAAK;GAAE;EACzE,MAAM,CAAC;EACR,CAAC,EAEI,IAAQ,GAAM,gBAAgB,SAAS,EAAE;AAe/C,QAXI,KAAW,CAAC,IAEZ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD,EAAK,WAAU,kFAAmF,CAAA;EAC9F,CAAA,GAGN,IACK,kBAAC,OAAD;EAAK,WAAU;YAAf,CAAsC,yBAAsB,EAAM,QAAc;MAIvF,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cAAyB;IAAU,CAAA,EACjD,kBAAC,KAAD;IAAG,WAAU;cAAb;KACG,GAAM,gBAAgB,cAAc,EAAM;KAAO;MAChD,GAAM,gBAAgB,cAAc,EAAM,YAAY,IAAI,KAAK;KAC/D;MACA,EAAA,CAAA,EACN,kBAAC,GAAD;IACE,MAAK;IACL,eAAY;IACZ,eAAe,EAAS,yBAAyB;cAHnD,CAKE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,WAE1B;MACL;MAEL,EAAM,WAAW,IAChB,kBAAC,KAAD;GAAG,WAAU;aAAkD;GAE3D,CAAA,GAEJ,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,MACV,kBAAC,GAAD;IAEE,eAAY;IACZ,GAAI,QACI,EAAS,EAAW,0BAA0B,EAAK,GAAG,CAAC,EAC7D,EAAK,KACN;cANH,CAQE,kBAAC,GAAD;KAAY,WAAU;eACpB,kBAAC,GAAD;MAAW,WAAU;gBAArB,CACE,kBAAC,GAAD,EAAO,WAAU,wBAAyB,CAAA,EACzC,EAAK,KACI;;KACD,CAAA,EACb,kBAAC,GAAD;KAAa,WAAU;eAAvB,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAK,eAAe;MACnB,CAAA,EACJ,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CACE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAChC,EAAK,SAAS,kBAAC,GAAD,EAAY,IAAI,EAAK,QAAU,CAAA,GAAG,UAC5C;;OACP,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;SAC5B,EAAK,QAAQ;SAAO;SAAQ,EAAK,QAAQ,WAAW,IAAI,KAAK;SACzD;;OACP,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;SACnC,EAAK,SAAS;SAAO;SAAS,EAAK,SAAS,WAAW,IAAI,KAAK;SAC5D;;OACH;QACM;OACT;MAhCA,EAAK,GAgCL,CACP;GACE,CAAA,CAEJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplatesEditTemplatePagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TemplatesEditTemplatePagePage.tsx"],"names":[],"mappings":"AAoHA,wBAAgB,6BAA6B,4CAmQ5C"}
|