@burdenoff/microfe-planmagnet 2026.1002.1 → 2026.1002.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/wspace-operations.d.ts +2533 -546
- package/dist/generated/wspace-operations.d.ts.map +1 -1
- package/dist/generated/wspace-types.d.ts +5654 -71
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +180 -162
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +100 -84
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/board/BulkActions.d.ts.map +1 -1
- package/dist/planmagnet/board/BulkActions.js +106 -55
- package/dist/planmagnet/board/BulkActions.js.map +1 -1
- package/dist/planmagnet/controls/Pickers.d.ts +10 -5
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
- package/dist/planmagnet/controls/Pickers.js +10 -9
- package/dist/planmagnet/controls/Pickers.js.map +1 -1
- package/dist/planmagnet/dashboards/DashboardUI.d.ts +0 -4
- package/dist/planmagnet/dashboards/DashboardUI.d.ts.map +1 -1
- package/dist/planmagnet/dashboards/DashboardUI.js +6 -13
- package/dist/planmagnet/dashboards/DashboardUI.js.map +1 -1
- package/dist/planmagnet/dashboards/cards/SprintCapacityCard.d.ts.map +1 -1
- package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js +70 -59
- package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js.map +1 -1
- package/dist/planmagnet/forecast/ResourceForecastCard.js +1 -1
- package/dist/planmagnet/forecast/ResourceForecastCard.js.map +1 -1
- package/dist/planmagnet/index.d.ts +1 -1
- package/dist/planmagnet/index.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.d.ts +3 -3
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.js +26 -19
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.js.map +1 -1
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.d.ts +2 -2
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.js +18 -12
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.js +251 -0
- package/dist/planmagnet/pages/ProductsCustomerSatisfactionPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js +4 -4
- package/dist/planmagnet/pages/ProductsFeatureAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +133 -131
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +5 -5
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +6 -6
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js +107 -82
- package/dist/planmagnet/pages/ProductsProductDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.js +174 -0
- package/dist/planmagnet/pages/ProductsProductFeatureDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.js +350 -0
- package/dist/planmagnet/pages/ProductsProductHierarchyPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsProductLinesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProductsProductLinesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProductsProductLinesPagePage.js +168 -0
- package/dist/planmagnet/pages/ProductsProductLinesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsProductsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js +116 -114
- package/dist/planmagnet/pages/ProductsReleaseDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +174 -159
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +159 -145
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js +161 -143
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +160 -156
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryKpisCard.d.ts.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js +97 -99
- package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js.map +1 -1
- package/dist/planmagnet/product/FeatureLinkPanels.d.ts +29 -0
- package/dist/planmagnet/product/FeatureLinkPanels.d.ts.map +1 -0
- package/dist/planmagnet/product/FeatureLinkPanels.js +373 -0
- package/dist/planmagnet/product/FeatureLinkPanels.js.map +1 -0
- package/dist/planmagnet/product/ProductControls.js +1 -1
- package/dist/planmagnet/product/ProductControls.js.map +1 -1
- package/dist/planmagnet/product/ProductFeatureControls.d.ts +39 -0
- package/dist/planmagnet/product/ProductFeatureControls.d.ts.map +1 -0
- package/dist/planmagnet/product/ProductFeatureControls.js +315 -0
- package/dist/planmagnet/product/ProductFeatureControls.js.map +1 -0
- package/dist/planmagnet/product/ProductFeatureLinkCard.d.ts +4 -0
- package/dist/planmagnet/product/ProductFeatureLinkCard.d.ts.map +1 -0
- package/dist/planmagnet/product/ProductFeatureLinkCard.js +192 -0
- package/dist/planmagnet/product/ProductFeatureLinkCard.js.map +1 -0
- package/dist/planmagnet/product/ProductLineControls.d.ts +52 -0
- package/dist/planmagnet/product/ProductLineControls.d.ts.map +1 -0
- package/dist/planmagnet/product/ProductLineControls.js +417 -0
- package/dist/planmagnet/product/ProductLineControls.js.map +1 -0
- package/dist/planmagnet/product/ProductTeamsPanel.d.ts +4 -0
- package/dist/planmagnet/product/ProductTeamsPanel.d.ts.map +1 -0
- package/dist/planmagnet/product/ProductTeamsPanel.js +129 -0
- package/dist/planmagnet/product/ProductTeamsPanel.js.map +1 -0
- package/dist/planmagnet/product/WorkItemProductFeatureChip.d.ts +4 -0
- package/dist/planmagnet/product/WorkItemProductFeatureChip.d.ts.map +1 -0
- package/dist/planmagnet/product/WorkItemProductFeatureChip.js +41 -0
- package/dist/planmagnet/product/WorkItemProductFeatureChip.js.map +1 -0
- package/dist/planmagnet/product/hierarchy.d.ts +127 -0
- package/dist/planmagnet/product/hierarchy.d.ts.map +1 -0
- package/dist/planmagnet/product/hierarchy.js +173 -0
- package/dist/planmagnet/product/hierarchy.js.map +1 -0
- package/dist/planmagnet/product/hierarchyOperations.d.ts +35 -0
- package/dist/planmagnet/product/hierarchyOperations.d.ts.map +1 -0
- package/dist/planmagnet/product/hierarchyOperations.js +440 -0
- package/dist/planmagnet/product/hierarchyOperations.js.map +1 -0
- package/dist/planmagnet/product/refusal.d.ts +14 -0
- package/dist/planmagnet/product/refusal.d.ts.map +1 -0
- package/dist/planmagnet/product/refusal.js +10 -0
- package/dist/planmagnet/product/refusal.js.map +1 -0
- package/dist/planmagnet/product/routes.d.ts +10 -0
- package/dist/planmagnet/product/routes.d.ts.map +1 -1
- package/dist/planmagnet/product/routes.js +2 -2
- package/dist/planmagnet/product/routes.js.map +1 -1
- package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.d.ts +20 -0
- package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.js +55 -0
- package/dist/planmagnet/satisfaction/DeliverySatisfactionSection.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionFigures.d.ts +30 -0
- package/dist/planmagnet/satisfaction/SatisfactionFigures.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionFigures.js +282 -0
- package/dist/planmagnet/satisfaction/SatisfactionFigures.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionImportDialog.d.ts +9 -0
- package/dist/planmagnet/satisfaction/SatisfactionImportDialog.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionImportDialog.js +390 -0
- package/dist/planmagnet/satisfaction/SatisfactionImportDialog.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionLinkFields.d.ts +17 -0
- package/dist/planmagnet/satisfaction/SatisfactionLinkFields.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionLinkFields.js +77 -0
- package/dist/planmagnet/satisfaction/SatisfactionLinkFields.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.d.ts +18 -0
- package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.js +87 -0
- package/dist/planmagnet/satisfaction/SatisfactionReleaseSelect.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.d.ts +13 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.js +326 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponseDialog.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.d.ts +23 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.js +258 -0
- package/dist/planmagnet/satisfaction/SatisfactionResponsesTable.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.d.ts +6 -0
- package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.js +56 -0
- package/dist/planmagnet/satisfaction/SatisfactionSummaryCard.js.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.d.ts +16 -0
- package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.js +102 -0
- package/dist/planmagnet/satisfaction/SatisfactionWindowPicker.js.map +1 -0
- package/dist/planmagnet/satisfaction/satisfaction.d.ts +154 -0
- package/dist/planmagnet/satisfaction/satisfaction.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/satisfaction.js +210 -0
- package/dist/planmagnet/satisfaction/satisfaction.js.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionCsv.d.ts +108 -0
- package/dist/planmagnet/satisfaction/satisfactionCsv.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionCsv.js +211 -0
- package/dist/planmagnet/satisfaction/satisfactionCsv.js.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionForm.d.ts +90 -0
- package/dist/planmagnet/satisfaction/satisfactionForm.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionForm.js +90 -0
- package/dist/planmagnet/satisfaction/satisfactionForm.js.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionOperations.d.ts +116 -0
- package/dist/planmagnet/satisfaction/satisfactionOperations.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/satisfactionOperations.js +86 -0
- package/dist/planmagnet/satisfaction/satisfactionOperations.js.map +1 -0
- package/dist/planmagnet/satisfaction/useSatisfactionAccess.d.ts +20 -0
- package/dist/planmagnet/satisfaction/useSatisfactionAccess.d.ts.map +1 -0
- package/dist/planmagnet/satisfaction/useSatisfactionAccess.js +31 -0
- package/dist/planmagnet/satisfaction/useSatisfactionAccess.js.map +1 -0
- package/dist/planmagnet/skills/RequiredSkillsEditor.d.ts +35 -0
- package/dist/planmagnet/skills/RequiredSkillsEditor.d.ts.map +1 -0
- package/dist/planmagnet/skills/RequiredSkillsEditor.js +124 -0
- package/dist/planmagnet/skills/RequiredSkillsEditor.js.map +1 -0
- package/dist/planmagnet/skills/SkillChips.d.ts +30 -0
- package/dist/planmagnet/skills/SkillChips.d.ts.map +1 -0
- package/dist/planmagnet/skills/SkillChips.js +57 -0
- package/dist/planmagnet/skills/SkillChips.js.map +1 -0
- package/dist/planmagnet/skills/SkillCoverageCard.d.ts +24 -0
- package/dist/planmagnet/skills/SkillCoverageCard.d.ts.map +1 -0
- package/dist/planmagnet/skills/SkillCoverageCard.js +256 -0
- package/dist/planmagnet/skills/SkillCoverageCard.js.map +1 -0
- package/dist/planmagnet/skills/WorkItemRequiredSkills.d.ts +10 -0
- package/dist/planmagnet/skills/WorkItemRequiredSkills.d.ts.map +1 -0
- package/dist/planmagnet/skills/WorkItemRequiredSkills.js +65 -0
- package/dist/planmagnet/skills/WorkItemRequiredSkills.js.map +1 -0
- package/dist/planmagnet/skills/skillOperations.d.ts +52 -0
- package/dist/planmagnet/skills/skillOperations.d.ts.map +1 -0
- package/dist/planmagnet/skills/skillOperations.js +44 -0
- package/dist/planmagnet/skills/skillOperations.js.map +1 -0
- package/dist/planmagnet/skills/skillTags.d.ts +103 -0
- package/dist/planmagnet/skills/skillTags.d.ts.map +1 -0
- package/dist/planmagnet/skills/skillTags.js +115 -0
- package/dist/planmagnet/skills/skillTags.js.map +1 -0
- package/dist/planmagnet/skills/useRequiredSkillsDraft.d.ts +28 -0
- package/dist/planmagnet/skills/useRequiredSkillsDraft.d.ts.map +1 -0
- package/dist/planmagnet/skills/useRequiredSkillsDraft.js +30 -0
- package/dist/planmagnet/skills/useRequiredSkillsDraft.js.map +1 -0
- package/dist/shared/utils/i18n.d.ts +3 -0
- package/dist/shared/utils/i18n.d.ts.map +1 -1
- package/dist/shared/utils/i18n.js +1 -1
- package/dist/shared/utils/i18n.js.map +1 -1
- package/package.json +4 -4
|
@@ -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, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { MilestoneSelect } from '../milestones/MilestoneControls';\nimport { throwOnError } from '../utils/mutationResult';\nimport { parseEstimateHours, parseIntField } from '../utils/formValidation';\nimport { AssigneeSelect, WORK_ITEM_PRIORITIES } from '../controls/WorkItemControls';\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\n// Sprints of the chosen project that can still take work (BOFF-7962: this was a free-text \"Sprint ID\" box — the id\n// was only discoverable from a sprint URL, and a name or another project's id was refused).\nconst GET_SPRINTS = gql`\n query GetSprintsForTaskCreate($workspaceId: ID!, $projectId: String) {\n planmagnetSprints(\n workspaceId: $workspaceId\n filter: { projectId: $projectId }\n pagination: { first: 100 }\n ) {\n items {\n id\n name\n status\n }\n }\n }\n`;\nconst OPEN_SPRINT_STATUSES = new Set(['PLANNING', 'ACTIVE', 'REVIEW']);\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 milestoneId: '',\n assigneeId: '',\n dueDate: '',\n estimateHours: '',\n });\n\n const {\n data: projectsData,\n loading: projectsLoading,\n error: projectsError,\n refetch: refetchProjects,\n } = useQuery<{ planmagnetProjects?: { items: PlanmagnetProjectOption[] } }>(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 const { data: sprintsData, loading: sprintsLoading } = useQuery<{\n planmagnetSprints?: { items: { id: string; name: string; status: string }[] };\n }>(GET_SPRINTS, {\n variables: { workspaceId: workspaceId ?? 'default', projectId: selectedProjectId },\n skip: !workspaceId || !selectedProjectId,\n });\n const openSprints = (sprintsData?.planmagnetSprints?.items ?? []).filter((s) =>\n OPEN_SPRINT_STATUSES.has(s.status)\n );\n\n const navigate = usePlanMagnetNavigate();\n const [createWorkItem, { loading: saving }] = useMutation(CREATE_WORK_ITEM, {\n refetchQueries: ['GetWorkItems'],\n });\n const [saveError, setSaveError] = useState<string | null>(null);\n // Story points are a whole number, 0 or more (BOFF-7833: prod accepted -3).\n const storyPoints = parseIntField(form.storyPoints, { min: 0 });\n const estimate = parseEstimateHours(form.estimateHours);\n\n const handleCreate = async () => {\n if (\n !form.title.trim() ||\n !selectedProjectId ||\n !workspaceId ||\n storyPoints.invalid ||\n estimate.invalid\n )\n return;\n setSaveError(null);\n // Success opens the new task; a refusal shows the service's reason (errorPolicy 'all' resolves refused\n // mutations, so the old code showed nothing either way).\n try {\n const result = await throwOnError(\n 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: storyPoints.value,\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 milestoneId: form.milestoneId || undefined,\n assigneeId: form.assigneeId || undefined,\n dueDate: form.dueDate || undefined,\n estimateMinutes: estimate.minutes,\n },\n },\n })\n );\n const id = (result.data as { planmagnetCreateWorkItem?: { id: string } } | undefined)\n ?.planmagnetCreateWorkItem?.id;\n navigate(\n id ? `/tasks/task-detail-page?taskId=${encodeURIComponent(id)}` : '/tasks/tasks-page'\n );\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The task could not be created.');\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\" onClick={() => navigate('/tasks/tasks-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={\n saving ||\n !form.title.trim() ||\n !selectedProjectId ||\n storyPoints.invalid ||\n estimate.invalid\n }\n >\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Creating...' : 'Create Task'}\n </Button>\n </div>\n </div>\n {saveError && (\n <div role=\"alert\" className=\"p-3 bg-destructive/10 text-destructive rounded-md text-sm\">\n {saveError}\n </div>\n )}\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 // A sprint belongs to one project: changing the project clears the chosen sprint.\n onChange={(e) =>\n setForm({ ...form, projectId: e.target.value, sprintId: '', milestoneId: '' })\n }\n >\n {projects.length === 0 && (\n <option value=\"\" disabled>\n {projectsLoading && !projectsData\n ? 'Loading projects…'\n : projectsError\n ? 'Projects could not be loaded'\n : 'No projects yet'}\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 {/* C2 (BOFF-7833): loading, failure and \"no projects\" are told apart. */}\n {projectsError && (\n <p role=\"alert\" className=\"mt-1 flex items-center gap-2 text-xs text-destructive\">\n {projectsError.message}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-2 text-xs\"\n onClick={() => void refetchProjects()}\n >\n Retry\n </Button>\n </p>\n )}\n {!projectsLoading && !projectsError && projectsData && projects.length === 0 && (\n <button\n type=\"button\"\n className=\"mt-1 text-xs text-muted-foreground underline\"\n onClick={() => navigate('/projects/create-project-page')}\n >\n Create a project first\n </button>\n )}\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 {WORK_ITEM_PRIORITIES.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 htmlFor=\"task-story-points\" className=\"text-sm font-medium\">\n Story Points\n </label>\n <Input\n id=\"task-story-points\"\n type=\"number\"\n min={0}\n step={1}\n value={form.storyPoints}\n onChange={(e) => setForm({ ...form, storyPoints: e.target.value })}\n aria-invalid={storyPoints.invalid}\n className=\"mt-1\"\n />\n {storyPoints.invalid && (\n <p role=\"alert\" className=\"mt-1 text-xs text-destructive\">\n Story points must be a whole number, 0 or more.\n </p>\n )}\n </div>\n <div>\n <label htmlFor=\"task-milestone\" className=\"text-sm font-medium\">\n Milestone\n </label>\n <MilestoneSelect\n id=\"task-milestone\"\n projectId={selectedProjectId}\n value={form.milestoneId}\n onChange={(milestoneId) => setForm({ ...form, milestoneId })}\n />\n </div>\n <div>\n <label htmlFor=\"task-sprint\" className=\"text-sm font-medium\">\n Sprint\n </label>\n <select\n id=\"task-sprint\"\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.sprintId}\n onChange={(e) => setForm({ ...form, sprintId: e.target.value })}\n >\n <option value=\"\">\n {sprintsLoading && !sprintsData ? 'Loading sprints…' : 'No sprint'}\n </option>\n {openSprints.map((s) => (\n <option key={s.id} value={s.id}>\n {s.name} ({s.status.toLowerCase()})\n </option>\n ))}\n </select>\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 className=\"grid grid-cols-3 gap-4\">\n <div>\n <label htmlFor=\"task-estimate-hours\" className=\"text-sm font-medium\">\n Estimate (hours)\n </label>\n <Input\n id=\"task-estimate-hours\"\n type=\"number\"\n min={0}\n step={0.25}\n value={form.estimateHours}\n onChange={(e) => setForm({ ...form, estimateHours: e.target.value })}\n aria-invalid={estimate.invalid}\n aria-describedby=\"task-estimate-hint\"\n className=\"mt-1\"\n />\n {estimate.invalid ? (\n <p role=\"alert\" className=\"mt-1 text-xs text-destructive\">\n The estimate must be a number of hours, 0 or more.\n </p>\n ) : (\n <p id=\"task-estimate-hint\" className=\"mt-1 text-xs text-muted-foreground\">\n Used as the task's duration on the critical path.\n </p>\n )}\n </div>\n </div>\n <div>\n <label htmlFor=\"task-assignee\" className=\"text-sm font-medium\">\n Assignee\n </label>\n <div className=\"mt-1\">\n <AssigneeSelect\n id=\"task-assignee\"\n value={form.assigneeId}\n onChange={(assigneeId) => setForm({ ...form, assigneeId })}\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, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { MilestoneSelect } from '../milestones/MilestoneControls';\nimport { throwOnError } from '../utils/mutationResult';\nimport { parseEstimateHours, parseIntField } from '../utils/formValidation';\nimport { AssigneeSelect, WORK_ITEM_PRIORITIES } from '../controls/WorkItemControls';\nimport { RequiredSkillsField } from '../skills/RequiredSkillsEditor';\nimport { requiredSkillsRefusal } from '../skills/skillTags';\nimport { useTr } from '../../shared/hooks/useTr';\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\n// Sprints of the chosen project that can still take work (BOFF-7962: this was a free-text \"Sprint ID\" box — the id\n// was only discoverable from a sprint URL, and a name or another project's id was refused).\nconst GET_SPRINTS = gql`\n query GetSprintsForTaskCreate($workspaceId: ID!, $projectId: String) {\n planmagnetSprints(\n workspaceId: $workspaceId\n filter: { projectId: $projectId }\n pagination: { first: 100 }\n ) {\n items {\n id\n name\n status\n }\n }\n }\n`;\nconst OPEN_SPRINT_STATUSES = new Set(['PLANNING', 'ACTIVE', 'REVIEW']);\n\nexport function TasksCreateTaskPagePage() {\n const { workspaceId } = usePlanMagnet();\n const tr = useTr();\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 milestoneId: '',\n assigneeId: '',\n dueDate: '',\n estimateHours: '',\n });\n\n const {\n data: projectsData,\n loading: projectsLoading,\n error: projectsError,\n refetch: refetchProjects,\n } = useQuery<{ planmagnetProjects?: { items: PlanmagnetProjectOption[] } }>(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 const { data: sprintsData, loading: sprintsLoading } = useQuery<{\n planmagnetSprints?: { items: { id: string; name: string; status: string }[] };\n }>(GET_SPRINTS, {\n variables: { workspaceId: workspaceId ?? 'default', projectId: selectedProjectId },\n skip: !workspaceId || !selectedProjectId,\n });\n const openSprints = (sprintsData?.planmagnetSprints?.items ?? []).filter((s) =>\n OPEN_SPRINT_STATUSES.has(s.status)\n );\n\n const navigate = usePlanMagnetNavigate();\n const [createWorkItem, { loading: saving }] = useMutation(CREATE_WORK_ITEM, {\n refetchQueries: ['GetWorkItems'],\n });\n const [saveError, setSaveError] = useState<string | null>(null);\n // ANR-07/ANR-28: the skills this task needs, sent only when there are some; a refusal of them shows on the field.\n const [requiredSkills, setRequiredSkills] = useState<string[]>([]);\n const [skillsError, setSkillsError] = useState<string | null>(null);\n // Story points are a whole number, 0 or more (BOFF-7833: prod accepted -3).\n const storyPoints = parseIntField(form.storyPoints, { min: 0 });\n const estimate = parseEstimateHours(form.estimateHours);\n\n const handleCreate = async () => {\n if (\n !form.title.trim() ||\n !selectedProjectId ||\n !workspaceId ||\n storyPoints.invalid ||\n estimate.invalid\n )\n return;\n setSaveError(null);\n setSkillsError(null);\n // Success opens the new task; a refusal shows the service's reason (errorPolicy 'all' resolves refused\n // mutations, so the old code showed nothing either way).\n try {\n const result = await throwOnError(\n 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: storyPoints.value,\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 milestoneId: form.milestoneId || undefined,\n assigneeId: form.assigneeId || undefined,\n dueDate: form.dueDate || undefined,\n estimateMinutes: estimate.minutes,\n requiredSkills: requiredSkills.length > 0 ? requiredSkills : undefined,\n },\n },\n })\n );\n const id = (result.data as { planmagnetCreateWorkItem?: { id: string } } | undefined)\n ?.planmagnetCreateWorkItem?.id;\n navigate(\n id ? `/tasks/task-detail-page?taskId=${encodeURIComponent(id)}` : '/tasks/tasks-page'\n );\n } catch (e) {\n const skillsRefusal = requiredSkillsRefusal(e);\n if (skillsRefusal) {\n setSkillsError(skillsRefusal);\n setSaveError(\n tr(\n 'planmagnet.skills.editor.createRefused',\n 'The task was not created: see Required skills below.'\n )\n );\n } else {\n setSaveError(e instanceof Error ? e.message : 'The task could not be created.');\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\" onClick={() => navigate('/tasks/tasks-page')}>\n <X className=\"mr-1 h-4 w-4\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n onClick={handleCreate}\n disabled={\n saving ||\n !form.title.trim() ||\n !selectedProjectId ||\n storyPoints.invalid ||\n estimate.invalid\n }\n >\n <Save className=\"mr-1 h-4 w-4\" />\n {saving ? 'Creating...' : 'Create Task'}\n </Button>\n </div>\n </div>\n {saveError && (\n <div role=\"alert\" className=\"p-3 bg-destructive/10 text-destructive rounded-md text-sm\">\n {saveError}\n </div>\n )}\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 // A sprint belongs to one project: changing the project clears the chosen sprint.\n onChange={(e) =>\n setForm({ ...form, projectId: e.target.value, sprintId: '', milestoneId: '' })\n }\n >\n {projects.length === 0 && (\n <option value=\"\" disabled>\n {projectsLoading && !projectsData\n ? 'Loading projects…'\n : projectsError\n ? 'Projects could not be loaded'\n : 'No projects yet'}\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 {/* C2 (BOFF-7833): loading, failure and \"no projects\" are told apart. */}\n {projectsError && (\n <p role=\"alert\" className=\"mt-1 flex items-center gap-2 text-xs text-destructive\">\n {projectsError.message}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-2 text-xs\"\n onClick={() => void refetchProjects()}\n >\n Retry\n </Button>\n </p>\n )}\n {!projectsLoading && !projectsError && projectsData && projects.length === 0 && (\n <button\n type=\"button\"\n className=\"mt-1 text-xs text-muted-foreground underline\"\n onClick={() => navigate('/projects/create-project-page')}\n >\n Create a project first\n </button>\n )}\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 {WORK_ITEM_PRIORITIES.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 htmlFor=\"task-story-points\" className=\"text-sm font-medium\">\n Story Points\n </label>\n <Input\n id=\"task-story-points\"\n type=\"number\"\n min={0}\n step={1}\n value={form.storyPoints}\n onChange={(e) => setForm({ ...form, storyPoints: e.target.value })}\n aria-invalid={storyPoints.invalid}\n className=\"mt-1\"\n />\n {storyPoints.invalid && (\n <p role=\"alert\" className=\"mt-1 text-xs text-destructive\">\n Story points must be a whole number, 0 or more.\n </p>\n )}\n </div>\n <div>\n <label htmlFor=\"task-milestone\" className=\"text-sm font-medium\">\n Milestone\n </label>\n <MilestoneSelect\n id=\"task-milestone\"\n projectId={selectedProjectId}\n value={form.milestoneId}\n onChange={(milestoneId) => setForm({ ...form, milestoneId })}\n />\n </div>\n <div>\n <label htmlFor=\"task-sprint\" className=\"text-sm font-medium\">\n Sprint\n </label>\n <select\n id=\"task-sprint\"\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={form.sprintId}\n onChange={(e) => setForm({ ...form, sprintId: e.target.value })}\n >\n <option value=\"\">\n {sprintsLoading && !sprintsData ? 'Loading sprints…' : 'No sprint'}\n </option>\n {openSprints.map((s) => (\n <option key={s.id} value={s.id}>\n {s.name} ({s.status.toLowerCase()})\n </option>\n ))}\n </select>\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 className=\"grid grid-cols-3 gap-4\">\n <div>\n <label htmlFor=\"task-estimate-hours\" className=\"text-sm font-medium\">\n Estimate (hours)\n </label>\n <Input\n id=\"task-estimate-hours\"\n type=\"number\"\n min={0}\n step={0.25}\n value={form.estimateHours}\n onChange={(e) => setForm({ ...form, estimateHours: e.target.value })}\n aria-invalid={estimate.invalid}\n aria-describedby=\"task-estimate-hint\"\n className=\"mt-1\"\n />\n {estimate.invalid ? (\n <p role=\"alert\" className=\"mt-1 text-xs text-destructive\">\n The estimate must be a number of hours, 0 or more.\n </p>\n ) : (\n <p id=\"task-estimate-hint\" className=\"mt-1 text-xs text-muted-foreground\">\n Used as the task's duration on the critical path.\n </p>\n )}\n </div>\n </div>\n <div>\n <label htmlFor=\"task-assignee\" className=\"text-sm font-medium\">\n Assignee\n </label>\n <div className=\"mt-1\">\n <AssigneeSelect\n id=\"task-assignee\"\n value={form.assigneeId}\n onChange={(assigneeId) => setForm({ ...form, assigneeId })}\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 <RequiredSkillsField\n id=\"task-required-skills\"\n value={requiredSkills}\n onChange={(next) => {\n setRequiredSkills(next);\n setSkillsError(null);\n }}\n disabled={saving}\n serverError={skillsError}\n />\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAsBA,IAAM,IAAmB,CAAG;;;;;;;;;;;;;;;;GAqBtB,IAAe,CAAG;;;;;;;;;;GAclB,IAAc,CAAG;;;;;;;;;;;;;;GAejB,IAAuB,IAAI,IAAI;CAAC;CAAY;CAAU;CAAS,CAAC;AAEtE,SAAgB,IAA0B;CACxC,IAAM,EAAE,mBAAgB,GAAe,EACjC,IAAK,GAAO,EACZ,CAAC,GAAM,KAAW,EAAS;EAC/B,OAAO;EACP,aAAa;EACb,WAAW;EACX,UAAU;EACV,MAAM;EACN,aAAa;EACb,QAAQ;EACR,UAAU;EACV,aAAa;EACb,YAAY;EACZ,SAAS;EACT,eAAe;EAChB,CAAC,EAEI,EACJ,MAAM,GACN,SAAS,GACT,OAAO,GACP,SAAS,MACP,EAAwE,GAAc;EACxF,WAAW,EAAE,aAAa,KAAe,WAAW;EACpD,MAAM,CAAC;EACR,CAAC,EACI,IAAsC,GAAc,oBAAoB,SAAS,EAAE,EAInF,IAAoB,EAAK,aAAa,EAAS,IAAI,MAAM,IACzD,EAAE,MAAM,GAAa,SAAS,MAAmB,EAEpD,GAAa;EACd,WAAW;GAAE,aAAa,KAAe;GAAW,WAAW;GAAmB;EAClF,MAAM,CAAC,KAAe,CAAC;EACxB,CAAC,EACI,KAAe,GAAa,mBAAmB,SAAS,EAAE,EAAE,QAAQ,MACxE,EAAqB,IAAI,EAAE,OAAO,CACnC,EAEK,IAAW,GAAuB,EAClC,CAAC,GAAgB,EAAE,SAAS,OAAY,EAAY,GAAkB,EAC1E,gBAAgB,CAAC,eAAe,EACjC,CAAC,EACI,CAAC,GAAW,KAAgB,EAAwB,KAAK,EAEzD,CAAC,GAAgB,KAAqB,EAAmB,EAAE,CAAC,EAC5D,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAE7D,IAAc,EAAc,EAAK,aAAa,EAAE,KAAK,GAAG,CAAC,EACzD,IAAW,EAAmB,EAAK,cAAc;AA+DvD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eAAyB;KAAgB,CAAA,EACvD,kBAAC,KAAD;KAAG,WAAU;eAAgC;KAA0C,CAAA,CACnF,EAAA,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,MAAK;MAAK,eAAe,EAAS,oBAAoB;gBAAhF,CACE,kBAAC,GAAD,EAAG,WAAU,gBAAiB,CAAA,EAAA,SAEvB;SACT,kBAAC,GAAD;MACE,MAAK;MACL,SA3EW,YAAY;AAE7B,cAAC,EAAK,MAAM,MAAM,IAClB,CAAC,KACD,CAAC,KACD,EAAY,WACZ,EAAS,UAIX;QADA,EAAa,KAAK,EAClB,EAAe,KAAK;AAGpB,YAAI;SA2BF,IAAM,KA1BS,MAAM,EACnB,EAAe,EACb,WAAW,EACT,OAAO;UACL,WAAW;UACX,OAAO,EAAK;UACZ,aAAa,EAAK,eAAe,KAAA;UACjC,MAAM,EAAK;UACX,UAAU,EAAK;UACf,aAAa,EAAY;UACzB,QAAQ,EAAK,SACT,EAAK,OACF,MAAM,IAAI,CACV,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,OAAO,QAAQ,GAClB,KAAA;UACJ,UAAU,EAAK,YAAY,KAAA;UAC3B,aAAa,EAAK,eAAe,KAAA;UACjC,YAAY,EAAK,cAAc,KAAA;UAC/B,SAAS,EAAK,WAAW,KAAA;UACzB,iBAAiB,EAAS;UAC1B,gBAAgB,EAAe,SAAS,IAAI,IAAiB,KAAA;UAC9D,EACF,EACF,CAAC,CACH,EACkB,MACf,0BAA0B;AAC9B,WACE,IAAK,kCAAkC,mBAAmB,EAAG,KAAK,oBACnE;iBACM,GAAG;SACV,IAAM,IAAgB,EAAsB,EAAE;AAC9C,SAAI,KACF,EAAe,EAAc,EAC7B,EACE,EACE,0CACA,uDACD,CACF,IAED,EAAa,aAAa,QAAQ,EAAE,UAAU,iCAAiC;;;;MAoB3E,UACE,KACA,CAAC,EAAK,MAAM,MAAM,IAClB,CAAC,KACD,EAAY,WACZ,EAAS;gBARb,CAWE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAChC,IAAS,gBAAgB,cACnB;QACL;OACF;;GACL,KACC,kBAAC,OAAD;IAAK,MAAK;IAAQ,WAAU;cACzB;IACG,CAAA;GAER,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAW,WAAU;cAArB,CACE,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA,EAAA,eAEzB;OACD,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB;KACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAsB;MAAa,CAAA,EACpD,kBAAC,GAAD;MACE,OAAO,EAAK;MACZ,WAAW,MAAM,EAAQ;OAAE,GAAG;OAAM,OAAO,EAAE,OAAO;OAAO,CAAC;MAC5D,WAAU;MACV,aAAY;MACZ,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAsB;MAAmB,CAAA,EAC1D,kBAAC,YAAD;MACE,WAAU;MACV,OAAO,EAAK;MACZ,WAAW,MAAM,EAAQ;OAAE,GAAG;OAAM,aAAa,EAAE,OAAO;OAAO,CAAC;MAClE,aAAY;MACZ,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD,EAAA,UAAA;QACE,kBAAC,SAAD;SAAO,WAAU;mBAAsB;SAAe,CAAA;QACtD,kBAAC,UAAD;SACE,WAAU;SACV,OAAO;SAEP,WAAW,MACT,EAAQ;UAAE,GAAG;UAAM,WAAW,EAAE,OAAO;UAAO,UAAU;UAAI,aAAa;UAAI,CAAC;mBALlF,CAQG,EAAS,WAAW,KACnB,kBAAC,UAAD;UAAQ,OAAM;UAAG,UAAA;oBACd,KAAmB,CAAC,IACjB,sBACA,IACE,iCACA;UACC,CAAA,EAEV,EAAS,KAAK,MACb,kBAAC,UAAD;UAAmB,OAAO,EAAE;oBAA5B;WACG,EAAE;WAAI;WAAI,EAAE;WACN;YAFI,EAAE,GAEN,CACT,CACK;;QAER,KACC,kBAAC,KAAD;SAAG,MAAK;SAAQ,WAAU;mBAA1B,CACG,EAAc,SACf,kBAAC,GAAD;UACE,MAAK;UACL,MAAK;UACL,SAAQ;UACR,WAAU;UACV,eAAe,KAAK,GAAiB;oBACtC;UAEQ,CAAA,CACP;;QAEL,CAAC,KAAmB,CAAC,KAAiB,KAAgB,EAAS,WAAW,KACzE,kBAAC,UAAD;SACE,MAAK;SACL,WAAU;SACV,eAAe,EAAS,gCAAgC;mBACzD;SAEQ,CAAA;QAEP,EAAA,CAAA;OACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;kBAAsB;QAAgB,CAAA,EACvD,kBAAC,UAAD;QACE,WAAU;QACV,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,UAAU,EAAE,OAAO;SAAO,CAAC;kBAE9D,EAAqB,KAAK,MACzB,kBAAC,UAAD;SAAgB,OAAO;mBACpB,EAAE,aAAa;SACT,EAFI,EAEJ,CACT;QACK,CAAA,CACL,EAAA,CAAA;OACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;kBAAsB;QAAY,CAAA,EACnD,kBAAC,UAAD;QACE,WAAU;QACV,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,MAAM,EAAE,OAAO;SAAO,CAAC;kBAE1D;SAAC;SAAS;SAAO;SAAQ;SAAQ;SAAW,CAAC,KAAK,MACjD,kBAAC,UAAD;SAAgB,OAAO;mBACpB,EAAE,aAAa,CAAC,QAAQ,KAAK,IAAI;SAC3B,EAFI,EAEJ,CACT;QACK,CAAA,CACL,EAAA,CAAA;OACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD,EAAA,UAAA;QACE,kBAAC,SAAD;SAAO,SAAQ;SAAoB,WAAU;mBAAsB;SAE3D,CAAA;QACR,kBAAC,GAAD;SACE,IAAG;SACH,MAAK;SACL,KAAK;SACL,MAAM;SACN,OAAO,EAAK;SACZ,WAAW,MAAM,EAAQ;UAAE,GAAG;UAAM,aAAa,EAAE,OAAO;UAAO,CAAC;SAClE,gBAAc,EAAY;SAC1B,WAAU;SACV,CAAA;QACD,EAAY,WACX,kBAAC,KAAD;SAAG,MAAK;SAAQ,WAAU;mBAAgC;SAEtD,CAAA;QAEF,EAAA,CAAA;OACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAiB,WAAU;kBAAsB;QAExD,CAAA,EACR,kBAAC,GAAD;QACE,IAAG;QACH,WAAW;QACX,OAAO,EAAK;QACZ,WAAW,MAAgB,EAAQ;SAAE,GAAG;SAAM;SAAa,CAAC;QAC5D,CAAA,CACE,EAAA,CAAA;OACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAc,WAAU;kBAAsB;QAErD,CAAA,EACR,kBAAC,UAAD;QACE,IAAG;QACH,WAAU;QACV,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,UAAU,EAAE,OAAO;SAAO,CAAC;kBAJjE,CAME,kBAAC,UAAD;SAAQ,OAAM;mBACX,KAAkB,CAAC,IAAc,qBAAqB;SAChD,CAAA,EACR,EAAY,KAAK,MAChB,kBAAC,UAAD;SAAmB,OAAO,EAAE;mBAA5B;UACG,EAAE;UAAK;UAAG,EAAE,OAAO,aAAa;UAAC;UAC3B;WAFI,EAAE,GAEN,CACT,CACK;UACL,EAAA,CAAA;OACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,WAAU;kBAAsB;QAAgB,CAAA,EACvD,kBAAC,GAAD;QACE,MAAK;QACL,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,SAAS,EAAE,OAAO;SAAO,CAAC;QAC9D,WAAU;QACV,CAAA,CACE,EAAA,CAAA;OACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD,EAAA,UAAA;OACE,kBAAC,SAAD;QAAO,SAAQ;QAAsB,WAAU;kBAAsB;QAE7D,CAAA;OACR,kBAAC,GAAD;QACE,IAAG;QACH,MAAK;QACL,KAAK;QACL,MAAM;QACN,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ;SAAE,GAAG;SAAM,eAAe,EAAE,OAAO;SAAO,CAAC;QACpE,gBAAc,EAAS;QACvB,oBAAiB;QACjB,WAAU;QACV,CAAA;OACD,EAAS,UACR,kBAAC,KAAD;QAAG,MAAK;QAAQ,WAAU;kBAAgC;QAEtD,CAAA,GAEJ,kBAAC,KAAD;QAAG,IAAG;QAAqB,WAAU;kBAAqC;QAEtE,CAAA;OAEF,EAAA,CAAA;MACF,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,SAAQ;MAAgB,WAAU;gBAAsB;MAEvD,CAAA,EACR,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD;OACE,IAAG;OACH,OAAO,EAAK;OACZ,WAAW,MAAe,EAAQ;QAAE,GAAG;QAAM;QAAY,CAAC;OAC1D,CAAA;MACE,CAAA,CACF,EAAA,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAsB;MAAgC,CAAA,EACvE,kBAAC,GAAD;MACE,OAAO,EAAK;MACZ,WAAW,MAAM,EAAQ;OAAE,GAAG;OAAM,QAAQ,EAAE,OAAO;OAAO,CAAC;MAC7D,WAAU;MACV,aAAY;MACZ,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,GAAD;MACE,IAAG;MACH,OAAO;MACP,WAAW,MAAS;AAElB,OADA,EAAkB,EAAK,EACvB,EAAe,KAAK;;MAEtB,UAAU;MACV,aAAa;MACb,CAAA;KACU;MACT,EAAA,CAAA;GACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TasksEditTaskPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TasksEditTaskPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TasksEditTaskPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/TasksEditTaskPagePage.tsx"],"names":[],"mappings":"AA8EA,wBAAgB,qBAAqB,4CAsUpC"}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
2
|
+
import { useTr as n } from "../../shared/hooks/useTr.js";
|
|
3
|
+
import { throwOnError as r } from "../utils/mutationResult.js";
|
|
4
|
+
import { WORK_ITEM_PRIORITIES as i } from "../controls/WorkItemControls.js";
|
|
5
|
+
import { estimateHoursText as a, parseEstimateHours as o, parseIntField as s } from "../utils/formValidation.js";
|
|
6
|
+
import { requiredSkillsRefusal as c } from "../skills/skillTags.js";
|
|
7
|
+
import { MilestoneSelect as l } from "../milestones/MilestoneControls.js";
|
|
8
|
+
import { RequiredSkillsField as u } from "../skills/RequiredSkillsEditor.js";
|
|
9
|
+
import { useRequiredSkillsDraft as d } from "../skills/useRequiredSkillsDraft.js";
|
|
10
|
+
import { useMemo as f, useState as p } from "react";
|
|
11
|
+
import { ArrowLeft as m, Save as h } from "lucide-react";
|
|
12
|
+
import { gql as g } from "@apollo/client";
|
|
13
|
+
import { useMutation as _, useQuery as v } from "@apollo/client/react";
|
|
14
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
15
|
+
import { Button as x, Card as S, CardContent as C, CardHeader as w, CardTitle as T, Input as E } from "@burdenoff/fe-libs/ui";
|
|
12
16
|
//#region src/planmagnet/pages/TasksEditTaskPagePage.tsx
|
|
13
|
-
var
|
|
17
|
+
var D = g`
|
|
14
18
|
query GetWorkItem($workItemId: ID!) {
|
|
15
19
|
planmagnetWorkItem(id: $workItemId) {
|
|
16
20
|
id
|
|
@@ -31,7 +35,7 @@ var C = f`
|
|
|
31
35
|
updatedAt
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
|
-
`,
|
|
38
|
+
`, O = g`
|
|
35
39
|
mutation UpdateWorkItem($workItemId: ID!, $input: PlanmagnetUpdateWorkItemInput!) {
|
|
36
40
|
planmagnetUpdateWorkItem(id: $workItemId, input: $input) {
|
|
37
41
|
id
|
|
@@ -49,172 +53,177 @@ var C = f`
|
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
`;
|
|
52
|
-
function
|
|
53
|
-
let { workspaceId:
|
|
54
|
-
variables: { workItemId:
|
|
55
|
-
skip: !
|
|
56
|
-
}), [
|
|
56
|
+
function k() {
|
|
57
|
+
let { workspaceId: g } = e(), k = new URLSearchParams(window.location.search).get("taskId") ?? "", A = t(), j = n(), { data: M, loading: N, error: P } = v(D, {
|
|
58
|
+
variables: { workItemId: k },
|
|
59
|
+
skip: !g || !k
|
|
60
|
+
}), F = d(k, !g), [I, { loading: L }] = _(O, {
|
|
57
61
|
refetchQueries: [
|
|
58
62
|
"GetWorkItems",
|
|
59
63
|
"GetWorkItemDetail",
|
|
60
64
|
"GetWorkItemCounts",
|
|
61
|
-
"ProjectBoard"
|
|
65
|
+
"ProjectBoard",
|
|
66
|
+
"WorkItemRequiredSkills"
|
|
62
67
|
],
|
|
63
68
|
awaitRefetchQueries: !0
|
|
64
|
-
}), [
|
|
65
|
-
title:
|
|
66
|
-
description:
|
|
67
|
-
priority:
|
|
68
|
-
type:
|
|
69
|
-
storyPoints:
|
|
70
|
-
labels: (
|
|
71
|
-
dueDate:
|
|
72
|
-
estimateHours:
|
|
73
|
-
milestoneId:
|
|
74
|
-
}), [
|
|
75
|
-
...
|
|
76
|
-
...
|
|
77
|
-
},
|
|
78
|
-
if (!
|
|
79
|
-
if (!
|
|
80
|
-
|
|
69
|
+
}), [R, z] = p(null), [B, V] = p(!1), H = M?.planmagnetWorkItem, U = f(() => ({
|
|
70
|
+
title: H?.title ?? "",
|
|
71
|
+
description: H?.description ?? "",
|
|
72
|
+
priority: H?.priority ?? "MEDIUM",
|
|
73
|
+
type: H?.type ?? "STORY",
|
|
74
|
+
storyPoints: H?.storyPoints?.toString() ?? "",
|
|
75
|
+
labels: (H?.labels ?? []).join(", "),
|
|
76
|
+
dueDate: H?.dueDate ? String(H.dueDate).slice(0, 10) : "",
|
|
77
|
+
estimateHours: a(H?.estimateMinutes),
|
|
78
|
+
milestoneId: H?.milestoneId ?? ""
|
|
79
|
+
}), [H]), [W, G] = p({}), K = {
|
|
80
|
+
...U,
|
|
81
|
+
...W
|
|
82
|
+
}, q = (e) => G(e), J = s(K.storyPoints, { min: 0 }), Y = o(K.estimateHours), X = async () => {
|
|
83
|
+
if (!g || !k || J.invalid || Y.invalid) return;
|
|
84
|
+
if (!K.title.trim()) {
|
|
85
|
+
z("A task needs a title.");
|
|
81
86
|
return;
|
|
82
87
|
}
|
|
83
88
|
let e = (e) => e.split(",").map((e) => e.trim()).filter(Boolean), t = {
|
|
84
|
-
title:
|
|
85
|
-
description:
|
|
86
|
-
priority:
|
|
87
|
-
type:
|
|
88
|
-
storyPoints:
|
|
89
|
-
labels: e(
|
|
90
|
-
dueDate:
|
|
91
|
-
estimateMinutes:
|
|
92
|
-
milestoneId:
|
|
93
|
-
},
|
|
94
|
-
title:
|
|
95
|
-
description:
|
|
96
|
-
priority:
|
|
97
|
-
type:
|
|
98
|
-
storyPoints:
|
|
99
|
-
labels: e(
|
|
100
|
-
dueDate:
|
|
101
|
-
estimateMinutes:
|
|
102
|
-
milestoneId:
|
|
103
|
-
}, i =
|
|
104
|
-
|
|
105
|
-
F
|
|
89
|
+
title: K.title.trim(),
|
|
90
|
+
description: K.description.trim() || null,
|
|
91
|
+
priority: K.priority,
|
|
92
|
+
type: K.type,
|
|
93
|
+
storyPoints: J.value ?? null,
|
|
94
|
+
labels: e(K.labels),
|
|
95
|
+
dueDate: K.dueDate || null,
|
|
96
|
+
estimateMinutes: Y.minutes ?? null,
|
|
97
|
+
milestoneId: K.milestoneId || null
|
|
98
|
+
}, n = {
|
|
99
|
+
title: U.title,
|
|
100
|
+
description: U.description.trim() || null,
|
|
101
|
+
priority: U.priority,
|
|
102
|
+
type: U.type,
|
|
103
|
+
storyPoints: U.storyPoints === "" ? null : Number(U.storyPoints),
|
|
104
|
+
labels: e(U.labels),
|
|
105
|
+
dueDate: U.dueDate || null,
|
|
106
|
+
estimateMinutes: o(U.estimateHours).minutes ?? null,
|
|
107
|
+
milestoneId: U.milestoneId || null
|
|
108
|
+
}, i = {
|
|
109
|
+
...Object.fromEntries(Object.entries(t).filter(([e, t]) => JSON.stringify(t) !== JSON.stringify(n[e]))),
|
|
110
|
+
...F.changedValue ? { requiredSkills: F.changedValue } : {}
|
|
111
|
+
};
|
|
112
|
+
if (z(null), V(!1), F.setServerError(null), Object.keys(i).length === 0) {
|
|
113
|
+
V(!0);
|
|
106
114
|
return;
|
|
107
115
|
}
|
|
108
116
|
try {
|
|
109
|
-
await
|
|
110
|
-
workItemId:
|
|
117
|
+
await r(I({ variables: {
|
|
118
|
+
workItemId: k,
|
|
111
119
|
input: i
|
|
112
|
-
} })), F(!0);
|
|
120
|
+
} })), F.reset(), V(!0);
|
|
113
121
|
} catch (e) {
|
|
114
|
-
|
|
122
|
+
let t = c(e);
|
|
123
|
+
t ? (F.setServerError(t), z(j("planmagnet.skills.editor.saveRefused", "Not saved: see Required skills below."))) : z(e instanceof Error ? e.message : "The task could not be saved.");
|
|
115
124
|
}
|
|
116
125
|
};
|
|
117
|
-
if (
|
|
126
|
+
if (N && !M) return /* @__PURE__ */ y("div", {
|
|
118
127
|
className: "flex items-center justify-center p-12",
|
|
119
|
-
children: /* @__PURE__ */
|
|
128
|
+
children: /* @__PURE__ */ y("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
120
129
|
});
|
|
121
|
-
if (
|
|
130
|
+
if (P) return /* @__PURE__ */ b("div", {
|
|
122
131
|
className: "p-6 text-destructive",
|
|
123
|
-
children: ["Error: ",
|
|
132
|
+
children: ["Error: ", P.message]
|
|
124
133
|
});
|
|
125
|
-
if (!
|
|
134
|
+
if (!M?.planmagnetWorkItem) return /* @__PURE__ */ y("div", {
|
|
126
135
|
className: "p-6 text-muted-foreground",
|
|
127
136
|
children: "Task not found."
|
|
128
137
|
});
|
|
129
|
-
let
|
|
130
|
-
return /* @__PURE__ */
|
|
138
|
+
let Z = M.planmagnetWorkItem;
|
|
139
|
+
return /* @__PURE__ */ b("div", {
|
|
131
140
|
className: "space-y-6 p-6 max-w-4xl",
|
|
132
141
|
children: [
|
|
133
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ b("div", {
|
|
134
143
|
className: "flex items-center justify-between",
|
|
135
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ b("div", {
|
|
136
145
|
className: "flex items-center gap-3",
|
|
137
|
-
children: [/* @__PURE__ */
|
|
146
|
+
children: [/* @__PURE__ */ y(x, {
|
|
138
147
|
variant: "ghost",
|
|
139
148
|
size: "sm",
|
|
140
149
|
"aria-label": "Back to the task",
|
|
141
|
-
onClick: () =>
|
|
142
|
-
children: /* @__PURE__ */
|
|
143
|
-
}), /* @__PURE__ */
|
|
150
|
+
onClick: () => A(`/tasks/task-detail-page?taskId=${encodeURIComponent(k)}`),
|
|
151
|
+
children: /* @__PURE__ */ y(m, { className: "h-4 w-4" })
|
|
152
|
+
}), /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("h1", {
|
|
144
153
|
className: "text-2xl font-semibold",
|
|
145
154
|
children: "Edit Task"
|
|
146
|
-
}), /* @__PURE__ */
|
|
155
|
+
}), /* @__PURE__ */ y("p", {
|
|
147
156
|
className: "text-sm text-muted-foreground",
|
|
148
|
-
children:
|
|
157
|
+
children: Z.title
|
|
149
158
|
})] })]
|
|
150
|
-
}), /* @__PURE__ */
|
|
159
|
+
}), /* @__PURE__ */ b(x, {
|
|
151
160
|
size: "sm",
|
|
152
|
-
onClick:
|
|
153
|
-
disabled:
|
|
154
|
-
children: [/* @__PURE__ */ h
|
|
161
|
+
onClick: X,
|
|
162
|
+
disabled: L || J.invalid || Y.invalid,
|
|
163
|
+
children: [/* @__PURE__ */ y(h, { className: "mr-1 h-4 w-4" }), L ? "Saving..." : "Save Changes"]
|
|
155
164
|
})]
|
|
156
165
|
}),
|
|
157
|
-
|
|
166
|
+
B && /* @__PURE__ */ y("div", {
|
|
158
167
|
role: "status",
|
|
159
168
|
className: "p-3 bg-muted text-status-success-text rounded-md text-sm",
|
|
160
169
|
children: "Changes saved."
|
|
161
170
|
}),
|
|
162
|
-
|
|
171
|
+
R && /* @__PURE__ */ y("div", {
|
|
163
172
|
role: "alert",
|
|
164
173
|
className: "p-3 bg-destructive/10 text-destructive rounded-md text-sm",
|
|
165
|
-
children:
|
|
174
|
+
children: R
|
|
166
175
|
}),
|
|
167
|
-
/* @__PURE__ */
|
|
176
|
+
/* @__PURE__ */ b(S, { children: [/* @__PURE__ */ y(w, { children: /* @__PURE__ */ y(T, { children: "Task Details" }) }), /* @__PURE__ */ b(C, {
|
|
168
177
|
className: "space-y-4",
|
|
169
178
|
children: [
|
|
170
|
-
/* @__PURE__ */
|
|
179
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
171
180
|
className: "text-sm font-medium",
|
|
172
181
|
children: "Title"
|
|
173
|
-
}), /* @__PURE__ */
|
|
174
|
-
value:
|
|
175
|
-
onChange: (e) =>
|
|
176
|
-
...
|
|
182
|
+
}), /* @__PURE__ */ y(E, {
|
|
183
|
+
value: K.title,
|
|
184
|
+
onChange: (e) => q({
|
|
185
|
+
...K,
|
|
177
186
|
title: e.target.value
|
|
178
187
|
}),
|
|
179
188
|
className: "mt-1"
|
|
180
189
|
})] }),
|
|
181
|
-
/* @__PURE__ */
|
|
190
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
182
191
|
className: "text-sm font-medium",
|
|
183
192
|
children: "Description"
|
|
184
|
-
}), /* @__PURE__ */
|
|
193
|
+
}), /* @__PURE__ */ y("textarea", {
|
|
185
194
|
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[100px]",
|
|
186
|
-
value:
|
|
187
|
-
onChange: (e) =>
|
|
188
|
-
...
|
|
195
|
+
value: K.description,
|
|
196
|
+
onChange: (e) => q({
|
|
197
|
+
...K,
|
|
189
198
|
description: e.target.value
|
|
190
199
|
})
|
|
191
200
|
})] }),
|
|
192
|
-
/* @__PURE__ */
|
|
201
|
+
/* @__PURE__ */ b("div", {
|
|
193
202
|
className: "grid grid-cols-3 gap-4",
|
|
194
203
|
children: [
|
|
195
|
-
/* @__PURE__ */
|
|
204
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
196
205
|
className: "text-sm font-medium",
|
|
197
206
|
children: "Priority"
|
|
198
|
-
}), /* @__PURE__ */
|
|
207
|
+
}), /* @__PURE__ */ y("select", {
|
|
199
208
|
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
|
|
200
|
-
value:
|
|
201
|
-
onChange: (e) =>
|
|
202
|
-
...
|
|
209
|
+
value: K.priority,
|
|
210
|
+
onChange: (e) => q({
|
|
211
|
+
...K,
|
|
203
212
|
priority: e.target.value
|
|
204
213
|
}),
|
|
205
|
-
children:
|
|
214
|
+
children: i.map((e) => /* @__PURE__ */ y("option", {
|
|
206
215
|
value: e,
|
|
207
216
|
children: e.toLowerCase()
|
|
208
217
|
}, e))
|
|
209
218
|
})] }),
|
|
210
|
-
/* @__PURE__ */
|
|
219
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
211
220
|
className: "text-sm font-medium",
|
|
212
221
|
children: "Type"
|
|
213
|
-
}), /* @__PURE__ */
|
|
222
|
+
}), /* @__PURE__ */ y("select", {
|
|
214
223
|
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
|
|
215
|
-
value:
|
|
216
|
-
onChange: (e) =>
|
|
217
|
-
...
|
|
224
|
+
value: K.type,
|
|
225
|
+
onChange: (e) => q({
|
|
226
|
+
...K,
|
|
218
227
|
type: e.target.value
|
|
219
228
|
}),
|
|
220
229
|
children: [
|
|
@@ -223,31 +232,31 @@ function T() {
|
|
|
223
232
|
"TASK",
|
|
224
233
|
"EPIC",
|
|
225
234
|
"SUB_TASK"
|
|
226
|
-
].map((e) => /* @__PURE__ */
|
|
235
|
+
].map((e) => /* @__PURE__ */ y("option", {
|
|
227
236
|
value: e,
|
|
228
237
|
children: e.toLowerCase().replace("_", " ")
|
|
229
238
|
}, e))
|
|
230
239
|
})] }),
|
|
231
|
-
/* @__PURE__ */
|
|
232
|
-
/* @__PURE__ */
|
|
240
|
+
/* @__PURE__ */ b("div", { children: [
|
|
241
|
+
/* @__PURE__ */ y("label", {
|
|
233
242
|
htmlFor: "task-story-points",
|
|
234
243
|
className: "text-sm font-medium",
|
|
235
244
|
children: "Story Points"
|
|
236
245
|
}),
|
|
237
|
-
/* @__PURE__ */
|
|
246
|
+
/* @__PURE__ */ y(E, {
|
|
238
247
|
id: "task-story-points",
|
|
239
248
|
type: "number",
|
|
240
249
|
min: 0,
|
|
241
250
|
step: 1,
|
|
242
|
-
value:
|
|
243
|
-
onChange: (e) =>
|
|
244
|
-
...
|
|
251
|
+
value: K.storyPoints,
|
|
252
|
+
onChange: (e) => q({
|
|
253
|
+
...K,
|
|
245
254
|
storyPoints: e.target.value
|
|
246
255
|
}),
|
|
247
|
-
"aria-invalid":
|
|
256
|
+
"aria-invalid": J.invalid,
|
|
248
257
|
className: "mt-1"
|
|
249
258
|
}),
|
|
250
|
-
|
|
259
|
+
J.invalid && /* @__PURE__ */ y("p", {
|
|
251
260
|
role: "alert",
|
|
252
261
|
className: "mt-1 text-xs text-destructive",
|
|
253
262
|
children: "Story points must be a whole number, 0 or more."
|
|
@@ -255,79 +264,88 @@ function T() {
|
|
|
255
264
|
] })
|
|
256
265
|
]
|
|
257
266
|
}),
|
|
258
|
-
/* @__PURE__ */
|
|
267
|
+
/* @__PURE__ */ b("div", {
|
|
259
268
|
className: "grid grid-cols-3 gap-4",
|
|
260
269
|
children: [
|
|
261
|
-
/* @__PURE__ */
|
|
270
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
262
271
|
className: "text-sm font-medium",
|
|
263
272
|
children: "Due Date"
|
|
264
|
-
}), /* @__PURE__ */
|
|
273
|
+
}), /* @__PURE__ */ y(E, {
|
|
265
274
|
type: "date",
|
|
266
|
-
value:
|
|
267
|
-
onChange: (e) =>
|
|
268
|
-
...
|
|
275
|
+
value: K.dueDate,
|
|
276
|
+
onChange: (e) => q({
|
|
277
|
+
...K,
|
|
269
278
|
dueDate: e.target.value
|
|
270
279
|
}),
|
|
271
280
|
className: "mt-1"
|
|
272
281
|
})] }),
|
|
273
|
-
/* @__PURE__ */
|
|
274
|
-
/* @__PURE__ */
|
|
282
|
+
/* @__PURE__ */ b("div", { children: [
|
|
283
|
+
/* @__PURE__ */ y("label", {
|
|
275
284
|
htmlFor: "task-estimate-hours",
|
|
276
285
|
className: "text-sm font-medium",
|
|
277
286
|
children: "Estimate (hours)"
|
|
278
287
|
}),
|
|
279
|
-
/* @__PURE__ */
|
|
288
|
+
/* @__PURE__ */ y(E, {
|
|
280
289
|
id: "task-estimate-hours",
|
|
281
290
|
type: "number",
|
|
282
291
|
min: 0,
|
|
283
292
|
step: .25,
|
|
284
|
-
value:
|
|
285
|
-
onChange: (e) =>
|
|
286
|
-
...
|
|
293
|
+
value: K.estimateHours,
|
|
294
|
+
onChange: (e) => q({
|
|
295
|
+
...K,
|
|
287
296
|
estimateHours: e.target.value
|
|
288
297
|
}),
|
|
289
|
-
"aria-invalid":
|
|
298
|
+
"aria-invalid": Y.invalid,
|
|
290
299
|
"aria-describedby": "task-estimate-hint",
|
|
291
300
|
className: "mt-1"
|
|
292
301
|
}),
|
|
293
|
-
|
|
302
|
+
Y.invalid ? /* @__PURE__ */ y("p", {
|
|
294
303
|
role: "alert",
|
|
295
304
|
className: "mt-1 text-xs text-destructive",
|
|
296
305
|
children: "The estimate must be a number of hours, 0 or more."
|
|
297
|
-
}) : /* @__PURE__ */
|
|
306
|
+
}) : /* @__PURE__ */ y("p", {
|
|
298
307
|
id: "task-estimate-hint",
|
|
299
308
|
className: "mt-1 text-xs text-muted-foreground",
|
|
300
309
|
children: "Used as the task's duration on the critical path."
|
|
301
310
|
})
|
|
302
311
|
] }),
|
|
303
|
-
/* @__PURE__ */
|
|
312
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
304
313
|
className: "text-sm font-medium",
|
|
305
314
|
children: "Labels"
|
|
306
|
-
}), /* @__PURE__ */
|
|
307
|
-
value:
|
|
308
|
-
onChange: (e) =>
|
|
309
|
-
...
|
|
315
|
+
}), /* @__PURE__ */ y(E, {
|
|
316
|
+
value: K.labels,
|
|
317
|
+
onChange: (e) => q({
|
|
318
|
+
...K,
|
|
310
319
|
labels: e.target.value
|
|
311
320
|
}),
|
|
312
321
|
className: "mt-1"
|
|
313
322
|
})] })
|
|
314
323
|
]
|
|
315
324
|
}),
|
|
316
|
-
/* @__PURE__ */
|
|
325
|
+
/* @__PURE__ */ y("div", {
|
|
317
326
|
className: "grid grid-cols-3 gap-4",
|
|
318
|
-
children: /* @__PURE__ */
|
|
327
|
+
children: /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
|
|
319
328
|
htmlFor: "task-milestone",
|
|
320
329
|
className: "text-sm font-medium",
|
|
321
330
|
children: "Milestone"
|
|
322
|
-
}), /* @__PURE__ */
|
|
331
|
+
}), /* @__PURE__ */ y(l, {
|
|
323
332
|
id: "task-milestone",
|
|
324
|
-
projectId:
|
|
325
|
-
value:
|
|
326
|
-
onChange: (e) =>
|
|
327
|
-
...
|
|
333
|
+
projectId: Z.projectId,
|
|
334
|
+
value: K.milestoneId,
|
|
335
|
+
onChange: (e) => q({
|
|
336
|
+
...K,
|
|
328
337
|
milestoneId: e
|
|
329
338
|
})
|
|
330
339
|
})] })
|
|
340
|
+
}),
|
|
341
|
+
/* @__PURE__ */ y(u, {
|
|
342
|
+
id: "task-required-skills",
|
|
343
|
+
value: F.value,
|
|
344
|
+
onChange: F.setValue,
|
|
345
|
+
disabled: L,
|
|
346
|
+
serverError: F.serverError,
|
|
347
|
+
loading: F.loading,
|
|
348
|
+
loadError: F.loadError
|
|
331
349
|
})
|
|
332
350
|
]
|
|
333
351
|
})] })
|
|
@@ -335,6 +353,6 @@ function T() {
|
|
|
335
353
|
});
|
|
336
354
|
}
|
|
337
355
|
//#endregion
|
|
338
|
-
export {
|
|
356
|
+
export { k as TasksEditTaskPagePage };
|
|
339
357
|
|
|
340
358
|
//# sourceMappingURL=TasksEditTaskPagePage.js.map
|