@burdenoff/microfe-planmagnet 2026.930.21 → 2026.930.23
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/node_modules/lodash/_arrayEach.js +14 -0
- package/dist/node_modules/lodash/_arrayEach.js.map +1 -0
- package/dist/node_modules/lodash/_assignValue.js +17 -0
- package/dist/node_modules/lodash/_assignValue.js.map +1 -0
- package/dist/node_modules/lodash/_baseAssign.js +16 -0
- package/dist/node_modules/lodash/_baseAssign.js.map +1 -0
- package/dist/node_modules/lodash/_baseAssignIn.js +16 -0
- package/dist/node_modules/lodash/_baseAssignIn.js.map +1 -0
- package/dist/node_modules/lodash/_baseClone.js +64 -0
- package/dist/node_modules/lodash/_baseClone.js.map +1 -0
- package/dist/node_modules/lodash/_baseCreate.js +21 -0
- package/dist/node_modules/lodash/_baseCreate.js.map +1 -0
- package/dist/node_modules/lodash/_baseIsMap.js +16 -0
- package/dist/node_modules/lodash/_baseIsMap.js.map +1 -0
- package/dist/node_modules/lodash/_baseIsSet.js +16 -0
- package/dist/node_modules/lodash/_baseIsSet.js.map +1 -0
- package/dist/node_modules/lodash/_baseKeysIn.js +20 -0
- package/dist/node_modules/lodash/_baseKeysIn.js.map +1 -0
- package/dist/node_modules/lodash/_baseSum.js +17 -0
- package/dist/node_modules/lodash/_baseSum.js.map +1 -0
- package/dist/node_modules/lodash/_baseUnset.js +26 -0
- package/dist/node_modules/lodash/_baseUnset.js.map +1 -0
- package/dist/node_modules/lodash/_cloneArrayBuffer.js +16 -0
- package/dist/node_modules/lodash/_cloneArrayBuffer.js.map +1 -0
- package/dist/node_modules/lodash/_cloneBuffer.js +17 -0
- package/dist/node_modules/lodash/_cloneBuffer.js.map +1 -0
- package/dist/node_modules/lodash/_cloneDataView.js +16 -0
- package/dist/node_modules/lodash/_cloneDataView.js.map +1 -0
- package/dist/node_modules/lodash/_cloneRegExp.js +15 -0
- package/dist/node_modules/lodash/_cloneRegExp.js.map +1 -0
- package/dist/node_modules/lodash/_cloneSymbol.js +15 -0
- package/dist/node_modules/lodash/_cloneSymbol.js.map +1 -0
- package/dist/node_modules/lodash/_cloneTypedArray.js +16 -0
- package/dist/node_modules/lodash/_cloneTypedArray.js.map +1 -0
- package/dist/node_modules/lodash/_copyArray.js +15 -0
- package/dist/node_modules/lodash/_copyArray.js.map +1 -0
- package/dist/node_modules/lodash/_copyObject.js +22 -0
- package/dist/node_modules/lodash/_copyObject.js.map +1 -0
- package/dist/node_modules/lodash/_copySymbols.js +16 -0
- package/dist/node_modules/lodash/_copySymbols.js.map +1 -0
- package/dist/node_modules/lodash/_copySymbolsIn.js +16 -0
- package/dist/node_modules/lodash/_copySymbolsIn.js.map +1 -0
- package/dist/node_modules/lodash/_customOmitClone.js +15 -0
- package/dist/node_modules/lodash/_customOmitClone.js.map +1 -0
- package/dist/node_modules/lodash/_flatRest.js +17 -0
- package/dist/node_modules/lodash/_flatRest.js.map +1 -0
- package/dist/node_modules/lodash/_getAllKeysIn.js +17 -0
- package/dist/node_modules/lodash/_getAllKeysIn.js.map +1 -0
- package/dist/node_modules/lodash/_getSymbolsIn.js +18 -0
- package/dist/node_modules/lodash/_getSymbolsIn.js.map +1 -0
- package/dist/node_modules/lodash/_initCloneArray.js +15 -0
- package/dist/node_modules/lodash/_initCloneArray.js.map +1 -0
- package/dist/node_modules/lodash/_initCloneByTag.js +40 -0
- package/dist/node_modules/lodash/_initCloneByTag.js.map +1 -0
- package/dist/node_modules/lodash/_initCloneObject.js +17 -0
- package/dist/node_modules/lodash/_initCloneObject.js.map +1 -0
- package/dist/node_modules/lodash/_nativeKeysIn.js +15 -0
- package/dist/node_modules/lodash/_nativeKeysIn.js.map +1 -0
- package/dist/node_modules/lodash/_parent.js +16 -0
- package/dist/node_modules/lodash/_parent.js.map +1 -0
- package/dist/node_modules/lodash/flatten.js +15 -0
- package/dist/node_modules/lodash/flatten.js.map +1 -0
- package/dist/node_modules/lodash/isMap.js +14 -0
- package/dist/node_modules/lodash/isMap.js.map +1 -0
- package/dist/node_modules/lodash/isSet.js +14 -0
- package/dist/node_modules/lodash/isSet.js.map +1 -0
- package/dist/node_modules/lodash/keysIn.js +17 -0
- package/dist/node_modules/lodash/keysIn.js.map +1 -0
- package/dist/node_modules/lodash/maxBy.js +17 -0
- package/dist/node_modules/lodash/maxBy.js.map +1 -0
- package/dist/node_modules/lodash/omit.js +28 -0
- package/dist/node_modules/lodash/omit.js.map +1 -0
- package/dist/node_modules/lodash/sumBy.js +16 -0
- package/dist/node_modules/lodash/sumBy.js.map +1 -0
- package/dist/node_modules/recharts/es6/chart/Sankey.js +556 -0
- package/dist/node_modules/recharts/es6/chart/Sankey.js.map +1 -0
- package/dist/node_modules/recharts/es6/chart/Treemap.js +545 -0
- package/dist/node_modules/recharts/es6/chart/Treemap.js.map +1 -0
- package/dist/node_modules/recharts/es6/shape/Polygon.js +112 -0
- package/dist/node_modules/recharts/es6/shape/Polygon.js.map +1 -0
- package/dist/node_modules/recharts/es6/util/Constants.js +31 -0
- package/dist/node_modules/recharts/es6/util/Constants.js.map +1 -0
- package/dist/node_modules/recharts/es6/util/ReactUtils.js +15 -10
- package/dist/node_modules/recharts/es6/util/ReactUtils.js.map +1 -1
- package/dist/planmagnet/controls/AutomationRuleControls.js +10 -10
- package/dist/planmagnet/controls/CompetitorControls.js +7 -7
- package/dist/planmagnet/controls/FeatureControls.js +38 -38
- package/dist/planmagnet/controls/ProgramControls.js +8 -8
- package/dist/planmagnet/dependency/DependencyGraph.d.ts.map +1 -1
- package/dist/planmagnet/dependency/DependencyGraph.js +13 -10
- package/dist/planmagnet/dependency/DependencyGraph.js.map +1 -1
- package/dist/planmagnet/dependency/DependencyPanel.js +13 -13
- package/dist/planmagnet/dependency/GanttChart.d.ts.map +1 -1
- package/dist/planmagnet/dependency/GanttChart.js +11 -5
- package/dist/planmagnet/dependency/GanttChart.js.map +1 -1
- package/dist/planmagnet/pages/ActivityActivityPagePage.js +16 -16
- package/dist/planmagnet/pages/ActivityActivityPagePage.js.map +1 -1
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +91 -73
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js +6 -6
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +4 -4
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js +11 -11
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.js +5 -5
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.js +5 -5
- package/dist/planmagnet/pages/IntegrationsNewSyncPagePage.js +6 -6
- package/dist/planmagnet/pages/IntegrationsNewSyncPagePage.js.map +1 -1
- package/dist/planmagnet/pages/IntegrationsSyncsPagePage.js +8 -8
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +10 -10
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js +6 -6
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +5 -5
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js +8 -8
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +4 -4
- package/dist/planmagnet/pages/analytics/StatusFlowCard.d.ts +8 -0
- package/dist/planmagnet/pages/analytics/StatusFlowCard.d.ts.map +1 -0
- package/dist/planmagnet/pages/analytics/StatusFlowCard.js +234 -0
- package/dist/planmagnet/pages/analytics/StatusFlowCard.js.map +1 -0
- package/dist/planmagnet/pages/analytics/WorkBreakdownCard.d.ts +6 -0
- package/dist/planmagnet/pages/analytics/WorkBreakdownCard.d.ts.map +1 -0
- package/dist/planmagnet/pages/analytics/WorkBreakdownCard.js +367 -0
- package/dist/planmagnet/pages/analytics/WorkBreakdownCard.js.map +1 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.js +17 -17
- package/dist/planmagnet/utils/statusColor.d.ts +8 -9
- package/dist/planmagnet/utils/statusColor.d.ts.map +1 -1
- package/dist/planmagnet/utils/statusColor.js +8 -40
- package/dist/planmagnet/utils/statusColor.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IntegrationsNewSyncPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/IntegrationsNewSyncPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Checkbox,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, CheckCircle2, Github, Loader2, Plug, ShieldQuestion } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError } from '../utils/mutationResult';\nimport { isForbidden, mutationErrorMessage } from '../utils/graphqlErrors';\nimport { ErrorLine } from '../controls/ConfirmButton';\nimport { ProjectSelect } from '../controls/Pickers';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport {\n RunNowButton,\n SyncRunResultSummary,\n TestConnectionButton,\n CONFLICT_STRATEGY_EXPLANATION,\n} from '../controls/SyncControls';\nimport { useSyncProviderCapabilities } from '../integrations/useSyncProviderCapabilities';\nimport {\n CONFLICT_RESOLUTIONS,\n directionLabel,\n directionSupported,\n GITHUB_FIELD_MAPPING_DEFAULTS,\n isValidGithubOwner,\n isValidGithubRepo,\n providerIsLive,\n providerLabel,\n SYNC_DIRECTIONS,\n type ConflictResolution,\n type SyncDirection,\n type SyncProvider,\n type SyncProviderCapability,\n type SyncRunResult,\n} from '../integrations/syncTypes';\n\n/**\n * Sync setup wizard (AUT-08): create an ExternalSync step by step, driven entirely by\n * `planmagnetSupportedSyncProviders` — a provider is selectable, and a direction is offered, only when the\n * capability list says it is real, never a hard-coded \"GitHub only\" rule. Today that capability list happens to\n * make GITHUB the only live choice (BOFF-4446); the connection fields below (owner/repo/token) are GitHub's own\n * documented `connectionConfig` shape and only make sense for it — there is nothing to generalize them to until\n * a second connector ships.\n */\n\nconst label = 'text-sm font-medium';\n\nconst CREATE_SYNC = gql`\n mutation NewSyncCreate($input: PlanmagnetCreateExternalSyncInput!) {\n planmagnetCreateExternalSync(input: $input) {\n id\n provider\n status\n project {\n id\n name\n }\n }\n }\n`;\n\ninterface CreatedSync {\n id: string;\n provider: string;\n status: string;\n project: { id: string; name: string } | null;\n}\n\nfunction ProviderStep({\n capabilities,\n capabilitiesLoading,\n provider,\n onSelect,\n}: {\n capabilities: SyncProviderCapability[];\n capabilitiesLoading: boolean;\n provider: SyncProvider | '';\n onSelect: (p: SyncProvider) => void;\n}) {\n return (\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>1. Provider</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {capabilitiesLoading && <p className=\"text-sm text-muted-foreground\">Loading providers…</p>}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-2\">\n {capabilities.map((c) => {\n const live = providerIsLive(c);\n const selected = provider === c.provider;\n return (\n <button\n key={c.provider}\n type=\"button\"\n disabled={!live}\n aria-pressed={selected}\n data-testid={`sync-wizard-provider-${c.provider}`}\n onClick={() => live && onSelect(c.provider)}\n className={`flex items-start gap-2 rounded-md border p-3 text-left text-sm transition-colors ${\n selected ? 'border-primary bg-primary/5' : 'border-input'\n } ${live ? 'hover:bg-muted' : 'cursor-not-allowed opacity-50'}`}\n >\n {c.provider === 'GITHUB' ? (\n <Github className=\"mt-0.5 h-4 w-4 shrink-0\" />\n ) : (\n <Plug className=\"mt-0.5 h-4 w-4 shrink-0\" />\n )}\n <span>\n <span className=\"block font-medium\">{providerLabel(c.provider)}</span>\n <span className=\"block text-xs text-muted-foreground\">\n {live\n ? [\n c.supportsImport && 'inbound',\n c.supportsExport && 'outbound',\n c.supportsBidirectional && 'bidirectional',\n ]\n .filter(Boolean)\n .join(', ') + ' sync'\n : 'No live connector yet — inbound, outbound and bidirectional sync are all unavailable for this provider.'}\n </span>\n </span>\n </button>\n );\n })}\n </div>\n </CardContent>\n </Card>\n );\n}\n\nexport function IntegrationsNewSyncPagePage() {\n const navigate = usePlanMagnetNavigate();\n const { capabilities, loading: capabilitiesLoading } = useSyncProviderCapabilities();\n\n const [provider, setProvider] = useState<SyncProvider | ''>('');\n const [projectId, setProjectId] = useState('');\n const [owner, setOwner] = useState('');\n const [repo, setRepo] = useState('');\n const [direction, setDirection] = useState<SyncDirection | ''>('');\n const [token, setToken] = useState('');\n const [conflictStrategy, setConflictStrategy] = useState<ConflictResolution>('MANUAL');\n const [priorityPrefix, setPriorityPrefix] = useState('');\n const [dueDatePrefix, setDueDatePrefix] = useState('');\n const [verifyBeforeCreate, setVerifyBeforeCreate] = useState(true);\n const [formError, setFormError] = useState<string | null>(null);\n const [created, setCreated] = useState<CreatedSync | null>(null);\n const [runResult, setRunResult] = useState<SyncRunResult | null>(null);\n\n const [create, state] = useMutation<{ planmagnetCreateExternalSync: CreatedSync }>(CREATE_SYNC, {\n refetchQueries: ['SyncsList'],\n });\n\n const capability = capabilities.find((c) => c.provider === provider);\n const isGithub = provider === 'GITHUB';\n const allowedDirections = capability\n ? SYNC_DIRECTIONS.filter((d) => directionSupported(capability, d))\n : [];\n\n const ownerValid = owner.trim() !== '' && isValidGithubOwner(owner);\n const repoValid = repo.trim() !== '' && isValidGithubRepo(repo);\n const step2Complete =\n !!provider && !!projectId && (!isGithub || (ownerValid && repoValid)) && !!direction;\n const step3Complete = step2Complete && token.trim() !== '';\n\n const buildInput = () => {\n const fieldMapping: Record<string, string> = {};\n if (priorityPrefix.trim()) fieldMapping.priority = priorityPrefix.trim();\n if (dueDatePrefix.trim()) fieldMapping.dueDate = dueDatePrefix.trim();\n return {\n projectId,\n provider,\n direction,\n externalProjectId: isGithub ? `${owner.trim()}/${repo.trim()}` : '',\n externalProjectUrl: isGithub\n ? `https://github.com/${owner.trim()}/${repo.trim()}`\n : undefined,\n connectionConfig: isGithub\n ? { token: token.trim(), owner: owner.trim(), repo: repo.trim() }\n : {},\n conflictStrategy,\n ...(Object.keys(fieldMapping).length > 0 ? { fieldMapping } : {}),\n testConnection: verifyBeforeCreate,\n };\n };\n\n const submit = async () => {\n setFormError(null);\n if (!step3Complete) {\n setFormError(\n 'Fill in the project, external project and credentials above before creating the sync.'\n );\n return;\n }\n try {\n const res = await throwOnError(create({ variables: { input: buildInput() } }));\n if (res.data) setCreated(res.data.planmagnetCreateExternalSync);\n } catch (e) {\n setFormError(\n isForbidden(e)\n ? 'Your role can view integrations but not set them up.'\n : mutationErrorMessage(e, 'The sync could not be created.')\n );\n }\n };\n\n if (created) {\n return (\n <div className=\"space-y-6 p-6 max-w-2xl\">\n <Card data-testid=\"sync-wizard-created\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <CheckCircle2 className=\"h-5 w-5 text-status-success-text\" />\n Sync created\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">\n {providerLabel(created.provider)} sync for {created.project?.name ?? 'the project'} is\n set up and idle. Test the connection and run the first sync now, or do either later\n from the sync's own page.\n </p>\n <div className=\"flex flex-wrap items-center gap-3\">\n <TestConnectionButton syncId={created.id} />\n <RunNowButton syncId={created.id} onResult={setRunResult} />\n </div>\n {runResult && <SyncRunResultSummary result={runResult} />}\n <Button\n onClick={() => navigate(detailPath('/integrations/sync-detail-page', created.id))}\n data-testid=\"sync-wizard-view\"\n >\n View sync\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6 max-w-2xl\">\n <div className=\"flex items-start gap-3\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Back to Integrations\"\n onClick={() => navigate('/integrations/syncs-page')}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Set up a sync</h1>\n <p className=\"text-sm text-muted-foreground\">\n Connect a PlanMagnet project to an external issue tracker so work items stay in step on\n both sides.\n </p>\n </div>\n </div>\n\n <ProviderStep\n capabilities={capabilities}\n capabilitiesLoading={capabilitiesLoading}\n provider={provider}\n onSelect={(p) => {\n setProvider(p);\n setDirection('');\n setOwner('');\n setRepo('');\n setToken('');\n }}\n />\n\n {provider && (\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>2. Project, external project and direction</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label htmlFor=\"sync-wizard-project\" className={label}>\n PlanMagnet project\n </label>\n <div className=\"mt-1\">\n <ProjectSelect\n id=\"sync-wizard-project\"\n value={projectId}\n noneLabel=\"Choose a project\"\n onChange={setProjectId}\n />\n </div>\n </div>\n {isGithub && (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"sync-wizard-owner\" className={label}>\n GitHub owner (user or org)\n </label>\n <Input\n id=\"sync-wizard-owner\"\n className=\"mt-1\"\n placeholder=\"e.g. algoshred\"\n value={owner}\n data-testid=\"sync-wizard-owner\"\n onChange={(e) => setOwner(e.target.value)}\n />\n {owner.trim() !== '' && !ownerValid && (\n <ErrorLine message=\"Not a valid GitHub owner name.\" />\n )}\n </div>\n <div>\n <label htmlFor=\"sync-wizard-repo\" className={label}>\n Repository\n </label>\n <Input\n id=\"sync-wizard-repo\"\n className=\"mt-1\"\n placeholder=\"e.g. wspace-planmagnet-svc\"\n value={repo}\n data-testid=\"sync-wizard-repo\"\n onChange={(e) => setRepo(e.target.value)}\n />\n {repo.trim() !== '' && !repoValid && (\n <ErrorLine message=\"Not a valid repository name.\" />\n )}\n </div>\n </div>\n )}\n <div>\n <span className={label}>Direction</span>\n {allowedDirections.length === 0 ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">\n This provider offers no live sync direction yet.\n </p>\n ) : (\n <div className=\"mt-1 flex flex-col gap-1\" role=\"radiogroup\" aria-label=\"Direction\">\n {allowedDirections.map((d) => (\n <label key={d} className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name=\"sync-wizard-direction\"\n checked={direction === d}\n data-testid={`sync-wizard-direction-${d}`}\n onChange={() => setDirection(d)}\n />\n {directionLabel(d)}\n </label>\n ))}\n </div>\n )}\n </div>\n </CardContent>\n </Card>\n )}\n\n {step2Complete && (\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>3. Credentials</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {isGithub && (\n <>\n <p className=\"text-sm text-muted-foreground\">\n Use a GitHub fine-grained personal access token scoped to{' '}\n <strong>\n {owner}/{repo}\n </strong>\n , with Issues set to <strong>Read and write</strong> — no other repository\n permission is needed.\n </p>\n <div className=\"max-w-sm\">\n <label htmlFor=\"sync-wizard-token\" className={label}>\n Personal access token\n </label>\n <Input\n id=\"sync-wizard-token\"\n type=\"password\"\n autoComplete=\"off\"\n className=\"mt-1\"\n value={token}\n data-testid=\"sync-wizard-token\"\n onChange={(e) => setToken(e.target.value)}\n />\n </div>\n </>\n )}\n </CardContent>\n </Card>\n )}\n\n {step3Complete && (\n <>\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>4. Conflict strategy</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">\n What happens when the same item changed on both sides since the last sync.\n </p>\n <div className=\"flex flex-col gap-1\" role=\"radiogroup\" aria-label=\"Conflict strategy\">\n {CONFLICT_RESOLUTIONS.map((r) => (\n <label key={r} className=\"flex items-start gap-2 text-sm\">\n <input\n type=\"radio\"\n name=\"sync-wizard-strategy\"\n className=\"mt-0.5\"\n checked={conflictStrategy === r}\n data-testid={`sync-wizard-strategy-${r}`}\n onChange={() => setConflictStrategy(r)}\n />\n <span>\n <span className=\"font-medium\">{enumLabel(r)}</span>\n <span className=\"block text-xs text-muted-foreground\">\n {CONFLICT_STRATEGY_EXPLANATION[r]}\n </span>\n </span>\n </label>\n ))}\n </div>\n </CardContent>\n </Card>\n\n {isGithub && (\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>5. Field mapping (optional)</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <p className=\"text-sm text-muted-foreground\">\n GitHub issues have no native priority or due-date field — PlanMagnet encodes each\n as a label of the form <code>prefix+value</code> (e.g. <code>priority:HIGH</code>,{' '}\n <code>due:2026-10-01</code>\n ). Leave both blank to use the built-in prefixes.\n </p>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div>\n <label\n htmlFor=\"sync-wizard-priority-prefix\"\n className=\"text-xs text-muted-foreground\"\n >\n Priority label prefix (default "{GITHUB_FIELD_MAPPING_DEFAULTS.priority}\n ")\n </label>\n <Input\n id=\"sync-wizard-priority-prefix\"\n className=\"mt-1\"\n placeholder={GITHUB_FIELD_MAPPING_DEFAULTS.priority}\n value={priorityPrefix}\n onChange={(e) => setPriorityPrefix(e.target.value)}\n />\n </div>\n <div>\n <label\n htmlFor=\"sync-wizard-duedate-prefix\"\n className=\"text-xs text-muted-foreground\"\n >\n Due-date label prefix (default "{GITHUB_FIELD_MAPPING_DEFAULTS.dueDate}\n ")\n </label>\n <Input\n id=\"sync-wizard-duedate-prefix\"\n className=\"mt-1\"\n placeholder={GITHUB_FIELD_MAPPING_DEFAULTS.dueDate}\n value={dueDatePrefix}\n onChange={(e) => setDueDatePrefix(e.target.value)}\n />\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>6. Review & create</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <dl className=\"grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-1 text-sm\">\n <dt className=\"text-muted-foreground\">Provider</dt>\n <dd>{providerLabel(provider)}</dd>\n <dt className=\"text-muted-foreground\">Direction</dt>\n <dd>{direction ? directionLabel(direction) : '—'}</dd>\n <dt className=\"text-muted-foreground\">External project</dt>\n <dd>{isGithub ? `${owner}/${repo}` : '—'}</dd>\n <dt className=\"text-muted-foreground\">Conflict strategy</dt>\n <dd>{enumLabel(conflictStrategy)}</dd>\n </dl>\n <label className=\"flex items-start gap-2 text-sm\">\n <Checkbox\n checked={verifyBeforeCreate}\n onCheckedChange={(checked) => setVerifyBeforeCreate(checked === true)}\n data-testid=\"sync-wizard-verify\"\n />\n <span>\n Verify the connection before creating (recommended)\n <span className=\"block text-xs text-muted-foreground\">\n Probes the credentials first; the sync is not created if the probe fails.\n </span>\n </span>\n </label>\n {formError && <ErrorLine message={formError} />}\n <Button\n onClick={() => void submit()}\n disabled={state.loading}\n data-testid=\"sync-wizard-create\"\n >\n {state.loading ? (\n <Loader2 className=\"mr-1 h-4 w-4 animate-spin\" />\n ) : (\n <ShieldQuestion className=\"mr-1 h-4 w-4\" />\n )}\n Create sync\n </Button>\n </CardContent>\n </Card>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"IntegrationsNewSyncPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/IntegrationsNewSyncPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Checkbox,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, CheckCircle2, Github, Loader2, Plug, ShieldQuestion } from 'lucide-react';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError } from '../utils/mutationResult';\nimport { isForbidden, mutationErrorMessage } from '../utils/graphqlErrors';\nimport { ErrorLine } from '../controls/ConfirmButton';\nimport { ProjectSelect } from '../controls/Pickers';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport {\n RunNowButton,\n SyncRunResultSummary,\n TestConnectionButton,\n CONFLICT_STRATEGY_EXPLANATION,\n} from '../controls/SyncControls';\nimport { useSyncProviderCapabilities } from '../integrations/useSyncProviderCapabilities';\nimport {\n CONFLICT_RESOLUTIONS,\n directionLabel,\n directionSupported,\n GITHUB_FIELD_MAPPING_DEFAULTS,\n isValidGithubOwner,\n isValidGithubRepo,\n providerIsLive,\n providerLabel,\n SYNC_DIRECTIONS,\n type ConflictResolution,\n type SyncDirection,\n type SyncProvider,\n type SyncProviderCapability,\n type SyncRunResult,\n} from '../integrations/syncTypes';\n\n/**\n * Sync setup wizard (AUT-08): create an ExternalSync step by step, driven entirely by\n * `planmagnetSupportedSyncProviders` — a provider is selectable, and a direction is offered, only when the\n * capability list says it is real, never a hard-coded \"GitHub only\" rule. Today that capability list happens to\n * make GITHUB the only live choice (BOFF-4446); the connection fields below (owner/repo/token) are GitHub's own\n * documented `connectionConfig` shape and only make sense for it — there is nothing to generalize them to until\n * a second connector ships.\n */\n\nconst label = 'text-sm font-medium';\n\nconst CREATE_SYNC = gql`\n mutation NewSyncCreate($input: PlanmagnetCreateExternalSyncInput!) {\n planmagnetCreateExternalSync(input: $input) {\n id\n provider\n status\n project {\n id\n name\n }\n }\n }\n`;\n\ninterface CreatedSync {\n id: string;\n provider: string;\n status: string;\n project: { id: string; name: string } | null;\n}\n\nfunction ProviderStep({\n capabilities,\n capabilitiesLoading,\n provider,\n onSelect,\n}: {\n capabilities: SyncProviderCapability[];\n capabilitiesLoading: boolean;\n provider: SyncProvider | '';\n onSelect: (p: SyncProvider) => void;\n}) {\n return (\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>1. Provider</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n {capabilitiesLoading && <p className=\"text-sm text-muted-foreground\">Loading providers…</p>}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-2\">\n {capabilities.map((c) => {\n const live = providerIsLive(c);\n const selected = provider === c.provider;\n return (\n <button\n key={c.provider}\n type=\"button\"\n disabled={!live}\n aria-pressed={selected}\n data-testid={`sync-wizard-provider-${c.provider}`}\n onClick={() => live && onSelect(c.provider)}\n className={`flex items-start gap-2 rounded-md border p-3 text-left text-sm transition-colors ${\n selected ? 'border-primary bg-primary/5' : 'border-input'\n } ${live ? 'hover:bg-muted' : 'cursor-not-allowed opacity-50'}`}\n >\n {c.provider === 'GITHUB' ? (\n <Github className=\"mt-0.5 h-4 w-4 shrink-0\" />\n ) : (\n <Plug className=\"mt-0.5 h-4 w-4 shrink-0\" />\n )}\n <span>\n <span className=\"block font-medium\">{providerLabel(c.provider)}</span>\n <span className=\"block text-xs text-muted-foreground\">\n {live\n ? [\n c.supportsImport && 'inbound',\n c.supportsExport && 'outbound',\n c.supportsBidirectional && 'bidirectional',\n ]\n .filter(Boolean)\n .join(', ') + ' sync'\n : 'No live connector yet — inbound, outbound and bidirectional sync are all unavailable for this provider.'}\n </span>\n </span>\n </button>\n );\n })}\n </div>\n </CardContent>\n </Card>\n );\n}\n\nexport function IntegrationsNewSyncPagePage() {\n const navigate = usePlanMagnetNavigate();\n const { capabilities, loading: capabilitiesLoading } = useSyncProviderCapabilities();\n\n const [provider, setProvider] = useState<SyncProvider | ''>('');\n const [projectId, setProjectId] = useState('');\n const [owner, setOwner] = useState('');\n const [repo, setRepo] = useState('');\n const [direction, setDirection] = useState<SyncDirection | ''>('');\n const [token, setToken] = useState('');\n const [conflictStrategy, setConflictStrategy] = useState<ConflictResolution>('MANUAL');\n const [priorityPrefix, setPriorityPrefix] = useState('');\n const [dueDatePrefix, setDueDatePrefix] = useState('');\n const [verifyBeforeCreate, setVerifyBeforeCreate] = useState(true);\n const [formError, setFormError] = useState<string | null>(null);\n const [created, setCreated] = useState<CreatedSync | null>(null);\n const [runResult, setRunResult] = useState<SyncRunResult | null>(null);\n\n const [create, state] = useMutation<{ planmagnetCreateExternalSync: CreatedSync }>(CREATE_SYNC, {\n refetchQueries: ['SyncsList'],\n });\n\n const capability = capabilities.find((c) => c.provider === provider);\n const isGithub = provider === 'GITHUB';\n const allowedDirections = capability\n ? SYNC_DIRECTIONS.filter((d) => directionSupported(capability, d))\n : [];\n\n const ownerValid = owner.trim() !== '' && isValidGithubOwner(owner);\n const repoValid = repo.trim() !== '' && isValidGithubRepo(repo);\n const step2Complete =\n !!provider && !!projectId && (!isGithub || (ownerValid && repoValid)) && !!direction;\n const step3Complete = step2Complete && token.trim() !== '';\n\n const buildInput = () => {\n const fieldMapping: Record<string, string> = {};\n if (priorityPrefix.trim()) fieldMapping.priority = priorityPrefix.trim();\n if (dueDatePrefix.trim()) fieldMapping.dueDate = dueDatePrefix.trim();\n return {\n projectId,\n provider,\n direction,\n externalProjectId: isGithub ? `${owner.trim()}/${repo.trim()}` : '',\n externalProjectUrl: isGithub\n ? `https://github.com/${owner.trim()}/${repo.trim()}`\n : undefined,\n connectionConfig: isGithub\n ? { token: token.trim(), owner: owner.trim(), repo: repo.trim() }\n : {},\n conflictStrategy,\n ...(Object.keys(fieldMapping).length > 0 ? { fieldMapping } : {}),\n testConnection: verifyBeforeCreate,\n };\n };\n\n const submit = async () => {\n setFormError(null);\n if (!step3Complete) {\n setFormError(\n 'Fill in the project, external project and credentials above before creating the sync.'\n );\n return;\n }\n try {\n const res = await throwOnError(create({ variables: { input: buildInput() } }));\n if (res.data) setCreated(res.data.planmagnetCreateExternalSync);\n } catch (e) {\n setFormError(\n isForbidden(e)\n ? 'Your role can view integrations but not set them up.'\n : mutationErrorMessage(e, 'The sync could not be created.')\n );\n }\n };\n\n if (created) {\n return (\n <div className=\"space-y-6 p-6 max-w-2xl\">\n <Card data-testid=\"sync-wizard-created\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <CheckCircle2 className=\"h-5 w-5 text-status-success-text\" />\n Sync created\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">\n {providerLabel(created.provider)} sync for {created.project?.name ?? 'the project'} is\n set up and idle. Test the connection and run the first sync now, or do either later\n from the sync's own page.\n </p>\n <div className=\"flex flex-wrap items-center gap-3\">\n <TestConnectionButton syncId={created.id} />\n <RunNowButton syncId={created.id} onResult={setRunResult} />\n </div>\n {runResult && <SyncRunResultSummary result={runResult} />}\n <Button\n onClick={() => navigate(detailPath('/integrations/sync-detail-page', created.id))}\n data-testid=\"sync-wizard-view\"\n >\n View sync\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6 max-w-2xl\">\n <div className=\"flex items-start gap-3\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Back to Integrations\"\n onClick={() => navigate('/integrations/syncs-page')}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Set up a sync</h1>\n <p className=\"text-sm text-muted-foreground\">\n Connect a PlanMagnet project to an external issue tracker so work items stay in step on\n both sides.\n </p>\n </div>\n </div>\n\n <ProviderStep\n capabilities={capabilities}\n capabilitiesLoading={capabilitiesLoading}\n provider={provider}\n onSelect={(p) => {\n setProvider(p);\n setDirection('');\n setOwner('');\n setRepo('');\n setToken('');\n }}\n />\n\n {provider && (\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>2. Project, external project and direction</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label htmlFor=\"sync-wizard-project\" className={label}>\n PlanMagnet project\n </label>\n <div className=\"mt-1\">\n <ProjectSelect\n id=\"sync-wizard-project\"\n value={projectId}\n noneLabel=\"Choose a project\"\n onChange={setProjectId}\n />\n </div>\n </div>\n {isGithub && (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div>\n <label htmlFor=\"sync-wizard-owner\" className={label}>\n GitHub owner (user or org)\n </label>\n <Input\n id=\"sync-wizard-owner\"\n className=\"mt-1\"\n placeholder=\"e.g. algoshred\"\n value={owner}\n data-testid=\"sync-wizard-owner\"\n onChange={(e) => setOwner(e.target.value)}\n />\n {owner.trim() !== '' && !ownerValid && (\n <ErrorLine message=\"Not a valid GitHub owner name.\" />\n )}\n </div>\n <div>\n <label htmlFor=\"sync-wizard-repo\" className={label}>\n Repository\n </label>\n <Input\n id=\"sync-wizard-repo\"\n className=\"mt-1\"\n placeholder=\"e.g. wspace-planmagnet-svc\"\n value={repo}\n data-testid=\"sync-wizard-repo\"\n onChange={(e) => setRepo(e.target.value)}\n />\n {repo.trim() !== '' && !repoValid && (\n <ErrorLine message=\"Not a valid repository name.\" />\n )}\n </div>\n </div>\n )}\n <div>\n <span className={label}>Direction</span>\n {allowedDirections.length === 0 ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">\n This provider offers no live sync direction yet.\n </p>\n ) : (\n <div className=\"mt-1 flex flex-col gap-1\" role=\"radiogroup\" aria-label=\"Direction\">\n {allowedDirections.map((d) => (\n <label key={d} className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name=\"sync-wizard-direction\"\n checked={direction === d}\n data-testid={`sync-wizard-direction-${d}`}\n onChange={() => setDirection(d)}\n />\n {directionLabel(d)}\n </label>\n ))}\n </div>\n )}\n </div>\n </CardContent>\n </Card>\n )}\n\n {step2Complete && (\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>3. Credentials</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {isGithub && (\n <>\n <p className=\"text-sm text-muted-foreground\">\n Use a GitHub fine-grained personal access token scoped to{' '}\n <strong>\n {owner}/{repo}\n </strong>\n , with Issues set to <strong>Read and write</strong> — no other repository\n permission is needed.\n </p>\n <div className=\"max-w-sm\">\n <label htmlFor=\"sync-wizard-token\" className={label}>\n Personal access token\n </label>\n <Input\n id=\"sync-wizard-token\"\n type=\"password\"\n autoComplete=\"off\"\n className=\"mt-1\"\n value={token}\n data-testid=\"sync-wizard-token\"\n onChange={(e) => setToken(e.target.value)}\n />\n </div>\n </>\n )}\n </CardContent>\n </Card>\n )}\n\n {step3Complete && (\n <>\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>4. Conflict strategy</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <p className=\"text-sm text-muted-foreground\">\n What happens when the same item changed on both sides since the last sync.\n </p>\n <div className=\"flex flex-col gap-1\" role=\"radiogroup\" aria-label=\"Conflict strategy\">\n {CONFLICT_RESOLUTIONS.map((r) => (\n <label key={r} className=\"flex items-start gap-2 text-sm\">\n <input\n type=\"radio\"\n name=\"sync-wizard-strategy\"\n className=\"mt-0.5\"\n checked={conflictStrategy === r}\n data-testid={`sync-wizard-strategy-${r}`}\n onChange={() => setConflictStrategy(r)}\n />\n <span>\n <span className=\"font-medium\">{enumLabel(r)}</span>\n <span className=\"block text-xs text-muted-foreground\">\n {CONFLICT_STRATEGY_EXPLANATION[r]}\n </span>\n </span>\n </label>\n ))}\n </div>\n </CardContent>\n </Card>\n\n {isGithub && (\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>5. Field mapping (optional)</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <p className=\"text-sm text-muted-foreground\">\n GitHub issues have no native priority or due-date field — PlanMagnet encodes each\n as a label of the form <code>prefix+value</code> (e.g. <code>priority:HIGH</code>,{' '}\n <code>due:2026-10-01</code>\n ). Leave both blank to use the built-in prefixes.\n </p>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div>\n <label\n htmlFor=\"sync-wizard-priority-prefix\"\n className=\"text-xs text-muted-foreground\"\n >\n Priority label prefix (default "{GITHUB_FIELD_MAPPING_DEFAULTS.priority}\n ")\n </label>\n <Input\n id=\"sync-wizard-priority-prefix\"\n className=\"mt-1\"\n placeholder={GITHUB_FIELD_MAPPING_DEFAULTS.priority}\n value={priorityPrefix}\n onChange={(e) => setPriorityPrefix(e.target.value)}\n />\n </div>\n <div>\n <label\n htmlFor=\"sync-wizard-duedate-prefix\"\n className=\"text-xs text-muted-foreground\"\n >\n Due-date label prefix (default "{GITHUB_FIELD_MAPPING_DEFAULTS.dueDate}\n ")\n </label>\n <Input\n id=\"sync-wizard-duedate-prefix\"\n className=\"mt-1\"\n placeholder={GITHUB_FIELD_MAPPING_DEFAULTS.dueDate}\n value={dueDatePrefix}\n onChange={(e) => setDueDatePrefix(e.target.value)}\n />\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n <Card data-testid=\"sync-wizard-step\">\n <CardHeader>\n <CardTitle>6. Review & create</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <dl className=\"grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-1 text-sm\">\n <dt className=\"text-muted-foreground\">Provider</dt>\n <dd>{providerLabel(provider)}</dd>\n <dt className=\"text-muted-foreground\">Direction</dt>\n <dd>{direction ? directionLabel(direction) : '—'}</dd>\n <dt className=\"text-muted-foreground\">External project</dt>\n <dd>{isGithub ? `${owner}/${repo}` : '—'}</dd>\n <dt className=\"text-muted-foreground\">Conflict strategy</dt>\n <dd>{enumLabel(conflictStrategy)}</dd>\n </dl>\n <label className=\"flex items-start gap-2 text-sm\">\n <Checkbox\n checked={verifyBeforeCreate}\n onCheckedChange={(checked) => setVerifyBeforeCreate(checked === true)}\n data-testid=\"sync-wizard-verify\"\n />\n <span>\n Verify the connection before creating (recommended)\n <span className=\"block text-xs text-muted-foreground\">\n Probes the credentials first; the sync is not created if the probe fails.\n </span>\n </span>\n </label>\n {formError && <ErrorLine message={formError} />}\n <Button\n onClick={() => void submit()}\n disabled={state.loading}\n data-testid=\"sync-wizard-create\"\n >\n {state.loading ? (\n <Loader2 className=\"mr-1 h-4 w-4 animate-spin\" />\n ) : (\n <ShieldQuestion className=\"mr-1 h-4 w-4\" />\n )}\n Create sync\n </Button>\n </CardContent>\n </Card>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
2
|
import { enumLabel as n } from "../controls/WorkItemControls.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { detailPath as r, rowLinkProps as i, stopRowActivation as a } from "../utils/rowNavigation.js";
|
|
4
|
+
import { ProjectSelect as o } from "../controls/Pickers.js";
|
|
5
5
|
import { SYNC_STATUSES as s, directionLabel as c, providerLabel as l } from "../integrations/syncTypes.js";
|
|
6
6
|
import { PauseResumeButton as u, RunNowButton as d, SyncHealthSummary as f, SyncRunResultSummary as p, SyncStatusBadge as m, TruncatedText as h } from "../controls/SyncControls.js";
|
|
7
7
|
import { useDeferredValue as g, useState as _ } from "react";
|
|
@@ -119,7 +119,7 @@ function M() {
|
|
|
119
119
|
}), /* @__PURE__ */ w("div", {
|
|
120
120
|
className: "w-48",
|
|
121
121
|
"data-testid": "sync-list-project-filter",
|
|
122
|
-
children: /* @__PURE__ */ w(
|
|
122
|
+
children: /* @__PURE__ */ w(o, {
|
|
123
123
|
id: "sync-list-filter-project",
|
|
124
124
|
value: P,
|
|
125
125
|
onChange: F,
|
|
@@ -163,7 +163,7 @@ function M() {
|
|
|
163
163
|
/* @__PURE__ */ w("ul", {
|
|
164
164
|
className: "space-y-3",
|
|
165
165
|
children: Y.map((e) => {
|
|
166
|
-
let t =
|
|
166
|
+
let t = i(() => S(r("/integrations/sync-detail-page", e.id)), `${l(e.provider)} sync for ${e.project?.name ?? "unknown project"}`);
|
|
167
167
|
return /* @__PURE__ */ T("li", {
|
|
168
168
|
"data-testid": "sync-row",
|
|
169
169
|
...t,
|
|
@@ -197,7 +197,7 @@ function M() {
|
|
|
197
197
|
target: "_blank",
|
|
198
198
|
rel: "noreferrer noopener",
|
|
199
199
|
className: "inline-flex items-center gap-1 text-primary hover:underline",
|
|
200
|
-
onClick:
|
|
200
|
+
onClick: a,
|
|
201
201
|
children: [e.externalProjectId, /* @__PURE__ */ w(v, { className: "h-3 w-3" })]
|
|
202
202
|
}) : e.externalProjectId,
|
|
203
203
|
" · ",
|
|
@@ -220,7 +220,7 @@ function M() {
|
|
|
220
220
|
]
|
|
221
221
|
}), /* @__PURE__ */ T("div", {
|
|
222
222
|
className: "flex shrink-0 flex-wrap items-center gap-2",
|
|
223
|
-
onClick:
|
|
223
|
+
onClick: a,
|
|
224
224
|
onKeyDown: (e) => e.stopPropagation(),
|
|
225
225
|
children: [
|
|
226
226
|
/* @__PURE__ */ w(d, {
|
|
@@ -237,13 +237,13 @@ function M() {
|
|
|
237
237
|
/* @__PURE__ */ w(E, {
|
|
238
238
|
size: "sm",
|
|
239
239
|
variant: "ghost",
|
|
240
|
-
onClick: () => S(
|
|
240
|
+
onClick: () => S(r("/integrations/sync-detail-page", e.id)),
|
|
241
241
|
children: "Open"
|
|
242
242
|
})
|
|
243
243
|
]
|
|
244
244
|
})]
|
|
245
245
|
}), B[e.id] && /* @__PURE__ */ w("div", {
|
|
246
|
-
onClick:
|
|
246
|
+
onClick: a,
|
|
247
247
|
onKeyDown: (e) => e.stopPropagation(),
|
|
248
248
|
children: /* @__PURE__ */ w(p, { result: B[e.id] })
|
|
249
249
|
})]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
2
|
import { BUDGET_STATE_STYLE as n, budgetState as r, budgetUsage as i, money as a } from "../budgets/budgetMath.js";
|
|
3
3
|
import { enumLabel as o } from "../controls/WorkItemControls.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { detailPath as s, rowLinkProps as c } from "../utils/rowNavigation.js";
|
|
5
|
+
import { ProjectSelect as l } from "../controls/Pickers.js";
|
|
6
6
|
import { BUDGET_STATUSES as u, CreateBudgetDialog as d } from "../budgets/BudgetControls.js";
|
|
7
7
|
import { useDeferredValue as f, useState as p } from "react";
|
|
8
8
|
import { Wallet as m } from "lucide-react";
|
|
@@ -63,14 +63,14 @@ function O() {
|
|
|
63
63
|
children: R ? O("planmagnet.budgets.subtitle", "{{count}} budget(s) across projects", { count: H }) : O("planmagnet.budgets.subtitleFallback", "Financial plans, tracked against actuals")
|
|
64
64
|
})] }), /* @__PURE__ */ v(d, {
|
|
65
65
|
presetProjectId: A || void 0,
|
|
66
|
-
onCreated: (e) => g(
|
|
66
|
+
onCreated: (e) => g(s("/projects/budget-detail-page", e))
|
|
67
67
|
})]
|
|
68
68
|
}),
|
|
69
69
|
/* @__PURE__ */ y("div", {
|
|
70
70
|
className: "flex flex-wrap items-center gap-3",
|
|
71
71
|
children: [/* @__PURE__ */ v("div", {
|
|
72
72
|
className: "w-full max-w-xs",
|
|
73
|
-
children: /* @__PURE__ */ v(
|
|
73
|
+
children: /* @__PURE__ */ v(l, {
|
|
74
74
|
id: "budgets-project-filter",
|
|
75
75
|
value: A,
|
|
76
76
|
onChange: j,
|
|
@@ -116,9 +116,9 @@ function O() {
|
|
|
116
116
|
/* @__PURE__ */ v("div", {
|
|
117
117
|
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
118
118
|
children: V.map((e) => {
|
|
119
|
-
let t = i(e.plannedAmount, e.spentAmount),
|
|
119
|
+
let t = i(e.plannedAmount, e.spentAmount), l = n[r(t)], u = t === null ? null : Math.round(t * 100);
|
|
120
120
|
return /* @__PURE__ */ y(x, {
|
|
121
|
-
...
|
|
121
|
+
...c(() => g(s("/projects/budget-detail-page", e.id)), e.name),
|
|
122
122
|
children: [/* @__PURE__ */ v(C, {
|
|
123
123
|
className: "pb-2",
|
|
124
124
|
children: /* @__PURE__ */ y("div", {
|
|
@@ -159,15 +159,15 @@ function O() {
|
|
|
159
159
|
"aria-valuemax": Math.max(100, u ?? 0),
|
|
160
160
|
"aria-valuenow": u ?? 0,
|
|
161
161
|
"aria-label": `${e.name}: ${u === null ? "no plan" : `${u}%`} spent`,
|
|
162
|
-
className: `h-2 w-full overflow-hidden rounded-full ${
|
|
162
|
+
className: `h-2 w-full overflow-hidden rounded-full ${l.track}`,
|
|
163
163
|
children: /* @__PURE__ */ v("div", {
|
|
164
|
-
className: `h-full rounded-full ${
|
|
164
|
+
className: `h-full rounded-full ${l.fill}`,
|
|
165
165
|
style: { width: `${Math.min(u ?? 0, 100)}%` }
|
|
166
166
|
})
|
|
167
167
|
}),
|
|
168
168
|
/* @__PURE__ */ y("span", {
|
|
169
|
-
className: `flex items-center gap-1 text-xs ${
|
|
170
|
-
children: [/* @__PURE__ */ v(
|
|
169
|
+
className: `flex items-center gap-1 text-xs ${l.text}`,
|
|
170
|
+
children: [/* @__PURE__ */ v(l.icon, {
|
|
171
171
|
className: "h-3 w-3",
|
|
172
172
|
"aria-hidden": !0
|
|
173
173
|
}), u === null ? O("planmagnet.budgets.noPlan", "No plan set") : `${u}%`]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { DependencyGraph as n } from "../dependency/DependencyGraph.js";
|
|
3
|
+
import { ProjectSelect as r } from "../controls/Pickers.js";
|
|
4
|
+
import { useEntityId as i } from "../hooks/useEntityId.js";
|
|
5
5
|
import { criticalEdgeIdsFromPath as ee, useProjectWorkItemsGraph as a } from "../dependency/useProjectWorkItemsGraph.js";
|
|
6
6
|
import { useEffect as o, useState as s } from "react";
|
|
7
7
|
import { AlertTriangle as c, List as l, Route as u, Waypoints as d } from "lucide-react";
|
|
@@ -60,7 +60,7 @@ function E(e) {
|
|
|
60
60
|
return r === 0 ? `${i}h` : i > 0 ? `${r}d ${i}h` : `${r} day${r === 1 ? "" : "s"}`;
|
|
61
61
|
}
|
|
62
62
|
function D() {
|
|
63
|
-
let f =
|
|
63
|
+
let f = i(), { workspaceId: D } = e(), O = t(), [k, A] = s(""), [j, M] = s("list"), { data: N, loading: P, error: F } = p(S, {
|
|
64
64
|
variables: {
|
|
65
65
|
workspaceId: D ?? "",
|
|
66
66
|
projectId: f
|
|
@@ -117,7 +117,7 @@ function D() {
|
|
|
117
117
|
className: "text-sm font-medium",
|
|
118
118
|
children: "Project"
|
|
119
119
|
}),
|
|
120
|
-
/* @__PURE__ */ h(
|
|
120
|
+
/* @__PURE__ */ h(r, {
|
|
121
121
|
id: "critical-path-project",
|
|
122
122
|
value: k,
|
|
123
123
|
onChange: A,
|
|
@@ -218,7 +218,7 @@ function D() {
|
|
|
218
218
|
" are graphed."
|
|
219
219
|
]
|
|
220
220
|
}),
|
|
221
|
-
/* @__PURE__ */ h(
|
|
221
|
+
/* @__PURE__ */ h(n, {
|
|
222
222
|
nodes: B.items.map((e) => ({
|
|
223
223
|
id: e.id,
|
|
224
224
|
key: e.key,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
2
2
|
import { throwOnError as t } from "../utils/mutationResult.js";
|
|
3
3
|
import { enumLabel as n } from "../controls/WorkItemControls.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { detailPath as r } from "../utils/rowNavigation.js";
|
|
5
|
+
import { PortfolioSelect as i, ProgramSelect as a } from "../controls/Pickers.js";
|
|
6
6
|
import { endBeforeStart as o } from "../utils/formValidation.js";
|
|
7
7
|
import { useEntityId as s } from "../hooks/useEntityId.js";
|
|
8
8
|
import { PROJECT_STATUSES as c } from "../controls/ProjectControls.js";
|
|
@@ -101,7 +101,7 @@ function E() {
|
|
|
101
101
|
variant: "ghost",
|
|
102
102
|
size: "sm",
|
|
103
103
|
"aria-label": "Back to the project",
|
|
104
|
-
onClick: () => E(
|
|
104
|
+
onClick: () => E(r("/projects/project-detail-page", p)),
|
|
105
105
|
children: /* @__PURE__ */ g(d, { className: "h-4 w-4" })
|
|
106
106
|
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("h1", {
|
|
107
107
|
className: "text-2xl font-semibold",
|
|
@@ -203,7 +203,7 @@ function E() {
|
|
|
203
203
|
children: "Program"
|
|
204
204
|
}), /* @__PURE__ */ g("div", {
|
|
205
205
|
className: "mt-1",
|
|
206
|
-
children: /* @__PURE__ */ g(
|
|
206
|
+
children: /* @__PURE__ */ g(a, {
|
|
207
207
|
id: "project-program",
|
|
208
208
|
value: I.programId,
|
|
209
209
|
onChange: (e) => L({
|
|
@@ -219,7 +219,7 @@ function E() {
|
|
|
219
219
|
children: "Portfolio"
|
|
220
220
|
}), /* @__PURE__ */ g("div", {
|
|
221
221
|
className: "mt-1",
|
|
222
|
-
children: /* @__PURE__ */ g(
|
|
222
|
+
children: /* @__PURE__ */ g(i, {
|
|
223
223
|
id: "project-portfolio",
|
|
224
224
|
value: I.portfolioId,
|
|
225
225
|
onChange: (e) => L({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { detailPath as n, rowLinkProps as r } from "../utils/rowNavigation.js";
|
|
3
|
+
import { TeamSelect as i } from "../controls/Pickers.js";
|
|
4
4
|
import { NewSprintDialog as a } from "../sprints/SprintControls.js";
|
|
5
5
|
import { useState as o } from "react";
|
|
6
6
|
import { CalendarClock as s, FolderKanban as c, Users as l } from "lucide-react";
|
|
@@ -73,19 +73,19 @@ function S() {
|
|
|
73
73
|
children: [T?.planmagnetSprints?.totalCount ?? O.length, " sprints across all projects"]
|
|
74
74
|
})] }), /* @__PURE__ */ m("div", {
|
|
75
75
|
className: "flex items-center gap-2",
|
|
76
|
-
children: [/* @__PURE__ */ p(
|
|
76
|
+
children: [/* @__PURE__ */ p(i, {
|
|
77
77
|
value: C,
|
|
78
78
|
onChange: w,
|
|
79
79
|
noneLabel: "All teams"
|
|
80
|
-
}), /* @__PURE__ */ p(a, { onCreated: (e) => S(
|
|
80
|
+
}), /* @__PURE__ */ p(a, { onCreated: (e) => S(n("/projects/planning-detail-page", e)) })]
|
|
81
81
|
})]
|
|
82
82
|
}),
|
|
83
83
|
/* @__PURE__ */ p("div", {
|
|
84
84
|
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
85
85
|
children: O.map((e) => {
|
|
86
|
-
let t = e.workItems.reduce((e, t) => e + (t.storyPoints ?? 0), 0),
|
|
86
|
+
let t = e.workItems.reduce((e, t) => e + (t.storyPoints ?? 0), 0), i = e.capacity ?? 0, a = i > 0 ? Math.round(t / i * 100) : 0;
|
|
87
87
|
return /* @__PURE__ */ m(g, {
|
|
88
|
-
...
|
|
88
|
+
...r(() => S(n("/projects/planning-detail-page", e.id)), e.name),
|
|
89
89
|
children: [/* @__PURE__ */ p(v, {
|
|
90
90
|
className: "pb-2",
|
|
91
91
|
children: /* @__PURE__ */ m("div", {
|
|
@@ -133,7 +133,7 @@ function S() {
|
|
|
133
133
|
]
|
|
134
134
|
}), /* @__PURE__ */ m("span", { children: [e.workItems.length, " work items"] })]
|
|
135
135
|
}),
|
|
136
|
-
|
|
136
|
+
i > 0 && /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("div", {
|
|
137
137
|
className: "flex justify-between text-xs mb-1",
|
|
138
138
|
children: [/* @__PURE__ */ p("span", {
|
|
139
139
|
className: "text-muted-foreground",
|
|
@@ -143,7 +143,7 @@ function S() {
|
|
|
143
143
|
children: [
|
|
144
144
|
t,
|
|
145
145
|
"/",
|
|
146
|
-
|
|
146
|
+
i,
|
|
147
147
|
" pts (",
|
|
148
148
|
a,
|
|
149
149
|
"%)"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { usePlanMagnet as e, usePlanMagnetNavigate as t } from "../providers/PlanMagnetProvider.js";
|
|
2
2
|
import { PersonAvatar as n } from "../people/People.js";
|
|
3
3
|
import { countLabel as r, useSprintCounts as i, workProgress as a } from "../hooks/useCounts.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { detailPath as o } from "../utils/rowNavigation.js";
|
|
5
|
+
import { TeamSelect as s } from "../controls/Pickers.js";
|
|
6
6
|
import { NewSprintDialog as c, SprintLifecycleActions as l } from "../sprints/SprintControls.js";
|
|
7
7
|
import { SprintDates as u } from "../sprints/SprintDates.js";
|
|
8
8
|
import { useState as d } from "react";
|
|
@@ -113,7 +113,7 @@ function E() {
|
|
|
113
113
|
...O
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
}), F = i(), I = k?.planmagnetSprints?.items ?? [], L = [...N?.planmagnetSprints.items ?? [], ...P?.planmagnetSprints.items ?? []], R = I.filter((e) => e.status === "PLANNING"), z = I.filter((e) => e.status === "COMPLETED" || e.status === "CANCELLED"), B = t(), V = (e) => B(
|
|
116
|
+
}), F = i(), I = k?.planmagnetSprints?.items ?? [], L = [...N?.planmagnetSprints.items ?? [], ...P?.planmagnetSprints.items ?? []], R = I.filter((e) => e.status === "PLANNING"), z = I.filter((e) => e.status === "COMPLETED" || e.status === "CANCELLED"), B = t(), V = (e) => B(o("/projects/planning-detail-page", e));
|
|
117
117
|
return A && !k ? /* @__PURE__ */ g("div", {
|
|
118
118
|
className: "flex items-center justify-center p-12",
|
|
119
119
|
children: /* @__PURE__ */ g("div", { className: "animate-spin h-8 w-8 border-2 border-primary border-t-transparent rounded-full" })
|
|
@@ -138,7 +138,7 @@ function E() {
|
|
|
138
138
|
]
|
|
139
139
|
})] }), /* @__PURE__ */ _("div", {
|
|
140
140
|
className: "flex items-center gap-2",
|
|
141
|
-
children: [/* @__PURE__ */ g(
|
|
141
|
+
children: [/* @__PURE__ */ g(s, {
|
|
142
142
|
value: E,
|
|
143
143
|
onChange: D,
|
|
144
144
|
noneLabel: "All teams"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function StatusFlowCard({ workspaceId, projectId, startDate, endDate, }: {
|
|
2
|
+
workspaceId?: string | null;
|
|
3
|
+
/** Status flow is always one project (`projectId: ID!` on the server) — same convention as CycleTimeCard. */
|
|
4
|
+
projectId: string;
|
|
5
|
+
startDate: string;
|
|
6
|
+
endDate: string;
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=StatusFlowCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusFlowCard.d.ts","sourceRoot":"","sources":["../../../../src/planmagnet/pages/analytics/StatusFlowCard.tsx"],"names":[],"mappings":"AAoLA,wBAAgB,cAAc,CAAC,EAC7B,WAAW,EACX,SAAS,EACT,SAAS,EACT,OAAO,GACR,EAAE;IACD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,6GAA6G;IAC7G,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,2CAuJA"}
|