@burdenoff/microfe-planmagnet 2026.924.2 → 2026.924.3

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.
Files changed (68) hide show
  1. package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
  2. package/dist/planmagnet/PlanMagnetRoot.js +93 -142
  3. package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
  4. package/dist/planmagnet/admin/PlanMagnetAdminRoot.d.ts.map +1 -1
  5. package/dist/planmagnet/admin/PlanMagnetAdminRoot.js +150 -149
  6. package/dist/planmagnet/admin/PlanMagnetAdminRoot.js.map +1 -1
  7. package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +1 -1
  8. package/dist/planmagnet/pages/DashboardDashboardPagePage.js +113 -116
  9. package/dist/planmagnet/pages/DashboardDashboardPagePage.js.map +1 -1
  10. package/dist/planmagnet/pages/GoalsGoalsPagePage.d.ts.map +1 -1
  11. package/dist/planmagnet/pages/GoalsGoalsPagePage.js +59 -58
  12. package/dist/planmagnet/pages/GoalsGoalsPagePage.js.map +1 -1
  13. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.d.ts.map +1 -1
  14. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js +150 -149
  15. package/dist/planmagnet/pages/GoalsObjectiveDetailPagePage.js.map +1 -1
  16. package/dist/planmagnet/pages/ProductsEditProductPagePage.d.ts.map +1 -1
  17. package/dist/planmagnet/pages/ProductsEditProductPagePage.js +108 -107
  18. package/dist/planmagnet/pages/ProductsEditProductPagePage.js.map +1 -1
  19. package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
  20. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +93 -92
  21. package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
  22. package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
  23. package/dist/planmagnet/pages/ProductsProductsPagePage.js +89 -87
  24. package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
  25. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +1 -1
  26. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +94 -93
  27. package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
  28. package/dist/planmagnet/pages/ProductsReleasesPagePage.d.ts.map +1 -1
  29. package/dist/planmagnet/pages/ProductsReleasesPagePage.js +57 -56
  30. package/dist/planmagnet/pages/ProductsReleasesPagePage.js.map +1 -1
  31. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
  32. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +82 -81
  33. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
  34. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts.map +1 -1
  35. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js +72 -71
  36. package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js.map +1 -1
  37. package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.d.ts.map +1 -1
  38. package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js +38 -37
  39. package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js.map +1 -1
  40. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +1 -1
  41. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +72 -71
  42. package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js.map +1 -1
  43. package/dist/planmagnet/pages/ProjectsMilestonesPagePage.d.ts.map +1 -1
  44. package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js +47 -46
  45. package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js.map +1 -1
  46. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
  47. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +120 -119
  48. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
  49. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
  50. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +131 -130
  51. package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
  52. package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
  53. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +77 -75
  54. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
  55. package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +1 -1
  56. package/dist/planmagnet/pages/ReportsReportsPagePage.js +71 -70
  57. package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
  58. package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
  59. package/dist/planmagnet/pages/TeamTeamPagePage.js +58 -57
  60. package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
  61. package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.d.ts.map +1 -1
  62. package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.js +81 -72
  63. package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.js.map +1 -1
  64. package/dist/planmagnet/people/People.d.ts +20 -0
  65. package/dist/planmagnet/people/People.d.ts.map +1 -0
  66. package/dist/planmagnet/people/People.js +42 -0
  67. package/dist/planmagnet/people/People.js.map +1 -0
  68. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PlanMagnetAdminRoot.js","names":[],"sources":["../../../src/planmagnet/admin/PlanMagnetAdminRoot.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Checkbox,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { AlertCircle, Archive, FolderKanban, LayoutTemplate, Loader2, Zap } from 'lucide-react';\n\nimport { PlanMagnetProvider, usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { cn } from '../utils/cn';\nimport type { PlanMagnetRootProps } from '../types';\n\n// ------------------------------------------------------------------------------\n// Domain types (mirror the planmagnet subgraph until generated types are fixed)\n// ------------------------------------------------------------------------------\n\ntype ProjectStatus = 'ACTIVE' | 'ARCHIVED' | 'CANCELLED' | 'COMPLETED' | 'ON_HOLD' | 'PLANNING';\n\ninterface AdminProject {\n id: string;\n name: string;\n key: string;\n status: ProjectStatus;\n methodology: string;\n ownerId: string;\n createdAt: string;\n}\n\ninterface AdminBoard {\n id: string;\n name: string;\n type: string;\n projectId?: string | null;\n}\n\ninterface AdminAutomationRule {\n id: string;\n name: string;\n status: string;\n triggerType: string;\n executionCount: number;\n lastExecutedAt?: string | null;\n createdAt: string;\n}\n\n// ------------------------------------------------------------------------------\n// GraphQL documents (inline so the admin surface does not depend on generated\n// hooks while the rest of the MFE's operation files are being reconciled with\n// the schema).\n// ------------------------------------------------------------------------------\n\nconst ADMIN_PROJECTS_QUERY = gql`\n query AdminPlanmagnetProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n key\n status\n methodology\n ownerId\n createdAt\n }\n totalCount\n }\n }\n`;\n\nconst ADMIN_BOARDS_QUERY = gql`\n query AdminPlanmagnetBoards($workspaceId: ID!) {\n planmagnetBoards(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n type\n projectId\n }\n totalCount\n }\n }\n`;\n\nconst ADMIN_AUTOMATION_RULES_QUERY = gql`\n query AdminPlanmagnetAutomationRules($workspaceId: ID!) {\n planmagnetAutomationRules(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n status\n triggerType\n executionCount\n lastExecutedAt\n createdAt\n }\n totalCount\n }\n }\n`;\n\nconst ARCHIVE_PROJECT_MUTATION = gql`\n mutation AdminArchiveProjectr($id: ID!) {\n planmagnetUpdateProjectr(id: $id, input: { status: ARCHIVED }) {\n id\n status\n }\n }\n`;\n\n// ------------------------------------------------------------------------------\n// Presentation helpers\n// ------------------------------------------------------------------------------\n\nfunction projectStatusVariantr(status: ProjectStatus) {\n switch (status) {\n case 'ACTIVE':\n return 'success';\n case 'ARCHIVED':\n return 'secondary';\n case 'CANCELLED':\n return 'destructive';\n case 'COMPLETED':\n return 'info';\n case 'ON_HOLD':\n return 'warning';\n case 'PLANNING':\n return 'outline';\n default:\n return 'default';\n }\n}\n\nfunction automationStatusVariantr(status: string) {\n switch (status) {\n case 'ACTIVE':\n return 'success';\n case 'PAUSED':\n return 'warning';\n case 'ERROR':\n return 'destructive';\n case 'DISABLED':\n return 'secondary';\n default:\n return 'default';\n }\n}\n\nfunction formatDate(value: string | null | undefined) {\n if (!value) return '—';\n try {\n return new Date(value).toLocaleDateString();\n } catch {\n return value;\n }\n}\n\nfunction localizeMethodology(value: string) {\n return value.toLowerCase().replace(/_/g, ' ');\n}\n\nfunction localizeTrigger(value: string) {\n return value.toLowerCase().replace(/_/g, ' ');\n}\n\n// ------------------------------------------------------------------------------\n// Sub-components\n// ------------------------------------------------------------------------------\n\nfunction QuotaCard({\n icon: Icon,\n label,\n used,\n limit,\n className,\n}: {\n icon: React.ComponentType<{ className?: string }>;\n label: string;\n used: number;\n limit: number;\n className?: string;\n}) {\n const percentage = Math.min(100, Math.round((used / Math.max(1, limit)) * 100));\n\n return (\n <Card className={className}>\n <CardContent className=\"pt-6\">\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Icon className=\"h-4 w-4\" />\n <span className=\"text-sm\">{label}</span>\n </div>\n <div className=\"mt-2 flex items-baseline gap-2\">\n <span className=\"text-2xl font-semibold\">{used}</span>\n <span className=\"text-sm text-muted-foreground\">/ {limit}</span>\n </div>\n <div className=\"mt-3 h-2 w-full overflow-hidden rounded-full bg-muted\">\n <div\n className={cn(\n 'h-full rounded-full transition-all',\n percentage >= 90 ? 'bg-destructive' : percentage >= 70 ? 'bg-warning' : 'bg-success'\n )}\n style={{ width: `${percentage}%` }}\n />\n </div>\n <p className=\"mt-2 text-xs text-muted-foreground\">{percentage}% used</p>\n </CardContent>\n </Card>\n );\n}\n\nfunction SectionLoader() {\n return (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-8 w-1/3\" />\n <Skeleton className=\"h-32 w-full\" />\n </div>\n );\n}\n\ninterface SimpleTableColumn<T> {\n key: string;\n header: React.ReactNode;\n cell: (row: T) => React.ReactNode;\n className?: string;\n}\n\nfunction SimpleTable<T extends { id: string }>({\n columns,\n data,\n emptyState,\n}: {\n columns: SimpleTableColumn<T>[];\n data: T[];\n emptyState: React.ReactNode;\n}) {\n if (data.length === 0) {\n return <div className=\"py-8 text-center text-sm text-muted-foreground\">{emptyState}</div>;\n }\n\n return (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-muted/50\">\n <tr>\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n 'px-4 py-3 text-left font-medium text-muted-foreground',\n column.className\n )}\n >\n {column.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"divide-y\">\n {data.map((row) => (\n <tr key={row.id} className=\"hover:bg-muted/30\">\n {columns.map((column) => (\n <td key={`${row.id}-${column.key}`} className={cn('px-4 py-3', column.className)}>\n {column.cell(row)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n// ------------------------------------------------------------------------------\n// Main dashboard\n// ------------------------------------------------------------------------------\n\nfunction PlanMagnetAdminDashboard() {\n const { workspaceId } = usePlanMagnet();\n const tr = useTr();\n\n const [selectedProjectIds, setSelectedProjectIds] = useState<Set<string>>(new Set());\n const [archiving, setArchiving] = useState(false);\n const [archiveError, setArchiveError] = useState<string | null>(null);\n\n const projectsQuery = useQuery<{\n planmagnetProjects: { items: AdminProject[]; totalCount: number };\n }>(ADMIN_PROJECTS_QUERY, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !workspaceId,\n });\n\n const boardsQuery = useQuery<{\n planmagnetBoards: { items: AdminBoard[]; totalCount: number };\n }>(ADMIN_BOARDS_QUERY, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !workspaceId,\n });\n\n const rulesQuery = useQuery<{\n planmagnetAutomationRules: { items: AdminAutomationRule[]; totalCount: number };\n }>(ADMIN_AUTOMATION_RULES_QUERY, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !workspaceId,\n });\n\n const [archiveProject] = useMutation(ARCHIVE_PROJECT_MUTATION);\n\n const projects = projectsQuery.data?.planmagnetProjects.items ?? [];\n const boards = boardsQuery.data?.planmagnetBoards.items ?? [];\n const rules = rulesQuery.data?.planmagnetAutomationRules.items ?? [];\n\n const activeProjects = useMemo(\n () => projects.filter((project) => project.status === 'ACTIVE'),\n [projects]\n );\n\n const toggleProjectSelection = (id: string) => {\n setSelectedProjectIds((previous) => {\n const next = new Set(previous);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n };\n\n const toggleAll = () => {\n const selectable = activeProjects.filter((project) => project.status !== 'ARCHIVED');\n if (selectedProjectIds.size === selectable.length) {\n setSelectedProjectIds(new Set());\n } else {\n setSelectedProjectIds(new Set(selectable.map((project) => project.id)));\n }\n };\n\n const handleBulkArchive = async () => {\n if (selectedProjectIds.size === 0) return;\n setArchiving(true);\n setArchiveError(null);\n try {\n await Promise.all(\n Array.from(selectedProjectIds).map((id) => archiveProject({ variables: { id } }))\n );\n await projectsQuery.refetch();\n setSelectedProjectIds(new Set());\n } catch (error) {\n setArchiveError(\n error instanceof Error\n ? error.message\n : tr('planmagnet.admin.archive.unknownError', 'Bulk archive failed')\n );\n } finally {\n setArchiving(false);\n }\n };\n\n if (!workspaceId) {\n return (\n <div className=\"min-h-screen bg-background\">\n <div className=\"flex min-h-[320px] flex-col items-center justify-center gap-3 text-muted-foreground\">\n <AlertCircle className=\"h-8 w-8\" />\n <p>\n {tr(\n 'planmagnet.admin.noWorkspace',\n 'Select a workspace to manage PlanMagnet admin settings.'\n )}\n </p>\n </div>\n </div>\n );\n }\n\n const isLoading = projectsQuery.loading || boardsQuery.loading || rulesQuery.loading;\n\n return (\n <div className=\"min-h-screen bg-background\">\n <div className=\"mx-auto max-w-7xl space-y-6 p-6\">\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n {tr('planmagnet.admin.title', 'PlanMagnet Admin')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'planmagnet.admin.purpose',\n 'Workspace quota overview, bulk project archive, and automation rule audit.'\n )}\n </p>\n </div>\n </div>\n\n {/* Quota overview — counts are real; limits are placeholder until a\n dedicated admin quota query exists in the backend. */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n <QuotaCard\n icon={FolderKanban}\n label={tr('planmagnet.admin.quota.projects', 'Projects')}\n used={projects.length}\n limit={50}\n />\n <QuotaCard\n icon={LayoutTemplate}\n label={tr('planmagnet.admin.quota.boards', 'Boards')}\n used={boards.length}\n limit={100}\n />\n <QuotaCard\n icon={Zap}\n label={tr('planmagnet.admin.quota.automationRules', 'Automation Rules')}\n used={rules.length}\n limit={25}\n />\n </div>\n\n {isLoading ? (\n <SectionLoader />\n ) : (\n <>\n {/* Bulk project archive */}\n <Card>\n <CardHeader className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <CardTitle>\n {tr('planmagnet.admin.archive.title', 'Bulk Project Archive')}\n </CardTitle>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'planmagnet.admin.archive.subtitle',\n 'Select active projects and archive them in one action.'\n )}\n </p>\n </div>\n <Button\n size=\"sm\"\n variant=\"destructive\"\n disabled={selectedProjectIds.size === 0 || archiving}\n onClick={handleBulkArchive}\n >\n {archiving ? (\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n ) : (\n <Archive className=\"mr-2 h-4 w-4\" />\n )}\n {tr('planmagnet.admin.archive.action', 'Archive')} ({selectedProjectIds.size})\n </Button>\n </CardHeader>\n <CardContent>\n {archiveError && (\n <div className=\"mb-4 flex items-center gap-2 rounded-md bg-destructive/10 p-3 text-sm text-destructive\">\n <AlertCircle className=\"h-4 w-4\" />\n {archiveError}\n </div>\n )}\n <div className=\"rounded-md border\">\n <SimpleTable<AdminProject>\n data={activeProjects}\n columns={[\n {\n key: 'select',\n header: (\n <Checkbox\n checked={\n activeProjects.length > 0 &&\n selectedProjectIds.size === activeProjects.length\n }\n onCheckedChange={toggleAll}\n aria-label={tr(\n 'planmagnet.admin.archive.selectAll',\n 'Select all active projects'\n )}\n />\n ),\n cell: (row) => (\n <Checkbox\n checked={selectedProjectIds.has(row.id)}\n onCheckedChange={() => toggleProjectSelection(row.id)}\n aria-label={tr(\n 'planmagnet.admin.archive.selectProject',\n 'Select project'\n )}\n />\n ),\n className: 'w-12',\n },\n {\n key: 'name',\n header: tr('planmagnet.admin.archive.column.name', 'Project'),\n cell: (row) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.name}</span>\n <span className=\"text-xs text-muted-foreground font-mono\">\n {row.key}\n </span>\n </div>\n ),\n },\n {\n key: 'status',\n header: tr('planmagnet.admin.archive.column.status', 'Status'),\n cell: (row) => (\n <Badge variant={projectStatusVariantr(row.status)}>\n {row.status.toLowerCase().replace('_', ' ')}\n </Badge>\n ),\n },\n {\n key: 'methodology',\n header: tr('planmagnet.admin.archive.column.methodology', 'Methodology'),\n cell: (row) => (\n <span className=\"text-sm capitalize\">\n {localizeMethodology(row.methodology)}\n </span>\n ),\n },\n {\n key: 'owner',\n header: tr('planmagnet.admin.archive.column.owner', 'Owner'),\n cell: (row) => (\n <span className=\"text-sm text-muted-foreground font-mono\">\n {row.ownerId}\n </span>\n ),\n },\n {\n key: 'created',\n header: tr('planmagnet.admin.archive.column.created', 'Created'),\n cell: (row) => <span className=\"text-sm\">{formatDate(row.createdAt)}</span>,\n },\n ]}\n emptyState={tr(\n 'planmagnet.admin.archive.empty',\n 'No active projects to archive.'\n )}\n />\n </div>\n </CardContent>\n </Card>\n\n {/* Automation rule audit */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tr('planmagnet.admin.automation.title', 'Automation Rule Audit')}\n </CardTitle>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'planmagnet.admin.automation.subtitle',\n 'Review rule health, execution counts, and last run timestamps.'\n )}\n </p>\n </CardHeader>\n <CardContent>\n <div className=\"rounded-md border\">\n <SimpleTable<AdminAutomationRule>\n data={rules}\n columns={[\n {\n key: 'name',\n header: tr('planmagnet.admin.automation.column.name', 'Rule'),\n cell: (row) => <span className=\"font-medium\">{row.name}</span>,\n },\n {\n key: 'trigger',\n header: tr('planmagnet.admin.automation.column.trigger', 'Trigger'),\n cell: (row) => (\n <span className=\"text-sm\">{localizeTrigger(row.triggerType)}</span>\n ),\n },\n {\n key: 'status',\n header: tr('planmagnet.admin.automation.column.status', 'Status'),\n cell: (row) => (\n <Badge variant={automationStatusVariantr(row.status)}>\n {row.status.toLowerCase()}\n </Badge>\n ),\n },\n {\n key: 'executions',\n header: tr('planmagnet.admin.automation.column.executions', 'Executions'),\n cell: (row) => <span className=\"text-sm\">{row.executionCount}</span>,\n },\n {\n key: 'lastRun',\n header: tr('planmagnet.admin.automation.column.lastRun', 'Last Run'),\n cell: (row) => (\n <span className=\"text-sm\">{formatDate(row.lastExecutedAt)}</span>\n ),\n },\n {\n key: 'created',\n header: tr('planmagnet.admin.automation.column.created', 'Created'),\n cell: (row) => <span className=\"text-sm\">{formatDate(row.createdAt)}</span>,\n },\n ]}\n emptyState={tr(\n 'planmagnet.admin.automation.empty',\n 'No automation rules found.'\n )}\n />\n </div>\n </CardContent>\n </Card>\n </>\n )}\n </div>\n </div>\n );\n}\n\n// ------------------------------------------------------------------------------\n// Public root export consumed by the admin app shell\n// ------------------------------------------------------------------------------\n\nexport function PlanMagnetAdminRoot(props: PlanMagnetRootProps) {\n return (\n <PlanMagnetProvider {...props}>\n <PlanMagnetAdminDashboard />\n </PlanMagnetProvider>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PlanMagnetAdminRoot.js","names":[],"sources":["../../../src/planmagnet/admin/PlanMagnetAdminRoot.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Checkbox,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { AlertCircle, Archive, FolderKanban, LayoutTemplate, Loader2, Zap } from 'lucide-react';\n\nimport { PlanMagnetProvider, usePlanMagnet } from '../providers/PlanMagnetProvider';\nimport { cn } from '../utils/cn';\nimport type { PlanMagnetRootProps } from '../types';\nimport { PersonName } from '../people/People';\n\n// ------------------------------------------------------------------------------\n// Domain types (mirror the planmagnet subgraph until generated types are fixed)\n// ------------------------------------------------------------------------------\n\ntype ProjectStatus = 'ACTIVE' | 'ARCHIVED' | 'CANCELLED' | 'COMPLETED' | 'ON_HOLD' | 'PLANNING';\n\ninterface AdminProject {\n id: string;\n name: string;\n key: string;\n status: ProjectStatus;\n methodology: string;\n ownerId: string;\n createdAt: string;\n}\n\ninterface AdminBoard {\n id: string;\n name: string;\n type: string;\n projectId?: string | null;\n}\n\ninterface AdminAutomationRule {\n id: string;\n name: string;\n status: string;\n triggerType: string;\n executionCount: number;\n lastExecutedAt?: string | null;\n createdAt: string;\n}\n\n// ------------------------------------------------------------------------------\n// GraphQL documents (inline so the admin surface does not depend on generated\n// hooks while the rest of the MFE's operation files are being reconciled with\n// the schema).\n// ------------------------------------------------------------------------------\n\nconst ADMIN_PROJECTS_QUERY = gql`\n query AdminPlanmagnetProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n key\n status\n methodology\n ownerId\n createdAt\n }\n totalCount\n }\n }\n`;\n\nconst ADMIN_BOARDS_QUERY = gql`\n query AdminPlanmagnetBoards($workspaceId: ID!) {\n planmagnetBoards(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n type\n projectId\n }\n totalCount\n }\n }\n`;\n\nconst ADMIN_AUTOMATION_RULES_QUERY = gql`\n query AdminPlanmagnetAutomationRules($workspaceId: ID!) {\n planmagnetAutomationRules(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n status\n triggerType\n executionCount\n lastExecutedAt\n createdAt\n }\n totalCount\n }\n }\n`;\n\nconst ARCHIVE_PROJECT_MUTATION = gql`\n mutation AdminArchiveProjectr($id: ID!) {\n planmagnetUpdateProjectr(id: $id, input: { status: ARCHIVED }) {\n id\n status\n }\n }\n`;\n\n// ------------------------------------------------------------------------------\n// Presentation helpers\n// ------------------------------------------------------------------------------\n\nfunction projectStatusVariantr(status: ProjectStatus) {\n switch (status) {\n case 'ACTIVE':\n return 'success';\n case 'ARCHIVED':\n return 'secondary';\n case 'CANCELLED':\n return 'destructive';\n case 'COMPLETED':\n return 'info';\n case 'ON_HOLD':\n return 'warning';\n case 'PLANNING':\n return 'outline';\n default:\n return 'default';\n }\n}\n\nfunction automationStatusVariantr(status: string) {\n switch (status) {\n case 'ACTIVE':\n return 'success';\n case 'PAUSED':\n return 'warning';\n case 'ERROR':\n return 'destructive';\n case 'DISABLED':\n return 'secondary';\n default:\n return 'default';\n }\n}\n\nfunction formatDate(value: string | null | undefined) {\n if (!value) return '—';\n try {\n return new Date(value).toLocaleDateString();\n } catch {\n return value;\n }\n}\n\nfunction localizeMethodology(value: string) {\n return value.toLowerCase().replace(/_/g, ' ');\n}\n\nfunction localizeTrigger(value: string) {\n return value.toLowerCase().replace(/_/g, ' ');\n}\n\n// ------------------------------------------------------------------------------\n// Sub-components\n// ------------------------------------------------------------------------------\n\nfunction QuotaCard({\n icon: Icon,\n label,\n used,\n limit,\n className,\n}: {\n icon: React.ComponentType<{ className?: string }>;\n label: string;\n used: number;\n limit: number;\n className?: string;\n}) {\n const percentage = Math.min(100, Math.round((used / Math.max(1, limit)) * 100));\n\n return (\n <Card className={className}>\n <CardContent className=\"pt-6\">\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Icon className=\"h-4 w-4\" />\n <span className=\"text-sm\">{label}</span>\n </div>\n <div className=\"mt-2 flex items-baseline gap-2\">\n <span className=\"text-2xl font-semibold\">{used}</span>\n <span className=\"text-sm text-muted-foreground\">/ {limit}</span>\n </div>\n <div className=\"mt-3 h-2 w-full overflow-hidden rounded-full bg-muted\">\n <div\n className={cn(\n 'h-full rounded-full transition-all',\n percentage >= 90 ? 'bg-destructive' : percentage >= 70 ? 'bg-warning' : 'bg-success'\n )}\n style={{ width: `${percentage}%` }}\n />\n </div>\n <p className=\"mt-2 text-xs text-muted-foreground\">{percentage}% used</p>\n </CardContent>\n </Card>\n );\n}\n\nfunction SectionLoader() {\n return (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-8 w-1/3\" />\n <Skeleton className=\"h-32 w-full\" />\n </div>\n );\n}\n\ninterface SimpleTableColumn<T> {\n key: string;\n header: React.ReactNode;\n cell: (row: T) => React.ReactNode;\n className?: string;\n}\n\nfunction SimpleTable<T extends { id: string }>({\n columns,\n data,\n emptyState,\n}: {\n columns: SimpleTableColumn<T>[];\n data: T[];\n emptyState: React.ReactNode;\n}) {\n if (data.length === 0) {\n return <div className=\"py-8 text-center text-sm text-muted-foreground\">{emptyState}</div>;\n }\n\n return (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead className=\"bg-muted/50\">\n <tr>\n {columns.map((column) => (\n <th\n key={column.key}\n className={cn(\n 'px-4 py-3 text-left font-medium text-muted-foreground',\n column.className\n )}\n >\n {column.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"divide-y\">\n {data.map((row) => (\n <tr key={row.id} className=\"hover:bg-muted/30\">\n {columns.map((column) => (\n <td key={`${row.id}-${column.key}`} className={cn('px-4 py-3', column.className)}>\n {column.cell(row)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n// ------------------------------------------------------------------------------\n// Main dashboard\n// ------------------------------------------------------------------------------\n\nfunction PlanMagnetAdminDashboard() {\n const { workspaceId } = usePlanMagnet();\n const tr = useTr();\n\n const [selectedProjectIds, setSelectedProjectIds] = useState<Set<string>>(new Set());\n const [archiving, setArchiving] = useState(false);\n const [archiveError, setArchiveError] = useState<string | null>(null);\n\n const projectsQuery = useQuery<{\n planmagnetProjects: { items: AdminProject[]; totalCount: number };\n }>(ADMIN_PROJECTS_QUERY, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !workspaceId,\n });\n\n const boardsQuery = useQuery<{\n planmagnetBoards: { items: AdminBoard[]; totalCount: number };\n }>(ADMIN_BOARDS_QUERY, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !workspaceId,\n });\n\n const rulesQuery = useQuery<{\n planmagnetAutomationRules: { items: AdminAutomationRule[]; totalCount: number };\n }>(ADMIN_AUTOMATION_RULES_QUERY, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !workspaceId,\n });\n\n const [archiveProject] = useMutation(ARCHIVE_PROJECT_MUTATION);\n\n const projects = projectsQuery.data?.planmagnetProjects.items ?? [];\n const boards = boardsQuery.data?.planmagnetBoards.items ?? [];\n const rules = rulesQuery.data?.planmagnetAutomationRules.items ?? [];\n\n const activeProjects = useMemo(\n () => projects.filter((project) => project.status === 'ACTIVE'),\n [projects]\n );\n\n const toggleProjectSelection = (id: string) => {\n setSelectedProjectIds((previous) => {\n const next = new Set(previous);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n };\n\n const toggleAll = () => {\n const selectable = activeProjects.filter((project) => project.status !== 'ARCHIVED');\n if (selectedProjectIds.size === selectable.length) {\n setSelectedProjectIds(new Set());\n } else {\n setSelectedProjectIds(new Set(selectable.map((project) => project.id)));\n }\n };\n\n const handleBulkArchive = async () => {\n if (selectedProjectIds.size === 0) return;\n setArchiving(true);\n setArchiveError(null);\n try {\n await Promise.all(\n Array.from(selectedProjectIds).map((id) => archiveProject({ variables: { id } }))\n );\n await projectsQuery.refetch();\n setSelectedProjectIds(new Set());\n } catch (error) {\n setArchiveError(\n error instanceof Error\n ? error.message\n : tr('planmagnet.admin.archive.unknownError', 'Bulk archive failed')\n );\n } finally {\n setArchiving(false);\n }\n };\n\n if (!workspaceId) {\n return (\n <div className=\"min-h-screen bg-background\">\n <div className=\"flex min-h-[320px] flex-col items-center justify-center gap-3 text-muted-foreground\">\n <AlertCircle className=\"h-8 w-8\" />\n <p>\n {tr(\n 'planmagnet.admin.noWorkspace',\n 'Select a workspace to manage PlanMagnet admin settings.'\n )}\n </p>\n </div>\n </div>\n );\n }\n\n const isLoading = projectsQuery.loading || boardsQuery.loading || rulesQuery.loading;\n\n return (\n <div className=\"min-h-screen bg-background\">\n <div className=\"mx-auto max-w-7xl space-y-6 p-6\">\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n {tr('planmagnet.admin.title', 'PlanMagnet Admin')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'planmagnet.admin.purpose',\n 'Workspace quota overview, bulk project archive, and automation rule audit.'\n )}\n </p>\n </div>\n </div>\n\n {/* Quota overview — counts are real; limits are placeholder until a\n dedicated admin quota query exists in the backend. */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n <QuotaCard\n icon={FolderKanban}\n label={tr('planmagnet.admin.quota.projects', 'Projects')}\n used={projects.length}\n limit={50}\n />\n <QuotaCard\n icon={LayoutTemplate}\n label={tr('planmagnet.admin.quota.boards', 'Boards')}\n used={boards.length}\n limit={100}\n />\n <QuotaCard\n icon={Zap}\n label={tr('planmagnet.admin.quota.automationRules', 'Automation Rules')}\n used={rules.length}\n limit={25}\n />\n </div>\n\n {isLoading ? (\n <SectionLoader />\n ) : (\n <>\n {/* Bulk project archive */}\n <Card>\n <CardHeader className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <CardTitle>\n {tr('planmagnet.admin.archive.title', 'Bulk Project Archive')}\n </CardTitle>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'planmagnet.admin.archive.subtitle',\n 'Select active projects and archive them in one action.'\n )}\n </p>\n </div>\n <Button\n size=\"sm\"\n variant=\"destructive\"\n disabled={selectedProjectIds.size === 0 || archiving}\n onClick={handleBulkArchive}\n >\n {archiving ? (\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n ) : (\n <Archive className=\"mr-2 h-4 w-4\" />\n )}\n {tr('planmagnet.admin.archive.action', 'Archive')} ({selectedProjectIds.size})\n </Button>\n </CardHeader>\n <CardContent>\n {archiveError && (\n <div className=\"mb-4 flex items-center gap-2 rounded-md bg-destructive/10 p-3 text-sm text-destructive\">\n <AlertCircle className=\"h-4 w-4\" />\n {archiveError}\n </div>\n )}\n <div className=\"rounded-md border\">\n <SimpleTable<AdminProject>\n data={activeProjects}\n columns={[\n {\n key: 'select',\n header: (\n <Checkbox\n checked={\n activeProjects.length > 0 &&\n selectedProjectIds.size === activeProjects.length\n }\n onCheckedChange={toggleAll}\n aria-label={tr(\n 'planmagnet.admin.archive.selectAll',\n 'Select all active projects'\n )}\n />\n ),\n cell: (row) => (\n <Checkbox\n checked={selectedProjectIds.has(row.id)}\n onCheckedChange={() => toggleProjectSelection(row.id)}\n aria-label={tr(\n 'planmagnet.admin.archive.selectProject',\n 'Select project'\n )}\n />\n ),\n className: 'w-12',\n },\n {\n key: 'name',\n header: tr('planmagnet.admin.archive.column.name', 'Project'),\n cell: (row) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.name}</span>\n <span className=\"text-xs text-muted-foreground font-mono\">\n {row.key}\n </span>\n </div>\n ),\n },\n {\n key: 'status',\n header: tr('planmagnet.admin.archive.column.status', 'Status'),\n cell: (row) => (\n <Badge variant={projectStatusVariantr(row.status)}>\n {row.status.toLowerCase().replace('_', ' ')}\n </Badge>\n ),\n },\n {\n key: 'methodology',\n header: tr('planmagnet.admin.archive.column.methodology', 'Methodology'),\n cell: (row) => (\n <span className=\"text-sm capitalize\">\n {localizeMethodology(row.methodology)}\n </span>\n ),\n },\n {\n key: 'owner',\n header: tr('planmagnet.admin.archive.column.owner', 'Owner'),\n cell: (row) => (\n <span className=\"text-sm text-muted-foreground font-mono\">\n <PersonName id={row.ownerId} />\n </span>\n ),\n },\n {\n key: 'created',\n header: tr('planmagnet.admin.archive.column.created', 'Created'),\n cell: (row) => <span className=\"text-sm\">{formatDate(row.createdAt)}</span>,\n },\n ]}\n emptyState={tr(\n 'planmagnet.admin.archive.empty',\n 'No active projects to archive.'\n )}\n />\n </div>\n </CardContent>\n </Card>\n\n {/* Automation rule audit */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tr('planmagnet.admin.automation.title', 'Automation Rule Audit')}\n </CardTitle>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'planmagnet.admin.automation.subtitle',\n 'Review rule health, execution counts, and last run timestamps.'\n )}\n </p>\n </CardHeader>\n <CardContent>\n <div className=\"rounded-md border\">\n <SimpleTable<AdminAutomationRule>\n data={rules}\n columns={[\n {\n key: 'name',\n header: tr('planmagnet.admin.automation.column.name', 'Rule'),\n cell: (row) => <span className=\"font-medium\">{row.name}</span>,\n },\n {\n key: 'trigger',\n header: tr('planmagnet.admin.automation.column.trigger', 'Trigger'),\n cell: (row) => (\n <span className=\"text-sm\">{localizeTrigger(row.triggerType)}</span>\n ),\n },\n {\n key: 'status',\n header: tr('planmagnet.admin.automation.column.status', 'Status'),\n cell: (row) => (\n <Badge variant={automationStatusVariantr(row.status)}>\n {row.status.toLowerCase()}\n </Badge>\n ),\n },\n {\n key: 'executions',\n header: tr('planmagnet.admin.automation.column.executions', 'Executions'),\n cell: (row) => <span className=\"text-sm\">{row.executionCount}</span>,\n },\n {\n key: 'lastRun',\n header: tr('planmagnet.admin.automation.column.lastRun', 'Last Run'),\n cell: (row) => (\n <span className=\"text-sm\">{formatDate(row.lastExecutedAt)}</span>\n ),\n },\n {\n key: 'created',\n header: tr('planmagnet.admin.automation.column.created', 'Created'),\n cell: (row) => <span className=\"text-sm\">{formatDate(row.createdAt)}</span>,\n },\n ]}\n emptyState={tr(\n 'planmagnet.admin.automation.empty',\n 'No automation rules found.'\n )}\n />\n </div>\n </CardContent>\n </Card>\n </>\n )}\n </div>\n </div>\n );\n}\n\n// ------------------------------------------------------------------------------\n// Public root export consumed by the admin app shell\n// ------------------------------------------------------------------------------\n\nexport function PlanMagnetAdminRoot(props: PlanMagnetRootProps) {\n return (\n <PlanMagnetProvider {...props}>\n <PlanMagnetAdminDashboard />\n </PlanMagnetProvider>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardDashboardPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/DashboardDashboardPagePage.tsx"],"names":[],"mappings":"AAuFA,wBAAgB,0BAA0B,4CAwUzC"}
1
+ {"version":3,"file":"DashboardDashboardPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/DashboardDashboardPagePage.tsx"],"names":[],"mappings":"AAwFA,wBAAgB,0BAA0B,4CAyVzC"}
@@ -1,12 +1,13 @@
1
1
  import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
