@burdenoff/microfe-planmagnet 2026.928.4 → 2026.928.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +117 -93
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +156 -76
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/automation/AutomationExecutionsPanel.d.ts +5 -0
- package/dist/planmagnet/automation/AutomationExecutionsPanel.d.ts.map +1 -0
- package/dist/planmagnet/automation/AutomationExecutionsPanel.js +107 -0
- package/dist/planmagnet/automation/AutomationExecutionsPanel.js.map +1 -0
- package/dist/planmagnet/automation/AutomationRuleFields.d.ts +29 -0
- package/dist/planmagnet/automation/AutomationRuleFields.d.ts.map +1 -0
- package/dist/planmagnet/automation/AutomationRuleFields.js +308 -0
- package/dist/planmagnet/automation/AutomationRuleFields.js.map +1 -0
- package/dist/planmagnet/automation/automationRuleTypes.d.ts +60 -0
- package/dist/planmagnet/automation/automationRuleTypes.d.ts.map +1 -0
- package/dist/planmagnet/automation/automationRuleTypes.js +113 -0
- package/dist/planmagnet/automation/automationRuleTypes.js.map +1 -0
- package/dist/planmagnet/board/BulkActions.d.ts +11 -0
- package/dist/planmagnet/board/BulkActions.d.ts.map +1 -0
- package/dist/planmagnet/board/BulkActions.js +182 -0
- package/dist/planmagnet/board/BulkActions.js.map +1 -0
- package/dist/planmagnet/board/ProjectBoard.d.ts.map +1 -1
- package/dist/planmagnet/board/ProjectBoard.js +289 -254
- package/dist/planmagnet/board/ProjectBoard.js.map +1 -1
- package/dist/planmagnet/budgets/BudgetControls.d.ts +30 -0
- package/dist/planmagnet/budgets/BudgetControls.d.ts.map +1 -0
- package/dist/planmagnet/budgets/BudgetControls.js +470 -0
- package/dist/planmagnet/budgets/BudgetControls.js.map +1 -0
- package/dist/planmagnet/budgets/ExpenseControls.d.ts +27 -0
- package/dist/planmagnet/budgets/ExpenseControls.d.ts.map +1 -0
- package/dist/planmagnet/budgets/ExpenseControls.js +366 -0
- package/dist/planmagnet/budgets/ExpenseControls.js.map +1 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.d.ts +5 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.d.ts.map +1 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.js +112 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.js.map +1 -0
- package/dist/planmagnet/budgets/budgetMath.d.ts +26 -0
- package/dist/planmagnet/budgets/budgetMath.d.ts.map +1 -0
- package/dist/planmagnet/budgets/budgetMath.js +49 -0
- package/dist/planmagnet/budgets/budgetMath.js.map +1 -0
- package/dist/planmagnet/controls/AutomationRuleControls.d.ts +23 -0
- package/dist/planmagnet/controls/AutomationRuleControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/AutomationRuleControls.js +172 -0
- package/dist/planmagnet/controls/AutomationRuleControls.js.map +1 -0
- package/dist/planmagnet/controls/CompetitorControls.js +15 -15
- package/dist/planmagnet/controls/CustomFieldControls.d.ts +42 -0
- package/dist/planmagnet/controls/CustomFieldControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/CustomFieldControls.js +84 -0
- package/dist/planmagnet/controls/CustomFieldControls.js.map +1 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts +8 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts.map +1 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.js +315 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.js.map +1 -0
- package/dist/planmagnet/controls/FeatureControls.js +54 -54
- package/dist/planmagnet/controls/ObjectiveControls.js +15 -15
- package/dist/planmagnet/controls/PortfolioControls.js +7 -7
- package/dist/planmagnet/controls/ProgramControls.js +19 -19
- package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/ProjectControls.js +54 -47
- package/dist/planmagnet/controls/ProjectControls.js.map +1 -1
- package/dist/planmagnet/controls/ReleaseControls.js +7 -7
- package/dist/planmagnet/controls/RiskControls.d.ts +27 -0
- package/dist/planmagnet/controls/RiskControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/RiskControls.js +346 -0
- package/dist/planmagnet/controls/RiskControls.js.map +1 -0
- package/dist/planmagnet/controls/TemplateControls.d.ts +15 -0
- package/dist/planmagnet/controls/TemplateControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/TemplateControls.js +55 -0
- package/dist/planmagnet/controls/TemplateControls.js.map +1 -0
- package/dist/planmagnet/controls/WorkItemControls.js +1 -1
- package/dist/planmagnet/create/CreateDialogs.d.ts +20 -0
- package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
- package/dist/planmagnet/create/CreateDialogs.js +455 -116
- package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
- package/dist/planmagnet/dependency/DependencyPanel.d.ts +6 -0
- package/dist/planmagnet/dependency/DependencyPanel.d.ts.map +1 -0
- package/dist/planmagnet/dependency/DependencyPanel.js +310 -0
- package/dist/planmagnet/dependency/DependencyPanel.js.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js +171 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js +232 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts +2 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +93 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js.map +1 -0
- package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js +5 -5
- package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js +9 -9
- package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js +6 -6
- package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js +4 -4
- package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js +6 -6
- package/dist/planmagnet/pages/ProgramsProgramsPagePage.js +5 -5
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js +315 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +186 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js +164 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js +348 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +10 -10
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +4 -4
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +4 -4
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +6 -6
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +319 -203
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +81 -72
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.js +278 -0
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js +191 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +5 -5
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js +4 -4
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +161 -137
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.js +124 -113
- package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js +263 -0
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js +254 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.js +165 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js +316 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js.map +1 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js +208 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts +0 -5
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +47 -89
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js.map +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.js +24 -24
- package/dist/planmagnet/time/TaskTimePanel.d.ts +7 -0
- package/dist/planmagnet/time/TaskTimePanel.d.ts.map +1 -0
- package/dist/planmagnet/time/TaskTimePanel.js +104 -0
- package/dist/planmagnet/time/TaskTimePanel.js.map +1 -0
- package/dist/planmagnet/time/TimeEntryControls.d.ts +37 -0
- package/dist/planmagnet/time/TimeEntryControls.d.ts.map +1 -0
- package/dist/planmagnet/time/TimeEntryControls.js +338 -0
- package/dist/planmagnet/time/TimeEntryControls.js.map +1 -0
- package/dist/planmagnet/time/TimesheetControls.d.ts +18 -0
- package/dist/planmagnet/time/TimesheetControls.d.ts.map +1 -0
- package/dist/planmagnet/time/TimesheetControls.js +244 -0
- package/dist/planmagnet/time/TimesheetControls.js.map +1 -0
- package/dist/planmagnet/time/timeShared.d.ts +29 -0
- package/dist/planmagnet/time/timeShared.d.ts.map +1 -0
- package/dist/planmagnet/time/timeShared.js +34 -0
- package/dist/planmagnet/time/timeShared.js.map +1 -0
- package/dist/planmagnet/utils/rowNavigation.js +5 -2
- package/dist/planmagnet/utils/rowNavigation.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateDialogs.js","names":[],"sources":["../../../src/planmagnet/create/CreateDialogs.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Button,\n Input,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { Plus } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { throwOnError } from '../utils/mutationResult';\n\n/**\n * Create dialogs for records whose list pages had a dead \"New …\" button, or\n * none at all (QA report 2026-09-23: C4 New Release had no onClick; H7 there\n * was no way to create a milestone). Both mutations were already served and\n * verified in prod; only the UI trigger was missing.\n */\n\nconst DIALOG_PROJECTS = gql`\n query CreateDialogProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n }\n }\n`;\n\nconst FIELD = 'mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm';\n\nfunction ErrorLine({ message }: { message: string }) {\n return (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {message}\n </p>\n );\n}\n\n/**\n * C2 (BOFF-7833): the picker used to show one \"No projects\" option for three different situations —\n * still loading, the query failed, and genuinely no projects. It now says which, offers a retry on\n * failure, and a way to create a project when there are none.\n */\ninterface ProjectsState {\n projects: Array<{ id: string; name: string }>;\n loading: boolean;\n error: string | null;\n retry: () => void;\n}\n\nfunction useDialogProjects(open: boolean): ProjectsState {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error, refetch } = useQuery<{\n planmagnetProjects: { items: Array<{ id: string; name: string }> };\n }>(DIALOG_PROJECTS, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !open || !workspaceId,\n });\n return {\n projects: data?.planmagnetProjects.items ?? [],\n loading: loading && !data,\n error: error ? error.message : null,\n retry: () => void refetch(),\n };\n}\n\nfunction ProjectField({\n id,\n value,\n onChange,\n state,\n}: {\n id: string;\n value: string;\n onChange: (id: string) => void;\n state: ProjectsState;\n}) {\n const navigate = usePlanMagnetNavigate();\n const { projects, loading, error, retry } = state;\n const empty = !loading && !error && projects.length === 0;\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n Project\n </label>\n <select id={id} className={FIELD} value={value} onChange={(e) => onChange(e.target.value)}>\n {projects.length === 0 && (\n <option value=\"\">\n {loading\n ? 'Loading projects…'\n : error\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.name}\n </option>\n ))}\n </select>\n {error && (\n <p role=\"alert\" className=\"mt-1 flex items-center gap-2 text-xs text-destructive\">\n {error}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-2 text-xs\"\n onClick={retry}\n >\n Retry\n </Button>\n </p>\n )}\n {empty && (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n <button\n type=\"button\"\n className=\"underline\"\n onClick={() => navigate('/projects/create-project-page')}\n >\n Create a project first\n </button>\n </p>\n )}\n </div>\n );\n}\n\nfunction TextField({\n id,\n label,\n value,\n onChange,\n type = 'text',\n placeholder,\n}: {\n id: string;\n label: string;\n value: string;\n onChange: (value: string) => void;\n type?: string;\n placeholder?: string;\n}) {\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n {label}\n </label>\n <Input\n id={id}\n type={type}\n className=\"mt-1\"\n value={value}\n placeholder={placeholder}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n );\n}\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\n\n// ─── New release (C4) ────────────────────────────────────────────────────────\n\nconst CREATE_RELEASE = gql`\n mutation CreateDialogRelease($input: PlanmagnetCreateReleaseInput!) {\n planmagnetCreateRelease(input: $input) {\n id\n }\n }\n`;\n\nconst EMPTY_RELEASE = { name: '', version: '', projectId: '', plannedDate: '', description: '' };\n\nexport function NewReleaseDialog({ onCreated }: { onCreated: (releaseId: string) => void }) {\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(EMPTY_RELEASE);\n const [error, setError] = useState<string | null>(null);\n const projectsState = useDialogProjects(open);\n const { projects } = projectsState;\n const projectId = form.projectId || projects[0]?.id || '';\n const [create, { loading }] = useMutation<{ planmagnetCreateRelease: { id: string } }>(\n CREATE_RELEASE,\n { refetchQueries: ['ListReleases'], awaitRefetchQueries: true }\n );\n\n const canSubmit =\n form.name.trim() !== '' && form.version.trim() !== '' && projectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n create({\n variables: {\n input: {\n name: form.name.trim(),\n version: form.version.trim(),\n projectId,\n plannedDate: form.plannedDate || undefined,\n description: form.description.trim() || undefined,\n },\n },\n })\n );\n const id = result.data?.planmagnetCreateRelease.id;\n setForm(EMPTY_RELEASE);\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The release could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Release\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New release</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>The release starts in Planning.</ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"new-release-name\"\n label=\"Name\"\n value={form.name}\n onChange={(name) => setForm({ ...form, name })}\n />\n <TextField\n id=\"new-release-version\"\n label=\"Version\"\n placeholder=\"e.g. 1.4.0\"\n value={form.version}\n onChange={(version) => setForm({ ...form, version })}\n />\n <ProjectField\n id=\"new-release-project\"\n value={projectId}\n onChange={(id) => setForm({ ...form, projectId: id })}\n state={projectsState}\n />\n <TextField\n id=\"new-release-date\"\n label=\"Planned date\"\n type=\"date\"\n value={form.plannedDate}\n onChange={(plannedDate) => setForm({ ...form, plannedDate })}\n />\n <TextField\n id=\"new-release-description\"\n label=\"Description\"\n value={form.description}\n onChange={(description) => setForm({ ...form, description })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-release-submit\">\n {loading ? 'Creating…' : 'Create release'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New milestone (H7) ──────────────────────────────────────────────────────\n\nconst CREATE_MILESTONE = gql`\n mutation CreateDialogMilestone($input: PlanmagnetCreateMilestoneInput!) {\n planmagnetCreateMilestone(input: $input) {\n id\n }\n }\n`;\n\nconst EMPTY_MILESTONE = { name: '', projectId: '', dueDate: '', description: '' };\n\nexport function NewMilestoneDialog({ onCreated }: { onCreated: (milestoneId: string) => void }) {\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(EMPTY_MILESTONE);\n const [error, setError] = useState<string | null>(null);\n const projectsState = useDialogProjects(open);\n const { projects } = projectsState;\n const projectId = form.projectId || projects[0]?.id || '';\n const [create, { loading }] = useMutation<{ planmagnetCreateMilestone: { id: string } }>(\n CREATE_MILESTONE,\n { refetchQueries: ['GetMilestones'], awaitRefetchQueries: true }\n );\n\n const canSubmit = form.name.trim() !== '' && projectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n create({\n variables: {\n input: {\n name: form.name.trim(),\n projectId,\n dueDate: form.dueDate || undefined,\n description: form.description.trim() || undefined,\n },\n },\n })\n );\n const id = result.data?.planmagnetCreateMilestone.id;\n setForm(EMPTY_MILESTONE);\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The milestone could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Milestone\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New milestone</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n The milestone starts as Pending.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"new-milestone-name\"\n label=\"Name\"\n value={form.name}\n onChange={(name) => setForm({ ...form, name })}\n />\n <ProjectField\n id=\"new-milestone-project\"\n value={projectId}\n onChange={(id) => setForm({ ...form, projectId: id })}\n state={projectsState}\n />\n <TextField\n id=\"new-milestone-due\"\n label=\"Due date\"\n type=\"date\"\n value={form.dueDate}\n onChange={(dueDate) => setForm({ ...form, dueDate })}\n />\n <TextField\n id=\"new-milestone-description\"\n label=\"Description\"\n value={form.description}\n onChange={(description) => setForm({ ...form, description })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-milestone-submit\">\n {loading ? 'Creating…' : 'Create milestone'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CreateDialogs.js","names":[],"sources":["../../../src/planmagnet/create/CreateDialogs.tsx"],"sourcesContent":["import { useState, type ReactNode } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Button,\n Input,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { Plus } from 'lucide-react';\nimport { usePlanMagnet, usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { throwOnError } from '../utils/mutationResult';\nimport { AssigneeSelect, enumLabel } from '../controls/WorkItemControls';\nimport { RISK_SEVERITIES } from '../controls/RiskControls';\n\n/**\n * Create dialogs for records whose list pages had a dead \"New …\" button, or\n * none at all (QA report 2026-09-23: C4 New Release had no onClick; H7 there\n * was no way to create a milestone). Both mutations were already served and\n * verified in prod; only the UI trigger was missing.\n */\n\nconst DIALOG_PROJECTS = gql`\n query CreateDialogProjects($workspaceId: ID!) {\n planmagnetProjects(workspaceId: $workspaceId, pagination: { first: 100 }) {\n items {\n id\n name\n }\n }\n }\n`;\n\nconst FIELD = 'mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm';\n\nfunction ErrorLine({ message }: { message: string }) {\n return (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {message}\n </p>\n );\n}\n\n/**\n * C2 (BOFF-7833): the picker used to show one \"No projects\" option for three different situations —\n * still loading, the query failed, and genuinely no projects. It now says which, offers a retry on\n * failure, and a way to create a project when there are none.\n */\ninterface ProjectsState {\n projects: Array<{ id: string; name: string }>;\n loading: boolean;\n error: string | null;\n retry: () => void;\n}\n\nfunction useDialogProjects(open: boolean): ProjectsState {\n const { workspaceId } = usePlanMagnet();\n const { data, loading, error, refetch } = useQuery<{\n planmagnetProjects: { items: Array<{ id: string; name: string }> };\n }>(DIALOG_PROJECTS, {\n variables: { workspaceId: workspaceId ?? '' },\n skip: !open || !workspaceId,\n });\n return {\n projects: data?.planmagnetProjects.items ?? [],\n loading: loading && !data,\n error: error ? error.message : null,\n retry: () => void refetch(),\n };\n}\n\nfunction ProjectField({\n id,\n value,\n onChange,\n state,\n}: {\n id: string;\n value: string;\n onChange: (id: string) => void;\n state: ProjectsState;\n}) {\n const navigate = usePlanMagnetNavigate();\n const { projects, loading, error, retry } = state;\n const empty = !loading && !error && projects.length === 0;\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n Project\n </label>\n <select id={id} className={FIELD} value={value} onChange={(e) => onChange(e.target.value)}>\n {projects.length === 0 && (\n <option value=\"\">\n {loading\n ? 'Loading projects…'\n : error\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.name}\n </option>\n ))}\n </select>\n {error && (\n <p role=\"alert\" className=\"mt-1 flex items-center gap-2 text-xs text-destructive\">\n {error}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-2 text-xs\"\n onClick={retry}\n >\n Retry\n </Button>\n </p>\n )}\n {empty && (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n <button\n type=\"button\"\n className=\"underline\"\n onClick={() => navigate('/projects/create-project-page')}\n >\n Create a project first\n </button>\n </p>\n )}\n </div>\n );\n}\n\nfunction TextField({\n id,\n label,\n value,\n onChange,\n type = 'text',\n placeholder,\n}: {\n id: string;\n label: string;\n value: string;\n onChange: (value: string) => void;\n type?: string;\n placeholder?: string;\n}) {\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n {label}\n </label>\n <Input\n id={id}\n type={type}\n className=\"mt-1\"\n value={value}\n placeholder={placeholder}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n );\n}\n\nconst messageOf = (e: unknown, fallback: string) => (e instanceof Error ? e.message : fallback);\n\n// ─── New release (C4) ────────────────────────────────────────────────────────\n\nconst CREATE_RELEASE = gql`\n mutation CreateDialogRelease($input: PlanmagnetCreateReleaseInput!) {\n planmagnetCreateRelease(input: $input) {\n id\n }\n }\n`;\n\nconst EMPTY_RELEASE = { name: '', version: '', projectId: '', plannedDate: '', description: '' };\n\nexport function NewReleaseDialog({ onCreated }: { onCreated: (releaseId: string) => void }) {\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(EMPTY_RELEASE);\n const [error, setError] = useState<string | null>(null);\n const projectsState = useDialogProjects(open);\n const { projects } = projectsState;\n const projectId = form.projectId || projects[0]?.id || '';\n const [create, { loading }] = useMutation<{ planmagnetCreateRelease: { id: string } }>(\n CREATE_RELEASE,\n { refetchQueries: ['ListReleases'], awaitRefetchQueries: true }\n );\n\n const canSubmit =\n form.name.trim() !== '' && form.version.trim() !== '' && projectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n create({\n variables: {\n input: {\n name: form.name.trim(),\n version: form.version.trim(),\n projectId,\n plannedDate: form.plannedDate || undefined,\n description: form.description.trim() || undefined,\n },\n },\n })\n );\n const id = result.data?.planmagnetCreateRelease.id;\n setForm(EMPTY_RELEASE);\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The release could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Release\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New release</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>The release starts in Planning.</ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"new-release-name\"\n label=\"Name\"\n value={form.name}\n onChange={(name) => setForm({ ...form, name })}\n />\n <TextField\n id=\"new-release-version\"\n label=\"Version\"\n placeholder=\"e.g. 1.4.0\"\n value={form.version}\n onChange={(version) => setForm({ ...form, version })}\n />\n <ProjectField\n id=\"new-release-project\"\n value={projectId}\n onChange={(id) => setForm({ ...form, projectId: id })}\n state={projectsState}\n />\n <TextField\n id=\"new-release-date\"\n label=\"Planned date\"\n type=\"date\"\n value={form.plannedDate}\n onChange={(plannedDate) => setForm({ ...form, plannedDate })}\n />\n <TextField\n id=\"new-release-description\"\n label=\"Description\"\n value={form.description}\n onChange={(description) => setForm({ ...form, description })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-release-submit\">\n {loading ? 'Creating…' : 'Create release'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New milestone (H7) ──────────────────────────────────────────────────────\n\nconst CREATE_MILESTONE = gql`\n mutation CreateDialogMilestone($input: PlanmagnetCreateMilestoneInput!) {\n planmagnetCreateMilestone(input: $input) {\n id\n }\n }\n`;\n\nconst EMPTY_MILESTONE = { name: '', projectId: '', dueDate: '', description: '' };\n\nexport function NewMilestoneDialog({ onCreated }: { onCreated: (milestoneId: string) => void }) {\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(EMPTY_MILESTONE);\n const [error, setError] = useState<string | null>(null);\n const projectsState = useDialogProjects(open);\n const { projects } = projectsState;\n const projectId = form.projectId || projects[0]?.id || '';\n const [create, { loading }] = useMutation<{ planmagnetCreateMilestone: { id: string } }>(\n CREATE_MILESTONE,\n { refetchQueries: ['GetMilestones'], awaitRefetchQueries: true }\n );\n\n const canSubmit = form.name.trim() !== '' && projectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n create({\n variables: {\n input: {\n name: form.name.trim(),\n projectId,\n dueDate: form.dueDate || undefined,\n description: form.description.trim() || undefined,\n },\n },\n })\n );\n const id = result.data?.planmagnetCreateMilestone.id;\n setForm(EMPTY_MILESTONE);\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The milestone could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Milestone\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New milestone</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n The milestone starts as Pending.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"new-milestone-name\"\n label=\"Name\"\n value={form.name}\n onChange={(name) => setForm({ ...form, name })}\n />\n <ProjectField\n id=\"new-milestone-project\"\n value={projectId}\n onChange={(id) => setForm({ ...form, projectId: id })}\n state={projectsState}\n />\n <TextField\n id=\"new-milestone-due\"\n label=\"Due date\"\n type=\"date\"\n value={form.dueDate}\n onChange={(dueDate) => setForm({ ...form, dueDate })}\n />\n <TextField\n id=\"new-milestone-description\"\n label=\"Description\"\n value={form.description}\n onChange={(description) => setForm({ ...form, description })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-milestone-submit\">\n {loading ? 'Creating…' : 'Create milestone'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New template from project (BOFF-8047) ──────────────────────────────────\n//\n// Project templates (capability register: `api-only`, \"No UI anywhere\"). The only creation path this dialog\n// exposes is `planmagnetCreateTemplateFromProject` — capturing an existing, working project's methodology and\n// status as a reusable starting point — rather than a blank-JSON `planmagnetCreateProjectTemplate` form, which\n// would ask a user to hand-author `configuration`/`boardConfig`/`sprintConfig` JSON with nothing to check it\n// against.\n\nconst CREATE_TEMPLATE_FROM_PROJECT = gql`\n mutation CreateDialogTemplateFromProject($projectId: ID!, $name: String!, $description: String) {\n planmagnetCreateTemplateFromProject(\n projectId: $projectId\n name: $name\n description: $description\n ) {\n id\n }\n }\n`;\n\n/** `projectId`/`projectName` pre-fill the dialog when opened from a project's own page; otherwise the user\n * picks one. */\nexport function NewTemplateFromProjectDialog({\n projectId: fixedProjectId,\n projectName,\n onCreated,\n trigger,\n}: {\n projectId?: string;\n projectName?: string;\n onCreated: (templateId: string) => void;\n trigger?: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const [name, setName] = useState(projectName ? `${projectName} template` : '');\n const [description, setDescription] = useState('');\n const [projectId, setProjectId] = useState(fixedProjectId ?? '');\n const [error, setError] = useState<string | null>(null);\n const projectsState = useDialogProjects(open && !fixedProjectId);\n const { projects } = projectsState;\n const effectiveProjectId = fixedProjectId ?? (projectId || projects[0]?.id || '');\n const [create, { loading }] = useMutation<{\n planmagnetCreateTemplateFromProject: { id: string };\n }>(CREATE_TEMPLATE_FROM_PROJECT, {\n refetchQueries: ['TemplatesList'],\n awaitRefetchQueries: true,\n });\n\n const canSubmit = name.trim() !== '' && effectiveProjectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n create({\n variables: {\n projectId: effectiveProjectId,\n name: name.trim(),\n description: description.trim() || undefined,\n },\n })\n );\n const id = result.data?.planmagnetCreateTemplateFromProject.id;\n setName('');\n setDescription('');\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The template could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n {trigger ?? (\n <Button size=\"sm\" data-testid=\"new-template-trigger\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New template\n </Button>\n )}\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New template from project</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Captures this project's methodology and status as a reusable template. The project\n itself is unchanged.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField id=\"new-template-name\" label=\"Template name\" value={name} onChange={setName} />\n {!fixedProjectId && (\n <ProjectField\n id=\"new-template-project\"\n value={effectiveProjectId}\n onChange={setProjectId}\n state={projectsState}\n />\n )}\n <TextField\n id=\"new-template-description\"\n label=\"Description\"\n value={description}\n onChange={setDescription}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-template-submit\">\n {loading ? 'Creating…' : 'Create template'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── Apply template (create a project from a template, BOFF-8047) ──────────\n\nconst APPLY_TEMPLATE = gql`\n mutation CreateDialogApplyTemplate($input: PlanmagnetApplyTemplateInput!) {\n planmagnetApplyTemplate(input: $input) {\n id\n name\n }\n }\n`;\n\nexport function ApplyTemplateDialog({\n templateId,\n templateName,\n onApplied,\n}: {\n templateId: string;\n templateName: string;\n onApplied: (projectId: string) => void;\n}) {\n const { currentUser } = usePlanMagnet();\n const [open, setOpen] = useState(false);\n const [projectName, setProjectName] = useState('');\n const [projectDescription, setProjectDescription] = useState('');\n const [ownerId, setOwnerId] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [apply, { loading }] = useMutation<{\n planmagnetApplyTemplate: { id: string; name: string };\n }>(APPLY_TEMPLATE, {\n refetchQueries: ['GetProjects', 'GetActiveProjects', 'GetDashboardData'],\n awaitRefetchQueries: true,\n });\n const effectiveOwnerId = ownerId || currentUser?.id || '';\n\n const canSubmit = projectName.trim() !== '' && effectiveOwnerId !== '' && !loading;\n\n const handleApply = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n apply({\n variables: {\n input: {\n templateId,\n projectName: projectName.trim(),\n projectDescription: projectDescription.trim() || undefined,\n ownerId: effectiveOwnerId,\n },\n },\n })\n );\n const id = result.data?.planmagnetApplyTemplate.id;\n setProjectName('');\n setProjectDescription('');\n setOpen(false);\n if (id) onApplied(id);\n } catch (e) {\n setError(messageOf(e, 'The project could not be created from this template.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) setOwnerId(currentUser?.id ?? '');\n else setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\" variant=\"outline\" data-testid=\"apply-template-trigger\">\n <Plus className=\"mr-1 h-4 w-4\" />\n Use template\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New project from "{templateName}"</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Creates a project using this template's methodology and status. It counts toward\n the workspace's project quota like any other project.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"apply-template-name\"\n label=\"Project name\"\n value={projectName}\n onChange={setProjectName}\n />\n <TextField\n id=\"apply-template-description\"\n label=\"Description\"\n value={projectDescription}\n onChange={setProjectDescription}\n />\n <div>\n <label htmlFor=\"apply-template-owner\" className=\"text-sm font-medium\">\n Owner\n </label>\n <div className=\"mt-1\">\n <AssigneeSelect\n id=\"apply-template-owner\"\n value={effectiveOwnerId}\n onChange={setOwnerId}\n />\n </div>\n </div>\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleApply} disabled={!canSubmit} data-testid=\"apply-template-submit\">\n {loading ? 'Creating…' : 'Create project'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New risk (BOFF-8047) ────────────────────────────────────────────────────\n\nconst CREATE_RISK = gql`\n mutation CreateDialogRisk($input: PlanmagnetCreateRiskInput!) {\n planmagnetCreateRisk(input: $input) {\n id\n }\n }\n`;\n\nconst SCORES = [1, 2, 3, 4, 5] as const;\n\nfunction ScoreField({\n id,\n label,\n value,\n onChange,\n}: {\n id: string;\n label: string;\n value: number;\n onChange: (value: number) => void;\n}) {\n return (\n <div>\n <label htmlFor={id} className=\"text-sm font-medium\">\n {label}\n </label>\n <select\n id={id}\n className={FIELD}\n value={value}\n onChange={(e) => onChange(Number(e.target.value))}\n >\n {SCORES.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n </div>\n );\n}\n\n/** projectId, when given, pins the risk to that project and hides the project picker (opened from a project page). */\nexport function NewRiskDialog({\n projectId: fixedProjectId,\n onCreated,\n}: {\n projectId?: string;\n onCreated: (riskId: string) => void;\n}) {\n const EMPTY_RISK = {\n title: '',\n projectId: fixedProjectId ?? '',\n severity: 'MEDIUM' as (typeof RISK_SEVERITIES)[number],\n likelihood: 3,\n impact: 3,\n category: '',\n description: '',\n };\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState(EMPTY_RISK);\n const [error, setError] = useState<string | null>(null);\n const projectsState = useDialogProjects(open && !fixedProjectId);\n const { projects } = projectsState;\n const projectId = fixedProjectId || form.projectId || projects[0]?.id || '';\n const [create, { loading }] = useMutation<{ planmagnetCreateRisk: { id: string } }>(CREATE_RISK, {\n refetchQueries: ['GetRisks', 'GetRiskMatrix', 'GetProjectDetail'],\n awaitRefetchQueries: true,\n });\n\n const canSubmit = form.title.trim() !== '' && projectId !== '' && !loading;\n\n const handleCreate = async () => {\n setError(null);\n try {\n const result = await throwOnError(\n create({\n variables: {\n input: {\n title: form.title.trim(),\n projectId,\n severity: form.severity,\n likelihood: form.likelihood,\n impact: form.impact,\n category: form.category.trim() || undefined,\n description: form.description.trim() || undefined,\n },\n },\n })\n );\n const id = result.data?.planmagnetCreateRisk.id;\n setForm(EMPTY_RISK);\n setOpen(false);\n if (id) onCreated(id);\n } catch (e) {\n setError(messageOf(e, 'The risk could not be created.'));\n }\n };\n\n return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (next) setForm(EMPTY_RISK);\n else setError(null);\n }}\n >\n <ResponsiveDialogTrigger asChild>\n <Button size=\"sm\" data-testid=\"new-risk-trigger\">\n <Plus className=\"mr-1 h-4 w-4\" />\n New Risk\n </Button>\n </ResponsiveDialogTrigger>\n <ResponsiveDialogContent className=\"max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New risk</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n The risk starts as Identified. Likelihood and impact are each scored 1 (rare/minor) to 5\n (near-certain/severe).\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3\">\n <TextField\n id=\"new-risk-title\"\n label=\"Title\"\n value={form.title}\n onChange={(title) => setForm({ ...form, title })}\n />\n {!fixedProjectId && (\n <ProjectField\n id=\"new-risk-project\"\n value={projectId}\n onChange={(id) => setForm({ ...form, projectId: id })}\n state={projectsState}\n />\n )}\n <div>\n <label htmlFor=\"new-risk-severity\" className=\"text-sm font-medium\">\n Severity\n </label>\n <select\n id=\"new-risk-severity\"\n className={FIELD}\n value={form.severity}\n onChange={(e) =>\n setForm({ ...form, severity: e.target.value as (typeof RISK_SEVERITIES)[number] })\n }\n >\n {RISK_SEVERITIES.map((s) => (\n <option key={s} value={s}>\n {enumLabel(s)}\n </option>\n ))}\n </select>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <ScoreField\n id=\"new-risk-likelihood\"\n label=\"Likelihood\"\n value={form.likelihood}\n onChange={(likelihood) => setForm({ ...form, likelihood })}\n />\n <ScoreField\n id=\"new-risk-impact\"\n label=\"Impact\"\n value={form.impact}\n onChange={(impact) => setForm({ ...form, impact })}\n />\n </div>\n <TextField\n id=\"new-risk-category\"\n label=\"Category\"\n placeholder=\"e.g. schedule, budget, technical\"\n value={form.category}\n onChange={(category) => setForm({ ...form, category })}\n />\n <TextField\n id=\"new-risk-description\"\n label=\"Description\"\n value={form.description}\n onChange={(description) => setForm({ ...form, description })}\n />\n </div>\n {error && <ErrorLine message={error} />}\n <ResponsiveDialogFooter>\n <Button onClick={handleCreate} disabled={!canSubmit} data-testid=\"new-risk-submit\">\n {loading ? 'Creating…' : 'Create risk'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DependencyPanel.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/dependency/DependencyPanel.tsx"],"names":[],"mappings":"AAoRA,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,UAAU,EACV,SAAS,GACV,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,2CAyHA"}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
+
import { throwOnError as t } from "../utils/mutationResult.js";
|
|
3
|
+
import { ErrorLine as n } from "../controls/ConfirmButton.js";
|
|
4
|
+
import { WorkItemSearchSelect as r } from "../controls/Pickers.js";
|
|
5
|
+
import { enumLabel as i } from "../controls/WorkItemControls.js";
|
|
6
|
+
import { useState as a } from "react";
|
|
7
|
+
import { ArrowLeft as o, ArrowRight as s, Plus as c, X as l } from "lucide-react";
|
|
8
|
+
import { gql as u } from "@apollo/client";
|
|
9
|
+
import { useMutation as d, useQuery as f } from "@apollo/client/react";
|
|
10
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
11
|
+
import { Button as h, Card as g, CardContent as _, CardHeader as v, CardTitle as y } from "@burdenoff/fe-libs/ui";
|
|
12
|
+
//#region src/planmagnet/dependency/DependencyPanel.tsx
|
|
13
|
+
var b = [
|
|
14
|
+
"FINISH_TO_START",
|
|
15
|
+
"START_TO_START",
|
|
16
|
+
"FINISH_TO_FINISH",
|
|
17
|
+
"START_TO_FINISH"
|
|
18
|
+
], x = u`
|
|
19
|
+
query GetWorkItemDependencies($workspaceId: ID!, $workItemId: String!) {
|
|
20
|
+
blocks: planmagnetDependencies(
|
|
21
|
+
workspaceId: $workspaceId
|
|
22
|
+
filter: { predecessorId: $workItemId }
|
|
23
|
+
pagination: { first: 50 }
|
|
24
|
+
) {
|
|
25
|
+
items {
|
|
26
|
+
id
|
|
27
|
+
successorId
|
|
28
|
+
lagMinutes
|
|
29
|
+
type
|
|
30
|
+
status
|
|
31
|
+
description
|
|
32
|
+
successor {
|
|
33
|
+
id
|
|
34
|
+
title
|
|
35
|
+
key
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
totalCount
|
|
39
|
+
}
|
|
40
|
+
blockedBy: planmagnetDependencies(
|
|
41
|
+
workspaceId: $workspaceId
|
|
42
|
+
filter: { successorId: $workItemId }
|
|
43
|
+
pagination: { first: 50 }
|
|
44
|
+
) {
|
|
45
|
+
items {
|
|
46
|
+
id
|
|
47
|
+
predecessorId
|
|
48
|
+
lagMinutes
|
|
49
|
+
type
|
|
50
|
+
status
|
|
51
|
+
description
|
|
52
|
+
predecessor {
|
|
53
|
+
id
|
|
54
|
+
title
|
|
55
|
+
key
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
totalCount
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`, S = u`
|
|
62
|
+
mutation CreateWorkItemDependency($input: PlanmagnetCreateDependencyInput!) {
|
|
63
|
+
planmagnetCreateDependency(input: $input) {
|
|
64
|
+
id
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
`, C = u`
|
|
68
|
+
mutation DeleteWorkItemDependency($id: ID!) {
|
|
69
|
+
planmagnetDeleteDependency(id: $id)
|
|
70
|
+
}
|
|
71
|
+
`;
|
|
72
|
+
function w(e) {
|
|
73
|
+
if (!e) return null;
|
|
74
|
+
let t = e / 60, n = t / 24, r = e > 0 ? "lag" : "lead";
|
|
75
|
+
return Number.isInteger(n) && Math.abs(n) >= 1 ? `${Math.abs(n)}d ${r}` : Number.isInteger(t) ? `${Math.abs(t)}h ${r}` : `${Math.abs(e)}m ${r}`;
|
|
76
|
+
}
|
|
77
|
+
function T({ keyLabel: e, title: t, type: n, lagMinutes: r, onOpen: a, onRemove: o, removing: s }) {
|
|
78
|
+
let c = w(r);
|
|
79
|
+
return /* @__PURE__ */ m("div", {
|
|
80
|
+
className: "flex items-center justify-between gap-3 rounded-md border border-input p-3",
|
|
81
|
+
children: [/* @__PURE__ */ m("div", {
|
|
82
|
+
className: "min-w-0",
|
|
83
|
+
children: [/* @__PURE__ */ m("button", {
|
|
84
|
+
type: "button",
|
|
85
|
+
className: "block max-w-full truncate text-left text-sm font-medium hover:underline",
|
|
86
|
+
onClick: a,
|
|
87
|
+
children: [
|
|
88
|
+
e,
|
|
89
|
+
" ",
|
|
90
|
+
/* @__PURE__ */ p("span", {
|
|
91
|
+
className: "font-normal",
|
|
92
|
+
children: t
|
|
93
|
+
})
|
|
94
|
+
]
|
|
95
|
+
}), /* @__PURE__ */ m("p", {
|
|
96
|
+
className: "text-xs text-muted-foreground",
|
|
97
|
+
children: [i(n), c ? ` · ${c}` : ""]
|
|
98
|
+
})]
|
|
99
|
+
}), /* @__PURE__ */ p(h, {
|
|
100
|
+
size: "icon",
|
|
101
|
+
variant: "ghost",
|
|
102
|
+
disabled: s,
|
|
103
|
+
onClick: o,
|
|
104
|
+
"aria-label": `Remove dependency on ${t}`,
|
|
105
|
+
children: /* @__PURE__ */ p(l, { className: "h-4 w-4" })
|
|
106
|
+
})]
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function E({ workItemId: e, projectId: o, excludeIds: s, onDone: c }) {
|
|
110
|
+
let [l, u] = a("blocks"), [f, g] = a(""), [_, v] = a("FINISH_TO_START"), [y, x] = a(""), [C, w] = a(null), [T, { loading: E }] = d(S, {
|
|
111
|
+
refetchQueries: ["GetWorkItemDependencies", "GetProjectCriticalPath"],
|
|
112
|
+
awaitRefetchQueries: !0
|
|
113
|
+
}), D = async () => {
|
|
114
|
+
if (!f) return;
|
|
115
|
+
w(null);
|
|
116
|
+
let n = y.trim(), r = n === "" ? void 0 : Math.round(Number(n) * 24 * 60);
|
|
117
|
+
if (n !== "" && !Number.isFinite(r)) {
|
|
118
|
+
w("Lag must be a number of days.");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
let i = l === "blocks" ? {
|
|
122
|
+
predecessorId: e,
|
|
123
|
+
successorId: f,
|
|
124
|
+
type: _,
|
|
125
|
+
lagMinutes: r
|
|
126
|
+
} : {
|
|
127
|
+
predecessorId: f,
|
|
128
|
+
successorId: e,
|
|
129
|
+
type: _,
|
|
130
|
+
lagMinutes: r
|
|
131
|
+
};
|
|
132
|
+
try {
|
|
133
|
+
await t(T({ variables: { input: i } })), g(""), x(""), c();
|
|
134
|
+
} catch (e) {
|
|
135
|
+
w(e instanceof Error ? e.message : "The dependency could not be created.");
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
return /* @__PURE__ */ m("div", {
|
|
139
|
+
className: "space-y-3 rounded-md border border-input p-3",
|
|
140
|
+
children: [
|
|
141
|
+
/* @__PURE__ */ m("div", {
|
|
142
|
+
className: "flex gap-1",
|
|
143
|
+
children: [/* @__PURE__ */ p("button", {
|
|
144
|
+
type: "button",
|
|
145
|
+
"data-testid": "dependency-direction-blocks",
|
|
146
|
+
className: `px-3 py-1.5 text-xs rounded-md ${l === "blocks" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"}`,
|
|
147
|
+
onClick: () => u("blocks"),
|
|
148
|
+
children: "This blocks…"
|
|
149
|
+
}), /* @__PURE__ */ p("button", {
|
|
150
|
+
type: "button",
|
|
151
|
+
"data-testid": "dependency-direction-blockedby",
|
|
152
|
+
className: `px-3 py-1.5 text-xs rounded-md ${l === "blockedBy" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"}`,
|
|
153
|
+
onClick: () => u("blockedBy"),
|
|
154
|
+
children: "Blocked by…"
|
|
155
|
+
})]
|
|
156
|
+
}),
|
|
157
|
+
/* @__PURE__ */ p(r, {
|
|
158
|
+
id: "dependency-other-work-item",
|
|
159
|
+
projectId: o,
|
|
160
|
+
value: f,
|
|
161
|
+
onChange: g,
|
|
162
|
+
exclude: s
|
|
163
|
+
}),
|
|
164
|
+
/* @__PURE__ */ m("div", {
|
|
165
|
+
className: "grid grid-cols-2 gap-3",
|
|
166
|
+
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
167
|
+
htmlFor: "dependency-type",
|
|
168
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
169
|
+
children: "Relationship"
|
|
170
|
+
}), /* @__PURE__ */ p("select", {
|
|
171
|
+
id: "dependency-type",
|
|
172
|
+
className: "mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm",
|
|
173
|
+
value: _,
|
|
174
|
+
onChange: (e) => v(e.target.value),
|
|
175
|
+
children: b.map((e) => /* @__PURE__ */ p("option", {
|
|
176
|
+
value: e,
|
|
177
|
+
children: i(e)
|
|
178
|
+
}, e))
|
|
179
|
+
})] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
180
|
+
htmlFor: "dependency-lag",
|
|
181
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
182
|
+
children: "Lag (days, optional)"
|
|
183
|
+
}), /* @__PURE__ */ p("input", {
|
|
184
|
+
id: "dependency-lag",
|
|
185
|
+
type: "number",
|
|
186
|
+
step: "0.5",
|
|
187
|
+
className: "mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm",
|
|
188
|
+
value: y,
|
|
189
|
+
placeholder: "0",
|
|
190
|
+
onChange: (e) => x(e.target.value)
|
|
191
|
+
})] })]
|
|
192
|
+
}),
|
|
193
|
+
C && /* @__PURE__ */ p(n, { message: C }),
|
|
194
|
+
/* @__PURE__ */ m("div", {
|
|
195
|
+
className: "flex justify-end gap-2",
|
|
196
|
+
children: [/* @__PURE__ */ p(h, {
|
|
197
|
+
size: "sm",
|
|
198
|
+
variant: "ghost",
|
|
199
|
+
onClick: c,
|
|
200
|
+
children: "Cancel"
|
|
201
|
+
}), /* @__PURE__ */ p(h, {
|
|
202
|
+
size: "sm",
|
|
203
|
+
disabled: !f || E,
|
|
204
|
+
onClick: () => void D(),
|
|
205
|
+
children: E ? "Adding…" : "Add dependency"
|
|
206
|
+
})]
|
|
207
|
+
})
|
|
208
|
+
]
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
function D({ workspaceId: r, workItemId: i, projectId: l }) {
|
|
212
|
+
let u = e(), [b, S] = a(!1), [w, D] = a(null), { data: O, loading: k, error: A, refetch: j } = f(x, {
|
|
213
|
+
variables: {
|
|
214
|
+
workspaceId: r,
|
|
215
|
+
workItemId: i
|
|
216
|
+
},
|
|
217
|
+
skip: !r || !i
|
|
218
|
+
}), [M, { loading: N }] = d(C, { refetchQueries: ["GetWorkItemDependencies", "GetProjectCriticalPath"] }), P = O?.blocks.items ?? [], F = O?.blockedBy.items ?? [], I = [
|
|
219
|
+
i,
|
|
220
|
+
...P.map((e) => e.successorId),
|
|
221
|
+
...F.map((e) => e.predecessorId)
|
|
222
|
+
], L = async (e) => {
|
|
223
|
+
D(null);
|
|
224
|
+
try {
|
|
225
|
+
await t(M({ variables: { id: e } }));
|
|
226
|
+
} catch (e) {
|
|
227
|
+
D(e instanceof Error ? e.message : "The dependency could not be removed.");
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
return /* @__PURE__ */ m(g, { children: [/* @__PURE__ */ m(v, {
|
|
231
|
+
className: "flex flex-row items-center justify-between space-y-0",
|
|
232
|
+
children: [/* @__PURE__ */ p(y, { children: "Dependencies" }), !b && /* @__PURE__ */ m(h, {
|
|
233
|
+
size: "sm",
|
|
234
|
+
variant: "outline",
|
|
235
|
+
onClick: () => S(!0),
|
|
236
|
+
children: [/* @__PURE__ */ p(c, { className: "h-4 w-4 mr-1" }), "Add dependency"]
|
|
237
|
+
})]
|
|
238
|
+
}), /* @__PURE__ */ m(_, {
|
|
239
|
+
className: "space-y-4",
|
|
240
|
+
children: [
|
|
241
|
+
b && /* @__PURE__ */ p(E, {
|
|
242
|
+
workItemId: i,
|
|
243
|
+
projectId: l,
|
|
244
|
+
excludeIds: I,
|
|
245
|
+
onDone: () => {
|
|
246
|
+
S(!1), j();
|
|
247
|
+
}
|
|
248
|
+
}),
|
|
249
|
+
k && !O && /* @__PURE__ */ p("p", {
|
|
250
|
+
className: "text-sm text-muted-foreground",
|
|
251
|
+
children: "Loading dependencies…"
|
|
252
|
+
}),
|
|
253
|
+
A && /* @__PURE__ */ m("p", {
|
|
254
|
+
className: "text-sm text-red-500",
|
|
255
|
+
children: ["Error: ", A.message]
|
|
256
|
+
}),
|
|
257
|
+
w && /* @__PURE__ */ p(n, { message: w }),
|
|
258
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("p", {
|
|
259
|
+
className: "mb-2 flex items-center gap-1 text-xs font-medium text-muted-foreground uppercase",
|
|
260
|
+
children: [
|
|
261
|
+
/* @__PURE__ */ p(s, { className: "h-3 w-3" }),
|
|
262
|
+
"This blocks (",
|
|
263
|
+
P.length,
|
|
264
|
+
")"
|
|
265
|
+
]
|
|
266
|
+
}), /* @__PURE__ */ m("div", {
|
|
267
|
+
className: "space-y-2",
|
|
268
|
+
children: [P.map((e) => /* @__PURE__ */ p(T, {
|
|
269
|
+
keyLabel: e.successor?.key ?? "",
|
|
270
|
+
title: e.successor?.title ?? "Unknown work item",
|
|
271
|
+
type: e.type,
|
|
272
|
+
lagMinutes: e.lagMinutes,
|
|
273
|
+
removing: N,
|
|
274
|
+
onOpen: () => e.successor && u(`/tasks/task-detail-page?taskId=${encodeURIComponent(e.successor.id)}`),
|
|
275
|
+
onRemove: () => void L(e.id)
|
|
276
|
+
}, e.id)), !k && P.length === 0 && /* @__PURE__ */ p("p", {
|
|
277
|
+
className: "text-sm text-muted-foreground",
|
|
278
|
+
children: "Nothing depends on this task finishing."
|
|
279
|
+
})]
|
|
280
|
+
})] }),
|
|
281
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("p", {
|
|
282
|
+
className: "mb-2 flex items-center gap-1 text-xs font-medium text-muted-foreground uppercase",
|
|
283
|
+
children: [
|
|
284
|
+
/* @__PURE__ */ p(o, { className: "h-3 w-3" }),
|
|
285
|
+
"Blocked by (",
|
|
286
|
+
F.length,
|
|
287
|
+
")"
|
|
288
|
+
]
|
|
289
|
+
}), /* @__PURE__ */ m("div", {
|
|
290
|
+
className: "space-y-2",
|
|
291
|
+
children: [F.map((e) => /* @__PURE__ */ p(T, {
|
|
292
|
+
keyLabel: e.predecessor?.key ?? "",
|
|
293
|
+
title: e.predecessor?.title ?? "Unknown work item",
|
|
294
|
+
type: e.type,
|
|
295
|
+
lagMinutes: e.lagMinutes,
|
|
296
|
+
removing: N,
|
|
297
|
+
onOpen: () => e.predecessor && u(`/tasks/task-detail-page?taskId=${encodeURIComponent(e.predecessor.id)}`),
|
|
298
|
+
onRemove: () => void L(e.id)
|
|
299
|
+
}, e.id)), !k && F.length === 0 && /* @__PURE__ */ p("p", {
|
|
300
|
+
className: "text-sm text-muted-foreground",
|
|
301
|
+
children: "This task has no upstream dependency."
|
|
302
|
+
})]
|
|
303
|
+
})] })
|
|
304
|
+
]
|
|
305
|
+
})] });
|
|
306
|
+
}
|
|
307
|
+
//#endregion
|
|
308
|
+
export { D as DependencyPanel };
|
|
309
|
+
|
|
310
|
+
//# sourceMappingURL=DependencyPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DependencyPanel.js","names":[],"sources":["../../../src/planmagnet/dependency/DependencyPanel.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Button, Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, ArrowRight, Plus, X } from 'lucide-react';\nimport { WorkItemSearchSelect } from '../controls/Pickers';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport { ErrorLine } from '../controls/ConfirmButton';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { throwOnError } from '../utils/mutationResult';\n\n/**\n * Dependencies panel for the task detail page (BOFF-8047). `WorkItemDependency` is the CPM model only\n * (predecessor/successor + FINISH_TO_START/START_TO_START/FINISH_TO_FINISH/START_TO_FINISH + lagMinutes) — the\n * P0 architecture decision keeps issue-link verbs (blocks/relates-to) on the separate WorkItemLink type, out of\n * scope here. \"This blocks\" (this item is the predecessor) and \"Blocked by\" (this item is the successor) are the\n * two directions a FINISH_TO_START edge can be read in, which is the common case; the type select still shows all\n * four so a start-to-start or finish-to-finish constraint can be recorded correctly.\n */\n\nconst DEPENDENCY_TYPES = [\n 'FINISH_TO_START',\n 'START_TO_START',\n 'FINISH_TO_FINISH',\n 'START_TO_FINISH',\n] as const;\n\nconst GET_WORK_ITEM_DEPENDENCIES = gql`\n query GetWorkItemDependencies($workspaceId: ID!, $workItemId: String!) {\n blocks: planmagnetDependencies(\n workspaceId: $workspaceId\n filter: { predecessorId: $workItemId }\n pagination: { first: 50 }\n ) {\n items {\n id\n successorId\n lagMinutes\n type\n status\n description\n successor {\n id\n title\n key\n }\n }\n totalCount\n }\n blockedBy: planmagnetDependencies(\n workspaceId: $workspaceId\n filter: { successorId: $workItemId }\n pagination: { first: 50 }\n ) {\n items {\n id\n predecessorId\n lagMinutes\n type\n status\n description\n predecessor {\n id\n title\n key\n }\n }\n totalCount\n }\n }\n`;\n\nconst CREATE_DEPENDENCY = gql`\n mutation CreateWorkItemDependency($input: PlanmagnetCreateDependencyInput!) {\n planmagnetCreateDependency(input: $input) {\n id\n }\n }\n`;\n\nconst DELETE_DEPENDENCY = gql`\n mutation DeleteWorkItemDependency($id: ID!) {\n planmagnetDeleteDependency(id: $id)\n }\n`;\n\ninterface DependencyEdge {\n id: string;\n lagMinutes: number | null;\n type: string;\n status: string;\n description: string | null;\n}\ninterface BlockEdge extends DependencyEdge {\n successorId: string;\n successor: { id: string; title: string; key: string } | null;\n}\ninterface BlockedByEdge extends DependencyEdge {\n predecessorId: string;\n predecessor: { id: string; title: string; key: string } | null;\n}\n\nfunction lagLabel(lagMinutes: number | null): string | null {\n if (!lagMinutes) return null;\n const hours = lagMinutes / 60;\n const days = hours / 24;\n const verb = lagMinutes > 0 ? 'lag' : 'lead';\n if (Number.isInteger(days) && Math.abs(days) >= 1) return `${Math.abs(days)}d ${verb}`;\n if (Number.isInteger(hours)) return `${Math.abs(hours)}h ${verb}`;\n return `${Math.abs(lagMinutes)}m ${verb}`;\n}\n\nfunction EdgeRow({\n keyLabel,\n title,\n type,\n lagMinutes,\n onOpen,\n onRemove,\n removing,\n}: {\n keyLabel: string;\n title: string;\n type: string;\n lagMinutes: number | null;\n onOpen: () => void;\n onRemove: () => void;\n removing: boolean;\n}) {\n const lag = lagLabel(lagMinutes);\n return (\n <div className=\"flex items-center justify-between gap-3 rounded-md border border-input p-3\">\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n className=\"block max-w-full truncate text-left text-sm font-medium hover:underline\"\n onClick={onOpen}\n >\n {keyLabel} <span className=\"font-normal\">{title}</span>\n </button>\n <p className=\"text-xs text-muted-foreground\">\n {enumLabel(type)}\n {lag ? ` · ${lag}` : ''}\n </p>\n </div>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n disabled={removing}\n onClick={onRemove}\n aria-label={`Remove dependency on ${title}`}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n );\n}\n\n/** The \"add dependency\" form: pick a direction, a work item, a type and an optional lag. */\nfunction AddDependencyForm({\n workItemId,\n projectId,\n excludeIds,\n onDone,\n}: {\n workItemId: string;\n projectId: string;\n excludeIds: string[];\n onDone: () => void;\n}) {\n const [direction, setDirection] = useState<'blocks' | 'blockedBy'>('blocks');\n const [otherId, setOtherId] = useState('');\n const [type, setType] = useState<(typeof DEPENDENCY_TYPES)[number]>('FINISH_TO_START');\n const [lagDays, setLagDays] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [create, { loading }] = useMutation(CREATE_DEPENDENCY, {\n refetchQueries: ['GetWorkItemDependencies', 'GetProjectCriticalPath'],\n awaitRefetchQueries: true,\n });\n\n const submit = async () => {\n if (!otherId) return;\n setError(null);\n const lagTrimmed = lagDays.trim();\n const lagMinutes = lagTrimmed === '' ? undefined : Math.round(Number(lagTrimmed) * 24 * 60);\n if (lagTrimmed !== '' && !Number.isFinite(lagMinutes)) {\n setError('Lag must be a number of days.');\n return;\n }\n const input =\n direction === 'blocks'\n ? { predecessorId: workItemId, successorId: otherId, type, lagMinutes }\n : { predecessorId: otherId, successorId: workItemId, type, lagMinutes };\n try {\n await throwOnError(create({ variables: { input } }));\n setOtherId('');\n setLagDays('');\n onDone();\n } catch (e) {\n setError(e instanceof Error ? e.message : 'The dependency could not be created.');\n }\n };\n\n return (\n <div className=\"space-y-3 rounded-md border border-input p-3\">\n <div className=\"flex gap-1\">\n <button\n type=\"button\"\n data-testid=\"dependency-direction-blocks\"\n className={`px-3 py-1.5 text-xs rounded-md ${direction === 'blocks' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted'}`}\n onClick={() => setDirection('blocks')}\n >\n This blocks…\n </button>\n <button\n type=\"button\"\n data-testid=\"dependency-direction-blockedby\"\n className={`px-3 py-1.5 text-xs rounded-md ${direction === 'blockedBy' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted'}`}\n onClick={() => setDirection('blockedBy')}\n >\n Blocked by…\n </button>\n </div>\n <WorkItemSearchSelect\n id=\"dependency-other-work-item\"\n projectId={projectId}\n value={otherId}\n onChange={setOtherId}\n exclude={excludeIds}\n />\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"dependency-type\" className=\"text-xs font-medium text-muted-foreground\">\n Relationship\n </label>\n <select\n id=\"dependency-type\"\n className=\"mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm\"\n value={type}\n onChange={(e) => setType(e.target.value as (typeof DEPENDENCY_TYPES)[number])}\n >\n {DEPENDENCY_TYPES.map((t) => (\n <option key={t} value={t}>\n {enumLabel(t)}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"dependency-lag\" className=\"text-xs font-medium text-muted-foreground\">\n Lag (days, optional)\n </label>\n <input\n id=\"dependency-lag\"\n type=\"number\"\n step=\"0.5\"\n className=\"mt-1 w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm\"\n value={lagDays}\n placeholder=\"0\"\n onChange={(e) => setLagDays(e.target.value)}\n />\n </div>\n </div>\n {error && <ErrorLine message={error} />}\n <div className=\"flex justify-end gap-2\">\n <Button size=\"sm\" variant=\"ghost\" onClick={onDone}>\n Cancel\n </Button>\n <Button size=\"sm\" disabled={!otherId || loading} onClick={() => void submit()}>\n {loading ? 'Adding…' : 'Add dependency'}\n </Button>\n </div>\n </div>\n );\n}\n\nexport function DependencyPanel({\n workspaceId,\n workItemId,\n projectId,\n}: {\n workspaceId: string;\n workItemId: string;\n projectId: string;\n}) {\n const navigate = usePlanMagnetNavigate();\n const [isAdding, setIsAdding] = useState(false);\n const [removeError, setRemoveError] = useState<string | null>(null);\n const { data, loading, error, refetch } = useQuery<{\n blocks: { items: BlockEdge[]; totalCount: number };\n blockedBy: { items: BlockedByEdge[]; totalCount: number };\n }>(GET_WORK_ITEM_DEPENDENCIES, {\n variables: { workspaceId, workItemId },\n skip: !workspaceId || !workItemId,\n });\n const [remove, { loading: removing }] = useMutation(DELETE_DEPENDENCY, {\n refetchQueries: ['GetWorkItemDependencies', 'GetProjectCriticalPath'],\n });\n\n const blocks = data?.blocks.items ?? [];\n const blockedBy = data?.blockedBy.items ?? [];\n const excludeIds = [\n workItemId,\n ...blocks.map((e) => e.successorId),\n ...blockedBy.map((e) => e.predecessorId),\n ];\n\n const onRemove = async (id: string) => {\n setRemoveError(null);\n try {\n await throwOnError(remove({ variables: { id } }));\n } catch (e) {\n setRemoveError(e instanceof Error ? e.message : 'The dependency could not be removed.');\n }\n };\n\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0\">\n <CardTitle>Dependencies</CardTitle>\n {!isAdding && (\n <Button size=\"sm\" variant=\"outline\" onClick={() => setIsAdding(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add dependency\n </Button>\n )}\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {isAdding && (\n <AddDependencyForm\n workItemId={workItemId}\n projectId={projectId}\n excludeIds={excludeIds}\n onDone={() => {\n setIsAdding(false);\n void refetch();\n }}\n />\n )}\n {loading && !data && <p className=\"text-sm text-muted-foreground\">Loading dependencies…</p>}\n {error && <p className=\"text-sm text-red-500\">Error: {error.message}</p>}\n {removeError && <ErrorLine message={removeError} />}\n\n <div>\n <p className=\"mb-2 flex items-center gap-1 text-xs font-medium text-muted-foreground uppercase\">\n <ArrowRight className=\"h-3 w-3\" />\n This blocks ({blocks.length})\n </p>\n <div className=\"space-y-2\">\n {blocks.map((edge) => (\n <EdgeRow\n key={edge.id}\n keyLabel={edge.successor?.key ?? ''}\n title={edge.successor?.title ?? 'Unknown work item'}\n type={edge.type}\n lagMinutes={edge.lagMinutes}\n removing={removing}\n onOpen={() =>\n edge.successor &&\n navigate(\n `/tasks/task-detail-page?taskId=${encodeURIComponent(edge.successor.id)}`\n )\n }\n onRemove={() => void onRemove(edge.id)}\n />\n ))}\n {!loading && blocks.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">\n Nothing depends on this task finishing.\n </p>\n )}\n </div>\n </div>\n\n <div>\n <p className=\"mb-2 flex items-center gap-1 text-xs font-medium text-muted-foreground uppercase\">\n <ArrowLeft className=\"h-3 w-3\" />\n Blocked by ({blockedBy.length})\n </p>\n <div className=\"space-y-2\">\n {blockedBy.map((edge) => (\n <EdgeRow\n key={edge.id}\n keyLabel={edge.predecessor?.key ?? ''}\n title={edge.predecessor?.title ?? 'Unknown work item'}\n type={edge.type}\n lagMinutes={edge.lagMinutes}\n removing={removing}\n onOpen={() =>\n edge.predecessor &&\n navigate(\n `/tasks/task-detail-page?taskId=${encodeURIComponent(edge.predecessor.id)}`\n )\n }\n onRemove={() => void onRemove(edge.id)}\n />\n ))}\n {!loading && blockedBy.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">This task has no upstream dependency.</p>\n )}\n </div>\n </div>\n </CardContent>\n </Card>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutomationAutomationRuleDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/AutomationAutomationRuleDetailPagePage.tsx"],"names":[],"mappings":"AAuFA,wBAAgB,sCAAsC,4CA6IrD"}
|