@burdenoff/microfe-planmagnet 2026.518.1 → 2026.627.1
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/pages/AnalyticsAnalyticsPagePage.js +4 -4
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/CollaborationCollaborationPagePage.js +1 -1
- package/dist/planmagnet/pages/CollaborationCollaborationPagePage.js.map +1 -1
- package/dist/planmagnet/pages/CollaborationFilesPagePage.js +1 -1
- package/dist/planmagnet/pages/CollaborationFilesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/CollaborationMessagesPagePage.js +1 -1
- package/dist/planmagnet/pages/CollaborationMessagesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/CollaborationNewDiscussionPagePage.js +1 -1
- package/dist/planmagnet/pages/CollaborationNewDiscussionPagePage.js.map +1 -1
- package/dist/planmagnet/pages/MeetingsScheduleMeetingPagePage.js +2 -2
- package/dist/planmagnet/pages/MeetingsScheduleMeetingPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +2 -2
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js +3 -3
- package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleasesPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsReleasesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.js +1 -1
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.js +3 -3
- package/dist/planmagnet/pages/ReportsReportsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +2 -2
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.js +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.js +1 -1
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamInviteMemberPagePage.js +1 -1
- package/dist/planmagnet/pages/TeamInviteMemberPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.js +2 -2
- package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
- package/package.json +1 -1
- package/dist/dev/main.d.ts +0 -2
- package/dist/dev/main.d.ts.map +0 -1
- package/dist/generated/global-operations.d.ts +0 -2
- package/dist/generated/global-operations.d.ts.map +0 -1
- package/dist/generated/global-types.d.ts +0 -21459
- package/dist/generated/global-types.d.ts.map +0 -1
- package/dist/generated/wspace-operations.d.ts +0 -8370
- package/dist/generated/wspace-operations.d.ts.map +0 -1
- package/dist/generated/wspace-types.d.ts +0 -4182
- package/dist/generated/wspace-types.d.ts.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/planmagnet/PlanMagnetRoot.d.ts +0 -5
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +0 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts +0 -2
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +0 -1
- package/dist/planmagnet/index.d.ts +0 -5
- package/dist/planmagnet/index.d.ts.map +0 -1
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/CollaborationCollaborationPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/CollaborationCollaborationPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/CollaborationCreateChannelPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/CollaborationCreateChannelPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/CollaborationFilesPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/CollaborationFilesPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/CollaborationMessagesPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/CollaborationMessagesPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/CollaborationNewDiscussionPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/CollaborationNewDiscussionPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/DashboardDashboardPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/MeetingsScheduleMeetingPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/MeetingsScheduleMeetingPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsCreateProductPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsCreateProductPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsCreateRoadmapPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsCreateRoadmapPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsEditProductPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsEditProductPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsEditReleasePagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsEditReleasePagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsReleasesPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsReleasesPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsCreateProjectPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ReportsCreateReportPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/ReportsReportsPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/TeamCreateTeamPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/TeamInviteMemberPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/TeamInviteMemberPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.d.ts +0 -2
- package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +0 -1
- package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.d.ts +0 -2
- package/dist/planmagnet/pages/WorkspaceCreateWorkspacePagePage.d.ts.map +0 -1
- package/dist/planmagnet/providers/PlanMagnetProvider.d.ts +0 -31
- package/dist/planmagnet/providers/PlanMagnetProvider.d.ts.map +0 -1
- package/dist/planmagnet/store/planmagnetStore.d.ts +0 -30
- package/dist/planmagnet/store/planmagnetStore.d.ts.map +0 -1
- package/dist/planmagnet/types/index.d.ts +0 -317
- package/dist/planmagnet/types/index.d.ts.map +0 -1
- package/dist/planmagnet/utils/cn.d.ts +0 -4
- package/dist/planmagnet/utils/cn.d.ts.map +0 -1
- package/dist/planmagnet/utils/navigation.d.ts +0 -2
- package/dist/planmagnet/utils/navigation.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductsRoadmapsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsRoadmapsPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge, Button } from '@burdenoff/fe-libs/ui';\nimport { Map, Calendar, Plus, Filter, Loader2 } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst LIST_ROADMAPS = gql`\n query ListRoadmapsPage($workspaceId: ID!, $filter: RoadmapFilter, $pagination: PaginationInput) {\n planmagnetRoadmaps(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n workspaceId\n name\n description\n type\n isPublic\n ownerId\n createdAt\n updatedAt\n items {\n id\n title\n status\n startDate\n endDate\n }\n }\n totalCount\n }\n }\n`;\n\ninterface RoadmapItemNode {\n id: string;\n title: string;\n status: string;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface RoadmapNode {\n id: string;\n name: string;\n description: string | null;\n type: string;\n isPublic: boolean;\n ownerId: string;\n createdAt: string;\n updatedAt: string;\n items: RoadmapItemNode[];\n}\n\nconst typeColor: Record<string, string> = {\n TIMELINE: 'bg-purple-100 text-purple-800',\n GANTT: 'bg-orange-100 text-orange-800',\n SWIMLANE: 'bg-green-100 text-green-800',\n CUSTOM: 'bg-blue-100 text-blue-800',\n};\n\nexport function ProductsRoadmapsPagePage() {\n const { workspaceId } = usePlanMagnet();\n const [typeFilter, setTypeFilter] = useState<string>('all');\n const [visFilter, setVisFilter] = useState<string>('all');\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(LIST_ROADMAPS, {\n variables: {\n workspaceId,\n pagination: { first: 50 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load roadmaps: {error.message}</div>;\n }\n\n const roadmaps: RoadmapNode[] = data?.planmagnetRoadmaps?.items ?? [];\n const totalCount = data?.planmagnetRoadmaps?.totalCount ?? 0;\n\n const types = ['all', ...new Set(roadmaps.map((r) => r.type))];\n const visibilities = ['all', 'public', 'private'];\n\n const filtered = roadmaps.filter(\n (r) =>\n (typeFilter === 'all' || r.type === typeFilter) &&\n (visFilter === 'all' ||\n (visFilter === 'public' && r.isPublic) ||\n (visFilter === 'private' && !r.isPublic))\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\">Roadmaps</h1>\n <p className=\"text-sm text-muted-foreground\">{totalCount} roadmaps across all products</p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Roadmap\n </Button>\n </div>\n\n <div className=\"flex gap-4 flex-wrap\">\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-sm text-muted-foreground\">Type:</span>\n {types.map((t) => (\n <button\n key={t}\n onClick={() => setTypeFilter(t)}\n className={`px-2 py-1 text-xs rounded-md capitalize ${typeFilter === t ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {t === 'all' ? 'All' : t.toLowerCase()}\n </button>\n ))}\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Visibility:</span>\n {visibilities.map((v) => (\n <button\n key={v}\n onClick={() => setVisFilter(v)}\n className={`px-2 py-1 text-xs rounded-md capitalize ${visFilter === v ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {v}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {filtered.map((rm) => {\n const itemCount = rm.items?.length ?? 0;\n const completedItems =\n rm.items?.filter((i) => i.status === 'COMPLETED' || i.status === 'DONE').length ?? 0;\n const progress = itemCount > 0 ? Math.round((completedItems / itemCount) * 100) : 0;\n const startDates = rm.items?.map((i) => i.startDate).filter(Boolean) ?? [];\n const endDates = rm.items?.map((i) => i.endDate).filter(Boolean) ?? [];\n const earliestStart = startDates.length > 0 ? startDates.sort()[0] : null;\n const latestEnd = endDates.length > 0 ? endDates.sort().reverse()[0] : null;\n\n return (\n <Card key={rm.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{rm.name}</CardTitle>\n <Badge variant={rm.isPublic ? 'default' : 'secondary'} className=\"capitalize\">\n {rm.isPublic ? 'public' : 'private'}\n </Badge>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <p className=\"text-sm text-muted-foreground\">\n {rm.description ?? 'No description'}\n </p>\n <div className=\"flex items-center gap-2\">\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${typeColor[rm.type] ?? 'bg-gray-100'}`}\n >\n {rm.type.toLowerCase()}\n </span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {rm.isPublic ? 'public' : 'private'}\n </Badge>\n </div>\n <div>\n <div className=\"flex justify-between text-xs mb-1\">\n <span className=\"text-muted-foreground\">Progress</span>\n <span className=\"font-medium\">{progress}%</span>\n </div>\n <div className=\"w-full h-2 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full\"\n style={{ width: `${progress}%` }}\n />\n </div>\n </div>\n <div className=\"flex gap-4 text-xs text-muted-foreground\">\n <span className=\"flex items-center gap-1\">\n <Map className=\"h-3 w-3\" />\n {itemCount} items\n </span>\n </div>\n <div className=\"flex items-center justify-between text-xs text-muted-foreground border-t pt-2\">\n <span>Owner: {rm.ownerId}</span>\n {earliestStart && latestEnd && (\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n {new Date(earliestStart).toLocaleDateString()} -{' '}\n {new Date(latestEnd).toLocaleDateString()}\n </span>\n )}\n </div>\n </CardContent>\n </Card>\n );\n })}\n </div>\n {filtered.length === 0 && (\n <p className=\"text-center text-muted-foreground py-8\">\n No roadmaps match the selected filters.\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProductsRoadmapsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ProductsRoadmapsPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge, Button } from '@burdenoff/fe-libs/ui';\nimport { Map, Calendar, Plus, Filter, Loader2 } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst LIST_ROADMAPS = gql`\n query ListRoadmapsPage($workspaceId: ID!, $filter: RoadmapFilter, $pagination: PlanmagnetPaginationInput) {\n planmagnetRoadmaps(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n workspaceId\n name\n description\n type\n isPublic\n ownerId\n createdAt\n updatedAt\n items {\n id\n title\n status\n startDate\n endDate\n }\n }\n totalCount\n }\n }\n`;\n\ninterface RoadmapItemNode {\n id: string;\n title: string;\n status: string;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface RoadmapNode {\n id: string;\n name: string;\n description: string | null;\n type: string;\n isPublic: boolean;\n ownerId: string;\n createdAt: string;\n updatedAt: string;\n items: RoadmapItemNode[];\n}\n\nconst typeColor: Record<string, string> = {\n TIMELINE: 'bg-purple-100 text-purple-800',\n GANTT: 'bg-orange-100 text-orange-800',\n SWIMLANE: 'bg-green-100 text-green-800',\n CUSTOM: 'bg-blue-100 text-blue-800',\n};\n\nexport function ProductsRoadmapsPagePage() {\n const { workspaceId } = usePlanMagnet();\n const [typeFilter, setTypeFilter] = useState<string>('all');\n const [visFilter, setVisFilter] = useState<string>('all');\n\n const {\n data,\n loading,\n error,\n } = // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n useQuery<Record<string, any>>(LIST_ROADMAPS, {\n variables: {\n workspaceId,\n pagination: { first: 50 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load roadmaps: {error.message}</div>;\n }\n\n const roadmaps: RoadmapNode[] = data?.planmagnetRoadmaps?.items ?? [];\n const totalCount = data?.planmagnetRoadmaps?.totalCount ?? 0;\n\n const types = ['all', ...new Set(roadmaps.map((r) => r.type))];\n const visibilities = ['all', 'public', 'private'];\n\n const filtered = roadmaps.filter(\n (r) =>\n (typeFilter === 'all' || r.type === typeFilter) &&\n (visFilter === 'all' ||\n (visFilter === 'public' && r.isPublic) ||\n (visFilter === 'private' && !r.isPublic))\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\">Roadmaps</h1>\n <p className=\"text-sm text-muted-foreground\">{totalCount} roadmaps across all products</p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Roadmap\n </Button>\n </div>\n\n <div className=\"flex gap-4 flex-wrap\">\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"text-sm text-muted-foreground\">Type:</span>\n {types.map((t) => (\n <button\n key={t}\n onClick={() => setTypeFilter(t)}\n className={`px-2 py-1 text-xs rounded-md capitalize ${typeFilter === t ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {t === 'all' ? 'All' : t.toLowerCase()}\n </button>\n ))}\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Visibility:</span>\n {visibilities.map((v) => (\n <button\n key={v}\n onClick={() => setVisFilter(v)}\n className={`px-2 py-1 text-xs rounded-md capitalize ${visFilter === v ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {v}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {filtered.map((rm) => {\n const itemCount = rm.items?.length ?? 0;\n const completedItems =\n rm.items?.filter((i) => i.status === 'COMPLETED' || i.status === 'DONE').length ?? 0;\n const progress = itemCount > 0 ? Math.round((completedItems / itemCount) * 100) : 0;\n const startDates = rm.items?.map((i) => i.startDate).filter(Boolean) ?? [];\n const endDates = rm.items?.map((i) => i.endDate).filter(Boolean) ?? [];\n const earliestStart = startDates.length > 0 ? startDates.sort()[0] : null;\n const latestEnd = endDates.length > 0 ? endDates.sort().reverse()[0] : null;\n\n return (\n <Card key={rm.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{rm.name}</CardTitle>\n <Badge variant={rm.isPublic ? 'default' : 'secondary'} className=\"capitalize\">\n {rm.isPublic ? 'public' : 'private'}\n </Badge>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <p className=\"text-sm text-muted-foreground\">\n {rm.description ?? 'No description'}\n </p>\n <div className=\"flex items-center gap-2\">\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${typeColor[rm.type] ?? 'bg-gray-100'}`}\n >\n {rm.type.toLowerCase()}\n </span>\n <Badge variant=\"outline\" className=\"text-xs capitalize\">\n {rm.isPublic ? 'public' : 'private'}\n </Badge>\n </div>\n <div>\n <div className=\"flex justify-between text-xs mb-1\">\n <span className=\"text-muted-foreground\">Progress</span>\n <span className=\"font-medium\">{progress}%</span>\n </div>\n <div className=\"w-full h-2 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full\"\n style={{ width: `${progress}%` }}\n />\n </div>\n </div>\n <div className=\"flex gap-4 text-xs text-muted-foreground\">\n <span className=\"flex items-center gap-1\">\n <Map className=\"h-3 w-3\" />\n {itemCount} items\n </span>\n </div>\n <div className=\"flex items-center justify-between text-xs text-muted-foreground border-t pt-2\">\n <span>Owner: {rm.ownerId}</span>\n {earliestStart && latestEnd && (\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n {new Date(earliestStart).toLocaleDateString()} -{' '}\n {new Date(latestEnd).toLocaleDateString()}\n </span>\n )}\n </div>\n </CardContent>\n </Card>\n );\n })}\n </div>\n {filtered.length === 0 && (\n <p className=\"text-center text-muted-foreground py-8\">\n No roadmaps match the selected filters.\n </p>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
|
7
7
|
import { Button as u, Card as d, CardContent as f, CardHeader as p, CardTitle as m, Input as h } from "@burdenoff/fe-libs/ui";
|
|
8
8
|
//#region src/planmagnet/pages/ReportsCreateReportPagePage.tsx
|
|
9
9
|
var g = o`
|
|
10
|
-
query GetProjectsForReport($workspaceId: ID!, $pagination:
|
|
10
|
+
query GetProjectsForReport($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {
|
|
11
11
|
planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {
|
|
12
12
|
items {
|
|
13
13
|
id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsCreateReportPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ReportsCreateReportPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, BarChart3 } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_PROJECTS_FOR_REPORT = gql`\n query GetProjectsForReport($workspaceId: ID!, $pagination:
|
|
1
|
+
{"version":3,"file":"ReportsCreateReportPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ReportsCreateReportPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, BarChart3 } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_PROJECTS_FOR_REPORT = gql`\n query GetProjectsForReport($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n key\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n}\n\ninterface ProjectsData {\n projects: { items: ProjectNode[]; totalCount: number };\n}\n\nexport function ReportsCreateReportPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const { data, loading, error } = useQuery<ProjectsData>(GET_PROJECTS_FOR_REPORT, {\n variables: {\n workspaceId,\n pagination: { first: 100 },\n },\n skip: !workspaceId,\n });\n\n const [form, setForm] = useState({\n name: '',\n description: '',\n type: 'velocity',\n projectId: '',\n schedule: 'weekly',\n });\n const types = [\n 'velocity',\n 'burndown',\n 'burnup',\n 'cumulative_flow',\n 'cycle_time',\n 'lead_time',\n 'custom',\n ] as const;\n const schedules = ['daily', 'weekly', 'monthly'] as const;\n\n const projects = data?.planmagnetProjects?.items ?? [];\n\n const handleCreate = () => {\n if (!form.name.trim()) return;\n navigate('/reports');\n };\n\n if (loading) {\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\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Create Report</h1>\n <p className=\"text-sm text-muted-foreground\">Configure a new automated report.</p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/reports')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleCreate}>\n <Save className=\"mr-1 h-4 w-4\" />\n Create Report\n </Button>\n </div>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4\" />\n Report Configuration\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Report Name</label>\n <Input\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Sprint Velocity Report\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description</label>\n <textarea\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=\"What does this report track?\"\n />\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Type</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.type}\n onChange={(e) => setForm({ ...form, type: e.target.value })}\n >\n {types.map((t) => (\n <option key={t} value={t}>\n {t.replace('_', ' ')}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Project (optional)</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.projectId}\n onChange={(e) => setForm({ ...form, projectId: e.target.value })}\n >\n <option value=\"\">All projects</option>\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name} ({p.key})\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Schedule</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.schedule}\n onChange={(e) => setForm({ ...form, schedule: e.target.value })}\n >\n {schedules.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AASA,IAAM,IAA0B,CAAG;;;;;;;;;;;;AAuBnC,SAAgB,IAA8B;CAC5C,IAAM,EAAE,mBAAgB,GAAe,EACjC,IAAW,GAAuB,EAElC,EAAE,SAAM,YAAS,aAAU,EAAuB,GAAyB;EAC/E,WAAW;GACT;GACA,YAAY,EAAE,OAAO,KAAK;GAC3B;EACD,MAAM,CAAC;EACR,CAAC,EAEI,CAAC,GAAM,KAAW,EAAS;EAC/B,MAAM;EACN,aAAa;EACb,MAAM;EACN,WAAW;EACX,UAAU;EACX,CAAC,EACI,IAAQ;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACD,EACK,IAAY;EAAC;EAAS;EAAU;EAAU,EAE1C,IAAW,GAAM,oBAAoB,SAAS,EAAE;AAmBtD,QAZI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD,EAAK,WAAU,kFAAmF,CAAA;EAC9F,CAAA,GAIN,IACK,kBAAC,OAAD;EAAK,WAAU;YAAf,CAAkC,WAAQ,EAAM,QAAc;MAIrE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cAAyB;IAAkB,CAAA,EACzD,kBAAC,KAAD;IAAG,WAAU;cAAgC;IAAqC,CAAA,CAC9E,EAAA,CAAA,EACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAQ,SAAQ;KAAU,MAAK;KAAK,eAAe,EAAS,WAAW;eAAvE,CACE,kBAAC,GAAD,EAAG,WAAU,gBAAiB,CAAA,EAAA,SAEvB;QACT,kBAAC,GAAD;KAAQ,MAAK;KAAK,eA7BC;AACpB,QAAK,KAAK,MAAM,IACrB,EAAS,WAAW;;eA2Bd,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,gBAE1B;OACL;MACF;MACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;GAAW,WAAU;aAArB,CACE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAAA,uBAEvB;MACD,CAAA,EACb,kBAAC,GAAD;GAAa,WAAU;aAAvB;IACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;KAAO,WAAU;eAAsB;KAAmB,CAAA,EAC1D,kBAAC,GAAD;KACE,OAAO,EAAK;KACZ,WAAW,MAAM,EAAQ;MAAE,GAAG;MAAM,MAAM,EAAE,OAAO;MAAO,CAAC;KAC3D,WAAU;KACV,aAAY;KACZ,CAAA,CACE,EAAA,CAAA;IACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;KAAO,WAAU;eAAsB;KAAmB,CAAA,EAC1D,kBAAC,YAAD;KACE,WAAU;KACV,OAAO,EAAK;KACZ,WAAW,MAAM,EAAQ;MAAE,GAAG;MAAM,aAAa,EAAE,OAAO;MAAO,CAAC;KAClE,aAAY;KACZ,CAAA,CACE,EAAA,CAAA;IACN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,WAAU;iBAAsB;OAAY,CAAA,EACnD,kBAAC,UAAD;OACE,WAAU;OACV,OAAO,EAAK;OACZ,WAAW,MAAM,EAAQ;QAAE,GAAG;QAAM,MAAM,EAAE,OAAO;QAAO,CAAC;iBAE1D,EAAM,KAAK,MACV,kBAAC,UAAD;QAAgB,OAAO;kBACpB,EAAE,QAAQ,KAAK,IAAI;QACb,EAFI,EAEJ,CACT;OACK,CAAA,CACL,EAAA,CAAA;MACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,WAAU;iBAAsB;OAA0B,CAAA,EACjE,kBAAC,UAAD;OACE,WAAU;OACV,OAAO,EAAK;OACZ,WAAW,MAAM,EAAQ;QAAE,GAAG;QAAM,WAAW,EAAE,OAAO;QAAO,CAAC;iBAHlE,CAKE,kBAAC,UAAD;QAAQ,OAAM;kBAAG;QAAqB,CAAA,EACrC,EAAS,KAAK,MACb,kBAAC,UAAD;QAAmB,OAAO,EAAE;kBAA5B;SACG,EAAE;SAAK;SAAG,EAAE;SAAI;SACV;UAFI,EAAE,GAEN,CACT,CACK;SACL,EAAA,CAAA;MACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,WAAU;iBAAsB;OAAgB,CAAA,EACvD,kBAAC,UAAD;OACE,WAAU;OACV,OAAO,EAAK;OACZ,WAAW,MAAM,EAAQ;QAAE,GAAG;QAAM,UAAU,EAAE,OAAO;QAAO,CAAC;iBAE9D,EAAU,KAAK,MACd,kBAAC,UAAD;QAAgB,OAAO;kBACpB;QACM,EAFI,EAEJ,CACT;OACK,CAAA,CACL,EAAA,CAAA;MACF;;IACM;KACT,EAAA,CAAA,CACH"}
|
|
@@ -9,9 +9,9 @@ import { Button as d, Card as f, CardContent as p, CardHeader as m, CardTitle as
|
|
|
9
9
|
var g = s`
|
|
10
10
|
query GetReportsData(
|
|
11
11
|
$workspaceId: ID!
|
|
12
|
-
$projectPagination:
|
|
13
|
-
$sprintPagination:
|
|
14
|
-
$workItemPagination:
|
|
12
|
+
$projectPagination: PlanmagnetPaginationInput
|
|
13
|
+
$sprintPagination: PlanmagnetPaginationInput
|
|
14
|
+
$workItemPagination: PlanmagnetPaginationInput
|
|
15
15
|
) {
|
|
16
16
|
planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {
|
|
17
17
|
items {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsReportsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ReportsReportsPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button } from '@burdenoff/fe-libs/ui';\nimport { BarChart3, Plus, Clock, Calendar } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_REPORTS_DATA = gql`\n query GetReportsData(\n $workspaceId: ID!\n $projectPagination: PaginationInput\n $sprintPagination: PaginationInput\n $workItemPagination: PaginationInput\n ) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {\n items {\n id\n name\n key\n status\n methodology\n startDate\n endDate\n }\n totalCount\n }\n planmagnetSprints(workspaceId: $workspaceId, pagination: $sprintPagination) {\n items {\n id\n name\n status\n velocity\n startDate\n endDate\n }\n totalCount\n }\n planmagnetWorkItems(workspaceId: $workspaceId, pagination: $workItemPagination) {\n items {\n id\n status\n storyPoints\n createdAt\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n status: string;\n methodology: string | null;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface SprintNode {\n id: string;\n name: string;\n status: string;\n velocity: number | null;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface WorkItemNode {\n id: string;\n status: string;\n storyPoints: number | null;\n createdAt: string;\n}\n\ninterface ReportsData {\n projects: { items: ProjectNode[]; totalCount: number };\n sprints: { items: SprintNode[]; totalCount: number };\n workItems: { items: WorkItemNode[]; totalCount: number };\n}\n\nconst typeColor: Record<string, string> = {\n velocity: 'bg-blue-100 text-blue-800',\n burndown: 'bg-orange-100 text-orange-800',\n burnup: 'bg-green-100 text-green-800',\n cumulative_flow: 'bg-purple-100 text-purple-800',\n cycle_time: 'bg-yellow-100 text-yellow-800',\n lead_time: 'bg-pink-100 text-pink-800',\n project_status: 'bg-gray-100 text-gray-800',\n};\n\nexport function ReportsReportsPagePage() {\n const { workspaceId, currentUser } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n const [typeFilter, setTypeFilter] = useState<string>('all');\n\n const { data, loading, error } = useQuery<ReportsData>(GET_REPORTS_DATA, {\n variables: {\n workspaceId,\n projectPagination: { first: 100 },\n sprintPagination: { first: 100 },\n workItemPagination: { first: 500 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\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\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const projects = data?.planmagnetProjects?.items ?? [];\n const sprints = data?.planmagnetSprints?.items ?? [];\n const workItems = data?.planmagnetWorkItems?.items ?? [];\n\n const completedSprints = sprints.filter((s) => s.status === 'COMPLETED');\n const activeSprints = sprints.filter((s) => s.status === 'ACTIVE');\n const creatorName = currentUser?.name ?? currentUser?.firstName ?? 'System';\n\n const reports = [\n ...completedSprints.map((sprint) => ({\n id: `velocity-${sprint.id}`,\n name: `${sprint.name} Velocity Report`,\n description: `Velocity analysis for ${sprint.name} (${sprint.velocity ?? 0} pts)`,\n type: 'velocity',\n createdBy: creatorName,\n lastRun: sprint.endDate ?? '',\n schedule: null as string | null,\n })),\n ...activeSprints.map((sprint) => ({\n id: `burndown-${sprint.id}`,\n name: `${sprint.name} Burndown`,\n description: `Active burndown tracking for ${sprint.name}`,\n type: 'burndown',\n createdBy: creatorName,\n lastRun: new Date().toISOString().split('T')[0],\n schedule: 'daily' as string | null,\n })),\n ...projects\n .filter((p) => p.status === 'ACTIVE')\n .map((project) => ({\n id: `status-${project.id}`,\n name: `${project.name} Status Report`,\n description: `Project status overview for ${project.key}`,\n type: 'project_status',\n createdBy: creatorName,\n lastRun: new Date().toISOString().split('T')[0],\n schedule: 'weekly' as string | null,\n })),\n ];\n\n const types = ['all', ...new Set(reports.map((r) => r.type))];\n const filtered = typeFilter === 'all' ? reports : reports.filter((r) => r.type === typeFilter);\n\n const scheduledCount = reports.filter((r) => r.schedule).length;\n const todayStr = new Date().toISOString().split('T')[0];\n const runTodayCount = reports.filter((r) => r.lastRun === todayStr).length;\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\">Reports</h1>\n <p className=\"text-sm text-muted-foreground\">{reports.length} reports configured</p>\n </div>\n <Button size=\"sm\" onClick={() => navigate('/reports/create')}>\n <Plus className=\"mr-1 h-4 w-4\" />\n New Report\n </Button>\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Total Reports</p>\n <p className=\"text-xl font-bold\">{reports.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Scheduled</p>\n <p className=\"text-xl font-bold\">{scheduledCount}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Run Today</p>\n <p className=\"text-xl font-bold\">{runTodayCount}</p>\n </CardContent>\n </Card>\n </div>\n <div className=\"flex gap-1\">\n {types.map((t) => (\n <button\n key={t}\n onClick={() => setTypeFilter(t)}\n className={`px-3 py-1.5 text-sm rounded-md capitalize ${typeFilter === t ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted'}`}\n >\n {t === 'all' ? 'All' : t.replace('_', ' ')}\n </button>\n ))}\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {filtered.map((report) => (\n <Card key={report.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4 text-primary\" />\n {report.name}\n </CardTitle>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${typeColor[report.type] ?? 'bg-gray-100'}`}\n >\n {report.type.replace('_', ' ')}\n </span>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">{report.description}</p>\n <div className=\"flex gap-3 text-xs text-muted-foreground\">\n {report.schedule && (\n <span className=\"flex items-center gap-1\">\n <Clock className=\"h-3 w-3\" />\n {report.schedule}\n </span>\n )}\n {report.lastRun && (\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n Last: {report.lastRun}\n </span>\n )}\n <span className=\"flex items-center gap-1\">{report.createdBy}</span>\n </div>\n </CardContent>\n </Card>\n ))}\n {filtered.length === 0 && (\n <div className=\"col-span-2 text-center py-12\">\n <BarChart3 className=\"h-12 w-12 text-muted-foreground mx-auto mb-3\" />\n <p className=\"text-sm text-muted-foreground\">\n No reports found for the selected filter.\n </p>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ReportsReportsPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/ReportsReportsPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button } from '@burdenoff/fe-libs/ui';\nimport { BarChart3, Plus, Clock, Calendar } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_REPORTS_DATA = gql`\n query GetReportsData(\n $workspaceId: ID!\n $projectPagination: PlanmagnetPaginationInput\n $sprintPagination: PlanmagnetPaginationInput\n $workItemPagination: PlanmagnetPaginationInput\n ) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {\n items {\n id\n name\n key\n status\n methodology\n startDate\n endDate\n }\n totalCount\n }\n planmagnetSprints(workspaceId: $workspaceId, pagination: $sprintPagination) {\n items {\n id\n name\n status\n velocity\n startDate\n endDate\n }\n totalCount\n }\n planmagnetWorkItems(workspaceId: $workspaceId, pagination: $workItemPagination) {\n items {\n id\n status\n storyPoints\n createdAt\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n status: string;\n methodology: string | null;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface SprintNode {\n id: string;\n name: string;\n status: string;\n velocity: number | null;\n startDate: string | null;\n endDate: string | null;\n}\n\ninterface WorkItemNode {\n id: string;\n status: string;\n storyPoints: number | null;\n createdAt: string;\n}\n\ninterface ReportsData {\n projects: { items: ProjectNode[]; totalCount: number };\n sprints: { items: SprintNode[]; totalCount: number };\n workItems: { items: WorkItemNode[]; totalCount: number };\n}\n\nconst typeColor: Record<string, string> = {\n velocity: 'bg-blue-100 text-blue-800',\n burndown: 'bg-orange-100 text-orange-800',\n burnup: 'bg-green-100 text-green-800',\n cumulative_flow: 'bg-purple-100 text-purple-800',\n cycle_time: 'bg-yellow-100 text-yellow-800',\n lead_time: 'bg-pink-100 text-pink-800',\n project_status: 'bg-gray-100 text-gray-800',\n};\n\nexport function ReportsReportsPagePage() {\n const { workspaceId, currentUser } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n const [typeFilter, setTypeFilter] = useState<string>('all');\n\n const { data, loading, error } = useQuery<ReportsData>(GET_REPORTS_DATA, {\n variables: {\n workspaceId,\n projectPagination: { first: 100 },\n sprintPagination: { first: 100 },\n workItemPagination: { first: 500 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\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\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const projects = data?.planmagnetProjects?.items ?? [];\n const sprints = data?.planmagnetSprints?.items ?? [];\n const workItems = data?.planmagnetWorkItems?.items ?? [];\n\n const completedSprints = sprints.filter((s) => s.status === 'COMPLETED');\n const activeSprints = sprints.filter((s) => s.status === 'ACTIVE');\n const creatorName = currentUser?.name ?? currentUser?.firstName ?? 'System';\n\n const reports = [\n ...completedSprints.map((sprint) => ({\n id: `velocity-${sprint.id}`,\n name: `${sprint.name} Velocity Report`,\n description: `Velocity analysis for ${sprint.name} (${sprint.velocity ?? 0} pts)`,\n type: 'velocity',\n createdBy: creatorName,\n lastRun: sprint.endDate ?? '',\n schedule: null as string | null,\n })),\n ...activeSprints.map((sprint) => ({\n id: `burndown-${sprint.id}`,\n name: `${sprint.name} Burndown`,\n description: `Active burndown tracking for ${sprint.name}`,\n type: 'burndown',\n createdBy: creatorName,\n lastRun: new Date().toISOString().split('T')[0],\n schedule: 'daily' as string | null,\n })),\n ...projects\n .filter((p) => p.status === 'ACTIVE')\n .map((project) => ({\n id: `status-${project.id}`,\n name: `${project.name} Status Report`,\n description: `Project status overview for ${project.key}`,\n type: 'project_status',\n createdBy: creatorName,\n lastRun: new Date().toISOString().split('T')[0],\n schedule: 'weekly' as string | null,\n })),\n ];\n\n const types = ['all', ...new Set(reports.map((r) => r.type))];\n const filtered = typeFilter === 'all' ? reports : reports.filter((r) => r.type === typeFilter);\n\n const scheduledCount = reports.filter((r) => r.schedule).length;\n const todayStr = new Date().toISOString().split('T')[0];\n const runTodayCount = reports.filter((r) => r.lastRun === todayStr).length;\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\">Reports</h1>\n <p className=\"text-sm text-muted-foreground\">{reports.length} reports configured</p>\n </div>\n <Button size=\"sm\" onClick={() => navigate('/reports/create')}>\n <Plus className=\"mr-1 h-4 w-4\" />\n New Report\n </Button>\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Total Reports</p>\n <p className=\"text-xl font-bold\">{reports.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Scheduled</p>\n <p className=\"text-xl font-bold\">{scheduledCount}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-xs text-muted-foreground\">Run Today</p>\n <p className=\"text-xl font-bold\">{runTodayCount}</p>\n </CardContent>\n </Card>\n </div>\n <div className=\"flex gap-1\">\n {types.map((t) => (\n <button\n key={t}\n onClick={() => setTypeFilter(t)}\n className={`px-3 py-1.5 text-sm rounded-md capitalize ${typeFilter === t ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted'}`}\n >\n {t === 'all' ? 'All' : t.replace('_', ' ')}\n </button>\n ))}\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {filtered.map((report) => (\n <Card key={report.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4 text-primary\" />\n {report.name}\n </CardTitle>\n <span\n className={`text-xs px-2 py-0.5 rounded-full capitalize ${typeColor[report.type] ?? 'bg-gray-100'}`}\n >\n {report.type.replace('_', ' ')}\n </span>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">{report.description}</p>\n <div className=\"flex gap-3 text-xs text-muted-foreground\">\n {report.schedule && (\n <span className=\"flex items-center gap-1\">\n <Clock className=\"h-3 w-3\" />\n {report.schedule}\n </span>\n )}\n {report.lastRun && (\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n Last: {report.lastRun}\n </span>\n )}\n <span className=\"flex items-center gap-1\">{report.createdBy}</span>\n </div>\n </CardContent>\n </Card>\n ))}\n {filtered.length === 0 && (\n <div className=\"col-span-2 text-center py-12\">\n <BarChart3 className=\"h-12 w-12 text-muted-foreground mx-auto mb-3\" />\n <p className=\"text-sm text-muted-foreground\">\n No reports found for the selected filter.\n </p>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@ import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
|
6
6
|
import { Badge as u, Button as d, Card as f, CardContent as p, CardHeader as m, CardTitle as h } from "@burdenoff/fe-libs/ui";
|
|
7
7
|
//#region src/planmagnet/pages/SprintsStartSprintPagePage.tsx
|
|
8
8
|
var g = a`
|
|
9
|
-
query GetSprints($workspaceId: ID!, $filter: SprintFilter, $pagination:
|
|
9
|
+
query GetSprints($workspaceId: ID!, $filter: SprintFilter, $pagination: PlanmagnetPaginationInput) {
|
|
10
10
|
planmagnetSprints(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {
|
|
11
11
|
items {
|
|
12
12
|
id
|
|
@@ -29,7 +29,7 @@ var g = a`
|
|
|
29
29
|
query GetSprintWorkItems(
|
|
30
30
|
$workspaceId: ID!
|
|
31
31
|
$filter: WorkItemFilter
|
|
32
|
-
$pagination:
|
|
32
|
+
$pagination: PlanmagnetPaginationInput
|
|
33
33
|
) {
|
|
34
34
|
planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {
|
|
35
35
|
items {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SprintsStartSprintPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/SprintsStartSprintPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery, useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge, Button } from '@burdenoff/fe-libs/ui';\nimport { Zap, Calendar, Users, Play } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_SPRINTS = gql`\n query GetSprints($workspaceId: ID!, $filter: SprintFilter, $pagination: PaginationInput) {\n planmagnetSprints(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n name\n goal\n status\n startDate\n endDate\n totalPoints\n completedPoints\n tasksTotal\n tasksCompleted\n velocity\n teamMemberIds\n }\n totalCount\n }\n }\n`;\n\nconst GET_SPRINT_WORK_ITEMS = gql`\n query GetSprintWorkItems(\n $workspaceId: ID!\n $filter: WorkItemFilter\n $pagination: PaginationInput\n ) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n title\n status\n storyPoints\n sprintId\n }\n totalCount\n }\n }\n`;\n\nconst START_SPRINT = gql`\n mutation StartSprint($workspaceId: ID!, $sprintId: ID!) {\n planmagnetStartSprint(workspaceId: $workspaceId, id: $sprintId) {\n id\n status\n startDate\n }\n }\n`;\n\ninterface SprintNode {\n id: string;\n name: string;\n goal: string | null;\n status: string;\n startDate: string | null;\n endDate: string | null;\n totalPoints: number;\n completedPoints: number;\n tasksTotal: number;\n tasksCompleted: number;\n velocity: number;\n teamMemberIds: string[];\n}\n\ninterface SprintWorkItem {\n id: string;\n title: string;\n status: string;\n storyPoints: number | null;\n sprintId: string | null;\n}\n\nexport function SprintsStartSprintPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n const {\n data: sprintData,\n loading: sprintsLoading,\n error: sprintsError,\n } = useQuery<{\n sprints: { items: SprintNode[]; totalCount: number };\n }>(GET_SPRINTS, {\n variables: { workspaceId, pagination: { first: 50 } },\n skip: !workspaceId,\n });\n\n const sprints = sprintData?.sprints?.items ?? [];\n const activeSprints = sprints.filter((s) => s.status === 'ACTIVE');\n const planningSprints = sprints.filter((s) => s.status === 'PLANNING');\n\n // Fetch work items for active sprints\n const activeSprintIds = activeSprints.map((s) => s.id);\n const { data: workItemsData } = useQuery<{\n workItems: { items: SprintWorkItem[]; totalCount: number };\n }>(GET_SPRINT_WORK_ITEMS, {\n variables: {\n workspaceId,\n filter: { sprintIds: activeSprintIds },\n pagination: { first: 200 },\n },\n skip: !workspaceId || activeSprintIds.length === 0,\n });\n\n const sprintWorkItems = workItemsData?.workItems?.items ?? [];\n\n const [startSprint, { loading: startingSprintLoading }] = useMutation(START_SPRINT, {\n refetchQueries: ['GetSprints'],\n });\n\n const handleStartSprint = async (sprintId: string) => {\n if (!workspaceId) return;\n await startSprint({ variables: { workspaceId, sprintId } });\n };\n\n if (sprintsLoading) {\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\n if (sprintsError) {\n return <div className=\"p-6 text-red-500\">Error: {sprintsError.message}</div>;\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Sprint Management</h1>\n <p className=\"text-sm text-muted-foreground\">\n {sprints.length} sprints total · {activeSprints.length} active\n </p>\n </div>\n\n {activeSprints.length > 0 && (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Active Sprints</h2>\n {activeSprints.map((sprint) => {\n const tasksForSprint = sprintWorkItems.filter((t) => t.sprintId === sprint.id);\n const pctDone =\n sprint.totalPoints > 0\n ? Math.round((sprint.completedPoints / sprint.totalPoints) * 100)\n : 0;\n return (\n <Card key={sprint.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base flex items-center gap-2\">\n <Zap className=\"h-4 w-4 text-primary\" />\n {sprint.name}\n </CardTitle>\n <Badge>Active</Badge>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">{sprint.goal ?? ''}</p>\n <div className=\"flex gap-4 text-xs text-muted-foreground\">\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n {sprint.startDate ?? '?'} - {sprint.endDate ?? '?'}\n </span>\n <span className=\"flex items-center gap-1\">\n <Users className=\"h-3 w-3\" />\n {sprint.teamMemberIds.length} members\n </span>\n </div>\n <div className=\"grid grid-cols-3 gap-4 text-center\">\n <div className=\"p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-bold\">\n {sprint.completedPoints}/{sprint.totalPoints}\n </p>\n <p className=\"text-xs text-muted-foreground\">Points</p>\n </div>\n <div className=\"p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-bold\">\n {sprint.tasksCompleted}/{sprint.tasksTotal}\n </p>\n <p className=\"text-xs text-muted-foreground\">Tasks</p>\n </div>\n <div className=\"p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-bold\">{sprint.velocity}</p>\n <p className=\"text-xs text-muted-foreground\">Velocity</p>\n </div>\n </div>\n <div>\n <div className=\"flex justify-between text-xs mb-1\">\n <span className=\"text-muted-foreground\">Sprint Progress</span>\n <span className=\"font-medium\">{pctDone}%</span>\n </div>\n <div className=\"w-full h-2 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full\"\n style={{ width: `${pctDone}%` }}\n />\n </div>\n </div>\n {tasksForSprint.length > 0 && (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-2\">\n Sprint Backlog\n </p>\n <div className=\"space-y-1\">\n {tasksForSprint.map((t) => (\n <div\n key={t.id}\n className=\"flex items-center justify-between border rounded p-2 text-sm\"\n >\n <span>{t.title}</span>\n <div className=\"flex gap-1\">\n <Badge variant=\"secondary\" className=\"text-xs capitalize\">\n {t.status.toLowerCase().replace('_', ' ')}\n </Badge>\n <span className=\"text-xs text-muted-foreground\">\n {t.storyPoints ?? 0}pts\n </span>\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-1\">Team</p>\n <div className=\"flex gap-2\">\n {sprint.teamMemberIds.map((memberId) => (\n <div\n key={memberId}\n className=\"h-7 w-7 rounded-full bg-primary/10 flex items-center justify-center text-[10px] font-medium text-primary\"\n title={memberId}\n >\n {memberId.slice(0, 2).toUpperCase()}\n </div>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n );\n })}\n </div>\n )}\n\n {planningSprints.length > 0 && (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Planning</h2>\n {planningSprints.map((sprint) => (\n <Card key={sprint.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{sprint.name}</CardTitle>\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"secondary\">Planning</Badge>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => handleStartSprint(sprint.id)}\n disabled={startingSprintLoading}\n >\n <Play className=\"mr-1 h-3 w-3\" />\n Start Sprint\n </Button>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">{sprint.goal ?? ''}</p>\n <div className=\"flex gap-4 text-xs text-muted-foreground\">\n <span>\n {sprint.startDate ?? '?'} - {sprint.endDate ?? '?'}\n </span>\n <span>{sprint.totalPoints} points planned</span>\n <span>{sprint.teamMemberIds.length} members</span>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SprintsStartSprintPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/SprintsStartSprintPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery, useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge, Button } from '@burdenoff/fe-libs/ui';\nimport { Zap, Calendar, Users, Play } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_SPRINTS = gql`\n query GetSprints($workspaceId: ID!, $filter: SprintFilter, $pagination: PlanmagnetPaginationInput) {\n planmagnetSprints(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n name\n goal\n status\n startDate\n endDate\n totalPoints\n completedPoints\n tasksTotal\n tasksCompleted\n velocity\n teamMemberIds\n }\n totalCount\n }\n }\n`;\n\nconst GET_SPRINT_WORK_ITEMS = gql`\n query GetSprintWorkItems(\n $workspaceId: ID!\n $filter: WorkItemFilter\n $pagination: PlanmagnetPaginationInput\n ) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n title\n status\n storyPoints\n sprintId\n }\n totalCount\n }\n }\n`;\n\nconst START_SPRINT = gql`\n mutation StartSprint($workspaceId: ID!, $sprintId: ID!) {\n planmagnetStartSprint(workspaceId: $workspaceId, id: $sprintId) {\n id\n status\n startDate\n }\n }\n`;\n\ninterface SprintNode {\n id: string;\n name: string;\n goal: string | null;\n status: string;\n startDate: string | null;\n endDate: string | null;\n totalPoints: number;\n completedPoints: number;\n tasksTotal: number;\n tasksCompleted: number;\n velocity: number;\n teamMemberIds: string[];\n}\n\ninterface SprintWorkItem {\n id: string;\n title: string;\n status: string;\n storyPoints: number | null;\n sprintId: string | null;\n}\n\nexport function SprintsStartSprintPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n const {\n data: sprintData,\n loading: sprintsLoading,\n error: sprintsError,\n } = useQuery<{\n sprints: { items: SprintNode[]; totalCount: number };\n }>(GET_SPRINTS, {\n variables: { workspaceId, pagination: { first: 50 } },\n skip: !workspaceId,\n });\n\n const sprints = sprintData?.sprints?.items ?? [];\n const activeSprints = sprints.filter((s) => s.status === 'ACTIVE');\n const planningSprints = sprints.filter((s) => s.status === 'PLANNING');\n\n // Fetch work items for active sprints\n const activeSprintIds = activeSprints.map((s) => s.id);\n const { data: workItemsData } = useQuery<{\n workItems: { items: SprintWorkItem[]; totalCount: number };\n }>(GET_SPRINT_WORK_ITEMS, {\n variables: {\n workspaceId,\n filter: { sprintIds: activeSprintIds },\n pagination: { first: 200 },\n },\n skip: !workspaceId || activeSprintIds.length === 0,\n });\n\n const sprintWorkItems = workItemsData?.workItems?.items ?? [];\n\n const [startSprint, { loading: startingSprintLoading }] = useMutation(START_SPRINT, {\n refetchQueries: ['GetSprints'],\n });\n\n const handleStartSprint = async (sprintId: string) => {\n if (!workspaceId) return;\n await startSprint({ variables: { workspaceId, sprintId } });\n };\n\n if (sprintsLoading) {\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\n if (sprintsError) {\n return <div className=\"p-6 text-red-500\">Error: {sprintsError.message}</div>;\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Sprint Management</h1>\n <p className=\"text-sm text-muted-foreground\">\n {sprints.length} sprints total · {activeSprints.length} active\n </p>\n </div>\n\n {activeSprints.length > 0 && (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Active Sprints</h2>\n {activeSprints.map((sprint) => {\n const tasksForSprint = sprintWorkItems.filter((t) => t.sprintId === sprint.id);\n const pctDone =\n sprint.totalPoints > 0\n ? Math.round((sprint.completedPoints / sprint.totalPoints) * 100)\n : 0;\n return (\n <Card key={sprint.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base flex items-center gap-2\">\n <Zap className=\"h-4 w-4 text-primary\" />\n {sprint.name}\n </CardTitle>\n <Badge>Active</Badge>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">{sprint.goal ?? ''}</p>\n <div className=\"flex gap-4 text-xs text-muted-foreground\">\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n {sprint.startDate ?? '?'} - {sprint.endDate ?? '?'}\n </span>\n <span className=\"flex items-center gap-1\">\n <Users className=\"h-3 w-3\" />\n {sprint.teamMemberIds.length} members\n </span>\n </div>\n <div className=\"grid grid-cols-3 gap-4 text-center\">\n <div className=\"p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-bold\">\n {sprint.completedPoints}/{sprint.totalPoints}\n </p>\n <p className=\"text-xs text-muted-foreground\">Points</p>\n </div>\n <div className=\"p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-bold\">\n {sprint.tasksCompleted}/{sprint.tasksTotal}\n </p>\n <p className=\"text-xs text-muted-foreground\">Tasks</p>\n </div>\n <div className=\"p-3 bg-muted rounded-md\">\n <p className=\"text-lg font-bold\">{sprint.velocity}</p>\n <p className=\"text-xs text-muted-foreground\">Velocity</p>\n </div>\n </div>\n <div>\n <div className=\"flex justify-between text-xs mb-1\">\n <span className=\"text-muted-foreground\">Sprint Progress</span>\n <span className=\"font-medium\">{pctDone}%</span>\n </div>\n <div className=\"w-full h-2 rounded-full bg-muted overflow-hidden\">\n <div\n className=\"h-full bg-primary rounded-full\"\n style={{ width: `${pctDone}%` }}\n />\n </div>\n </div>\n {tasksForSprint.length > 0 && (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-2\">\n Sprint Backlog\n </p>\n <div className=\"space-y-1\">\n {tasksForSprint.map((t) => (\n <div\n key={t.id}\n className=\"flex items-center justify-between border rounded p-2 text-sm\"\n >\n <span>{t.title}</span>\n <div className=\"flex gap-1\">\n <Badge variant=\"secondary\" className=\"text-xs capitalize\">\n {t.status.toLowerCase().replace('_', ' ')}\n </Badge>\n <span className=\"text-xs text-muted-foreground\">\n {t.storyPoints ?? 0}pts\n </span>\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-1\">Team</p>\n <div className=\"flex gap-2\">\n {sprint.teamMemberIds.map((memberId) => (\n <div\n key={memberId}\n className=\"h-7 w-7 rounded-full bg-primary/10 flex items-center justify-center text-[10px] font-medium text-primary\"\n title={memberId}\n >\n {memberId.slice(0, 2).toUpperCase()}\n </div>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n );\n })}\n </div>\n )}\n\n {planningSprints.length > 0 && (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Planning</h2>\n {planningSprints.map((sprint) => (\n <Card key={sprint.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{sprint.name}</CardTitle>\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"secondary\">Planning</Badge>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => handleStartSprint(sprint.id)}\n disabled={startingSprintLoading}\n >\n <Play className=\"mr-1 h-3 w-3\" />\n Start Sprint\n </Button>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">{sprint.goal ?? ''}</p>\n <div className=\"flex gap-4 text-xs text-muted-foreground\">\n <span>\n {sprint.startDate ?? '?'} - {sprint.endDate ?? '?'}\n </span>\n <span>{sprint.totalPoints} points planned</span>\n <span>{sprint.teamMemberIds.length} members</span>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
|
7
7
|
import { Card as s, CardContent as c } from "@burdenoff/fe-libs/ui";
|
|
8
8
|
//#region src/planmagnet/pages/TasksTasksPagePage.tsx
|
|
9
9
|
var l = r`
|
|
10
|
-
query GetWorkItems($workspaceId: ID!, $filter: WorkItemFilter, $pagination:
|
|
10
|
+
query GetWorkItems($workspaceId: ID!, $filter: WorkItemFilter, $pagination: PlanmagnetPaginationInput) {
|
|
11
11
|
planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {
|
|
12
12
|
items {
|
|
13
13
|
id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksTasksPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksTasksPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent } from '@burdenoff/fe-libs/ui';\nimport { Filter } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_WORK_ITEMS = gql`\n query GetWorkItems($workspaceId: ID!, $filter: WorkItemFilter, $pagination: PaginationInput) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n title\n type\n status\n priority\n key\n assigneeId\n reporterId\n sprintId\n boardColumnId\n storyPoints\n estimatedHours\n dueDate\n labels\n tags\n createdAt\n }\n totalCount\n }\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n type: string;\n status: string;\n priority: string;\n key: string;\n assigneeId: string | null;\n reporterId: string | null;\n sprintId: string | null;\n boardColumnId: string | null;\n storyPoints: number | null;\n estimatedHours: number | null;\n dueDate: string | null;\n labels: string[];\n tags: string[];\n createdAt: string;\n}\n\nconst columns = ['BACKLOG', 'TODO', 'IN_PROGRESS', 'IN_REVIEW', 'DONE', 'BLOCKED'] as const;\n\nconst colLabel: Record<string, string> = {\n BACKLOG: 'Backlog',\n TODO: 'To Do',\n IN_PROGRESS: 'In Progress',\n IN_REVIEW: 'In Review',\n DONE: 'Done',\n BLOCKED: 'Blocked',\n};\n\nconst colColor: Record<string, string> = {\n BACKLOG: 'border-t-gray-400',\n TODO: 'border-t-blue-400',\n IN_PROGRESS: 'border-t-yellow-400',\n IN_REVIEW: 'border-t-purple-400',\n DONE: 'border-t-green-400',\n BLOCKED: 'border-t-red-400',\n};\n\nconst priorityColor: Record<string, string> = {\n LOW: 'bg-gray-100 text-gray-700',\n MEDIUM: 'bg-blue-100 text-blue-700',\n HIGH: 'bg-orange-100 text-orange-700',\n CRITICAL: 'bg-red-100 text-red-700',\n};\n\nconst typeColor: Record<string, string> = {\n STORY: 'bg-green-100 text-green-700',\n BUG: 'bg-red-100 text-red-700',\n TASK: 'bg-blue-100 text-blue-700',\n EPIC: 'bg-purple-100 text-purple-700',\n SUBTASK: 'bg-gray-100 text-gray-700',\n};\n\nexport function TasksTasksPagePage() {\n const { workspaceId } = usePlanMagnet();\n const [priorityFilter, setPriorityFilter] = useState<string>('all');\n const [typeFilter, setTypeFilter] = useState<string>('all');\n\n const { data, loading, error } = useQuery<{\n workItems: { items: WorkItemNode[]; totalCount: number };\n }>(GET_WORK_ITEMS, {\n variables: {\n workspaceId,\n pagination: { first: 200 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\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\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const tasks = data?.planmagnetWorkItems?.items ?? [];\n\n const filtered = tasks.filter(\n (t) =>\n (priorityFilter === 'all' || t.priority === priorityFilter.toUpperCase()) &&\n (typeFilter === 'all' || t.type === typeFilter.toUpperCase())\n );\n\n return (\n <div className=\"space-y-4 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Task Board</h1>\n <p className=\"text-sm text-muted-foreground\">{tasks.length} tasks across all projects</p>\n </div>\n </div>\n <div className=\"flex gap-4 items-center flex-wrap\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n <div className=\"flex gap-1\">\n {['all', 'low', 'medium', 'high', 'critical'].map((p) => (\n <button\n key={p}\n onClick={() => setPriorityFilter(p)}\n className={`px-2 py-1 text-xs rounded capitalize ${priorityFilter === p ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {p}\n </button>\n ))}\n </div>\n <div className=\"flex gap-1\">\n {['all', 'story', 'bug', 'task', 'epic'].map((t) => (\n <button\n key={t}\n onClick={() => setTypeFilter(t)}\n className={`px-2 py-1 text-xs rounded capitalize ${typeFilter === t ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {t}\n </button>\n ))}\n </div>\n </div>\n <div className=\"grid grid-cols-6 gap-3 overflow-x-auto\">\n {columns.map((col) => {\n const colTasks = filtered.filter((t) => t.status === col);\n return (\n <div key={col} className=\"min-w-[200px]\">\n <div className={`border-t-2 ${colColor[col]} rounded-t-md p-2 bg-muted/50`}>\n <div className=\"flex justify-between items-center\">\n <span className=\"text-sm font-medium\">{colLabel[col]}</span>\n <span className=\"text-xs bg-muted rounded-full px-1.5\">{colTasks.length}</span>\n </div>\n </div>\n <div className=\"space-y-2 mt-2\">\n {colTasks.map((task) => (\n <Card key={task.id} className=\"shadow-sm\">\n <CardContent className=\"p-3 space-y-2\">\n <p className=\"text-sm font-medium leading-tight\">{task.title}</p>\n <p className=\"text-xs text-muted-foreground\">{task.key}</p>\n <div className=\"flex gap-1 flex-wrap\">\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${priorityColor[task.priority] ?? ''}`}\n >\n {task.priority.toLowerCase()}\n </span>\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${typeColor[task.type] ?? ''}`}\n >\n {task.type.toLowerCase()}\n </span>\n </div>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex gap-1\">\n {(task.labels ?? []).slice(0, 2).map((l) => (\n <span key={l} className=\"text-[9px] px-1 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] font-medium bg-primary/10 text-primary rounded-full h-5 w-5 flex items-center justify-center\">\n {task.storyPoints ?? 0}\n </span>\n </div>\n </div>\n <div className=\"flex justify-between text-[10px] text-muted-foreground\">\n <span>{task.assigneeId ?? 'Unassigned'}</span>\n <span>{task.dueDate ?? ''}</span>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TasksTasksPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksTasksPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent } from '@burdenoff/fe-libs/ui';\nimport { Filter } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_WORK_ITEMS = gql`\n query GetWorkItems($workspaceId: ID!, $filter: WorkItemFilter, $pagination: PlanmagnetPaginationInput) {\n planmagnetWorkItems(workspaceId: $workspaceId, filter: $filter, pagination: $pagination) {\n items {\n id\n title\n type\n status\n priority\n key\n assigneeId\n reporterId\n sprintId\n boardColumnId\n storyPoints\n estimatedHours\n dueDate\n labels\n tags\n createdAt\n }\n totalCount\n }\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n type: string;\n status: string;\n priority: string;\n key: string;\n assigneeId: string | null;\n reporterId: string | null;\n sprintId: string | null;\n boardColumnId: string | null;\n storyPoints: number | null;\n estimatedHours: number | null;\n dueDate: string | null;\n labels: string[];\n tags: string[];\n createdAt: string;\n}\n\nconst columns = ['BACKLOG', 'TODO', 'IN_PROGRESS', 'IN_REVIEW', 'DONE', 'BLOCKED'] as const;\n\nconst colLabel: Record<string, string> = {\n BACKLOG: 'Backlog',\n TODO: 'To Do',\n IN_PROGRESS: 'In Progress',\n IN_REVIEW: 'In Review',\n DONE: 'Done',\n BLOCKED: 'Blocked',\n};\n\nconst colColor: Record<string, string> = {\n BACKLOG: 'border-t-gray-400',\n TODO: 'border-t-blue-400',\n IN_PROGRESS: 'border-t-yellow-400',\n IN_REVIEW: 'border-t-purple-400',\n DONE: 'border-t-green-400',\n BLOCKED: 'border-t-red-400',\n};\n\nconst priorityColor: Record<string, string> = {\n LOW: 'bg-gray-100 text-gray-700',\n MEDIUM: 'bg-blue-100 text-blue-700',\n HIGH: 'bg-orange-100 text-orange-700',\n CRITICAL: 'bg-red-100 text-red-700',\n};\n\nconst typeColor: Record<string, string> = {\n STORY: 'bg-green-100 text-green-700',\n BUG: 'bg-red-100 text-red-700',\n TASK: 'bg-blue-100 text-blue-700',\n EPIC: 'bg-purple-100 text-purple-700',\n SUBTASK: 'bg-gray-100 text-gray-700',\n};\n\nexport function TasksTasksPagePage() {\n const { workspaceId } = usePlanMagnet();\n const [priorityFilter, setPriorityFilter] = useState<string>('all');\n const [typeFilter, setTypeFilter] = useState<string>('all');\n\n const { data, loading, error } = useQuery<{\n workItems: { items: WorkItemNode[]; totalCount: number };\n }>(GET_WORK_ITEMS, {\n variables: {\n workspaceId,\n pagination: { first: 200 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\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\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const tasks = data?.planmagnetWorkItems?.items ?? [];\n\n const filtered = tasks.filter(\n (t) =>\n (priorityFilter === 'all' || t.priority === priorityFilter.toUpperCase()) &&\n (typeFilter === 'all' || t.type === typeFilter.toUpperCase())\n );\n\n return (\n <div className=\"space-y-4 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Task Board</h1>\n <p className=\"text-sm text-muted-foreground\">{tasks.length} tasks across all projects</p>\n </div>\n </div>\n <div className=\"flex gap-4 items-center flex-wrap\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n <div className=\"flex gap-1\">\n {['all', 'low', 'medium', 'high', 'critical'].map((p) => (\n <button\n key={p}\n onClick={() => setPriorityFilter(p)}\n className={`px-2 py-1 text-xs rounded capitalize ${priorityFilter === p ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {p}\n </button>\n ))}\n </div>\n <div className=\"flex gap-1\">\n {['all', 'story', 'bug', 'task', 'epic'].map((t) => (\n <button\n key={t}\n onClick={() => setTypeFilter(t)}\n className={`px-2 py-1 text-xs rounded capitalize ${typeFilter === t ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}\n >\n {t}\n </button>\n ))}\n </div>\n </div>\n <div className=\"grid grid-cols-6 gap-3 overflow-x-auto\">\n {columns.map((col) => {\n const colTasks = filtered.filter((t) => t.status === col);\n return (\n <div key={col} className=\"min-w-[200px]\">\n <div className={`border-t-2 ${colColor[col]} rounded-t-md p-2 bg-muted/50`}>\n <div className=\"flex justify-between items-center\">\n <span className=\"text-sm font-medium\">{colLabel[col]}</span>\n <span className=\"text-xs bg-muted rounded-full px-1.5\">{colTasks.length}</span>\n </div>\n </div>\n <div className=\"space-y-2 mt-2\">\n {colTasks.map((task) => (\n <Card key={task.id} className=\"shadow-sm\">\n <CardContent className=\"p-3 space-y-2\">\n <p className=\"text-sm font-medium leading-tight\">{task.title}</p>\n <p className=\"text-xs text-muted-foreground\">{task.key}</p>\n <div className=\"flex gap-1 flex-wrap\">\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${priorityColor[task.priority] ?? ''}`}\n >\n {task.priority.toLowerCase()}\n </span>\n <span\n className={`text-[10px] px-1.5 py-0.5 rounded-full capitalize ${typeColor[task.type] ?? ''}`}\n >\n {task.type.toLowerCase()}\n </span>\n </div>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex gap-1\">\n {(task.labels ?? []).slice(0, 2).map((l) => (\n <span key={l} className=\"text-[9px] px-1 py-0.5 rounded bg-muted\">\n {l}\n </span>\n ))}\n </div>\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] font-medium bg-primary/10 text-primary rounded-full h-5 w-5 flex items-center justify-center\">\n {task.storyPoints ?? 0}\n </span>\n </div>\n </div>\n <div className=\"flex justify-between text-[10px] text-muted-foreground\">\n <span>{task.assigneeId ?? 'Unassigned'}</span>\n <span>{task.dueDate ?? ''}</span>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
|
7
7
|
import { Button as u, Card as d, CardContent as f, CardHeader as p, CardTitle as m, Input as h } from "@burdenoff/fe-libs/ui";
|
|
8
8
|
//#region src/planmagnet/pages/TeamCreateTeamPagePage.tsx
|
|
9
9
|
var g = o`
|
|
10
|
-
query GetProjectsForTeamCreation($workspaceId: ID!, $pagination:
|
|
10
|
+
query GetProjectsForTeamCreation($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {
|
|
11
11
|
planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {
|
|
12
12
|
items {
|
|
13
13
|
id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamCreateTeamPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamCreateTeamPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, Users } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_PROJECTS_FOR_TEAM = gql`\n query GetProjectsForTeamCreation($workspaceId: ID!, $pagination:
|
|
1
|
+
{"version":3,"file":"TeamCreateTeamPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamCreateTeamPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, Users } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_PROJECTS_FOR_TEAM = gql`\n query GetProjectsForTeamCreation($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n key\n ownerId\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n ownerId: string | null;\n}\n\ninterface ProjectsData {\n projects: { items: ProjectNode[]; totalCount: number };\n}\n\nexport function TeamCreateTeamPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n const [form, setForm] = useState({ name: '', description: '', lead: '', projectId: '' });\n\n const { data, loading, error } = useQuery<ProjectsData>(GET_PROJECTS_FOR_TEAM, {\n variables: {\n workspaceId,\n pagination: { first: 100 },\n },\n skip: !workspaceId,\n });\n\n const projects = data?.planmagnetProjects?.items ?? [];\n\n const handleCreate = () => {\n if (!form.name.trim()) return;\n navigate('/team');\n };\n\n if (loading) {\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\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Create Team</h1>\n <p className=\"text-sm text-muted-foreground\">\n Set up a new team with members and a lead.\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/team')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleCreate}>\n <Save className=\"mr-1 h-4 w-4\" />\n Create Team\n </Button>\n </div>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Users className=\"h-4 w-4\" />\n Team Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Team Name</label>\n <Input\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Platform Engineering\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description</label>\n <textarea\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>\n <label className=\"text-sm font-medium\">Team Lead</label>\n <Input\n value={form.lead}\n onChange={(e) => setForm({ ...form, lead: e.target.value })}\n className=\"mt-1\"\n placeholder=\"Team lead name or email\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Associated Project (optional)</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.projectId}\n onChange={(e) => setForm({ ...form, projectId: e.target.value })}\n >\n <option value=\"\">No project</option>\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name} ({p.key})\n </option>\n ))}\n </select>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
|
7
7
|
import { Button as u, Card as d, CardContent as f, CardHeader as p, CardTitle as m, Input as h } from "@burdenoff/fe-libs/ui";
|
|
8
8
|
//#region src/planmagnet/pages/TeamInviteMemberPagePage.tsx
|
|
9
9
|
var g = o`
|
|
10
|
-
query GetProjectsForInvite($workspaceId: ID!, $pagination:
|
|
10
|
+
query GetProjectsForInvite($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {
|
|
11
11
|
planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {
|
|
12
12
|
items {
|
|
13
13
|
id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamInviteMemberPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamInviteMemberPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, UserPlus } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_PROJECTS_FOR_INVITE = gql`\n query GetProjectsForInvite($workspaceId: ID!, $pagination:
|
|
1
|
+
{"version":3,"file":"TeamInviteMemberPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamInviteMemberPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, UserPlus } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\n\nconst GET_PROJECTS_FOR_INVITE = gql`\n query GetProjectsForInvite($workspaceId: ID!, $pagination: PlanmagnetPaginationInput) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $pagination) {\n items {\n id\n name\n key\n methodology\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n methodology: string | null;\n}\n\ninterface ProjectsData {\n projects: { items: ProjectNode[]; totalCount: number };\n}\n\nexport function TeamInviteMemberPagePage() {\n const { workspaceId } = usePlanMagnet();\n const navigate = usePlanMagnetNavigate();\n\n const { data, loading, error } = useQuery<ProjectsData>(GET_PROJECTS_FOR_INVITE, {\n variables: {\n workspaceId,\n pagination: { first: 100 },\n },\n skip: !workspaceId,\n });\n\n const [form, setForm] = useState({\n email: '',\n role: 'developer',\n projectId: '',\n department: 'Engineering',\n });\n const roles = [\n 'developer',\n 'designer',\n 'product manager',\n 'qa engineer',\n 'engineering manager',\n 'data engineer',\n ] as const;\n const departments = ['Engineering', 'Product', 'Design', 'Quality', 'Data'] as const;\n\n const projects = data?.planmagnetProjects?.items ?? [];\n\n const teams = projects.reduce(\n (acc, p) => {\n const method = p.methodology ?? 'general';\n if (!acc.some((t) => t.id === method)) {\n acc.push({\n id: method,\n name: `${method.charAt(0).toUpperCase()}${method.slice(1)} Team`,\n });\n }\n return acc;\n },\n [] as Array<{ id: string; name: string }>\n );\n\n const handleInvite = () => {\n if (!form.email.trim()) return;\n navigate('/team');\n };\n\n if (loading) {\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\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Invite Team Member</h1>\n <p className=\"text-sm text-muted-foreground\">Add a new member to your workspace.</p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/team')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleInvite}>\n <Save className=\"mr-1 h-4 w-4\" />\n Send Invite\n </Button>\n </div>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <UserPlus className=\"h-4 w-4\" />\n Invitation Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Email Address</label>\n <Input\n type=\"email\"\n value={form.email}\n onChange={(e) => setForm({ ...form, email: e.target.value })}\n className=\"mt-1\"\n placeholder=\"colleague@company.com\"\n />\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Role</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm capitalize\"\n value={form.role}\n onChange={(e) => setForm({ ...form, role: e.target.value })}\n >\n {roles.map((r) => (\n <option key={r} value={r}>\n {r}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Department</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.department}\n onChange={(e) => setForm({ ...form, department: e.target.value })}\n >\n {departments.map((d) => (\n <option key={d} value={d}>\n {d}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Team</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.projectId}\n onChange={(e) => setForm({ ...form, projectId: e.target.value })}\n >\n <option value=\"\">No team</option>\n {teams.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -7,8 +7,8 @@ import { Badge as a, Card as o, CardContent as s, CardHeader as c, CardTitle as
|
|
|
7
7
|
var u = t`
|
|
8
8
|
query GetTeamData(
|
|
9
9
|
$workspaceId: ID!
|
|
10
|
-
$projectPagination:
|
|
11
|
-
$workItemPagination:
|
|
10
|
+
$projectPagination: PlanmagnetPaginationInput
|
|
11
|
+
$workItemPagination: PlanmagnetPaginationInput
|
|
12
12
|
) {
|
|
13
13
|
planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {
|
|
14
14
|
items {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamTeamPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamTeamPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport { Users } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_TEAM_DATA = gql`\n query GetTeamData(\n $workspaceId: ID!\n $projectPagination: PaginationInput\n $workItemPagination: PaginationInput\n ) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {\n items {\n id\n name\n key\n status\n ownerId\n methodology\n }\n totalCount\n }\n planmagnetWorkItems(workspaceId: $workspaceId, pagination: $workItemPagination) {\n items {\n id\n status\n assigneeId\n storyPoints\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n status: string;\n ownerId: string | null;\n methodology: string | null;\n}\n\ninterface WorkItemNode {\n id: string;\n status: string;\n assigneeId: string | null;\n storyPoints: number | null;\n}\n\ninterface TeamData {\n projects: { items: ProjectNode[]; totalCount: number };\n workItems: { items: WorkItemNode[]; totalCount: number };\n}\n\nconst statusColor: Record<string, string> = {\n active: 'bg-green-400',\n away: 'bg-yellow-400',\n busy: 'bg-red-400',\n offline: 'bg-gray-300',\n};\n\nexport function TeamTeamPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n const { data, loading, error } = useQuery<TeamData>(GET_TEAM_DATA, {\n variables: {\n workspaceId,\n projectPagination: { first: 100 },\n workItemPagination: { first: 500 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\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\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const projects = data?.planmagnetProjects?.items ?? [];\n const workItems = data?.planmagnetWorkItems?.items ?? [];\n\n const assigneeIds = new Set(\n workItems.filter((wi) => wi.assigneeId).map((wi) => wi.assigneeId as string)\n );\n const ownerIds = new Set(projects.filter((p) => p.ownerId).map((p) => p.ownerId as string));\n const allMemberIds = new Set([...assigneeIds, ...ownerIds]);\n\n const members = Array.from(allMemberIds).map((memberId) => {\n const memberWorkItems = workItems.filter((wi) => wi.assigneeId === memberId);\n const assigned = memberWorkItems.length;\n const completed = memberWorkItems.filter((wi) => wi.status === 'DONE').length;\n const velocity = memberWorkItems\n .filter((wi) => wi.status === 'DONE')\n .reduce((s, wi) => s + (wi.storyPoints ?? 0), 0);\n const memberProjects = projects.filter((p) => p.ownerId === memberId);\n\n return {\n id: memberId,\n name: memberId,\n role: memberProjects.length > 0 ? 'Project Owner' : 'Contributor',\n department: 'Engineering',\n tasksAssigned: assigned,\n tasksCompleted: completed,\n velocity,\n status: assigned > 0 ? 'active' : 'offline',\n };\n });\n\n const teamsByMethodology = projects.reduce(\n (acc, p) => {\n const method = p.methodology ?? 'unassigned';\n if (!acc[method]) {\n acc[method] = { projects: [], ownerIds: new Set<string>() };\n }\n acc[method].projects.push(p);\n if (p.ownerId) acc[method].ownerIds.add(p.ownerId);\n return acc;\n },\n {} as Record<string, { projects: ProjectNode[]; ownerIds: Set<string> }>\n );\n\n const teams = Object.entries(teamsByMethodology).map(([methodology, group]) => ({\n id: methodology,\n name: `${methodology.charAt(0).toUpperCase()}${methodology.slice(1)} Team`,\n description: `Projects using ${methodology} methodology`,\n projectsCount: group.projects.length,\n leadId: Array.from(group.ownerIds)[0] ?? 'Unassigned',\n }));\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Team Overview</h1>\n <p className=\"text-sm text-muted-foreground\">\n {members.length} contributors across {teams.length} teams\n </p>\n </div>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Teams</h2>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {teams.map((team) => (\n <Card key={team.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{team.name}</CardTitle>\n <Badge variant=\"outline\">{team.projectsCount} projects</Badge>\n </div>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-muted-foreground\">{team.description}</p>\n <p className=\"text-xs text-muted-foreground mt-2\">Lead: {team.leadId}</p>\n </CardContent>\n </Card>\n ))}\n {teams.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-2 text-center py-4\">\n No teams found. Create projects to see team groupings.\n </p>\n )}\n </div>\n </div>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Members</h2>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {members.map((member) => (\n <Card key={member.id}>\n <CardContent className=\"pt-4 space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <div className=\"h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center text-sm font-medium text-primary\">\n {member.name\n .split(/[\\s-]+/)\n .slice(0, 2)\n .map((n) => n[0]?.toUpperCase() ?? '')\n .join('')}\n </div>\n <div\n className={`absolute -bottom-0.5 -right-0.5 h-3 w-3 rounded-full border-2 border-background ${statusColor[member.status]}`}\n />\n </div>\n <div>\n <p className=\"text-sm font-medium\">{member.name}</p>\n <p className=\"text-xs text-muted-foreground\">{member.role}</p>\n </div>\n </div>\n <div className=\"grid grid-cols-3 gap-2 text-center text-xs\">\n <div>\n <p className=\"font-semibold\">{member.tasksAssigned}</p>\n <p className=\"text-muted-foreground\">Assigned</p>\n </div>\n <div>\n <p className=\"font-semibold\">{member.tasksCompleted}</p>\n <p className=\"text-muted-foreground\">Done</p>\n </div>\n <div>\n <p className=\"font-semibold\">{member.velocity}</p>\n <p className=\"text-muted-foreground\">Velocity</p>\n </div>\n </div>\n <div className=\"flex justify-between text-xs\">\n <span className=\"text-muted-foreground\">{member.department}</span>\n <span className=\"capitalize text-muted-foreground\">{member.status}</span>\n </div>\n </CardContent>\n </Card>\n ))}\n {members.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-3 text-center py-4\">\n No team members found. Assign work items to see members here.\n </p>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TeamTeamPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TeamTeamPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Badge } from '@burdenoff/fe-libs/ui';\nimport { Users } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_TEAM_DATA = gql`\n query GetTeamData(\n $workspaceId: ID!\n $projectPagination: PlanmagnetPaginationInput\n $workItemPagination: PlanmagnetPaginationInput\n ) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: $projectPagination) {\n items {\n id\n name\n key\n status\n ownerId\n methodology\n }\n totalCount\n }\n planmagnetWorkItems(workspaceId: $workspaceId, pagination: $workItemPagination) {\n items {\n id\n status\n assigneeId\n storyPoints\n }\n totalCount\n }\n }\n`;\n\ninterface ProjectNode {\n id: string;\n name: string;\n key: string;\n status: string;\n ownerId: string | null;\n methodology: string | null;\n}\n\ninterface WorkItemNode {\n id: string;\n status: string;\n assigneeId: string | null;\n storyPoints: number | null;\n}\n\ninterface TeamData {\n projects: { items: ProjectNode[]; totalCount: number };\n workItems: { items: WorkItemNode[]; totalCount: number };\n}\n\nconst statusColor: Record<string, string> = {\n active: 'bg-green-400',\n away: 'bg-yellow-400',\n busy: 'bg-red-400',\n offline: 'bg-gray-300',\n};\n\nexport function TeamTeamPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n const { data, loading, error } = useQuery<TeamData>(GET_TEAM_DATA, {\n variables: {\n workspaceId,\n projectPagination: { first: 100 },\n workItemPagination: { first: 500 },\n },\n skip: !workspaceId,\n });\n\n if (loading) {\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\n if (error) {\n return <div className=\"p-6 text-red-500\">Error: {error.message}</div>;\n }\n\n const projects = data?.planmagnetProjects?.items ?? [];\n const workItems = data?.planmagnetWorkItems?.items ?? [];\n\n const assigneeIds = new Set(\n workItems.filter((wi) => wi.assigneeId).map((wi) => wi.assigneeId as string)\n );\n const ownerIds = new Set(projects.filter((p) => p.ownerId).map((p) => p.ownerId as string));\n const allMemberIds = new Set([...assigneeIds, ...ownerIds]);\n\n const members = Array.from(allMemberIds).map((memberId) => {\n const memberWorkItems = workItems.filter((wi) => wi.assigneeId === memberId);\n const assigned = memberWorkItems.length;\n const completed = memberWorkItems.filter((wi) => wi.status === 'DONE').length;\n const velocity = memberWorkItems\n .filter((wi) => wi.status === 'DONE')\n .reduce((s, wi) => s + (wi.storyPoints ?? 0), 0);\n const memberProjects = projects.filter((p) => p.ownerId === memberId);\n\n return {\n id: memberId,\n name: memberId,\n role: memberProjects.length > 0 ? 'Project Owner' : 'Contributor',\n department: 'Engineering',\n tasksAssigned: assigned,\n tasksCompleted: completed,\n velocity,\n status: assigned > 0 ? 'active' : 'offline',\n };\n });\n\n const teamsByMethodology = projects.reduce(\n (acc, p) => {\n const method = p.methodology ?? 'unassigned';\n if (!acc[method]) {\n acc[method] = { projects: [], ownerIds: new Set<string>() };\n }\n acc[method].projects.push(p);\n if (p.ownerId) acc[method].ownerIds.add(p.ownerId);\n return acc;\n },\n {} as Record<string, { projects: ProjectNode[]; ownerIds: Set<string> }>\n );\n\n const teams = Object.entries(teamsByMethodology).map(([methodology, group]) => ({\n id: methodology,\n name: `${methodology.charAt(0).toUpperCase()}${methodology.slice(1)} Team`,\n description: `Projects using ${methodology} methodology`,\n projectsCount: group.projects.length,\n leadId: Array.from(group.ownerIds)[0] ?? 'Unassigned',\n }));\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Team Overview</h1>\n <p className=\"text-sm text-muted-foreground\">\n {members.length} contributors across {teams.length} teams\n </p>\n </div>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Teams</h2>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {teams.map((team) => (\n <Card key={team.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{team.name}</CardTitle>\n <Badge variant=\"outline\">{team.projectsCount} projects</Badge>\n </div>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-muted-foreground\">{team.description}</p>\n <p className=\"text-xs text-muted-foreground mt-2\">Lead: {team.leadId}</p>\n </CardContent>\n </Card>\n ))}\n {teams.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-2 text-center py-4\">\n No teams found. Create projects to see team groupings.\n </p>\n )}\n </div>\n </div>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-medium\">Members</h2>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {members.map((member) => (\n <Card key={member.id}>\n <CardContent className=\"pt-4 space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <div className=\"h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center text-sm font-medium text-primary\">\n {member.name\n .split(/[\\s-]+/)\n .slice(0, 2)\n .map((n) => n[0]?.toUpperCase() ?? '')\n .join('')}\n </div>\n <div\n className={`absolute -bottom-0.5 -right-0.5 h-3 w-3 rounded-full border-2 border-background ${statusColor[member.status]}`}\n />\n </div>\n <div>\n <p className=\"text-sm font-medium\">{member.name}</p>\n <p className=\"text-xs text-muted-foreground\">{member.role}</p>\n </div>\n </div>\n <div className=\"grid grid-cols-3 gap-2 text-center text-xs\">\n <div>\n <p className=\"font-semibold\">{member.tasksAssigned}</p>\n <p className=\"text-muted-foreground\">Assigned</p>\n </div>\n <div>\n <p className=\"font-semibold\">{member.tasksCompleted}</p>\n <p className=\"text-muted-foreground\">Done</p>\n </div>\n <div>\n <p className=\"font-semibold\">{member.velocity}</p>\n <p className=\"text-muted-foreground\">Velocity</p>\n </div>\n </div>\n <div className=\"flex justify-between text-xs\">\n <span className=\"text-muted-foreground\">{member.department}</span>\n <span className=\"capitalize text-muted-foreground\">{member.status}</span>\n </div>\n </CardContent>\n </Card>\n ))}\n {members.length === 0 && (\n <p className=\"text-sm text-muted-foreground col-span-3 text-center py-4\">\n No team members found. Assign work items to see members here.\n </p>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
package/dist/dev/main.d.ts
DELETED
package/dist/dev/main.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/dev/main.tsx"],"names":[],"mappings":"AAIA,OAAO,cAAc,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"global-operations.d.ts","sourceRoot":"","sources":["../../src/generated/global-operations.ts"],"names":[],"mappings":""}
|