2
- import { AlertTriangle as t, ArrowUpRight as n, Calendar as r, CheckSquare as i, FolderKanban as a, LayoutDashboard as o, TrendingUp as s, Users as c, Zap as l } from "lucide-react";
3
- import { gql as u } from "@apollo/client";
4
- import { useQuery as d } from "@apollo/client/react";
5
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
6
- import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
- import { Badge as h, Card as g, CardContent as _, CardHeader as v, CardTitle as y } from "@burdenoff/fe-libs/ui";
2
+ import { PersonName as t } from "../people/People.js";
3
+ import { AlertTriangle as n, ArrowUpRight as r, Calendar as i, CheckSquare as a, FolderKanban as o, LayoutDashboard as s, TrendingUp as c, Users as l, Zap as u } from "lucide-react";
4
+ import { gql as d } from "@apollo/client";
5
+ import { useQuery as f } from "@apollo/client/react";
6
+ import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
7
+ import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
8
+ import { Badge as _, Card as v, CardContent as y, CardHeader as b, CardTitle as x } from "@burdenoff/fe-libs/ui";
8
9
  //#region src/planmagnet/pages/DashboardDashboardPagePage.tsx
9
- var b = u`
10
+ var S = d`
10
11
  query GetDashboardData($workspaceId: ID!) {
11
12
  planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 50 }) {
12
13
  items {
@@ -73,126 +74,126 @@ var b = u`
73
74
  }
74
75
  }
75
76
  `;
76
- function x() {
77
- let { workspaceId: u } = e(), { t: x } = m(), { data: S, loading: C, error: w } = d(b, { variables: { workspaceId: u ?? "default" } });
78
- if (C) return /* @__PURE__ */ f("div", {
77
+ function C() {
78
+ let { workspaceId: d } = e(), { t: C } = g(), { data: w, loading: T, error: E } = f(S, { variables: { workspaceId: d ?? "default" } });
79
+ if (T) return /* @__PURE__ */ m("div", {
79
80
  className: "flex items-center justify-center p-12",
80
- children: /* @__PURE__ */ f("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
81
+ children: /* @__PURE__ */ m("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
81
82
  });
82
- if (w) return /* @__PURE__ */ p("div", {
83
+ if (E) return /* @__PURE__ */ h("div", {
83
84
  className: "p-6 text-red-500",
84
85
  children: [
85
- x("planmagnet.dashboard.errorLoading", "Error loading dashboard"),
86
+ C("planmagnet.dashboard.errorLoading", "Error loading dashboard"),
86
87
  ": ",
87
- w.message
88
+ E.message
88
89
  ]
89
90
  });
90
- let T = S?.planmagnetProjects?.items ?? [], E = S?.planmagnetSprints?.items ?? [], D = S?.planmagnetMilestones?.items ?? [], O = S?.planmagnetWorkItems?.items ?? [], k = T.filter((e) => e.status === "ACTIVE");
91
- T.filter((e) => e.status === "COMPLETED");
92
- let A = E.filter((e) => e.status === "ACTIVE"), j = D.filter((e) => e.status === "PENDING" || e.status === "IN_PROGRESS").slice(0, 4), M = O.slice(0, 5), N = [
91
+ let D = w?.planmagnetProjects?.items ?? [], O = w?.planmagnetSprints?.items ?? [], k = w?.planmagnetMilestones?.items ?? [], A = w?.planmagnetWorkItems?.items ?? [], j = D.filter((e) => e.status === "ACTIVE");
92
+ D.filter((e) => e.status === "COMPLETED");
93
+ let M = O.filter((e) => e.status === "ACTIVE"), N = k.filter((e) => e.status === "PENDING" || e.status === "IN_PROGRESS").slice(0, 4), P = A.slice(0, 5), F = new Map(D.map((e) => [e.id, e.name])), I = [
93
94
  {
94
- label: x("planmagnet.dashboard.metrics.totalProjects.label", "Total Projects"),
95
- value: String(T.length),
96
- trend: `${k.length} ${x("planmagnet.dashboard.metrics.totalProjects.trend", "active")}`
95
+ label: C("planmagnet.dashboard.metrics.totalProjects.label", "Total Projects"),
96
+ value: String(D.length),
97
+ trend: `${j.length} ${C("planmagnet.dashboard.metrics.totalProjects.trend", "active")}`
97
98
  },
98
99
  {
99
- label: x("planmagnet.dashboard.metrics.activeSprints.label", "Active Sprints"),
100
- value: String(A.length),
101
- trend: `${E.length} ${x("planmagnet.dashboard.metrics.activeSprints.trend", "total")}`
100
+ label: C("planmagnet.dashboard.metrics.activeSprints.label", "Active Sprints"),
101
+ value: String(M.length),
102
+ trend: `${O.length} ${C("planmagnet.dashboard.metrics.activeSprints.trend", "total")}`
102
103
  },
103
104
  {
104
- label: x("planmagnet.dashboard.metrics.workItems.label", "Work Items"),
105
- value: String(S?.planmagnetWorkItems?.totalCount ?? 0),
106
- trend: x("planmagnet.dashboard.metrics.workItems.trend", "across all projects")
105
+ label: C("planmagnet.dashboard.metrics.workItems.label", "Work Items"),
106
+ value: String(w?.planmagnetWorkItems?.totalCount ?? 0),
107
+ trend: C("planmagnet.dashboard.metrics.workItems.trend", "across all projects")
107
108
  },
108
109
  {
109
- label: x("planmagnet.dashboard.metrics.milestones.label", "Milestones"),
110
- value: String(D.length),
111
- trend: `${j.length} ${x("planmagnet.dashboard.metrics.milestones.trend", "upcoming")}`
110
+ label: C("planmagnet.dashboard.metrics.milestones.label", "Milestones"),
111
+ value: String(k.length),
112
+ trend: `${N.length} ${C("planmagnet.dashboard.metrics.milestones.trend", "upcoming")}`
112
113
  }
113
114
  ];
114
- return /* @__PURE__ */ p("div", {
115
+ return /* @__PURE__ */ h("div", {
115
116
  className: "space-y-6 p-6",
116
117
  children: [
117
- /* @__PURE__ */ f("div", {
118
+ /* @__PURE__ */ m("div", {
118
119
  className: "flex items-center justify-between",
119
- children: /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ p("h1", {
120
+ children: /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ h("h1", {
120
121
  className: "text-2xl font-semibold flex items-center gap-2",
121
- children: [/* @__PURE__ */ f(o, { className: "h-6 w-6" }), x("planmagnet.dashboard.title", "Dashboard")]
122
- }), /* @__PURE__ */ f("p", {
122
+ children: [/* @__PURE__ */ m(s, { className: "h-6 w-6" }), C("planmagnet.dashboard.title", "Dashboard")]
123
+ }), /* @__PURE__ */ m("p", {
123
124
  className: "text-sm text-muted-foreground mt-1",
124
- children: x("planmagnet.dashboard.subtitle", "Welcome back! Here is your project overview.")
125
+ children: C("planmagnet.dashboard.subtitle", "Welcome back! Here is your project overview.")
125
126
  })] })
126
127
  }),
127
- /* @__PURE__ */ f("div", {
128
+ /* @__PURE__ */ m("div", {
128
129
  className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
129
- children: N.map((e) => /* @__PURE__ */ p(g, { children: [/* @__PURE__ */ p(v, {
130
+ children: I.map((e) => /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ h(b, {
130
131
  className: "flex flex-row items-center justify-between space-y-0 pb-2",
131
- children: [/* @__PURE__ */ f(y, {
132
+ children: [/* @__PURE__ */ m(x, {
132
133
  className: "text-sm font-medium",
133
134
  children: e.label
134
- }), /* @__PURE__ */ f(s, { className: "h-4 w-4 text-muted-foreground" })]
135
- }), /* @__PURE__ */ p(_, { children: [/* @__PURE__ */ f("div", {
135
+ }), /* @__PURE__ */ m(c, { className: "h-4 w-4 text-muted-foreground" })]
136
+ }), /* @__PURE__ */ h(y, { children: [/* @__PURE__ */ m("div", {
136
137
  className: "text-2xl font-bold",
137
138
  children: e.value
138
- }), /* @__PURE__ */ f("p", {
139
+ }), /* @__PURE__ */ m("p", {
139
140
  className: "text-xs text-muted-foreground",
140
141
  children: e.trend
141
142
  })] })] }, e.label))
142
143
  }),
143
- /* @__PURE__ */ p("div", {
144
+ /* @__PURE__ */ h("div", {
144
145
  className: "grid gap-6 lg:grid-cols-12",
145
- children: [/* @__PURE__ */ p(g, {
146
+ children: [/* @__PURE__ */ h(v, {
146
147
  className: "lg:col-span-8",
147
- children: [/* @__PURE__ */ f(v, { children: /* @__PURE__ */ p(y, {
148
+ children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ h(x, {
148
149
  className: "flex items-center gap-2 text-base",
149
- children: [/* @__PURE__ */ f(l, { className: "h-5 w-5 text-blue-500" }), x("planmagnet.dashboard.activeSprints.title", "Active Sprints")]
150
- }) }), /* @__PURE__ */ p(_, {
150
+ children: [/* @__PURE__ */ m(u, { className: "h-5 w-5 text-blue-500" }), C("planmagnet.dashboard.activeSprints.title", "Active Sprints")]
151
+ }) }), /* @__PURE__ */ h(y, {
151
152
  className: "space-y-4",
152
- children: [A.map((e) => {
153
+ children: [M.map((e) => {
153
154
  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), r = e.workItems.length, i = e.workItems.filter((e) => e.status === "DONE").length, a = t > 0 ? Math.round(n / t * 100) : 0;
154
- return /* @__PURE__ */ p("div", {
155
+ return /* @__PURE__ */ h("div", {
155
156
  className: "rounded-lg border p-4",
156
157
  children: [
157
- /* @__PURE__ */ p("div", {
158
+ /* @__PURE__ */ h("div", {
158
159
  className: "flex items-center justify-between mb-2",
159
- children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
160
+ children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
160
161
  className: "font-medium",
161
162
  children: e.name
162
- }), /* @__PURE__ */ p("p", {
163
+ }), /* @__PURE__ */ h("p", {
163
164
  className: "text-xs text-muted-foreground",
164
165
  children: [
165
- x("planmagnet.dashboard.shared.project", "Project"),
166
+ C("planmagnet.dashboard.shared.project", "Project"),
166
167
  ": ",
167
168
  e.projectId
168
169
  ]
169
- })] }), /* @__PURE__ */ p(h, {
170
+ })] }), /* @__PURE__ */ h(_, {
170
171
  variant: "secondary",
171
172
  children: [
172
173
  n,
173
174
  "/",
174
175
  t,
175
176
  " ",
176
- x("planmagnet.dashboard.shared.pointsShort", "pts")
177
+ C("planmagnet.dashboard.shared.pointsShort", "pts")
177
178
  ]
178
179
  })]
179
180
  }),
180
- /* @__PURE__ */ f("div", {
181
+ /* @__PURE__ */ m("div", {
181
182
  className: "w-full h-2 bg-muted rounded-full overflow-hidden",
182
- children: /* @__PURE__ */ f("div", {
183
+ children: /* @__PURE__ */ m("div", {
183
184
  className: "h-full bg-primary rounded-full transition-all",
184
185
  style: { width: `${a}%` }
185
186
  })
186
187
  }),
187
- /* @__PURE__ */ p("div", {
188
+ /* @__PURE__ */ h("div", {
188
189
  className: "flex items-center justify-between mt-2 text-xs text-muted-foreground",
189
- children: [/* @__PURE__ */ p("span", { children: [
190
+ children: [/* @__PURE__ */ h("span", { children: [
190
191
  i,
191
192
  "/",
192
193
  r,
193
194
  " ",
194
- x("planmagnet.dashboard.shared.tasks", "tasks")
195
- ] }), /* @__PURE__ */ p("span", { children: [
195
+ C("planmagnet.dashboard.shared.tasks", "tasks")
196
+ ] }), /* @__PURE__ */ h("span", { children: [
196
197
  e.startDate ? new Date(e.startDate).toLocaleDateString() : "—",
197
198
  " -",
198
199
  " ",
@@ -201,143 +202,139 @@ function x() {
201
202
  })
202
203
  ]
203
204
  }, e.id);
204
- }), A.length === 0 && /* @__PURE__ */ f("p", {
205
+ }), M.length === 0 && /* @__PURE__ */ m("p", {
205
206
  className: "text-sm text-muted-foreground text-center py-4",
206
- children: x("planmagnet.dashboard.activeSprints.empty", "No active sprints.")
207
+ children: C("planmagnet.dashboard.activeSprints.empty", "No active sprints.")
207
208
  })]
208
209
  })]
209
- }), /* @__PURE__ */ p("div", {
210
+ }), /* @__PURE__ */ h("div", {
210
211
  className: "lg:col-span-4 space-y-6",
211
- children: [T.filter((e) => e.status === "ON_HOLD").length > 0 && /* @__PURE__ */ p(g, { children: [/* @__PURE__ */ f(v, { children: /* @__PURE__ */ p(y, {
212
+ children: [D.filter((e) => e.status === "ON_HOLD").length > 0 && /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ h(x, {
212
213
  className: "flex items-center gap-2 text-base",
213
- children: [/* @__PURE__ */ f(t, { className: "h-5 w-5 text-orange-500" }), x("planmagnet.dashboard.onHoldProjects.title", "On-Hold Projects")]
214
- }) }), /* @__PURE__ */ f(_, {
214
+ children: [/* @__PURE__ */ m(n, { className: "h-5 w-5 text-orange-500" }), C("planmagnet.dashboard.onHoldProjects.title", "On-Hold Projects")]
215
+ }) }), /* @__PURE__ */ m(y, {
215
216
  className: "space-y-3",
216
- children: T.filter((e) => e.status === "ON_HOLD").map((e) => /* @__PURE__ */ p("div", {
217
+ children: D.filter((e) => e.status === "ON_HOLD").map((e) => /* @__PURE__ */ h("div", {
217
218
  className: "flex items-center justify-between rounded border p-2",
218
- children: [/* @__PURE__ */ f("div", { children: /* @__PURE__ */ f("p", {
219
+ children: [/* @__PURE__ */ m("div", { children: /* @__PURE__ */ m("p", {
219
220
  className: "text-sm font-medium",
220
221
  children: e.name
221
- }) }), /* @__PURE__ */ f(h, {
222
+ }) }), /* @__PURE__ */ m(_, {
222
223
  variant: "destructive",
223
224
  children: e.status.toLowerCase().replace("_", " ")
224
225
  })]
225
226
  }, e.id))
226
- })] }), /* @__PURE__ */ p(g, { children: [/* @__PURE__ */ f(v, { children: /* @__PURE__ */ p(y, {
227
+ })] }), /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ h(x, {
227
228
  className: "flex items-center gap-2 text-base",
228
- children: [/* @__PURE__ */ f(r, { className: "h-5 w-5 text-green-500" }), x("planmagnet.dashboard.upcomingMilestones.title", "Upcoming Milestones")]
229
- }) }), /* @__PURE__ */ p(_, {
229
+ children: [/* @__PURE__ */ m(i, { className: "h-5 w-5 text-green-500" }), C("planmagnet.dashboard.upcomingMilestones.title", "Upcoming Milestones")]
230
+ }) }), /* @__PURE__ */ h(y, {
230
231
  className: "space-y-3",
231
- children: [j.map((e) => /* @__PURE__ */ p("div", {
232
+ children: [N.map((e) => /* @__PURE__ */ h("div", {
232
233
  className: "flex items-start gap-3 rounded border p-2",
233
- children: [/* @__PURE__ */ p("div", {
234
+ children: [/* @__PURE__ */ h("div", {
234
235
  className: "flex-1 min-w-0",
235
236
  children: [
236
- /* @__PURE__ */ f("p", {
237
+ /* @__PURE__ */ m("p", {
237
238
  className: "text-sm font-medium truncate",
238
239
  children: e.name
239
240
  }),
240
- /* @__PURE__ */ p("p", {
241
+ /* @__PURE__ */ h("p", {
241
242
  className: "text-xs text-muted-foreground",
242
243
  children: [
243
- x("planmagnet.dashboard.shared.project", "Project"),
244
+ C("planmagnet.dashboard.shared.project", "Project"),
244
245
  ": ",
245
246
  e.projectId
246
247
  ]
247
248
  }),
248
- /* @__PURE__ */ p("p", {
249
+ /* @__PURE__ */ h("p", {
249
250
  className: "text-xs text-muted-foreground",
250
251
  children: [
251
- x("planmagnet.dashboard.shared.due", "Due"),
252
+ C("planmagnet.dashboard.shared.due", "Due"),
252
253
  " ",
253
254
  e.dueDate ? new Date(e.dueDate).toLocaleDateString() : "—"
254
255
  ]
255
256
  })
256
257
  ]
257
- }), /* @__PURE__ */ f(h, {
258
+ }), /* @__PURE__ */ m(_, {
258
259
  variant: "secondary",
259
260
  className: "text-xs flex-shrink-0 capitalize",
260
261
  children: e.status.toLowerCase().replace("_", " ")
261
262
  })]
262
- }, e.id)), j.length === 0 && /* @__PURE__ */ f("p", {
263
+ }, e.id)), N.length === 0 && /* @__PURE__ */ m("p", {
263
264
  className: "text-sm text-muted-foreground text-center py-2",
264
- children: x("planmagnet.dashboard.upcomingMilestones.empty", "No upcoming milestones.")
265
+ children: C("planmagnet.dashboard.upcomingMilestones.empty", "No upcoming milestones.")
265
266
  })]
266
267
  })] })]
267
268
  })]
268
269
  }),
269
- /* @__PURE__ */ p("div", {
270
+ /* @__PURE__ */ h("div", {
270
271
  className: "grid gap-6 lg:grid-cols-2",
271
- children: [/* @__PURE__ */ p(g, { children: [/* @__PURE__ */ f(v, { children: /* @__PURE__ */ p(y, {
272
+ children: [/* @__PURE__ */ h(v, { children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ h(x, {
272
273
  className: "flex items-center gap-2 text-base",
273
- children: [/* @__PURE__ */ f(i, { className: "h-5 w-5 text-purple-500" }), x("planmagnet.dashboard.recentWorkItems.title", "Recent Work Items")]
274
- }) }), /* @__PURE__ */ p(_, {
274
+ children: [/* @__PURE__ */ m(a, { className: "h-5 w-5 text-purple-500" }), C("planmagnet.dashboard.recentWorkItems.title", "Recent Work Items")]
275
+ }) }), /* @__PURE__ */ h(y, {
275
276
  className: "space-y-3",
276
- children: [M.map((e) => /* @__PURE__ */ p("div", {
277
+ children: [P.map((e) => /* @__PURE__ */ h("div", {
277
278
  className: "flex items-center justify-between rounded border p-2",
278
- children: [/* @__PURE__ */ p("div", {
279
+ children: [/* @__PURE__ */ h("div", {
279
280
  className: "min-w-0 flex-1",
280
- children: [/* @__PURE__ */ f("p", {
281
+ children: [/* @__PURE__ */ m("p", {
281
282
  className: "text-sm font-medium truncate",
282
283
  children: e.key
283
- }), /* @__PURE__ */ p("p", {
284
+ }), /* @__PURE__ */ h("p", {
284
285
  className: "text-xs text-muted-foreground",
285
- children: [
286
- e.projectId,
287
- " ",
288
- e.assigneeId ? `\u00b7 ${e.assigneeId}` : ""
289
- ]
286
+ children: [F.get(e.projectId) ?? `Project ${e.projectId.slice(0, 6)}`, e.assigneeId ? /* @__PURE__ */ h(p, { children: [" · ", /* @__PURE__ */ m(t, { id: e.assigneeId })] }) : null]
290
287
  })]
291
- }), /* @__PURE__ */ p("div", {
288
+ }), /* @__PURE__ */ h("div", {
292
289
  className: "flex items-center gap-2 flex-shrink-0",
293
- children: [/* @__PURE__ */ p(h, {
290
+ children: [/* @__PURE__ */ h(_, {
294
291
  variant: "outline",
295
292
  className: "text-xs",
296
293
  children: [
297
294
  e.storyPoints ?? 0,
298
295
  " ",
299
- x("planmagnet.dashboard.shared.pointsShort", "pts")
296
+ C("planmagnet.dashboard.shared.pointsShort", "pts")
300
297
  ]
301
- }), /* @__PURE__ */ f(h, {
298
+ }), /* @__PURE__ */ m(_, {
302
299
  variant: "secondary",
303
300
  className: "text-xs capitalize",
304
301
  children: e.status.toLowerCase().replace("_", " ")
305
302
  })]
306
303
  })]
307
- }, e.id)), M.length === 0 && /* @__PURE__ */ f("p", {
304
+ }, e.id)), P.length === 0 && /* @__PURE__ */ m("p", {
308
305
  className: "text-sm text-muted-foreground text-center py-4",
309
- children: x("planmagnet.dashboard.recentWorkItems.empty", "No work items yet.")
306
+ children: C("planmagnet.dashboard.recentWorkItems.empty", "No work items yet.")
310
307
  })]
311
- })] }), /* @__PURE__ */ p(g, { children: [/* @__PURE__ */ f(v, { children: /* @__PURE__ */ p(y, {
308
+ })] }), /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ h(x, {
312
309
  className: "flex items-center gap-2 text-base",
313
- children: [/* @__PURE__ */ f(a, { className: "h-5 w-5 text-cyan-500" }), x("planmagnet.dashboard.projectStatus.title", "Project Status")]
314
- }) }), /* @__PURE__ */ p(_, {
310
+ children: [/* @__PURE__ */ m(o, { className: "h-5 w-5 text-cyan-500" }), C("planmagnet.dashboard.projectStatus.title", "Project Status")]
311
+ }) }), /* @__PURE__ */ h(y, {
315
312
  className: "space-y-3",
316
- children: [k.map((e) => /* @__PURE__ */ p("div", {
313
+ children: [j.map((e) => /* @__PURE__ */ h("div", {
317
314
  className: "flex items-center justify-between rounded border p-2",
318
- children: [/* @__PURE__ */ p("div", {
315
+ children: [/* @__PURE__ */ h("div", {
319
316
  className: "min-w-0 flex-1",
320
- children: [/* @__PURE__ */ f("p", {
317
+ children: [/* @__PURE__ */ m("p", {
321
318
  className: "text-sm font-medium truncate",
322
319
  children: e.name
323
- }), /* @__PURE__ */ f("p", {
320
+ }), /* @__PURE__ */ m("p", {
324
321
  className: "text-xs text-muted-foreground capitalize",
325
322
  children: e.status.toLowerCase().replace("_", " ")
326
323
  })]
327
- }), /* @__PURE__ */ p("div", {
324
+ }), /* @__PURE__ */ h("div", {
328
325
  className: "flex items-center gap-2 ml-3 flex-shrink-0",
329
326
  children: [
330
- /* @__PURE__ */ f(c, { className: "h-3 w-3 text-muted-foreground" }),
331
- /* @__PURE__ */ f("span", {
327
+ /* @__PURE__ */ m(l, { className: "h-3 w-3 text-muted-foreground" }),
328
+ /* @__PURE__ */ m("span", {
332
329
  className: "text-xs text-muted-foreground",
333
- children: e.ownerId
330
+ children: /* @__PURE__ */ m(t, { id: e.ownerId })
334
331
  }),
335
- /* @__PURE__ */ f(n, { className: "h-3 w-3 text-muted-foreground" })
332
+ /* @__PURE__ */ m(r, { className: "h-3 w-3 text-muted-foreground" })
336
333
  ]
337
334
  })]
338
- }, e.id)), k.length === 0 && /* @__PURE__ */ f("p", {
335
+ }, e.id)), j.length === 0 && /* @__PURE__ */ m("p", {
339
336
  className: "text-sm text-muted-foreground text-center py-4",
340
- children: x("planmagnet.dashboard.projectStatus.empty", "No active projects.")
337
+ children: C("planmagnet.dashboard.projectStatus.empty", "No active projects.")
341
338
  })]
342
339
  })] })]
343
340
  })
@@ -345,6 +342,6 @@ function x() {
345
342
  });
346
343
  }
347
344
  //#endregion
348
- export { x as DashboardDashboardPagePage };
345
+ export { C as DashboardDashboardPagePage };
349
346
 
350
347
  //# sourceMappingURL=DashboardDashboardPagePage.js.map