@burdenoff/microfe-planmagnet 2026.830.1 → 2026.923.2
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/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +52 -0
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/hooks/useEntityId.d.ts +14 -0
- package/dist/planmagnet/hooks/useEntityId.d.ts.map +1 -0
- package/dist/planmagnet/hooks/useEntityId.js +15 -0
- package/dist/planmagnet/hooks/useEntityId.js.map +1 -0
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +148 -144
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js +85 -84
- package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleasesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsReleasesPagePage.js +95 -91
- package/dist/planmagnet/pages/ProductsReleasesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js +117 -113
- package/dist/planmagnet/pages/ProductsRoadmapsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js +74 -70
- package/dist/planmagnet/pages/ProjectsActiveProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +21 -17
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +21 -16
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js +67 -63
- package/dist/planmagnet/pages/ProjectsMilestonesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +61 -56
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +107 -99
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js +94 -90
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +46 -41
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +110 -106
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +2 -2
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js +2 -2
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.js +67 -66
- package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
- package/dist/planmagnet/utils/rowNavigation.d.ts +29 -0
- package/dist/planmagnet/utils/rowNavigation.d.ts.map +1 -0
- package/dist/planmagnet/utils/rowNavigation.js +20 -0
- package/dist/planmagnet/utils/rowNavigation.js.map +1 -0
- package/package.json +1 -1
|
@@ -180,10 +180,10 @@ function v() {
|
|
|
180
180
|
"BUG",
|
|
181
181
|
"TASK",
|
|
182
182
|
"EPIC",
|
|
183
|
-
"
|
|
183
|
+
"SUB_TASK"
|
|
184
184
|
].map((e) => /* @__PURE__ */ c("option", {
|
|
185
185
|
value: e,
|
|
186
|
-
children: e.toLowerCase()
|
|
186
|
+
children: e.toLowerCase().replace("_", " ")
|
|
187
187
|
}, e))
|
|
188
188
|
})] })
|
|
189
189
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksCreateTaskPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksCreateTaskPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, CheckSquare } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\ninterface PlanmagnetProjectOption {\n id: string;\n name: string;\n key: string;\n}\n\nconst CREATE_WORK_ITEM = gql`\n mutation CreateWorkItem($input: PlanmagnetCreateWorkItemInput!) {\n planmagnetCreateWorkItem(input: $input) {\n id\n title\n type\n status\n priority\n key\n storyPoints\n dueDate\n labels\n sprintId\n createdAt\n }\n }\n`;\n\n// BOFF-4442/4443 live-verify fix: a WorkItem must belong to a real project\n// (PlanmagnetCreateWorkItemInput.projectId is non-null); the form needs the\n// caller's actual projects to choose from rather than a free-text name.\nconst GET_PROJECTS = gql`\n query GetProjectsForTaskCreate($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n key\n }\n }\n }\n`;\n\nexport function TasksCreateTaskPagePage() {\n const { workspaceId } = usePlanMagnet();\n const [form, setForm] = useState({\n title: '',\n description: '',\n projectId: '',\n priority: 'MEDIUM',\n type: 'STORY',\n storyPoints: '5',\n labels: '',\n sprintId: '',\n dueDate: '',\n });\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { data: projectsData } = useQuery<Record<string, any>>(GET_PROJECTS, {\n variables: { workspaceId: workspaceId ?? 'default' },\n skip: !workspaceId,\n });\n const projects: PlanmagnetProjectOption[] = projectsData?.planmagnetProjects?.items ?? [];\n // Fall back to the first loaded project when the user hasn't picked one\n // yet, without stashing derived state in an effect (avoids the extra\n // render cycle and keeps a single source of truth: `projects`).\n const selectedProjectId = form.projectId || projects[0]?.id || '';\n\n const [createWorkItem, { loading: saving, error }] = useMutation(CREATE_WORK_ITEM, {\n refetchQueries: ['GetWorkItems'],\n });\n\n const handleCreate = async () => {\n if (!form.title.trim() || !selectedProjectId || !workspaceId) return;\n await createWorkItem({\n variables: {\n input: {\n projectId: selectedProjectId,\n title: form.title,\n description: form.description || undefined,\n type: form.type,\n priority: form.priority,\n storyPoints: form.storyPoints ? parseInt(form.storyPoints, 10) : undefined,\n labels: form.labels\n ? form.labels\n .split(',')\n .map((l) => l.trim())\n .filter(Boolean)\n : undefined,\n sprintId: form.sprintId || undefined,\n dueDate: form.dueDate || undefined,\n },\n },\n });\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 Task</h1>\n <p className=\"text-sm text-muted-foreground\">Add a new task to the project backlog.</p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\">\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={saving || !form.title.trim() || !selectedProjectId}\n >\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Creating...' : 'Create Task'}\n </Button>\n </div>\n </div>\n {error && <div className=\"p-6 text-red-500\">Error: {error.message}</div>}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <CheckSquare className=\"h-4 w-4\" />\n Task Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Implement search query parser\"\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-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Describe the task requirements...\"\n />\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Project</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={selectedProjectId}\n onChange={(e) => setForm({ ...form, projectId: e.target.value })}\n >\n {projects.length === 0 && (\n <option value=\"\" disabled>\n No projects available\n </option>\n )}\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.key} — {p.name}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Priority</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.priority}\n onChange={(e) => setForm({ ...form, priority: e.target.value })}\n >\n {['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'].map((p) => (\n <option key={p} value={p}>\n {p.toLowerCase()}\n </option>\n ))}\n </select>\n </div>\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 {['STORY', 'BUG', 'TASK', 'EPIC', 'SUBTASK'].map((t) => (\n <option key={t} value={t}>\n {t.toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Story Points</label>\n <Input\n type=\"number\"\n value={form.storyPoints}\n onChange={(e) => setForm({ ...form, storyPoints: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Sprint ID</label>\n <Input\n value={form.sprintId}\n onChange={(e) => setForm({ ...form, sprintId: e.target.value })}\n className=\"mt-1\"\n placeholder=\"Sprint ID\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Due Date</label>\n <Input\n type=\"date\"\n value={form.dueDate}\n onChange={(e) => setForm({ ...form, dueDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Labels (comma-separated)</label>\n <Input\n value={form.labels}\n onChange={(e) => setForm({ ...form, labels: e.target.value })}\n className=\"mt-1\"\n placeholder=\"backend, search, performance\"\n />\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TasksCreateTaskPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksCreateTaskPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, X, CheckSquare } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\ninterface PlanmagnetProjectOption {\n id: string;\n name: string;\n key: string;\n}\n\nconst CREATE_WORK_ITEM = gql`\n mutation CreateWorkItem($input: PlanmagnetCreateWorkItemInput!) {\n planmagnetCreateWorkItem(input: $input) {\n id\n title\n type\n status\n priority\n key\n storyPoints\n dueDate\n labels\n sprintId\n createdAt\n }\n }\n`;\n\n// BOFF-4442/4443 live-verify fix: a WorkItem must belong to a real project\n// (PlanmagnetCreateWorkItemInput.projectId is non-null); the form needs the\n// caller's actual projects to choose from rather than a free-text name.\nconst GET_PROJECTS = gql`\n query GetProjectsForTaskCreate($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n key\n }\n }\n }\n`;\n\nexport function TasksCreateTaskPagePage() {\n const { workspaceId } = usePlanMagnet();\n const [form, setForm] = useState({\n title: '',\n description: '',\n projectId: '',\n priority: 'MEDIUM',\n type: 'STORY',\n storyPoints: '5',\n labels: '',\n sprintId: '',\n dueDate: '',\n });\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { data: projectsData } = useQuery<Record<string, any>>(GET_PROJECTS, {\n variables: { workspaceId: workspaceId ?? 'default' },\n skip: !workspaceId,\n });\n const projects: PlanmagnetProjectOption[] = projectsData?.planmagnetProjects?.items ?? [];\n // Fall back to the first loaded project when the user hasn't picked one\n // yet, without stashing derived state in an effect (avoids the extra\n // render cycle and keeps a single source of truth: `projects`).\n const selectedProjectId = form.projectId || projects[0]?.id || '';\n\n const [createWorkItem, { loading: saving, error }] = useMutation(CREATE_WORK_ITEM, {\n refetchQueries: ['GetWorkItems'],\n });\n\n const handleCreate = async () => {\n if (!form.title.trim() || !selectedProjectId || !workspaceId) return;\n await createWorkItem({\n variables: {\n input: {\n projectId: selectedProjectId,\n title: form.title,\n description: form.description || undefined,\n type: form.type,\n priority: form.priority,\n storyPoints: form.storyPoints ? parseInt(form.storyPoints, 10) : undefined,\n labels: form.labels\n ? form.labels\n .split(',')\n .map((l) => l.trim())\n .filter(Boolean)\n : undefined,\n sprintId: form.sprintId || undefined,\n dueDate: form.dueDate || undefined,\n },\n },\n });\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 Task</h1>\n <p className=\"text-sm text-muted-foreground\">Add a new task to the project backlog.</p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\">\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={saving || !form.title.trim() || !selectedProjectId}\n >\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Creating...' : 'Create Task'}\n </Button>\n </div>\n </div>\n {error && <div className=\"p-6 text-red-500\">Error: {error.message}</div>}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <CheckSquare className=\"h-4 w-4\" />\n Task Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\n placeholder=\"e.g. Implement search query parser\"\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-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Describe the task requirements...\"\n />\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Project</label>\n <select\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={selectedProjectId}\n onChange={(e) => setForm({ ...form, projectId: e.target.value })}\n >\n {projects.length === 0 && (\n <option value=\"\" disabled>\n No projects available\n </option>\n )}\n {projects.map((p) => (\n <option key={p.id} value={p.id}>\n {p.key} — {p.name}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Priority</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.priority}\n onChange={(e) => setForm({ ...form, priority: e.target.value })}\n >\n {['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'].map((p) => (\n <option key={p} value={p}>\n {p.toLowerCase()}\n </option>\n ))}\n </select>\n </div>\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 {['STORY', 'BUG', 'TASK', 'EPIC', 'SUB_TASK'].map((t) => (\n <option key={t} value={t}>\n {t.toLowerCase().replace('_', ' ')}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Story Points</label>\n <Input\n type=\"number\"\n value={form.storyPoints}\n onChange={(e) => setForm({ ...form, storyPoints: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Sprint ID</label>\n <Input\n value={form.sprintId}\n onChange={(e) => setForm({ ...form, sprintId: e.target.value })}\n className=\"mt-1\"\n placeholder=\"Sprint ID\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Due Date</label>\n <Input\n type=\"date\"\n value={form.dueDate}\n onChange={(e) => setForm({ ...form, dueDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Labels (comma-separated)</label>\n <Input\n value={form.labels}\n onChange={(e) => setForm({ ...form, labels: e.target.value })}\n className=\"mt-1\"\n placeholder=\"backend, search, performance\"\n />\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -174,10 +174,10 @@ function v() {
|
|
|
174
174
|
"BUG",
|
|
175
175
|
"TASK",
|
|
176
176
|
"EPIC",
|
|
177
|
-
"
|
|
177
|
+
"SUB_TASK"
|
|
178
178
|
].map((e) => /* @__PURE__ */ c("option", {
|
|
179
179
|
value: e,
|
|
180
|
-
children: e.toLowerCase()
|
|
180
|
+
children: e.toLowerCase().replace("_", " ")
|
|
181
181
|
}, e))
|
|
182
182
|
})] }),
|
|
183
183
|
/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksEditTaskPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksEditTaskPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState, useMemo } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery, useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, ArrowLeft } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_WORK_ITEM = gql`\n query GetWorkItem($workItemId: ID!) {\n planmagnetWorkItem(id: $workItemId) {\n id\n title\n description\n type\n status\n priority\n key\n storyPoints\n dueDate\n labels\n tags\n createdAt\n updatedAt\n }\n }\n`;\n\nconst UPDATE_WORK_ITEM = gql`\n mutation UpdateWorkItem($workItemId: ID!, $input: PlanmagnetUpdateWorkItemInput!) {\n planmagnetUpdateWorkItem(id: $workItemId, input: $input) {\n id\n title\n description\n type\n status\n priority\n storyPoints\n dueDate\n labels\n updatedAt\n }\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n description: string | null;\n type: string;\n status: string;\n priority: string;\n key: string;\n storyPoints: number | null;\n dueDate: string | null;\n labels: string[];\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport function TasksEditTaskPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n // In a real app, workItemId comes from the route params.\n // For now we use a placeholder that the host shell should provide.\n const workItemId = new URLSearchParams(window.location.search).get('taskId') ?? '';\n\n const { data, loading, error } = useQuery<{\n planmagnetWorkItem: WorkItemNode;\n }>(GET_WORK_ITEM, {\n variables: { workItemId },\n skip: !workspaceId || !workItemId,\n });\n\n const [updateWorkItem, { loading: saving, error: saveError }] = useMutation(UPDATE_WORK_ITEM, {\n refetchQueries: ['GetWorkItems', 'GetWorkItem'],\n });\n\n const workItem = data?.planmagnetWorkItem;\n\n const defaultForm = useMemo(\n () => ({\n title: workItem?.title ?? '',\n description: workItem?.description ?? '',\n priority: workItem?.priority ?? 'MEDIUM',\n type: workItem?.type ?? 'STORY',\n storyPoints: workItem?.storyPoints?.toString() ?? '0',\n labels: (workItem?.labels ?? []).join(', '),\n dueDate: workItem?.dueDate ?? '',\n }),\n [workItem]\n );\n\n const [formOverrides, setFormOverrides] = useState<Record<string, string>>({});\n const form = { ...defaultForm, ...formOverrides };\n const setForm = (updates: Record<string, string>) => setFormOverrides(updates);\n\n const handleSave = async () => {\n if (!workspaceId || !workItemId) return;\n await updateWorkItem({\n variables: {\n workItemId,\n input: {\n title: form.title,\n description: form.description || undefined,\n priority: form.priority,\n type: form.type,\n storyPoints: form.storyPoints ? parseInt(form.storyPoints, 10) : undefined,\n labels: form.labels\n ? form.labels\n .split(',')\n .map((l) => l.trim())\n .filter(Boolean)\n : undefined,\n dueDate: form.dueDate || undefined,\n },\n },\n });\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 if (!data?.planmagnetWorkItem) {\n return <div className=\"p-6 text-muted-foreground\">Task not found.</div>;\n }\n\n const task = data.planmagnetWorkItem;\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Edit Task</h1>\n <p className=\"text-sm text-muted-foreground\">{task.title}</p>\n </div>\n </div>\n <Button size=\"sm\" onClick={handleSave} disabled={saving}>\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Saving...' : 'Save Changes'}\n </Button>\n </div>\n {saveError && <div className=\"p-6 text-red-500\">Error: {saveError.message}</div>}\n <Card>\n <CardHeader>\n <CardTitle>Task Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\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-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Priority</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.priority}\n onChange={(e) => setForm({ ...form, priority: e.target.value })}\n >\n {['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'].map((p) => (\n <option key={p} value={p}>\n {p.toLowerCase()}\n </option>\n ))}\n </select>\n </div>\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 {['STORY', 'BUG', 'TASK', 'EPIC', 'SUBTASK'].map((t) => (\n <option key={t} value={t}>\n {t.toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Story Points</label>\n <Input\n type=\"number\"\n value={form.storyPoints}\n onChange={(e) => setForm({ ...form, storyPoints: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Due Date</label>\n <Input\n type=\"date\"\n value={form.dueDate}\n onChange={(e) => setForm({ ...form, dueDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Labels</label>\n <Input\n value={form.labels}\n onChange={(e) => setForm({ ...form, labels: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TasksEditTaskPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/TasksEditTaskPagePage.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { useState, useMemo } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery, useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, ArrowLeft } from 'lucide-react';\nimport { usePlanMagnet } from '../providers/PlanMagnetProvider';\n\nconst GET_WORK_ITEM = gql`\n query GetWorkItem($workItemId: ID!) {\n planmagnetWorkItem(id: $workItemId) {\n id\n title\n description\n type\n status\n priority\n key\n storyPoints\n dueDate\n labels\n tags\n createdAt\n updatedAt\n }\n }\n`;\n\nconst UPDATE_WORK_ITEM = gql`\n mutation UpdateWorkItem($workItemId: ID!, $input: PlanmagnetUpdateWorkItemInput!) {\n planmagnetUpdateWorkItem(id: $workItemId, input: $input) {\n id\n title\n description\n type\n status\n priority\n storyPoints\n dueDate\n labels\n updatedAt\n }\n }\n`;\n\ninterface WorkItemNode {\n id: string;\n title: string;\n description: string | null;\n type: string;\n status: string;\n priority: string;\n key: string;\n storyPoints: number | null;\n dueDate: string | null;\n labels: string[];\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport function TasksEditTaskPagePage() {\n const { workspaceId } = usePlanMagnet();\n\n // In a real app, workItemId comes from the route params.\n // For now we use a placeholder that the host shell should provide.\n const workItemId = new URLSearchParams(window.location.search).get('taskId') ?? '';\n\n const { data, loading, error } = useQuery<{\n planmagnetWorkItem: WorkItemNode;\n }>(GET_WORK_ITEM, {\n variables: { workItemId },\n skip: !workspaceId || !workItemId,\n });\n\n const [updateWorkItem, { loading: saving, error: saveError }] = useMutation(UPDATE_WORK_ITEM, {\n refetchQueries: ['GetWorkItems', 'GetWorkItem'],\n });\n\n const workItem = data?.planmagnetWorkItem;\n\n const defaultForm = useMemo(\n () => ({\n title: workItem?.title ?? '',\n description: workItem?.description ?? '',\n priority: workItem?.priority ?? 'MEDIUM',\n type: workItem?.type ?? 'STORY',\n storyPoints: workItem?.storyPoints?.toString() ?? '0',\n labels: (workItem?.labels ?? []).join(', '),\n dueDate: workItem?.dueDate ?? '',\n }),\n [workItem]\n );\n\n const [formOverrides, setFormOverrides] = useState<Record<string, string>>({});\n const form = { ...defaultForm, ...formOverrides };\n const setForm = (updates: Record<string, string>) => setFormOverrides(updates);\n\n const handleSave = async () => {\n if (!workspaceId || !workItemId) return;\n await updateWorkItem({\n variables: {\n workItemId,\n input: {\n title: form.title,\n description: form.description || undefined,\n priority: form.priority,\n type: form.type,\n storyPoints: form.storyPoints ? parseInt(form.storyPoints, 10) : undefined,\n labels: form.labels\n ? form.labels\n .split(',')\n .map((l) => l.trim())\n .filter(Boolean)\n : undefined,\n dueDate: form.dueDate || undefined,\n },\n },\n });\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 if (!data?.planmagnetWorkItem) {\n return <div className=\"p-6 text-muted-foreground\">Task not found.</div>;\n }\n\n const task = data.planmagnetWorkItem;\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Edit Task</h1>\n <p className=\"text-sm text-muted-foreground\">{task.title}</p>\n </div>\n </div>\n <Button size=\"sm\" onClick={handleSave} disabled={saving}>\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Saving...' : 'Save Changes'}\n </Button>\n </div>\n {saveError && <div className=\"p-6 text-red-500\">Error: {saveError.message}</div>}\n <Card>\n <CardHeader>\n <CardTitle>Task Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Title</label>\n <Input\n value={form.title}\n onChange={(e) => setForm({ ...form, title: e.target.value })}\n className=\"mt-1\"\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-[100px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n <div className=\"grid grid-cols-3 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Priority</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.priority}\n onChange={(e) => setForm({ ...form, priority: e.target.value })}\n >\n {['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'].map((p) => (\n <option key={p} value={p}>\n {p.toLowerCase()}\n </option>\n ))}\n </select>\n </div>\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 {['STORY', 'BUG', 'TASK', 'EPIC', 'SUB_TASK'].map((t) => (\n <option key={t} value={t}>\n {t.toLowerCase().replace('_', ' ')}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"text-sm font-medium\">Story Points</label>\n <Input\n type=\"number\"\n value={form.storyPoints}\n onChange={(e) => setForm({ ...form, storyPoints: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"text-sm font-medium\">Due Date</label>\n <Input\n type=\"date\"\n value={form.dueDate}\n onChange={(e) => setForm({ ...form, dueDate: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Labels</label>\n <Input\n value={form.labels}\n onChange={(e) => setForm({ ...form, labels: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksTasksPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TasksTasksPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TasksTasksPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TasksTasksPagePage.tsx"],"names":[],"mappings":"AA4FA,wBAAgB,kBAAkB,4CAqIjC"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { rowLinkProps as n } from "../utils/rowNavigation.js";
|
|
3
|
+
import { useState as r } from "react";
|
|
4
|
+
import { Filter as i } from "lucide-react";
|
|
5
|
+
import { gql as a } from "@apollo/client";
|
|
6
|
+
import { useQuery as o } from "@apollo/client/react";
|
|
7
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
8
|
+
import { Card as l, CardContent as u } from "@burdenoff/fe-libs/ui";
|
|
8
9
|
//#region src/planmagnet/pages/TasksTasksPagePage.tsx
|
|
9
|
-
var
|
|
10
|
+
var d = a`
|
|
10
11
|
query GetWorkItems(
|
|
11
12
|
$workspaceId: ID!
|
|
12
13
|
$filter: PlanmagnetWorkItemFilter
|
|
@@ -33,74 +34,74 @@ var l = r`
|
|
|
33
34
|
totalCount
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
|
-
`,
|
|
37
|
+
`, f = [
|
|
37
38
|
"BACKLOG",
|
|
38
39
|
"TODO",
|
|
39
40
|
"IN_PROGRESS",
|
|
40
41
|
"IN_REVIEW",
|
|
41
42
|
"TESTING",
|
|
42
43
|
"DONE"
|
|
43
|
-
],
|
|
44
|
+
], p = {
|
|
44
45
|
BACKLOG: "Backlog",
|
|
45
46
|
TODO: "To Do",
|
|
46
47
|
IN_PROGRESS: "In Progress",
|
|
47
48
|
IN_REVIEW: "In Review",
|
|
48
49
|
TESTING: "Testing",
|
|
49
50
|
DONE: "Done"
|
|
50
|
-
},
|
|
51
|
+
}, m = {
|
|
51
52
|
BACKLOG: "border-t-gray-400",
|
|
52
53
|
TODO: "border-t-blue-400",
|
|
53
54
|
IN_PROGRESS: "border-t-yellow-400",
|
|
54
55
|
IN_REVIEW: "border-t-purple-400",
|
|
55
56
|
TESTING: "border-t-teal-400",
|
|
56
57
|
DONE: "border-t-green-400"
|
|
57
|
-
},
|
|
58
|
+
}, h = {
|
|
58
59
|
LOW: "bg-gray-100 text-gray-700",
|
|
59
60
|
MEDIUM: "bg-blue-100 text-blue-700",
|
|
60
61
|
HIGH: "bg-orange-100 text-orange-700",
|
|
61
62
|
CRITICAL: "bg-red-100 text-red-700"
|
|
62
|
-
},
|
|
63
|
+
}, g = {
|
|
63
64
|
STORY: "bg-green-100 text-green-700",
|
|
64
65
|
BUG: "bg-red-100 text-red-700",
|
|
65
66
|
TASK: "bg-blue-100 text-blue-700",
|
|
66
67
|
EPIC: "bg-purple-100 text-purple-700",
|
|
67
68
|
SUBTASK: "bg-gray-100 text-gray-700"
|
|
68
69
|
};
|
|
69
|
-
function
|
|
70
|
-
let { workspaceId:
|
|
70
|
+
function _() {
|
|
71
|
+
let { workspaceId: a } = e(), _ = t(), [v, y] = r("all"), [b, x] = r("all"), { data: S, loading: C, error: w } = o(d, {
|
|
71
72
|
variables: {
|
|
72
|
-
workspaceId:
|
|
73
|
+
workspaceId: a,
|
|
73
74
|
pagination: { first: 200 }
|
|
74
75
|
},
|
|
75
|
-
skip: !
|
|
76
|
+
skip: !a
|
|
76
77
|
});
|
|
77
|
-
if (
|
|
78
|
+
if (C) return /* @__PURE__ */ s("div", {
|
|
78
79
|
className: "flex items-center justify-center p-12",
|
|
79
|
-
children: /* @__PURE__ */
|
|
80
|
+
children: /* @__PURE__ */ s("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
80
81
|
});
|
|
81
|
-
if (
|
|
82
|
+
if (w) return /* @__PURE__ */ c("div", {
|
|
82
83
|
className: "p-6 text-red-500",
|
|
83
|
-
children: ["Error: ",
|
|
84
|
+
children: ["Error: ", w.message]
|
|
84
85
|
});
|
|
85
|
-
let
|
|
86
|
-
return /* @__PURE__ */
|
|
86
|
+
let T = S?.planmagnetWorkItems?.items ?? [], E = T.filter((e) => (v === "all" || e.priority === v.toUpperCase()) && (b === "all" || e.type === b.toUpperCase()));
|
|
87
|
+
return /* @__PURE__ */ c("div", {
|
|
87
88
|
className: "space-y-4 p-6",
|
|
88
89
|
children: [
|
|
89
|
-
/* @__PURE__ */
|
|
90
|
+
/* @__PURE__ */ s("div", {
|
|
90
91
|
className: "flex items-center justify-between",
|
|
91
|
-
children: /* @__PURE__ */
|
|
92
|
+
children: /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("h1", {
|
|
92
93
|
className: "text-2xl font-semibold",
|
|
93
94
|
children: "Task Board"
|
|
94
|
-
}), /* @__PURE__ */
|
|
95
|
+
}), /* @__PURE__ */ c("p", {
|
|
95
96
|
className: "text-sm text-muted-foreground",
|
|
96
|
-
children: [
|
|
97
|
+
children: [T.length, " tasks across all projects"]
|
|
97
98
|
})] })
|
|
98
99
|
}),
|
|
99
|
-
/* @__PURE__ */
|
|
100
|
+
/* @__PURE__ */ c("div", {
|
|
100
101
|
className: "flex gap-4 items-center flex-wrap",
|
|
101
102
|
children: [
|
|
102
|
-
/* @__PURE__ */
|
|
103
|
-
/* @__PURE__ */
|
|
103
|
+
/* @__PURE__ */ s(i, { className: "h-4 w-4 text-muted-foreground" }),
|
|
104
|
+
/* @__PURE__ */ s("div", {
|
|
104
105
|
className: "flex gap-1",
|
|
105
106
|
children: [
|
|
106
107
|
"all",
|
|
@@ -108,13 +109,13 @@ function h() {
|
|
|
108
109
|
"medium",
|
|
109
110
|
"high",
|
|
110
111
|
"critical"
|
|
111
|
-
].map((e) => /* @__PURE__ */
|
|
112
|
-
onClick: () =>
|
|
113
|
-
className: `px-2 py-1 text-xs rounded capitalize ${
|
|
112
|
+
].map((e) => /* @__PURE__ */ s("button", {
|
|
113
|
+
onClick: () => y(e),
|
|
114
|
+
className: `px-2 py-1 text-xs rounded capitalize ${v === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
|
|
114
115
|
children: e
|
|
115
116
|
}, e))
|
|
116
117
|
}),
|
|
117
|
-
/* @__PURE__ */
|
|
118
|
+
/* @__PURE__ */ s("div", {
|
|
118
119
|
className: "flex gap-1",
|
|
119
120
|
children: [
|
|
120
121
|
"all",
|
|
@@ -122,76 +123,76 @@ function h() {
|
|
|
122
123
|
"bug",
|
|
123
124
|
"task",
|
|
124
125
|
"epic"
|
|
125
|
-
].map((e) => /* @__PURE__ */
|
|
126
|
-
onClick: () =>
|
|
127
|
-
className: `px-2 py-1 text-xs rounded capitalize ${
|
|
126
|
+
].map((e) => /* @__PURE__ */ s("button", {
|
|
127
|
+
onClick: () => x(e),
|
|
128
|
+
className: `px-2 py-1 text-xs rounded capitalize ${b === e ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"}`,
|
|
128
129
|
children: e
|
|
129
130
|
}, e))
|
|
130
131
|
})
|
|
131
132
|
]
|
|
132
133
|
}),
|
|
133
|
-
/* @__PURE__ */
|
|
134
|
+
/* @__PURE__ */ s("div", {
|
|
134
135
|
className: "grid grid-cols-6 gap-3 overflow-x-auto",
|
|
135
|
-
children:
|
|
136
|
-
let t =
|
|
137
|
-
return /* @__PURE__ */
|
|
136
|
+
children: f.map((e) => {
|
|
137
|
+
let t = E.filter((t) => t.status === e);
|
|
138
|
+
return /* @__PURE__ */ c("div", {
|
|
138
139
|
className: "min-w-[200px]",
|
|
139
|
-
children: [/* @__PURE__ */
|
|
140
|
-
className: `border-t-2 ${
|
|
141
|
-
children: /* @__PURE__ */
|
|
140
|
+
children: [/* @__PURE__ */ s("div", {
|
|
141
|
+
className: `border-t-2 ${m[e]} rounded-t-md p-2 bg-muted/50`,
|
|
142
|
+
children: /* @__PURE__ */ c("div", {
|
|
142
143
|
className: "flex justify-between items-center",
|
|
143
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ s("span", {
|
|
144
145
|
className: "text-sm font-medium",
|
|
145
|
-
children:
|
|
146
|
-
}), /* @__PURE__ */
|
|
146
|
+
children: p[e]
|
|
147
|
+
}), /* @__PURE__ */ s("span", {
|
|
147
148
|
className: "text-xs bg-muted rounded-full px-1.5",
|
|
148
149
|
children: t.length
|
|
149
150
|
})]
|
|
150
151
|
})
|
|
151
|
-
}), /* @__PURE__ */
|
|
152
|
+
}), /* @__PURE__ */ s("div", {
|
|
152
153
|
className: "space-y-2 mt-2",
|
|
153
|
-
children: t.map((e) => /* @__PURE__ */
|
|
154
|
-
|
|
155
|
-
children: /* @__PURE__ */
|
|
154
|
+
children: t.map((e) => /* @__PURE__ */ s(l, {
|
|
155
|
+
...n(() => _(`/tasks/task-detail-page?taskId=${encodeURIComponent(e.id)}`), e.title),
|
|
156
|
+
children: /* @__PURE__ */ c(u, {
|
|
156
157
|
className: "p-3 space-y-2",
|
|
157
158
|
children: [
|
|
158
|
-
/* @__PURE__ */
|
|
159
|
+
/* @__PURE__ */ s("p", {
|
|
159
160
|
className: "text-sm font-medium leading-tight",
|
|
160
161
|
children: e.title
|
|
161
162
|
}),
|
|
162
|
-
/* @__PURE__ */
|
|
163
|
+
/* @__PURE__ */ s("p", {
|
|
163
164
|
className: "text-xs text-muted-foreground",
|
|
164
165
|
children: e.key
|
|
165
166
|
}),
|
|
166
|
-
/* @__PURE__ */
|
|
167
|
+
/* @__PURE__ */ c("div", {
|
|
167
168
|
className: "flex gap-1 flex-wrap",
|
|
168
|
-
children: [/* @__PURE__ */
|
|
169
|
-
className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${
|
|
169
|
+
children: [/* @__PURE__ */ s("span", {
|
|
170
|
+
className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${h[e.priority] ?? ""}`,
|
|
170
171
|
children: e.priority.toLowerCase()
|
|
171
|
-
}), /* @__PURE__ */
|
|
172
|
-
className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${
|
|
172
|
+
}), /* @__PURE__ */ s("span", {
|
|
173
|
+
className: `text-[10px] px-1.5 py-0.5 rounded-full capitalize ${g[e.type] ?? ""}`,
|
|
173
174
|
children: e.type.toLowerCase()
|
|
174
175
|
})]
|
|
175
176
|
}),
|
|
176
|
-
/* @__PURE__ */
|
|
177
|
+
/* @__PURE__ */ c("div", {
|
|
177
178
|
className: "flex items-center justify-between",
|
|
178
|
-
children: [/* @__PURE__ */
|
|
179
|
+
children: [/* @__PURE__ */ s("div", {
|
|
179
180
|
className: "flex gap-1",
|
|
180
|
-
children: (e.labels ?? []).slice(0, 2).map((e) => /* @__PURE__ */
|
|
181
|
+
children: (e.labels ?? []).slice(0, 2).map((e) => /* @__PURE__ */ s("span", {
|
|
181
182
|
className: "text-[9px] px-1 py-0.5 rounded bg-muted",
|
|
182
183
|
children: e
|
|
183
184
|
}, e))
|
|
184
|
-
}), /* @__PURE__ */
|
|
185
|
+
}), /* @__PURE__ */ s("div", {
|
|
185
186
|
className: "flex items-center gap-1",
|
|
186
|
-
children: /* @__PURE__ */
|
|
187
|
+
children: /* @__PURE__ */ s("span", {
|
|
187
188
|
className: "text-[10px] font-medium bg-primary/10 text-primary rounded-full h-5 w-5 flex items-center justify-center",
|
|
188
189
|
children: e.storyPoints ?? 0
|
|
189
190
|
})
|
|
190
191
|
})]
|
|
191
192
|
}),
|
|
192
|
-
/* @__PURE__ */
|
|
193
|
+
/* @__PURE__ */ c("div", {
|
|
193
194
|
className: "flex justify-between text-[10px] text-muted-foreground",
|
|
194
|
-
children: [/* @__PURE__ */
|
|
195
|
+
children: [/* @__PURE__ */ s("span", { children: e.assigneeId ?? "Unassigned" }), /* @__PURE__ */ s("span", { children: e.dueDate ?? "" })]
|
|
195
196
|
})
|
|
196
197
|
]
|
|
197
198
|
})
|
|
@@ -204,6 +205,6 @@ function h() {
|
|
|
204
205
|
});
|
|
205
206
|
}
|
|
206
207
|
//#endregion
|
|
207
|
-
export {
|
|
208
|
+
export { _ as TasksTasksPagePage };
|
|
208
209
|
|
|
209
210
|
//# sourceMappingURL=TasksTasksPagePage.js.map
|
|
@@ -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(\n $workspaceId: ID!\n $filter: PlanmagnetWorkItemFilter\n $pagination: PlanmagnetPaginationInput\n ) {\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 storyPoints\n estimateMinutes\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 storyPoints: number | null;\n estimateMinutes: 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', 'TESTING', 'DONE'] 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 TESTING: 'Testing',\n DONE: 'Done',\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 TESTING: 'border-t-teal-400',\n DONE: 'border-t-green-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 planmagnetWorkItems: { 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, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { rowLinkProps } from '../utils/rowNavigation';\n\nconst GET_WORK_ITEMS = gql`\n query GetWorkItems(\n $workspaceId: ID!\n $filter: PlanmagnetWorkItemFilter\n $pagination: PlanmagnetPaginationInput\n ) {\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 storyPoints\n estimateMinutes\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 storyPoints: number | null;\n estimateMinutes: 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', 'TESTING', 'DONE'] 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 TESTING: 'Testing',\n DONE: 'Done',\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 TESTING: 'border-t-teal-400',\n DONE: 'border-t-green-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 navigate = usePlanMagnetNavigate();\n const [priorityFilter, setPriorityFilter] = useState<string>('all');\n const [typeFilter, setTypeFilter] = useState<string>('all');\n\n const { data, loading, error } = useQuery<{\n planmagnetWorkItems: { 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\n key={task.id}\n {...rowLinkProps(\n () =>\n navigate(`/tasks/task-detail-page?taskId=${encodeURIComponent(task.id)}`),\n task.title\n )}\n >\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":";;;;;;;;;AAUA,IAAM,IAAiB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CpB,IAAU;CAAC;CAAW;CAAQ;CAAe;CAAa;CAAW;CAAO,EAE5E,IAAmC;CACvC,SAAS;CACT,MAAM;CACN,aAAa;CACb,WAAW;CACX,SAAS;CACT,MAAM;CACP,EAEK,IAAmC;CACvC,SAAS;CACT,MAAM;CACN,aAAa;CACb,WAAW;CACX,SAAS;CACT,MAAM;CACP,EAEK,IAAwC;CAC5C,KAAK;CACL,QAAQ;CACR,MAAM;CACN,UAAU;CACX,EAEK,IAAoC;CACxC,OAAO;CACP,KAAK;CACL,MAAM;CACN,MAAM;CACN,SAAS;CACV;AAED,SAAgB,IAAqB;CACnC,IAAM,EAAE,mBAAgB,GAAe,EACjC,IAAW,GAAuB,EAClC,CAAC,GAAgB,KAAqB,EAAiB,MAAM,EAC7D,CAAC,GAAY,KAAiB,EAAiB,MAAM,EAErD,EAAE,SAAM,YAAS,aAAU,EAE9B,GAAgB;EACjB,WAAW;GACT;GACA,YAAY,EAAE,OAAO,KAAK;GAC3B;EACD,MAAM,CAAC;EACR,CAAC;AAEF,KAAI,EACF,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD,EAAK,WAAU,kFAAmF,CAAA;EAC9F,CAAA;AAIV,KAAI,EACF,QAAO,kBAAC,OAAD;EAAK,WAAU;YAAf,CAAkC,WAAQ,EAAM,QAAc;;CAGvE,IAAM,IAAQ,GAAM,qBAAqB,SAAS,EAAE,EAE9C,IAAW,EAAM,QACpB,OACE,MAAmB,SAAS,EAAE,aAAa,EAAe,aAAa,MACvE,MAAe,SAAS,EAAE,SAAS,EAAW,aAAa,EAC/D;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eAAyB;KAAe,CAAA,EACtD,kBAAC,KAAD;KAAG,WAAU;eAAb,CAA8C,EAAM,QAAO,6BAA8B;OACrF,EAAA,CAAA;IACF,CAAA;GACN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAQ,WAAU,iCAAkC,CAAA;KACpD,kBAAC,OAAD;MAAK,WAAU;gBACZ;OAAC;OAAO;OAAO;OAAU;OAAQ;OAAW,CAAC,KAAK,MACjD,kBAAC,UAAD;OAEE,eAAe,EAAkB,EAAE;OACnC,WAAW,wCAAwC,MAAmB,IAAI,uCAAuC;iBAEhH;OACM,EALF,EAKE,CACT;MACE,CAAA;KACN,kBAAC,OAAD;MAAK,WAAU;gBACZ;OAAC;OAAO;OAAS;OAAO;OAAQ;OAAO,CAAC,KAAK,MAC5C,kBAAC,UAAD;OAEE,eAAe,EAAc,EAAE;OAC/B,WAAW,wCAAwC,MAAe,IAAI,uCAAuC;iBAE5G;OACM,EALF,EAKE,CACT;MACE,CAAA;KACF;;GACN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAQ,KAAK,MAAQ;KACpB,IAAM,IAAW,EAAS,QAAQ,MAAM,EAAE,WAAW,EAAI;AACzD,YACE,kBAAC,OAAD;MAAe,WAAU;gBAAzB,CACE,kBAAC,OAAD;OAAK,WAAW,cAAc,EAAS,GAAK;iBAC1C,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAuB,EAAS;SAAY,CAAA,EAC5D,kBAAC,QAAD;SAAM,WAAU;mBAAwC,EAAS;SAAc,CAAA,CAC3E;;OACF,CAAA,EACN,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAS,KAAK,MACb,kBAAC,GAAD;QAEE,GAAI,QAEA,EAAS,kCAAkC,mBAAmB,EAAK,GAAG,GAAG,EAC3E,EAAK,MACN;kBAED,kBAAC,GAAD;SAAa,WAAU;mBAAvB;UACE,kBAAC,KAAD;WAAG,WAAU;qBAAqC,EAAK;WAAU,CAAA;UACjE,kBAAC,KAAD;WAAG,WAAU;qBAAiC,EAAK;WAAQ,CAAA;UAC3D,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YACE,WAAW,qDAAqD,EAAc,EAAK,aAAa;sBAE/F,EAAK,SAAS,aAAa;YACvB,CAAA,EACP,kBAAC,QAAD;YACE,WAAW,qDAAqD,EAAU,EAAK,SAAS;sBAEvF,EAAK,KAAK,aAAa;YACnB,CAAA,CACH;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,OAAD;YAAK,WAAU;uBACX,EAAK,UAAU,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC,KAAK,MACpC,kBAAC,QAAD;aAAc,WAAU;uBACrB;aACI,EAFI,EAEJ,CACP;YACE,CAAA,EACN,kBAAC,OAAD;YAAK,WAAU;sBACb,kBAAC,QAAD;aAAM,WAAU;uBACb,EAAK,eAAe;aAChB,CAAA;YACH,CAAA,CACF;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD,EAAA,UAAO,EAAK,cAAc,cAAoB,CAAA,EAC9C,kBAAC,QAAD,EAAA,UAAO,EAAK,WAAW,IAAU,CAAA,CAC7B;;UACM;;QACT,EAzCA,EAAK,GAyCL,CACP;OACE,CAAA,CACF;QAtDI,EAsDJ;MAER;IACE,CAAA;GACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { KeyboardEvent, MouseEvent } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props that turn a non-interactive container (a Card, a table row) into an
|
|
5
|
+
* activatable one, so a list row can open its detail page by click OR keyboard.
|
|
6
|
+
*
|
|
7
|
+
* Kept as a props factory rather than a wrapper component so it can be spread onto
|
|
8
|
+
* whatever element a given list already renders, without changing that list's layout.
|
|
9
|
+
*/
|
|
10
|
+
export declare function rowLinkProps(onActivate: () => void, label?: string): {
|
|
11
|
+
role: "button";
|
|
12
|
+
tabIndex: number;
|
|
13
|
+
'aria-label': string | undefined;
|
|
14
|
+
className: string;
|
|
15
|
+
onClick: () => void;
|
|
16
|
+
onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Stops a click on a nested control (a button, a menu) from also activating the row
|
|
20
|
+
* it sits inside. Spread onto the nested control, not the row.
|
|
21
|
+
*/
|
|
22
|
+
export declare function stopRowActivation(event: MouseEvent<HTMLElement>): void;
|
|
23
|
+
/**
|
|
24
|
+
* Builds the path to a detail page that reads its id from a ":id" route segment.
|
|
25
|
+
* Returns the bare path when no id is available, so a missing id degrades to the
|
|
26
|
+
* list-style page rather than producing a path ending in "undefined".
|
|
27
|
+
*/
|
|
28
|
+
export declare function detailPath(route: string, id: string | null | undefined): string;
|
|
29
|
+
//# sourceMappingURL=rowNavigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rowNavigation.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/utils/rowNavigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEvD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM;;;;;;uBAS5C,aAAa,CAAC,WAAW,CAAC;EAOhD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,QAE/D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE/E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/planmagnet/utils/rowNavigation.ts
|
|
2
|
+
function e(e, t) {
|
|
3
|
+
return {
|
|
4
|
+
role: "button",
|
|
5
|
+
tabIndex: 0,
|
|
6
|
+
"aria-label": t,
|
|
7
|
+
className: "cursor-pointer transition-shadow hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
8
|
+
onClick: () => e(),
|
|
9
|
+
onKeyDown: (t) => {
|
|
10
|
+
t.key !== "Enter" && t.key !== " " || (t.preventDefault(), e());
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function t(e, t) {
|
|
15
|
+
return t ? `${e}/${encodeURIComponent(t)}` : e;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as detailPath, e as rowLinkProps };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=rowNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rowNavigation.js","names":[],"sources":["../../../src/planmagnet/utils/rowNavigation.ts"],"sourcesContent":["import type { KeyboardEvent, MouseEvent } from 'react';\n\n/**\n * Props that turn a non-interactive container (a Card, a table row) into an\n * activatable one, so a list row can open its detail page by click OR keyboard.\n *\n * Kept as a props factory rather than a wrapper component so it can be spread onto\n * whatever element a given list already renders, without changing that list's layout.\n */\nexport function rowLinkProps(onActivate: () => void, label?: string) {\n return {\n role: 'button' as const,\n tabIndex: 0,\n 'aria-label': label,\n className:\n 'cursor-pointer transition-shadow hover:shadow-md focus-visible:outline-none ' +\n 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n onClick: () => onActivate(),\n onKeyDown: (event: KeyboardEvent<HTMLElement>) => {\n // Enter and Space are the two activation keys a role=\"button\" must honour.\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n onActivate();\n },\n };\n}\n\n/**\n * Stops a click on a nested control (a button, a menu) from also activating the row\n * it sits inside. Spread onto the nested control, not the row.\n */\nexport function stopRowActivation(event: MouseEvent<HTMLElement>) {\n event.stopPropagation();\n}\n\n/**\n * Builds the path to a detail page that reads its id from a \":id\" route segment.\n * Returns the bare path when no id is available, so a missing id degrades to the\n * list-style page rather than producing a path ending in \"undefined\".\n */\nexport function detailPath(route: string, id: string | null | undefined): string {\n return id ? `${route}/${encodeURIComponent(id)}` : route;\n}\n"],"mappings":";AASA,SAAgB,EAAa,GAAwB,GAAgB;AACnE,QAAO;EACL,MAAM;EACN,UAAU;EACV,cAAc;EACd,WACE;EAEF,eAAe,GAAY;EAC3B,YAAY,MAAsC;AAE5C,KAAM,QAAQ,WAAW,EAAM,QAAQ,QAC3C,EAAM,gBAAgB,EACtB,GAAY;;EAEf;;AAgBH,SAAgB,EAAW,GAAe,GAAuC;AAC/E,QAAO,IAAK,GAAG,EAAM,GAAG,mBAAmB,EAAG,KAAK"}
|