@knpkv/control-center 0.1.0 → 0.2.0
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/client/.vite/manifest.json +127 -125
- package/dist/client/assets/{ActiveWorkPage-Bvji6Tys.js → ActiveWorkPage-C6QwDV1Y.js} +2 -2
- package/dist/client/assets/{ActiveWorkPage-Bvji6Tys.js.map → ActiveWorkPage-C6QwDV1Y.js.map} +1 -1
- package/dist/client/assets/{AgentPage-Bom41la2.js → AgentPage-OqwP6uRi.js} +2 -2
- package/dist/client/assets/{AgentPage-Bom41la2.js.map → AgentPage-OqwP6uRi.js.map} +1 -1
- package/dist/client/assets/{AtlassianOAuthCallbackPage-dr-B9-DD.js → AtlassianOAuthCallbackPage-Bm7UhU-h.js} +2 -2
- package/dist/client/assets/{AtlassianOAuthCallbackPage-dr-B9-DD.js.map → AtlassianOAuthCallbackPage-Bm7UhU-h.js.map} +1 -1
- package/dist/client/assets/{AuthorizedSharePage-C-P-PNfm.js → AuthorizedSharePage-DblP3USU.js} +2 -2
- package/dist/client/assets/{AuthorizedSharePage-C-P-PNfm.js.map → AuthorizedSharePage-DblP3USU.js.map} +1 -1
- package/dist/client/assets/{BrowserCrypto-BPiuCuW-.js → BrowserCrypto-BGGRC6iW.js} +2 -2
- package/dist/client/assets/{BrowserCrypto-BPiuCuW-.js.map → BrowserCrypto-BGGRC6iW.js.map} +1 -1
- package/dist/client/assets/{BrowserSessionHydrator-C8F_LGhg.js → BrowserSessionHydrator-39UDbHf0.js} +2 -2
- package/dist/client/assets/{BrowserSessionHydrator-C8F_LGhg.js.map → BrowserSessionHydrator-39UDbHf0.js.map} +1 -1
- package/dist/client/assets/{CommandSearch-D6iFcdvj.js → CommandSearch-D4Fnjsl-.js} +2 -2
- package/dist/client/assets/{CommandSearch-D6iFcdvj.js.map → CommandSearch-D4Fnjsl-.js.map} +1 -1
- package/dist/client/assets/{ItemsPage-x39U11an.js → ItemsPage-BZQiTh9b.js} +2 -2
- package/dist/client/assets/{ItemsPage-x39U11an.js.map → ItemsPage-BZQiTh9b.js.map} +1 -1
- package/dist/client/assets/{PairPage-D5vlz4OG.js → PairPage-Dvfse5ky.js} +2 -2
- package/dist/client/assets/{PairPage-D5vlz4OG.js.map → PairPage-Dvfse5ky.js.map} +1 -1
- package/dist/client/assets/{PortfolioOverview-DSUabOmm.js → PortfolioOverview-DeJcfXcw.js} +2 -2
- package/dist/client/assets/{PortfolioOverview-DSUabOmm.js.map → PortfolioOverview-DeJcfXcw.js.map} +1 -1
- package/dist/client/assets/{ReleaseRoute-DyDm5s85.js → ReleaseRoute-D9q8_sCk.js} +2 -2
- package/dist/client/assets/{ReleaseRoute-DyDm5s85.js.map → ReleaseRoute-D9q8_sCk.js.map} +1 -1
- package/dist/client/assets/ReleaseWorkset-Bs_FXlbC.js +2 -0
- package/dist/client/assets/ReleaseWorkset-Bs_FXlbC.js.map +1 -0
- package/dist/client/assets/{ServicesPage-CoMVH2Si.js → ServicesPage-Co6GJHgc.js} +2 -2
- package/dist/client/assets/{ServicesPage-CoMVH2Si.js.map → ServicesPage-Co6GJHgc.js.map} +1 -1
- package/dist/client/assets/{TimelinePage-D8Fj_351.js → TimelinePage-CM2og72M.js} +2 -2
- package/dist/client/assets/{TimelinePage-D8Fj_351.js.map → TimelinePage-CM2og72M.js.map} +1 -1
- package/dist/client/assets/{WorkspaceEntityLink-BRifdJHn.js → WorkspaceEntityLink-CTw_He-8.js} +2 -2
- package/dist/client/assets/{WorkspaceEntityLink-BRifdJHn.js.map → WorkspaceEntityLink-CTw_He-8.js.map} +1 -1
- package/dist/client/assets/{WorkspaceEntityRoute-BwpujSqk.css → WorkspaceEntityRoute-Bdmv6ki4.css} +1 -1
- package/dist/client/assets/WorkspaceEntityRoute-BnsmaeS2.js +30 -0
- package/dist/client/assets/WorkspaceEntityRoute-BnsmaeS2.js.map +1 -0
- package/dist/client/assets/{WorkspaceReleaseLayout-DDLdY0rU.js → WorkspaceReleaseLayout-Ba6keUju.js} +2 -2
- package/dist/client/assets/{WorkspaceReleaseLayout-DDLdY0rU.js.map → WorkspaceReleaseLayout-Ba6keUju.js.map} +1 -1
- package/dist/client/assets/{authenticatedMutationClient-D5yD0rch.js → authenticatedMutationClient-CJklf3iD.js} +2 -2
- package/dist/client/assets/{authenticatedMutationClient-D5yD0rch.js.map → authenticatedMutationClient-CJklf3iD.js.map} +1 -1
- package/dist/client/assets/{authorizedShareTransport-Dyj53kJf.js → authorizedShareTransport-Xg20SHJ5.js} +2 -2
- package/dist/client/assets/{authorizedShareTransport-Dyj53kJf.js.map → authorizedShareTransport-Xg20SHJ5.js.map} +1 -1
- package/dist/client/assets/{client-OmvShYdC.js → client-P7FaPwzJ.js} +2 -2
- package/dist/client/assets/{client-OmvShYdC.js.map → client-P7FaPwzJ.js.map} +1 -1
- package/dist/client/assets/{connectionTestTransport-c25QXx7A.js → connectionTestTransport-C9iPOkKM.js} +2 -2
- package/dist/client/assets/{connectionTestTransport-c25QXx7A.js.map → connectionTestTransport-C9iPOkKM.js.map} +1 -1
- package/dist/client/assets/{index-DLoOV6Hp.js → index-DpW_ckau.js} +3 -3
- package/dist/client/assets/{index-DLoOV6Hp.js.map → index-DpW_ckau.js.map} +1 -1
- package/dist/client/assets/{patterns-DEbg7R-A-Cw0A2uKS.js → patterns-DEbg7R-A-BhsMyh9D.js} +2 -2
- package/dist/client/assets/{patterns-DEbg7R-A-Cw0A2uKS.js.map → patterns-DEbg7R-A-BhsMyh9D.js.map} +1 -1
- package/dist/client/assets/{presentPortfolio-CkRqd_zz.js → presentPortfolio-D-v615bg.js} +2 -2
- package/dist/client/assets/{presentPortfolio-CkRqd_zz.js.map → presentPortfolio-D-v615bg.js.map} +1 -1
- package/dist/client/assets/presentWorkspaceItems-IAp5SnpB.js +2 -0
- package/dist/client/assets/presentWorkspaceItems-IAp5SnpB.js.map +1 -0
- package/dist/client/assets/{releaseRoutes-DSWkTh-E.js → releaseRoutes-CfaNElmG.js} +2 -2
- package/dist/client/assets/{releaseRoutes-DSWkTh-E.js.map → releaseRoutes-CfaNElmG.js.map} +1 -1
- package/dist/client/assets/{serviceOnboarding-B9pvdyWf.js → serviceOnboarding-BZ2U_Ugw.js} +2 -2
- package/dist/client/assets/{serviceOnboarding-B9pvdyWf.js.map → serviceOnboarding-BZ2U_Ugw.js.map} +1 -1
- package/dist/client/assets/{useWorkspaceItems-D0FuHGto.js → useWorkspaceItems-DQTYaq1R.js} +2 -2
- package/dist/client/assets/{useWorkspaceItems-D0FuHGto.js.map → useWorkspaceItems-DQTYaq1R.js.map} +1 -1
- package/dist/client/assets/workspaceEntityRoutes-Biw67kRR.js +2 -0
- package/dist/client/assets/workspaceEntityRoutes-Biw67kRR.js.map +1 -0
- package/dist/client/build-graph.json +32 -2
- package/dist/client/index.html +1 -1
- package/dist/server/api/deliveryGraph.d.ts +126 -0
- package/dist/server/api/deliveryGraph.d.ts.map +1 -1
- package/dist/server/api/index.js +2 -2
- package/dist/server/api/shares.d.ts +14 -0
- package/dist/server/api/shares.d.ts.map +1 -1
- package/dist/server/assets/{BindConfig-BjK10BEb.js → BindConfig-Dk3vjYZc.js} +7 -7
- package/dist/server/assets/{BindConfig-BjK10BEb.js.map → BindConfig-Dk3vjYZc.js.map} +1 -1
- package/dist/server/assets/{controlCenterApi-tZPvRPRH.js → controlCenterApi-Dsug4Rzi.js} +2 -2
- package/dist/server/assets/{controlCenterApi-tZPvRPRH.js.map → controlCenterApi-Dsug4Rzi.js.map} +1 -1
- package/dist/server/assets/{domainEvent-x7yeq-gU.js → domainEvent-CZLKMqgn.js} +13 -2
- package/dist/server/assets/{domainEvent-x7yeq-gU.js.map → domainEvent-CZLKMqgn.js.map} +1 -1
- package/dist/server/assets/{firstPartyServices-Y41P8uke.js → firstPartyServices-BWdrzdfD.js} +2 -2
- package/dist/server/assets/{firstPartyServices-Y41P8uke.js.map → firstPartyServices-BWdrzdfD.js.map} +1 -1
- package/dist/server/assets/{manualPluginSynchronization-C0aHB4UM.js → manualPluginSynchronization-CDnX9qXi.js} +64 -23
- package/dist/server/assets/manualPluginSynchronization-CDnX9qXi.js.map +1 -0
- package/dist/server/assets/{portfolioInvalidation-Ds9Xm4_P.js → portfolioInvalidation-iTUo5N4r.js} +26 -6
- package/dist/server/assets/portfolioInvalidation-iTUo5N4r.js.map +1 -0
- package/dist/server/assets/{readiness-CzU3vjYQ.js → readiness-CZBkcjLP.js} +2 -2
- package/dist/server/assets/{readiness-CzU3vjYQ.js.map → readiness-CZBkcjLP.js.map} +1 -1
- package/dist/server/build-graph.json +1 -0
- package/dist/server/domain/deliveryGraph.d.ts +14 -0
- package/dist/server/domain/deliveryGraph.d.ts.map +1 -1
- package/dist/server/domain/index.js +3 -3
- package/dist/server/index.js +4 -4
- package/dist/server/server/application/normalizedPluginPageMaterialization.d.ts +1 -1
- package/dist/server/server/application/normalizedPluginPageMaterialization.d.ts.map +1 -1
- package/dist/server/server/cli.js +4 -4
- package/dist/server/server/index.js +3 -3
- package/dist/server/server/persistence/Persistence.d.ts +35 -0
- package/dist/server/server/persistence/Persistence.d.ts.map +1 -1
- package/dist/server/server/persistence/repositories/delivery-graph/contract.d.ts +56 -0
- package/dist/server/server/persistence/repositories/delivery-graph/contract.d.ts.map +1 -1
- package/dist/server/server/persistence/repositories/delivery-graph/decode.d.ts +7 -0
- package/dist/server/server/persistence/repositories/delivery-graph/decode.d.ts.map +1 -1
- package/dist/server/server/persistence/repositories/delivery-graph/read.d.ts +35 -0
- package/dist/server/server/persistence/repositories/delivery-graph/read.d.ts.map +1 -1
- package/dist/server/server/persistence/repositories/delivery-graph/rows.d.ts +7 -0
- package/dist/server/server/persistence/repositories/delivery-graph/rows.d.ts.map +1 -1
- package/dist/server/server/persistence/repositories/delivery-graph/write.d.ts +14 -0
- package/dist/server/server/persistence/repositories/delivery-graph/write.d.ts.map +1 -1
- package/dist/server/server/persistence/repositories/deliveryGraphRepository.d.ts +35 -0
- package/dist/server/server/persistence/repositories/deliveryGraphRepository.d.ts.map +1 -1
- package/package.json +6 -6
- package/dist/client/assets/ReleaseWorkset-BhGacsgb.js +0 -2
- package/dist/client/assets/ReleaseWorkset-BhGacsgb.js.map +0 -1
- package/dist/client/assets/WorkspaceEntityRoute-DPci8Q8I.js +0 -30
- package/dist/client/assets/WorkspaceEntityRoute-DPci8Q8I.js.map +0 -1
- package/dist/client/assets/presentWorkspaceItems-BU__8LcC.js +0 -2
- package/dist/client/assets/presentWorkspaceItems-BU__8LcC.js.map +0 -1
- package/dist/client/assets/workspaceEntityRoutes-CRcfSq7c.js +0 -2
- package/dist/client/assets/workspaceEntityRoutes-CRcfSq7c.js.map +0 -1
- package/dist/server/assets/manualPluginSynchronization-C0aHB4UM.js.map +0 -1
- package/dist/server/assets/portfolioInvalidation-Ds9Xm4_P.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReleaseWorkset-Bs_FXlbC.js","names":[],"sources":["../../../src/client/releases/presentReleaseWorkset.ts","../../../src/client/releases/RelationshipDetailSheet.module.css","../../../src/client/releases/useRelationshipDetails.ts","../../../src/client/releases/RelationshipDetailSheet.tsx","../../../src/client/releases/relationshipDetailRoute.ts","../../../src/client/releases/ReleaseWorkset.module.css","../../../src/client/releases/loadReleaseEnvironmentSlices.ts","../../../src/client/releases/useReleaseWorkset.ts","../../../src/client/releases/ReleaseWorkset.tsx"],"sourcesContent":["import type {\n RlyService,\n RlyStage,\n RlyWorksetGap,\n RlyWorksetJiraItem,\n RlyWorksetPipeline,\n RlyWorksetPullRequestGroup\n} from \"@knpkv/rly/patterns\"\nimport type { RlyStateTone } from \"@knpkv/rly/primitives\"\n\nimport type { ReleaseDeliveryGraphInspection } from \"../../api/deliveryGraph.js\"\nimport type {\n DeliveryEntityDetails,\n DeliveryEntityProjection,\n DeliveryRelationship,\n EvidenceClaim\n} from \"../../domain/deliveryGraph.js\"\nimport type {\n EntityId,\n EvidenceId,\n GraphNodeId,\n RelationshipId,\n ReleaseId,\n WorkspaceId\n} from \"../../domain/identifiers.js\"\nimport { workspaceEntityPath } from \"../workspaceEntityPaths.js\"\n\ntype Projection = ReleaseDeliveryGraphInspection[\"entityProjections\"][number][\"projection\"]\ntype ProjectionWithDetails<Tag extends DeliveryEntityDetails[\"_tag\"]> = Projection & {\n readonly details: Extract<DeliveryEntityDetails, { readonly _tag: Tag }>\n}\n\nexport interface ReleaseWorksetRunbook {\n readonly href: string\n readonly id: EntityId\n readonly reference: string\n readonly state: string\n readonly title: string\n}\n\nexport interface SelectedReleaseWorksetObject {\n readonly facts: ReadonlyArray<{ readonly label: string; readonly value: string }>\n readonly id: EntityId\n readonly kind: DeliveryEntityProjection[\"entityType\"]\n readonly label: string\n readonly service: RlyService\n readonly status: string\n readonly title: string\n readonly tone: RlyStateTone\n}\n\nexport interface SelectedReleaseWorksetTraceConnection {\n readonly href: string | null\n readonly kind: string\n readonly label: string\n readonly service: RlyService | null\n readonly title: string\n}\n\nexport interface SelectedReleaseWorksetTraceRelationship {\n readonly confidence: string\n readonly detailsHref: string\n readonly direction: \"incoming\" | \"outgoing\"\n readonly evidenceCount: number\n readonly id: RelationshipId\n readonly kind: DeliveryRelationship[\"kind\"]\n readonly lifecycle: string\n readonly other: SelectedReleaseWorksetTraceConnection\n readonly tone: RlyStateTone\n}\n\nexport interface SelectedReleaseWorksetTrace {\n readonly relationships: ReadonlyArray<SelectedReleaseWorksetTraceRelationship>\n readonly truncated: boolean\n}\n\nexport interface ReleaseWorksetPresentation {\n readonly gaps: ReadonlyArray<RlyWorksetGap>\n readonly jiraItems: ReadonlyArray<RlyWorksetJiraItem>\n readonly pipelines: ReadonlyArray<RlyWorksetPipeline>\n readonly pullRequestGroups: ReadonlyArray<RlyWorksetPullRequestGroup>\n readonly runbooks: ReadonlyArray<ReleaseWorksetRunbook>\n readonly truncated: boolean\n}\n\nconst relationshipHref = (\n workspaceId: WorkspaceId,\n releaseId: ReleaseId,\n entityId: EntityId,\n relationshipId: RelationshipId\n): string =>\n `/w/${workspaceId}/releases/${releaseId}?object=${encodeURIComponent(entityId)}&relationship=${\n encodeURIComponent(relationshipId)\n }#release-work`\n\nconst statusTone = (status: string): RlyStateTone => {\n const normalized = status.toLocaleLowerCase(\"en-US\")\n if (\n [\"blocked\", \"changes requested\", \"failed\", \"rejected\", \"rolled back\", \"stopped\", \"superseded\"].some(\n (value) => normalized.includes(value)\n )\n ) {\n return \"critical\"\n }\n if (\n [\"approved\", \"closed\", \"current\", \"done\", \"merged\", \"not required\", \"passed\", \"ready\", \"resolved\", \"succeeded\"]\n .some((value) => normalized.includes(value))\n ) return \"positive\"\n if (\n [\"deploying\", \"in progress\", \"in review\", \"pending\", \"queued\", \"requested\", \"running\", \"verifying\"]\n .some((value) => normalized.includes(value))\n ) return \"progress\"\n return \"neutral\"\n}\n\nconst reviewStateLabel = (\n state: Extract<DeliveryEntityDetails, { readonly _tag: \"pull-request\" }>[\"reviewState\"]\n): string => {\n switch (state) {\n case \"not-requested\":\n return \"Review not requested\"\n case \"requested\":\n return \"Review requested\"\n case \"changes-requested\":\n return \"Changes requested\"\n case \"approved\":\n return \"Approved\"\n case \"merged\":\n return \"Merged\"\n }\n}\n\nconst pullRequestStateLabel = (\n details: Extract<DeliveryEntityDetails, { readonly _tag: \"pull-request\" }>\n): string => {\n switch (details.reviewState) {\n case \"approved\":\n case \"changes-requested\":\n case \"merged\":\n return reviewStateLabel(details.reviewState)\n case \"not-requested\":\n case \"requested\":\n return details.lifecycle === \"merged\"\n ? \"Merged\"\n : details.lifecycle === \"closed\"\n ? \"Closed\"\n : reviewStateLabel(details.reviewState)\n }\n}\n\nconst pipelineStateLabel = (\n state: Extract<DeliveryEntityDetails, { readonly _tag: \"pipeline-execution\" }>[\"status\"]\n): string => `${state.charAt(0).toLocaleUpperCase(\"en-US\")}${state.slice(1)}`\n\nconst titleCase = (value: string): string =>\n value.split(\"-\").map((part) => `${part.charAt(0).toLocaleUpperCase(\"en-US\")}${part.slice(1)}`).join(\" \")\n\nconst selectedObjectService = (kind: DeliveryEntityProjection[\"entityType\"]): RlyService => {\n switch (kind) {\n case \"issue\":\n return \"jira\"\n case \"pull-request\":\n return \"codecommit\"\n case \"page\":\n return \"confluence\"\n case \"pipeline-execution\":\n case \"deployment\":\n return \"codepipeline\"\n case \"time-entry\":\n return \"clockify\"\n }\n}\n\nconst selectedObjectStatus = (details: DeliveryEntityDetails): string => {\n switch (details._tag) {\n case \"issue\":\n return details.status\n case \"pull-request\":\n return pullRequestStateLabel(details)\n case \"page\":\n case \"deployment\":\n return titleCase(details.status)\n case \"pipeline-execution\":\n return pipelineStateLabel(details.status)\n case \"time-entry\":\n return titleCase(details.approvalState)\n }\n}\n\nconst selectedObjectFacts = (\n details: DeliveryEntityDetails\n): ReadonlyArray<{ readonly label: string; readonly value: string }> => {\n switch (details._tag) {\n case \"issue\":\n return [\n { label: \"Priority\", value: details.priority ?? \"Not set\" },\n { label: \"Estimate\", value: details.estimatePoints === null ? \"Not set\" : `${details.estimatePoints} points` }\n ]\n case \"pull-request\":\n return [\n { label: \"Repository\", value: details.repository },\n { label: \"Branch\", value: `${details.sourceBranch} → ${details.targetBranch}` },\n { label: \"Revision\", value: details.headRevision }\n ]\n case \"page\":\n return [\n { label: \"Space\", value: details.spaceKey },\n { label: \"Revision\", value: details.revision }\n ]\n case \"pipeline-execution\":\n return [\n { label: \"Pipeline\", value: details.pipelineName },\n { label: \"Execution\", value: details.executionId },\n { label: \"Revision\", value: details.triggerRevision }\n ]\n case \"deployment\":\n return [\n { label: \"Environment\", value: details.environmentId },\n { label: \"Revision\", value: details.revision }\n ]\n case \"time-entry\":\n return [\n { label: \"Duration\", value: `${details.durationMinutes} minutes` },\n { label: \"Billing\", value: details.billable ? \"Billable\" : \"Non-billable\" }\n ]\n }\n}\n\nconst presentSelectedObject = (selected: DeliveryEntityProjection): SelectedReleaseWorksetObject => {\n const status = selectedObjectStatus(selected.details)\n return {\n facts: selectedObjectFacts(selected.details),\n id: selected.entityId,\n kind: selected.entityType,\n label: selected.displayKey,\n service: selectedObjectService(selected.entityType),\n status,\n title: selected.title,\n tone: statusTone(status)\n }\n}\n\n/** Resolve every present normalized object into an inspectable selected-object surface. */\nexport const selectReleaseWorksetObject = (\n inspection: ReleaseDeliveryGraphInspection,\n selectedObjectId: string | null\n): SelectedReleaseWorksetObject | null => {\n if (selectedObjectId === null) return null\n const selected = inspection.entityProjections.find(\n ({ projection }) => projection.entityState === \"present\" && projection.entityId === selectedObjectId\n )?.projection\n if (selected === undefined) return null\n return presentSelectedObject(selected)\n}\n\nconst currentRelationship = (relationship: DeliveryRelationship): boolean =>\n relationship.lifecycle._tag !== \"missing\" &&\n relationship.lifecycle._tag !== \"rejected\" &&\n relationship.lifecycle._tag !== \"superseded\"\n\nconst gapService = (relationship: DeliveryRelationship): RlyService => {\n const missingKind = relationship.sourceNodeKind === \"release\"\n ? relationship.targetNodeKind\n : relationship.sourceNodeKind\n switch (missingKind) {\n case \"issue\":\n return \"jira\"\n case \"page\":\n return \"confluence\"\n case \"pipeline-execution\":\n case \"deployment\":\n return \"codepipeline\"\n case \"time-entry\":\n return \"clockify\"\n case \"pull-request\":\n case \"release\":\n case \"environment\":\n return \"codecommit\"\n }\n return \"codecommit\"\n}\n\nconst entityProjectionByNode = (\n inspection: ReleaseDeliveryGraphInspection\n): ReadonlyMap<GraphNodeId, DeliveryEntityProjection> => {\n const projections = new Map(inspection.entityProjections.map(({ projection }) => [projection.entityId, projection]))\n return new Map(\n inspection.nodes.flatMap((node): ReadonlyArray<readonly [GraphNodeId, DeliveryEntityProjection]> => {\n if (node.resolution._tag !== \"resolved\" || node.resolution.target._tag !== \"entity\") return []\n const projection = projections.get(node.resolution.target.entityId)\n return projection === undefined ? [] : [[node.nodeId, projection]]\n })\n )\n}\n\nconst relationshipLifecycleTone = (lifecycle: DeliveryRelationship[\"lifecycle\"][\"_tag\"]): RlyStateTone => {\n switch (lifecycle) {\n case \"missing\":\n case \"rejected\":\n return \"critical\"\n case \"governed\":\n case \"verified\":\n return \"positive\"\n case \"inferred\":\n case \"proposed\":\n return \"progress\"\n case \"superseded\":\n return \"neutral\"\n }\n}\n\nconst relationshipConfidenceLabel = (confidence: DeliveryRelationship[\"confidence\"]): string => {\n switch (confidence._tag) {\n case \"confirmed\":\n return \"Confirmed\"\n case \"inferred\":\n return `Inferred ${String(Math.round(confidence.score * 100))}%`\n case \"unknown\":\n return \"Confidence unknown\"\n }\n}\n\nconst traceConnection = (\n inspection: ReleaseDeliveryGraphInspection,\n workspaceId: WorkspaceId,\n nodeId: GraphNodeId,\n projections: ReadonlyMap<GraphNodeId, DeliveryEntityProjection>\n): SelectedReleaseWorksetTraceConnection => {\n const projection = projections.get(nodeId)\n if (projection !== undefined) {\n const selected = presentSelectedObject(projection)\n return {\n href: projection.entityState === \"present\"\n ? workspaceEntityPath(workspaceId, projection.entityId)\n : null,\n kind: selected.kind,\n label: selected.label,\n service: selected.service,\n title: projection.entityState === \"present\" ? selected.title : `${selected.title} · Deleted`\n }\n }\n const node = inspection.nodes.find((candidate) => candidate.nodeId === nodeId)\n if (node?.resolution._tag === \"missing\") {\n return {\n href: null,\n kind: node.endpointKind,\n label: node.resolution.missingKey,\n service: null,\n title: `Missing ${titleCase(node.endpointKind)}`\n }\n }\n if (node?.resolution._tag === \"resolved\" && node.resolution.target._tag === \"release\") {\n const isCurrentRelease = node.resolution.target.releaseId === inspection.releaseId\n return {\n href: null,\n kind: \"release\",\n label: `Release ${node.resolution.target.releaseId.slice(-6)}`,\n service: null,\n title: isCurrentRelease ? \"Current release context\" : \"Connected release\"\n }\n }\n if (node?.resolution._tag === \"resolved\" && node.resolution.target._tag === \"environment\") {\n return {\n href: null,\n kind: \"environment\",\n label: `Environment ${node.resolution.target.environmentId.slice(-6)}`,\n service: null,\n title: \"Delivery environment\"\n }\n }\n return { href: null, kind: \"unknown\", label: nodeId.slice(-6), service: null, title: \"Unresolved graph node\" }\n}\n\n/** Center the bounded current release graph on one selected normalized object. */\nexport const selectReleaseWorksetTrace = (\n inspection: ReleaseDeliveryGraphInspection,\n workspaceId: WorkspaceId,\n selectedObjectId: string | null\n): SelectedReleaseWorksetTrace | null => {\n const selectedObject = selectReleaseWorksetObject(inspection, selectedObjectId)\n if (selectedObject === null || selectedObjectId === null) return null\n const selectedNodeIds = new Set(\n inspection.nodes.flatMap((node): ReadonlyArray<GraphNodeId> =>\n node.resolution._tag === \"resolved\" &&\n node.resolution.target._tag === \"entity\" &&\n node.resolution.target.entityId === selectedObjectId\n ? [node.nodeId]\n : []\n )\n )\n const projections = entityProjectionByNode(inspection)\n const relationships = inspection.relationships.flatMap(\n (relationship): ReadonlyArray<SelectedReleaseWorksetTraceRelationship> => {\n const direction = selectedNodeIds.has(relationship.sourceNodeId)\n ? \"outgoing\"\n : selectedNodeIds.has(relationship.targetNodeId)\n ? \"incoming\"\n : null\n if (direction === null) return []\n const otherNodeId = direction === \"outgoing\" ? relationship.targetNodeId : relationship.sourceNodeId\n return [{\n confidence: relationshipConfidenceLabel(relationship.confidence),\n detailsHref: relationshipHref(\n workspaceId,\n inspection.releaseId,\n selectedObject.id,\n relationship.relationshipId\n ),\n direction,\n evidenceCount: relationship.evidenceClaimIds.length,\n id: relationship.relationshipId,\n kind: relationship.kind,\n lifecycle: titleCase(relationship.lifecycle._tag),\n other: traceConnection(inspection, workspaceId, otherNodeId, projections),\n tone: relationshipLifecycleTone(relationship.lifecycle._tag)\n }]\n }\n ).sort((left, right) =>\n left.kind.localeCompare(right.kind) || left.other.label.localeCompare(right.other.label) ||\n left.id.localeCompare(right.id)\n )\n return { relationships, truncated: inspection.truncated }\n}\n\n/** Resolve a URL-selected relationship only when it touches the selected object in this bounded slice. */\nexport const selectReleaseWorksetRelationship = (\n inspection: ReleaseDeliveryGraphInspection,\n selectedObjectId: string | null,\n selectedRelationshipId: string | null\n): DeliveryRelationship | null => {\n if (\n selectedRelationshipId === null ||\n selectedObjectId === null ||\n selectReleaseWorksetObject(inspection, selectedObjectId) === null\n ) return null\n const selectedNodeIds = new Set(\n inspection.nodes.flatMap((node): ReadonlyArray<GraphNodeId> =>\n node.resolution._tag === \"resolved\" &&\n node.resolution.target._tag === \"entity\" &&\n node.resolution.target.entityId === selectedObjectId\n ? [node.nodeId]\n : []\n )\n )\n let selected: DeliveryRelationship | null = null\n for (const relationship of inspection.relationships) {\n if (\n relationship.relationshipId === selectedRelationshipId &&\n (selectedNodeIds.has(relationship.sourceNodeId) || selectedNodeIds.has(relationship.targetNodeId)) &&\n (selected === null || relationship.revision > selected.revision)\n ) selected = relationship\n }\n return selected\n}\n\n/** Resolve exact referenced claims from the closure-checked release slice. */\nexport const releaseWorksetRelationshipEvidenceClaims = (\n inspection: ReleaseDeliveryGraphInspection,\n relationship: DeliveryRelationship | null\n): ReadonlyArray<EvidenceClaim> => {\n if (relationship === null) return []\n const claimById = new Map(inspection.evidenceClaims.map((claim) => [claim.evidenceClaimId, claim]))\n return relationship.evidenceClaimIds.flatMap((claimId) => {\n const claim = claimById.get(claimId)\n return claim === undefined ? [] : [claim]\n })\n}\n\n/** Resolve the unique evidence observations referenced by one relationship from the closed release slice. */\nexport const releaseWorksetRelationshipEvidenceIds = (\n inspection: ReleaseDeliveryGraphInspection,\n relationship: DeliveryRelationship | null\n): ReadonlyArray<EvidenceId> => {\n const evidenceIds = new Set<EvidenceId>()\n for (const claim of releaseWorksetRelationshipEvidenceClaims(inspection, relationship)) {\n evidenceIds.add(claim.evidenceId)\n }\n return [...evidenceIds].sort((left, right) => left.localeCompare(right))\n}\n\nconst releaseRunbookEntityIds = (\n inspection: ReleaseDeliveryGraphInspection,\n projections: ReadonlyMap<GraphNodeId, DeliveryEntityProjection>\n): ReadonlySet<EntityId> => {\n const nodes = new Map(inspection.nodes.map((node) => [node.nodeId, node]))\n return new Set(\n inspection.relationships.flatMap((relationship): ReadonlyArray<EntityId> => {\n if (\n relationship.kind !== \"documented-by\" ||\n relationship.sourceNodeKind !== \"release\" ||\n relationship.targetNodeKind !== \"page\" ||\n !currentRelationship(relationship)\n ) return []\n const source = nodes.get(relationship.sourceNodeId)\n const target = projections.get(relationship.targetNodeId)\n return source?.resolution._tag === \"resolved\" &&\n source.resolution.target._tag === \"release\" &&\n source.resolution.target.releaseId === inspection.releaseId &&\n target?.details._tag === \"page\"\n ? [target.entityId]\n : []\n })\n )\n}\n\nconst gapLabel = (\n relationship: DeliveryRelationship,\n projections: ReadonlyMap<GraphNodeId, DeliveryEntityProjection>\n): string => {\n const issue = relationship.sourceNodeKind === \"issue\"\n ? projections.get(relationship.sourceNodeId)\n : relationship.targetNodeKind === \"issue\"\n ? projections.get(relationship.targetNodeId)\n : undefined\n if (issue?.details._tag === \"issue\" && relationship.sourceNodeKind === \"pull-request\") {\n return `${issue.details.key} has no CodeCommit pull request`\n }\n return `Missing ${relationship.sourceNodeKind} → ${relationship.targetNodeKind} relationship`\n}\n\n/** Present one bounded graph inspection as three explicit release-work dimensions. */\nexport const presentReleaseWorkset = (\n inspection: ReleaseDeliveryGraphInspection,\n workspaceId: WorkspaceId,\n stages: ReadonlyArray<RlyStage>\n): ReleaseWorksetPresentation => {\n const projections = entityProjectionByNode(inspection)\n const runbookEntityIds = releaseRunbookEntityIds(inspection, projections)\n const href = (projection: DeliveryEntityProjection): string => workspaceEntityPath(workspaceId, projection.entityId)\n const issues = inspection.entityProjections\n .map(({ projection }) => projection)\n .filter((projection): projection is ProjectionWithDetails<\"issue\"> =>\n projection.entityType === \"issue\" && projection.details._tag === \"issue\" && projection.entityState === \"present\"\n )\n const pullRequests = inspection.entityProjections\n .map(({ projection }) => projection)\n .filter((projection): projection is ProjectionWithDetails<\"pull-request\"> =>\n projection.entityType === \"pull-request\" &&\n projection.details._tag === \"pull-request\" &&\n projection.entityState === \"present\"\n )\n const pipelineExecutions = inspection.entityProjections\n .map(({ projection }) => projection)\n .filter((projection): projection is ProjectionWithDetails<\"pipeline-execution\"> =>\n projection.entityType === \"pipeline-execution\" &&\n projection.details._tag === \"pipeline-execution\" &&\n projection.entityState === \"present\"\n )\n const pages = inspection.entityProjections\n .map(({ projection }) => projection)\n .filter((projection): projection is ProjectionWithDetails<\"page\"> =>\n projection.entityType === \"page\" &&\n projection.details._tag === \"page\" &&\n projection.entityState === \"present\" &&\n runbookEntityIds.has(projection.entityId)\n )\n\n return {\n jiraItems: issues.map((issue) => ({\n id: issue.entityId,\n key: issue.details.key,\n title: issue.title,\n state: issue.details.status,\n tone: statusTone(issue.details.status),\n href: href(issue)\n })),\n pullRequestGroups: pullRequests.map((pullRequest) => {\n const sourceNodes = new Set(\n Array.from(projections).flatMap(([nodeId, projection]): ReadonlyArray<GraphNodeId> =>\n projection.entityId === pullRequest.entityId ? [nodeId] : []\n )\n )\n const linkedJiraKeys = Array.from(\n new Set(inspection.relationships.flatMap((relationship): ReadonlyArray<string> => {\n if (\n relationship.kind !== \"implements\" ||\n !sourceNodes.has(relationship.sourceNodeId) ||\n !currentRelationship(relationship)\n ) return []\n const issue = projections.get(relationship.targetNodeId)\n return issue?.details._tag === \"issue\" ? [issue.details.key] : []\n }))\n )\n const state = pullRequestStateLabel(pullRequest.details)\n return {\n id: pullRequest.entityId,\n title: pullRequest.title,\n reference: pullRequest.displayKey,\n state,\n tone: statusTone(state),\n href: href(pullRequest),\n linkedJiraKeys\n }\n }),\n gaps: inspection.relationships.flatMap((relationship): ReadonlyArray<RlyWorksetGap> =>\n relationship.lifecycle._tag === \"missing\"\n ? [{\n id: relationship.relationshipId,\n label: gapLabel(relationship, projections),\n reason: relationship.lifecycle.reason,\n service: gapService(relationship)\n }]\n : []\n ),\n pipelines: pipelineExecutions.map((pipeline) => {\n const state = pipelineStateLabel(pipeline.details.status)\n return {\n id: pipeline.entityId,\n title: pipeline.title,\n reference: pipeline.displayKey,\n state,\n tone: statusTone(state),\n href: href(pipeline),\n stages\n }\n }),\n runbooks: pages.map((page) => ({\n href: href(page),\n id: page.entityId,\n reference: page.displayKey,\n state: page.details.status,\n title: page.title\n })),\n truncated: inspection.truncated\n }\n}\n",".body,\n.loading,\n.content,\n.summary,\n.section,\n.history,\n.evidence,\n.evidenceCard,\n.claims {\n display: grid;\n}\n\n.integrity {\n display: flex;\n align-items: flex-start;\n gap: var(--rly-space-8);\n}\n\n.integrity p {\n margin: 0;\n}\n\n.body,\n.content,\n.loading {\n gap: var(--rly-space-20);\n}\n\n.content,\n.summary,\n.section,\n.evidenceCard {\n gap: var(--rly-space-12);\n}\n\n.summary,\n.evidenceCard {\n padding: var(--rly-space-16);\n border: 1px solid var(--rly-color-border-1);\n border-radius: var(--rly-radius-group);\n background: var(--rly-color-surface-2);\n}\n\n.summaryHeading,\n.sectionHeading,\n.historyHeading,\n.evidenceHeading,\n.tags {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--rly-space-8);\n}\n\n.tags {\n justify-content: flex-end;\n}\n\n.summary h3,\n.section h3,\n.evidenceCard h4,\n.summary p,\n.history p,\n.facts dd {\n margin: 0;\n}\n\n.facts {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--rly-space-12);\n margin: 0;\n}\n\n.facts div {\n min-width: 0;\n}\n\n.facts dt {\n color: var(--rly-color-text-2);\n font: var(--rly-type-meta-weight) var(--rly-type-meta-size) / var(--rly-type-meta-line-height)\n var(--rly-type-meta-font);\n}\n\n.facts dd {\n overflow-wrap: anywhere;\n}\n\n.history,\n.claims {\n gap: var(--rly-space-8);\n padding: 0;\n margin: 0;\n list-style: none;\n}\n\n.history li,\n.claims li {\n display: grid;\n gap: var(--rly-space-4);\n padding: var(--rly-space-12);\n border-block-start: 1px solid var(--rly-color-border-1);\n}\n\n.history li:first-child,\n.claims li:first-child {\n border-block-start: 0;\n}\n\n.claims li {\n grid-template-columns: minmax(8rem, auto) minmax(0, 1fr);\n}\n\n@media (max-width: 36rem) {\n .facts,\n .claims li {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n","import * as Effect from \"effect/Effect\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as FetchHttpClient from \"effect/unstable/http/FetchHttpClient\"\nimport { useCallback, useEffect, useRef, useState } from \"react\"\n\nimport { makeControlCenterApiClient } from \"../../api/client.js\"\nimport type { EvidenceInspection, RelationshipHistoryInspection } from \"../../api/deliveryGraph.js\"\nimport type { EvidenceId, RelationshipId } from \"../../domain/identifiers.js\"\n\nexport const MAXIMUM_RELATIONSHIP_EVIDENCE_REQUEST_CONCURRENCY = 4\n\nexport interface RelationshipDetails {\n readonly evidence: ReadonlyArray<EvidenceInspection>\n readonly history: RelationshipHistoryInspection\n}\n\nexport interface RelationshipDetailsTransport {\n readonly load: (\n relationshipId: RelationshipId,\n evidenceIds: ReadonlyArray<EvidenceId>,\n signal: AbortSignal\n ) => Promise<RelationshipDetails>\n}\n\nconst isUnauthorizedFailure = Predicate.isTagged(\"UnauthorizedApiError\")\n\n/** Load one relationship ledger and only the immutable evidence it references. */\nexport const browserRelationshipDetailsTransport: RelationshipDetailsTransport = {\n load: (relationshipId, evidenceIds, signal) =>\n Effect.runPromise(\n Effect.gen(function*() {\n const client = yield* makeControlCenterApiClient()\n const history = yield* client.deliveryGraph.relationshipHistory({ params: { relationshipId } })\n const evidence = yield* Effect.forEach(\n evidenceIds,\n (evidenceId) => client.deliveryGraph.evidence({ params: { evidenceId } }),\n { concurrency: MAXIMUM_RELATIONSHIP_EVIDENCE_REQUEST_CONCURRENCY }\n )\n return { evidence, history }\n }).pipe(Effect.provide(FetchHttpClient.layer)),\n { signal }\n )\n}\n\nexport type RelationshipDetailsState =\n | { readonly _tag: \"idle\" }\n | {\n readonly _tag: \"loading\"\n readonly evidenceKey: string\n readonly relationshipId: RelationshipId\n readonly sessionKey: string\n }\n | {\n readonly _tag: \"failed\"\n readonly evidenceKey: string\n readonly relationshipId: RelationshipId\n readonly sessionKey: string\n }\n | {\n readonly _tag: \"ready\"\n readonly details: RelationshipDetails\n readonly evidenceKey: string\n readonly relationshipId: RelationshipId\n readonly sessionKey: string\n }\n\n/** Keep relationship details bound to the exact selection and authenticated browser session. */\nexport const useRelationshipDetails = (\n relationshipId: RelationshipId | null,\n evidenceIds: ReadonlyArray<EvidenceId>,\n sessionKey: string | null,\n onSessionExpired: (sessionKey: string) => void,\n transport: RelationshipDetailsTransport = browserRelationshipDetailsTransport\n): { readonly retry: () => void; readonly state: RelationshipDetailsState } => {\n const [requestRevision, setRequestRevision] = useState(0)\n const [state, setState] = useState<RelationshipDetailsState>({ _tag: \"idle\" })\n const evidenceKey = evidenceIds.join(\":\")\n const evidenceIdsRef = useRef(evidenceIds)\n\n useEffect(() => {\n evidenceIdsRef.current = evidenceIds\n }, [evidenceIds])\n\n useEffect(() => {\n if (relationshipId === null || sessionKey === null) {\n setState({ _tag: \"idle\" })\n return\n }\n const abort = new AbortController()\n setState({ _tag: \"loading\", evidenceKey, relationshipId, sessionKey })\n transport.load(relationshipId, evidenceIdsRef.current, abort.signal).then(\n (details) => {\n if (!abort.signal.aborted) setState({ _tag: \"ready\", details, evidenceKey, relationshipId, sessionKey })\n },\n (failure) => {\n if (!abort.signal.aborted) {\n if (isUnauthorizedFailure(failure)) onSessionExpired(sessionKey)\n setState({ _tag: \"failed\", evidenceKey, relationshipId, sessionKey })\n }\n }\n )\n return () => abort.abort()\n }, [evidenceKey, onSessionExpired, relationshipId, requestRevision, sessionKey, transport])\n\n const currentState: RelationshipDetailsState = relationshipId === null || sessionKey === null\n ? { _tag: \"idle\" }\n : state._tag === \"idle\" ||\n state.relationshipId !== relationshipId ||\n state.sessionKey !== sessionKey ||\n state.evidenceKey !== evidenceKey\n ? { _tag: \"loading\", evidenceKey, relationshipId, sessionKey }\n : state\n\n return {\n retry: useCallback(() => setRequestRevision((revision) => revision + 1), []),\n state: currentState\n }\n}\n","import { Button, Sheet, Skeleton, StateLabel, StatePanel, Text } from \"@knpkv/rly/primitives\"\nimport type { RlyStateTone } from \"@knpkv/rly/primitives\"\nimport * as DateTime from \"effect/DateTime\"\nimport type { ReactElement } from \"react\"\n\nimport type { EvidenceInspection, RelationshipHistoryInspection } from \"../../api/deliveryGraph.js\"\nimport type { DeliveryRelationship, EvidenceClaim, EvidenceItem } from \"../../domain/deliveryGraph.js\"\nimport type { EvidenceId } from \"../../domain/identifiers.js\"\nimport type { UtcTimestamp } from \"../../domain/utcTimestamp.js\"\nimport styles from \"./RelationshipDetailSheet.module.css\"\nimport { type RelationshipDetailsTransport, useRelationshipDetails } from \"./useRelationshipDetails.js\"\n\nconst titleCase = (value: string): string =>\n value\n .split(\"-\")\n .map((part) => `${part.charAt(0).toLocaleUpperCase(\"en-US\")}${part.slice(1)}`)\n .join(\" \")\n\nexport const formatRelationshipTimestamp = (value: UtcTimestamp): string =>\n DateTime.formatUtc(value, {\n day: \"2-digit\",\n hour: \"2-digit\",\n hour12: false,\n locale: \"en-GB\",\n minute: \"2-digit\",\n month: \"short\",\n year: \"numeric\"\n })\n\nexport const relationshipActorLabel = (actor: DeliveryRelationship[\"recordedBy\"]): string => {\n switch (actor._tag) {\n case \"human\":\n return `Human · ${actor.personId.slice(-6)}`\n case \"agent\":\n return `Agent · ${actor.agentId.slice(-6)}`\n case \"system\":\n return `System · ${actor.component}`\n }\n}\n\nexport const relationshipProvenanceLabel = (provenance: DeliveryRelationship[\"provenance\"]): string => {\n switch (provenance._tag) {\n case \"plugin\":\n return `Plugin source · ${provenance.pluginConnectionId.slice(-6)}`\n case \"human\":\n return `Human decision · ${provenance.personId.slice(-6)}`\n case \"agent\":\n return `Agent proposal · ${provenance.agentId.slice(-6)}`\n case \"rule\":\n return `Rule · ${provenance.ruleId} v${String(provenance.ruleVersion)}`\n }\n}\n\nconst relationshipRationale = (relationship: DeliveryRelationship): string => {\n switch (relationship.confidence._tag) {\n case \"confirmed\":\n return \"Confirmed by immutable evidence.\"\n case \"inferred\":\n case \"unknown\":\n return relationship.confidence.rationale\n }\n}\n\nconst relationshipConfidenceLabel = (relationship: DeliveryRelationship): string => {\n switch (relationship.confidence._tag) {\n case \"confirmed\":\n return \"Confirmed\"\n case \"inferred\":\n return `Inferred ${String(Math.round(relationship.confidence.score * 100))}%`\n case \"unknown\":\n return \"Confidence unknown\"\n }\n}\n\nconst relationshipLifecycleTone = (relationship: DeliveryRelationship): RlyStateTone => {\n switch (relationship.lifecycle._tag) {\n case \"missing\":\n case \"rejected\":\n return \"critical\"\n case \"governed\":\n case \"verified\":\n return \"positive\"\n case \"inferred\":\n case \"proposed\":\n return \"progress\"\n case \"superseded\":\n return \"neutral\"\n }\n}\n\nconst relationshipScopeLabel = (relationship: DeliveryRelationship): string => {\n if (relationship.scope === null) return \"Workspace\"\n if (relationship.scope._tag === \"release\") return `Release · ${relationship.scope.releaseId.slice(-6)}`\n return `Environment · ${relationship.scope.environmentId.slice(-6)}`\n}\n\nconst evidenceFreshnessTone = (evidence: EvidenceItem): RlyStateTone => {\n switch (evidence.freshness._tag) {\n case \"current\":\n return \"positive\"\n case \"stale\":\n return \"caution\"\n case \"missing\":\n case \"unavailable\":\n return \"critical\"\n }\n}\n\nconst lifecycleReason = (relationship: DeliveryRelationship): string | null => {\n switch (relationship.lifecycle._tag) {\n case \"missing\":\n case \"rejected\":\n case \"superseded\":\n return relationship.lifecycle.reason\n case \"governed\":\n case \"inferred\":\n case \"proposed\":\n case \"verified\":\n return null\n }\n}\n\nconst evidencePartyLabel = (party: EvidenceItem[\"attribution\"] | EvidenceItem[\"verifier\"]): string => {\n switch (party._tag) {\n case \"plugin\":\n return `Plugin · ${party.pluginConnectionId.slice(-6)}`\n case \"human\":\n return `Human · ${party.personId.slice(-6)}`\n case \"agent\":\n return `Agent · ${party.agentId.slice(-6)}`\n case \"system\":\n return `System · ${party.component}`\n }\n}\n\nexport const evidenceClaimValueLabel = (claim: EvidenceClaim): string => {\n switch (claim.value._tag) {\n case \"flag\":\n return claim.value.value ? \"Yes\" : \"No\"\n case \"state\":\n case \"revision\":\n return claim.value.value\n case \"reference\":\n return `Node ${claim.value.targetNodeId.slice(-6)}`\n }\n}\n\nconst EvidenceCard = ({\n claims,\n inspection,\n relationship\n}: {\n readonly claims: ReadonlyArray<EvidenceClaim>\n readonly inspection: EvidenceInspection\n readonly relationship: DeliveryRelationship\n}): ReactElement => {\n const relatedClaimIds = new Set(relationship.evidenceClaimIds)\n const relatedClaims = claims.filter(\n ({ evidenceClaimId, evidenceId }) =>\n evidenceId === inspection.evidence.evidenceId && relatedClaimIds.has(evidenceClaimId)\n )\n const evidence = inspection.evidence\n return (\n <article className={styles.evidenceCard}>\n <div className={styles.evidenceHeading}>\n <Text as=\"h4\" variant=\"label\">\n Evidence {evidence.evidenceId.slice(-6)}\n </Text>\n <StateLabel label={titleCase(evidence.freshness._tag)} size=\"compact\" tone={evidenceFreshnessTone(evidence)} />\n </div>\n <dl className={styles.facts}>\n <div>\n <dt>Observed</dt>\n <dd>{formatRelationshipTimestamp(evidence.observedAt)}</dd>\n </div>\n <div>\n <dt>Source</dt>\n <dd>{evidencePartyLabel(evidence.attribution)}</dd>\n </div>\n <div>\n <dt>Verified by</dt>\n <dd>{evidencePartyLabel(evidence.verifier)}</dd>\n </div>\n <div>\n <dt>Retention</dt>\n <dd>\n {titleCase(evidence.retention.classification)}\n {evidence.retention.legalHold ? \" · Legal hold\" : \"\"}\n </dd>\n </div>\n <div>\n <dt>Valid until</dt>\n <dd>\n {evidence.validUntil === null ? \"No expiry recorded\" : formatRelationshipTimestamp(evidence.validUntil)}\n </dd>\n </div>\n </dl>\n {relatedClaims.length === 0 ? (\n <Text tone=\"secondary\" variant=\"meta\">\n No referenced claim was returned for this observation.\n </Text>\n ) : (\n <ul className={styles.claims}>\n {relatedClaims.map((claim) => (\n <li key={claim.evidenceClaimId}>\n <Text as=\"span\" variant=\"label\">\n {titleCase(claim.predicate)}\n </Text>\n <Text as=\"span\" tone=\"secondary\">\n {evidenceClaimValueLabel(claim)}\n </Text>\n </li>\n ))}\n </ul>\n )}\n </article>\n )\n}\n\n/** Report the bounded history prefix without presenting it as a complete ledger. */\nexport const relationshipHistoryCountLabel = (revisions: RelationshipHistoryInspection[\"revisions\"]): string => {\n let newestRevision = 0\n for (const revision of revisions) newestRevision = Math.max(newestRevision, revision.revision)\n if (newestRevision > revisions.length) return `${String(revisions.length)} of ${String(newestRevision)} revisions`\n return `${String(revisions.length)} revision${revisions.length === 1 ? \"\" : \"s\"}`\n}\n\n/** URL-owned detail panel for immutable relationship history and evidence. */\nexport const RelationshipDetailSheet = ({\n claims,\n evidenceIds,\n onClose,\n onSessionExpired,\n relationship,\n sessionKey,\n transport\n}: {\n readonly claims: ReadonlyArray<EvidenceClaim>\n readonly evidenceIds: ReadonlyArray<EvidenceId>\n readonly onClose: () => void\n readonly onSessionExpired: (sessionKey: string) => void\n readonly relationship: DeliveryRelationship | null\n readonly sessionKey: string | null\n readonly transport?: RelationshipDetailsTransport\n}): ReactElement => {\n const controller = useRelationshipDetails(\n relationship?.relationshipId ?? null,\n evidenceIds,\n sessionKey,\n onSessionExpired,\n transport\n )\n const title = relationship === null ? \"Relationship details\" : `${titleCase(relationship.kind)} relationship`\n const evidenceIntegrityComplete = relationship === null || claims.length === relationship.evidenceClaimIds.length\n\n return (\n <Sheet.Root\n onOpenChange={(open) => {\n if (!open) onClose()\n }}\n open={relationship !== null}\n >\n <Sheet.Content\n closeLabel={`Close ${title}`}\n description=\"Immutable delivery history and the evidence used to establish this connection.\"\n title={title}\n >\n <Sheet.Body className={styles.body}>\n {relationship === null || controller.state._tag === \"idle\" || controller.state._tag === \"loading\" ? (\n <div aria-busy=\"true\" aria-label=\"Loading relationship details\" className={styles.loading}>\n <Skeleton height=\"7rem\" />\n <Skeleton height=\"12rem\" />\n </div>\n ) : controller.state._tag === \"failed\" ? (\n <StatePanel\n action={<Button onClick={controller.retry}>Try again</Button>}\n description=\"The selected relationship remains unchanged. Its history could not be loaded.\"\n title=\"Relationship details unavailable\"\n tone=\"caution\"\n />\n ) : (\n <div className={styles.content}>\n <section aria-labelledby=\"relationship-summary-title\" className={styles.summary}>\n <div className={styles.summaryHeading}>\n <Text as=\"h3\" id=\"relationship-summary-title\" variant=\"section-title\">\n {relationship.sourceNodeKind} → {relationship.targetNodeKind}\n </Text>\n <div className={styles.tags}>\n <StateLabel\n label={titleCase(relationship.lifecycle._tag)}\n size=\"compact\"\n tone={relationshipLifecycleTone(relationship)}\n />\n <StateLabel label={relationshipConfidenceLabel(relationship)} size=\"compact\" tone=\"neutral\" />\n </div>\n </div>\n <Text tone=\"secondary\">{relationshipRationale(relationship)}</Text>\n <dl className={styles.facts}>\n <div>\n <dt>Revision</dt>\n <dd>{String(relationship.revision)}</dd>\n </div>\n <div>\n <dt>Recorded by</dt>\n <dd>{relationshipActorLabel(relationship.recordedBy)}</dd>\n </div>\n <div>\n <dt>Origin</dt>\n <dd>{relationshipProvenanceLabel(relationship.provenance)}</dd>\n </div>\n <div>\n <dt>Scope</dt>\n <dd>{relationshipScopeLabel(relationship)}</dd>\n </div>\n <div>\n <dt>Recorded</dt>\n <dd>{formatRelationshipTimestamp(relationship.recordedAt)}</dd>\n </div>\n </dl>\n </section>\n\n <section aria-labelledby=\"relationship-history-title\" className={styles.section}>\n <div className={styles.sectionHeading}>\n <Text as=\"h3\" id=\"relationship-history-title\" variant=\"label\">\n History\n </Text>\n <StateLabel\n label={relationshipHistoryCountLabel(controller.state.details.history.revisions)}\n size=\"compact\"\n tone=\"neutral\"\n />\n </div>\n {controller.state.details.history.revisions.length === 0 ? (\n <Text tone=\"secondary\">No immutable ledger revisions were returned.</Text>\n ) : (\n <ol className={styles.history}>\n {controller.state.details.history.revisions.map((revision) => {\n const reason = lifecycleReason(revision)\n return (\n <li key={`${revision.relationshipId}:${String(revision.revision)}`}>\n <div className={styles.historyHeading}>\n <Text as=\"span\" variant=\"label\">\n Revision {String(revision.revision)}\n </Text>\n <StateLabel\n label={titleCase(revision.lifecycle._tag)}\n size=\"compact\"\n tone={relationshipLifecycleTone(revision)}\n />\n </div>\n <Text tone=\"secondary\" variant=\"meta\">\n {relationshipActorLabel(revision.recordedBy)} ·{\" \"}\n {formatRelationshipTimestamp(revision.recordedAt)}\n </Text>\n {reason === null ? null : <Text tone=\"secondary\">{reason}</Text>}\n </li>\n )\n })}\n </ol>\n )}\n </section>\n\n <section aria-labelledby=\"relationship-evidence-title\" className={styles.section}>\n <div className={styles.sectionHeading}>\n <Text as=\"h3\" id=\"relationship-evidence-title\" variant=\"label\">\n Evidence\n </Text>\n <StateLabel\n label={`${String(controller.state.details.evidence.length)} observation${controller.state.details.evidence.length === 1 ? \"\" : \"s\"}`}\n size=\"compact\"\n tone=\"neutral\"\n />\n </div>\n {evidenceIntegrityComplete ? null : (\n <div className={styles.integrity}>\n <StateLabel label=\"Evidence incomplete\" size=\"compact\" tone=\"critical\" />\n <Text tone=\"secondary\">\n One or more referenced claims are missing from the release slice. Refresh before relying on this\n relationship.\n </Text>\n </div>\n )}\n {controller.state.details.evidence.length === 0 ? (\n <Text tone=\"secondary\">No immutable evidence is attached to this relationship revision.</Text>\n ) : (\n <div className={styles.evidence}>\n {controller.state.details.evidence.map((inspection) => (\n <EvidenceCard\n claims={claims}\n inspection={inspection}\n key={inspection.evidence.evidenceId}\n relationship={relationship}\n />\n ))}\n </div>\n )}\n </section>\n </div>\n )}\n </Sheet.Body>\n </Sheet.Content>\n </Sheet.Root>\n )\n}\n","import * as Option from \"effect/Option\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Schema from \"effect/Schema\"\nimport type { NavigateFunction } from \"react-router\"\n\nimport {\n EntityId,\n type EntityId as EntityIdType,\n RelationshipId,\n type RelationshipId as RelationshipIdType\n} from \"../../domain/identifiers.js\"\n\nconst RelationshipDetailMarker = Schema.Struct({\n _tag: Schema.Literal(\"relationship-detail-origin/v1\"),\n objectId: EntityId,\n relationshipId: RelationshipId\n})\n\nconst RelationshipDetailRouteState = Schema.Struct({\n relationshipDetailOrigin: RelationshipDetailMarker\n})\n\n/** Preserve existing release-origin state while marking an in-app relationship-detail activation. */\nexport const makeRelationshipDetailRouteState = (\n state: unknown,\n objectId: EntityIdType,\n relationshipId: RelationshipIdType\n): unknown => ({\n ...(Predicate.isObject(state) ? state : {}),\n relationshipDetailOrigin: {\n _tag: \"relationship-detail-origin/v1\",\n objectId,\n relationshipId\n }\n})\n\n/** Accept Back navigation only for the exact versioned object/relationship activation. */\nexport const matchesRelationshipDetailRouteState = (\n state: unknown,\n objectId: EntityIdType,\n relationshipId: RelationshipIdType\n): boolean => {\n const decoded = Schema.decodeUnknownOption(RelationshipDetailRouteState)(state)\n return Option.isSome(decoded) &&\n decoded.value.relationshipDetailOrigin.objectId === objectId &&\n decoded.value.relationshipDetailOrigin.relationshipId === relationshipId\n}\n\n/** Close an in-app detail with Back; canonicalize direct detail URLs in place. */\nexport const closeRelationshipDetailRoute = (\n navigate: NavigateFunction,\n location: Readonly<{ hash: string; pathname: string; search: string; state: unknown }>,\n objectId: EntityIdType,\n relationshipId: RelationshipIdType\n): void => {\n if (matchesRelationshipDetailRouteState(location.state, objectId, relationshipId)) {\n navigate(-1)\n return\n }\n const next = new URLSearchParams(location.search)\n next.delete(\"relationship\")\n navigate(\n { hash: location.hash, pathname: location.pathname, search: next.size === 0 ? \"\" : `?${next.toString()}` },\n { replace: true, state: location.state }\n )\n}\n",".root,\n.loading,\n.context,\n.contextGroup,\n.selected,\n.selectedFacts,\n.trace,\n.traceList,\n.runbooks,\n.runbook {\n display: grid;\n}\n\n.root,\n.loading {\n gap: var(--rly-space-16);\n}\n\n.context {\n grid-template-columns: repeat(2, minmax(0, 1fr)) auto;\n align-items: start;\n gap: var(--rly-space-24);\n padding: var(--rly-space-16) var(--rly-space-20);\n border: 1px solid var(--rly-color-border-1);\n border-radius: var(--rly-radius-group);\n background: var(--rly-color-surface-2);\n}\n\n.contextGroup,\n.runbook {\n gap: var(--rly-space-4);\n}\n\n.contextHeading,\n.tags {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--rly-space-8);\n}\n\n.contextGroup h3 {\n margin: 0;\n}\n\n.selected {\n grid-column: 1 / -1;\n gap: var(--rly-space-12);\n padding: var(--rly-space-16);\n border: 1px solid var(--rly-color-border-2);\n border-radius: var(--rly-radius-group);\n background: var(--rly-color-surface-1);\n}\n\n.selected h3,\n.selected p,\n.selectedFacts dd {\n margin: 0;\n}\n\n.selectedHeading {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--rly-space-8);\n}\n\n.selectedFacts {\n grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));\n gap: var(--rly-space-12);\n margin: 0;\n}\n\n.selectedFacts div {\n min-width: 0;\n}\n\n.selectedFacts dt {\n color: var(--rly-color-text-2);\n font: var(--rly-type-meta-weight) var(--rly-type-meta-size) / var(--rly-type-meta-line-height)\n var(--rly-type-meta-font);\n}\n\n.selectedFacts dd {\n overflow-wrap: anywhere;\n}\n\n.trace {\n gap: var(--rly-space-8);\n padding-block-start: var(--rly-space-12);\n border-block-start: 1px solid var(--rly-color-border-1);\n}\n\n.traceHeading,\n.traceRelation {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--rly-space-8);\n}\n\n.traceHeading {\n justify-content: space-between;\n}\n\n.traceHeading h4,\n.traceConnection p {\n margin: 0;\n}\n\n.traceList {\n gap: var(--rly-space-4);\n padding: 0;\n margin: 0;\n list-style: none;\n}\n\n.traceList li {\n display: grid;\n grid-template-columns: auto minmax(10rem, 1fr) auto auto auto;\n align-items: center;\n gap: var(--rly-space-12);\n min-width: 0;\n padding: var(--rly-space-8) var(--rly-space-12);\n border-radius: var(--rly-radius-control);\n background: var(--rly-color-surface-2);\n}\n\n.traceConnection {\n min-width: 0;\n}\n\n.traceConnection a {\n color: var(--rly-color-text-1);\n overflow-wrap: anywhere;\n text-decoration-color: var(--rly-color-border-2);\n text-underline-offset: var(--rly-space-2);\n}\n\n.traceDetails {\n color: var(--rly-color-text-1);\n font: var(--rly-type-label-weight) var(--rly-type-label-size) / var(--rly-type-label-line-height)\n var(--rly-type-label-font);\n text-underline-offset: var(--rly-space-2);\n}\n\n.traceDetails:focus-visible {\n border-radius: var(--rly-radius-tag);\n outline: 2px solid var(--rly-color-focus);\n outline-offset: var(--rly-space-2);\n}\n\n.traceConnection a:focus-visible {\n border-radius: var(--rly-radius-tag);\n outline: 2px solid var(--rly-color-focus);\n outline-offset: var(--rly-space-2);\n}\n\n.runbooks {\n gap: var(--rly-space-8);\n}\n\n.runbook {\n color: inherit;\n text-decoration-color: var(--rly-color-border-2);\n text-underline-offset: var(--rly-space-2);\n}\n\n.runbook span {\n color: var(--rly-color-text-2);\n font: var(--rly-type-meta-weight) var(--rly-type-meta-size) / var(--rly-type-meta-line-height)\n var(--rly-type-meta-font);\n}\n\n.runbook:focus-visible {\n border-radius: var(--rly-radius-tag);\n outline: 2px solid var(--rly-color-focus);\n outline-offset: var(--rly-space-2);\n}\n\n@media (max-width: 48rem) {\n .context {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .traceList li {\n grid-template-columns: auto minmax(0, 1fr);\n }\n\n .traceRelation,\n .traceList li > span,\n .traceDetails {\n grid-column: 2;\n }\n}\n","import type { EnvironmentId } from \"../../domain/identifiers.js\"\n\nexport const MAXIMUM_RELEASE_ENVIRONMENT_REQUEST_CONCURRENCY = 4\n\n/** Load release scope followed by every target environment without saturating browser connection pools. */\nexport const loadReleaseEnvironmentSlices = async <Value>(\n environmentIds: ReadonlyArray<EnvironmentId>,\n load: (environmentId: EnvironmentId | null) => Promise<Value>\n): Promise<ReadonlyArray<Value>> => {\n const scopes: ReadonlyArray<EnvironmentId | null> = [null, ...environmentIds]\n const completed: Array<{ readonly index: number; readonly value: Value }> = []\n let nextIndex = 0\n let isStopped = false\n const loadNext = async (): Promise<void> => {\n while (!isStopped && nextIndex < scopes.length) {\n const index = nextIndex\n nextIndex += 1\n const environmentId = scopes[index]\n if (environmentId === undefined) return\n try {\n completed.push({ index, value: await load(environmentId) })\n } catch (failure) {\n isStopped = true\n throw failure\n }\n }\n }\n const workerCount = Math.min(MAXIMUM_RELEASE_ENVIRONMENT_REQUEST_CONCURRENCY, scopes.length)\n await Promise.all(Array.from({ length: workerCount }, () => loadNext()))\n return completed.sort((left, right) => left.index - right.index).map(({ value }) => value)\n}\n","import * as Effect from \"effect/Effect\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as FetchHttpClient from \"effect/unstable/http/FetchHttpClient\"\nimport { useCallback, useEffect, useState } from \"react\"\n\nimport { makeControlCenterApiClient } from \"../../api/client.js\"\nimport { MAXIMUM_RELEASE_SLICE_RECORDS, type ReleaseDeliveryGraphInspection } from \"../../api/deliveryGraph.js\"\nimport type { EnvironmentId, ReleaseId } from \"../../domain/identifiers.js\"\nimport {\n loadReleaseEnvironmentSlices,\n MAXIMUM_RELEASE_ENVIRONMENT_REQUEST_CONCURRENCY\n} from \"./loadReleaseEnvironmentSlices.js\"\n\nexport const MAXIMUM_AGGREGATED_RELEASE_WORKSET_RECORDS = MAXIMUM_RELEASE_SLICE_RECORDS\n\n/** Combine release and environment slices while retaining complete relationship closure. */\nexport const aggregateReleaseWorksetInspections = (\n releaseId: ReleaseId,\n inspections: ReadonlyArray<ReleaseDeliveryGraphInspection>\n): ReleaseDeliveryGraphInspection => {\n type Inspection = ReleaseDeliveryGraphInspection\n const availableNodes = new Map<string, Inspection[\"nodes\"][number]>()\n const availableProjections = new Map<string, Inspection[\"entityProjections\"][number]>()\n const availableClaims = new Map<string, Inspection[\"evidenceClaims\"][number]>()\n const availableEvidence = new Map<string, Inspection[\"evidenceItems\"][number]>()\n for (const inspection of inspections) {\n for (const node of inspection.nodes) availableNodes.set(node.nodeId, node)\n for (const entry of inspection.entityProjections) {\n availableProjections.set(entry.projection.entityId, entry)\n }\n for (const claim of inspection.evidenceClaims) availableClaims.set(claim.evidenceClaimId, claim)\n for (const item of inspection.evidenceItems) availableEvidence.set(item.evidenceId, item)\n }\n const nodes = new Map<string, Inspection[\"nodes\"][number]>()\n const entityProjections = new Map<string, Inspection[\"entityProjections\"][number]>()\n const relationships = new Map<string, Inspection[\"relationships\"][number]>()\n const evidenceClaims = new Map<string, Inspection[\"evidenceClaims\"][number]>()\n const evidenceItems = new Map<string, Inspection[\"evidenceItems\"][number]>()\n let truncated = inspections.some((inspection) => inspection.truncated)\n\n for (const relationship of inspections.flatMap(({ relationships }) => relationships)) {\n const relationshipKey = `${relationship.relationshipId}:${String(relationship.revision)}`\n if (relationships.has(relationshipKey)) continue\n const requiredNodes = [\n availableNodes.get(relationship.sourceNodeId),\n availableNodes.get(relationship.targetNodeId)\n ]\n if (requiredNodes.some((node) => node === undefined)) {\n truncated = true\n continue\n }\n const presentNodes = requiredNodes.filter((node) => node !== undefined)\n const entityNodes = presentNodes.filter(\n (node) => node.resolution._tag === \"resolved\" && node.resolution.target._tag === \"entity\"\n )\n const requiredProjections = entityNodes.flatMap((node) => {\n if (node.resolution._tag !== \"resolved\" || node.resolution.target._tag !== \"entity\") return []\n const projection = availableProjections.get(node.resolution.target.entityId)\n return projection === undefined ? [] : [projection]\n })\n const requiredClaims = relationship.evidenceClaimIds.flatMap((claimId) => {\n const claim = availableClaims.get(claimId)\n return claim === undefined ? [] : [claim]\n })\n const evidenceIds = new Set(requiredClaims.map(({ evidenceId }) => evidenceId))\n const requiredEvidence = [...evidenceIds].flatMap((evidenceId) => {\n const evidence = availableEvidence.get(evidenceId)\n return evidence === undefined ? [] : [evidence]\n })\n const closureMissing = requiredProjections.length !== entityNodes.length ||\n requiredClaims.length !== relationship.evidenceClaimIds.length ||\n requiredEvidence.length !== evidenceIds.size\n const newNodeCount = presentNodes.filter(({ nodeId }) => !nodes.has(nodeId)).length\n const newProjectionCount = requiredProjections.filter(({ projection }) =>\n !entityProjections.has(projection.entityId)\n ).length\n const newClaimCount = requiredClaims.filter(({ evidenceClaimId }) => !evidenceClaims.has(evidenceClaimId)).length\n const newEvidenceCount = requiredEvidence.filter(({ evidenceId }) => !evidenceItems.has(evidenceId)).length\n const closureExceedsBound = relationships.size === MAXIMUM_AGGREGATED_RELEASE_WORKSET_RECORDS ||\n nodes.size + newNodeCount > MAXIMUM_AGGREGATED_RELEASE_WORKSET_RECORDS ||\n entityProjections.size + newProjectionCount > MAXIMUM_AGGREGATED_RELEASE_WORKSET_RECORDS ||\n evidenceClaims.size + newClaimCount > MAXIMUM_AGGREGATED_RELEASE_WORKSET_RECORDS ||\n evidenceItems.size + newEvidenceCount > MAXIMUM_AGGREGATED_RELEASE_WORKSET_RECORDS\n if (closureMissing || closureExceedsBound) {\n truncated = true\n continue\n }\n relationships.set(relationshipKey, relationship)\n for (const node of presentNodes) nodes.set(node.nodeId, node)\n for (const entry of requiredProjections) entityProjections.set(entry.projection.entityId, entry)\n for (const claim of requiredClaims) evidenceClaims.set(claim.evidenceClaimId, claim)\n for (const item of requiredEvidence) evidenceItems.set(item.evidenceId, item)\n }\n return {\n releaseId,\n environmentId: null,\n truncated,\n nodes: [...nodes.values()],\n entityProjections: [...entityProjections.values()],\n relationships: [...relationships.values()],\n evidenceClaims: [...evidenceClaims.values()],\n evidenceItems: [...evidenceItems.values()]\n }\n}\n\nexport interface ReleaseWorksetTransport {\n readonly load: (\n releaseId: ReleaseId,\n environmentId: EnvironmentId | null,\n signal: AbortSignal\n ) => Promise<ReleaseDeliveryGraphInspection>\n}\n\nexport const MAXIMUM_RELEASE_WORKSET_REQUEST_CONCURRENCY = MAXIMUM_RELEASE_ENVIRONMENT_REQUEST_CONCURRENCY\n\nconst isUnauthorizedFailure = Predicate.isTagged(\"UnauthorizedApiError\")\n\n/** Load every release/environment slice without saturating browser or server connection pools. */\nexport const loadReleaseWorksetInspections = async (\n releaseId: ReleaseId,\n environmentIds: ReadonlyArray<EnvironmentId>,\n signal: AbortSignal,\n transport: ReleaseWorksetTransport\n): Promise<ReadonlyArray<ReleaseDeliveryGraphInspection>> => {\n return loadReleaseEnvironmentSlices(\n environmentIds,\n (environmentId) => transport.load(releaseId, environmentId, signal)\n )\n}\n\nexport type ReleaseWorksetState =\n | { readonly _tag: \"idle\" }\n | {\n readonly _tag: \"loading\"\n readonly environmentScopeKey: string\n readonly releaseId: ReleaseId\n readonly sessionKey: string\n }\n | {\n readonly _tag: \"failed\"\n readonly environmentScopeKey: string\n readonly releaseId: ReleaseId\n readonly sessionKey: string\n }\n | {\n readonly _tag: \"ready\"\n readonly inspection: ReleaseDeliveryGraphInspection\n readonly environmentScopeKey: string\n readonly releaseId: ReleaseId\n readonly sessionKey: string\n }\n\n/** Generated-client transport for one authenticated bounded release graph. */\nexport const browserReleaseWorksetTransport: ReleaseWorksetTransport = {\n load: (releaseId, environmentId, signal) =>\n Effect.runPromise(\n Effect.gen(function*() {\n const client = yield* makeControlCenterApiClient()\n return yield* client.deliveryGraph.releaseSlice({\n params: { releaseId },\n query: environmentId === null ? {} : { environmentId }\n })\n }).pipe(Effect.provide(FetchHttpClient.layer)),\n { signal }\n )\n}\n\n/** Keep one release workset scoped to the exact authenticated browser session. */\nexport const useReleaseWorkset = (\n releaseId: ReleaseId,\n environmentIds: ReadonlyArray<EnvironmentId>,\n sessionKey: string | null,\n onSessionExpired: (sessionKey: string) => void,\n transport: ReleaseWorksetTransport = browserReleaseWorksetTransport\n): { readonly retry: () => void; readonly state: ReleaseWorksetState } => {\n const [requestRevision, setRequestRevision] = useState(0)\n const [state, setState] = useState<ReleaseWorksetState>({ _tag: \"idle\" })\n const environmentScopeKey = environmentIds.join(\":\")\n\n useEffect(() => {\n if (sessionKey === null) {\n setState({ _tag: \"idle\" })\n return\n }\n const abort = new AbortController()\n setState({ _tag: \"loading\", environmentScopeKey, releaseId, sessionKey })\n loadReleaseWorksetInspections(releaseId, environmentIds, abort.signal, transport).then(\n (inspections) => {\n if (!abort.signal.aborted) {\n setState({\n _tag: \"ready\",\n environmentScopeKey,\n inspection: aggregateReleaseWorksetInspections(releaseId, inspections),\n releaseId,\n sessionKey\n })\n }\n },\n (failure) => {\n if (!abort.signal.aborted) {\n if (isUnauthorizedFailure(failure)) onSessionExpired(sessionKey)\n setState({ _tag: \"failed\", environmentScopeKey, releaseId, sessionKey })\n }\n }\n )\n return () => abort.abort()\n }, [environmentScopeKey, onSessionExpired, releaseId, requestRevision, sessionKey, transport])\n\n const currentState: ReleaseWorksetState = sessionKey === null\n ? { _tag: \"idle\" }\n : state._tag === \"idle\" ||\n state.releaseId !== releaseId ||\n state.sessionKey !== sessionKey ||\n state.environmentScopeKey !== environmentScopeKey\n ? { _tag: \"loading\", environmentScopeKey, releaseId, sessionKey }\n : state\n\n return {\n retry: useCallback(() => setRequestRevision((revision) => revision + 1), []),\n state: currentState\n }\n}\n","import { LinkProvider } from \"@knpkv/rly/foundations\"\nimport { ServiceMark, WorksetCard } from \"@knpkv/rly/patterns\"\nimport { Button, Skeleton, StateLabel, StatePanel, Text } from \"@knpkv/rly/primitives\"\nimport { type ReactElement } from \"react\"\nimport { Link, useLocation, useNavigate } from \"react-router\"\n\nimport { browserReadableSessionKey, useBrowserSession } from \"../BrowserSession.js\"\nimport type { WorkspaceId } from \"../../domain/identifiers.js\"\nimport { WorkspaceEntityLink, workspaceEntityStateForHref } from \"../entities/WorkspaceEntityLink.js\"\nimport type { PortfolioReleasePresentation } from \"../portfolio/presentPortfolio.js\"\nimport {\n presentReleaseWorkset,\n releaseWorksetRelationshipEvidenceClaims,\n releaseWorksetRelationshipEvidenceIds,\n selectReleaseWorksetObject,\n selectReleaseWorksetRelationship,\n selectReleaseWorksetTrace,\n type SelectedReleaseWorksetObject,\n type SelectedReleaseWorksetTrace\n} from \"./presentReleaseWorkset.js\"\nimport { RelationshipDetailSheet } from \"./RelationshipDetailSheet.js\"\nimport { closeRelationshipDetailRoute, makeRelationshipDetailRouteState } from \"./relationshipDetailRoute.js\"\nimport styles from \"./ReleaseWorkset.module.css\"\nimport { useReleaseWorkset } from \"./useReleaseWorkset.js\"\n\nconst LoadingWorkset = (): ReactElement => (\n <div aria-busy=\"true\" aria-label=\"Loading release work\" className={styles.loading}>\n <Skeleton height=\"3rem\" />\n <Skeleton height=\"15rem\" />\n </div>\n)\n\n/** Inspectable destination for an Items result selected within its release context. */\nexport const SelectedReleaseWorksetObjectPanel = ({\n linkLocation,\n selectedObject,\n trace\n}: {\n readonly linkLocation?: RouterLocationParts\n readonly selectedObject: SelectedReleaseWorksetObject\n readonly trace?: SelectedReleaseWorksetTrace\n}): ReactElement => {\n return (\n <section aria-label={`Selected ${selectedObject.kind} ${selectedObject.label}`} className={styles.selected}>\n <div className={styles.selectedHeading}>\n <ServiceMark service={selectedObject.service} size=\"compact\" />\n <Text as=\"p\" variant=\"label\">\n Selected object · {selectedObject.label}\n </Text>\n <StateLabel label={selectedObject.status} size=\"compact\" tone={selectedObject.tone} />\n </div>\n <Text as=\"h3\" variant=\"section-title\">\n {selectedObject.title}\n </Text>\n <Text tone=\"secondary\" variant=\"meta\">\n {selectedObject.kind}\n </Text>\n <dl className={styles.selectedFacts}>\n {selectedObject.facts.map((fact) => (\n <div key={fact.label}>\n <dt>{fact.label}</dt>\n <dd>{fact.value}</dd>\n </div>\n ))}\n </dl>\n {trace === undefined ? null : (\n <div className={styles.trace}>\n <div className={styles.traceHeading}>\n <Text as=\"h4\" variant=\"label\">\n Delivery trace\n </Text>\n <StateLabel\n label={`${trace.relationships.length} relationship${trace.relationships.length === 1 ? \"\" : \"s\"}${trace.truncated ? \"+\" : \"\"}`}\n size=\"compact\"\n tone={trace.truncated ? \"caution\" : \"neutral\"}\n />\n </div>\n {trace.relationships.length === 0 ? (\n <Text tone=\"secondary\">No relationship touches this object in the current release slice.</Text>\n ) : (\n <ul className={styles.traceList}>\n {trace.relationships.map((relationship) => (\n <li key={relationship.id}>\n {relationship.other.service === null ? null : (\n <ServiceMark service={relationship.other.service} size=\"compact\" />\n )}\n <div className={styles.traceConnection}>\n <Text as=\"p\" variant=\"label\">\n {relationship.direction === \"incoming\" ? \"From\" : \"To\"} {relationship.other.label}\n </Text>\n {relationship.other.href === null ? (\n <Text tone=\"secondary\">{relationship.other.title}</Text>\n ) : (\n <Link\n state={\n linkLocation === undefined\n ? undefined\n : workspaceEntityStateForHref(relationship.other.href, linkLocation)\n }\n to={relationship.other.href}\n >\n {relationship.other.title}\n </Link>\n )}\n </div>\n <div className={styles.traceRelation}>\n <Text as=\"span\" tone=\"secondary\" variant=\"meta\">\n {relationship.kind}\n </Text>\n <StateLabel label={relationship.lifecycle} size=\"compact\" tone={relationship.tone} />\n </div>\n <Text as=\"span\" tone=\"secondary\" variant=\"meta\">\n {relationship.confidence} · {relationship.evidenceCount} evidence claim\n {relationship.evidenceCount === 1 ? \"\" : \"s\"}\n </Text>\n <Link\n aria-label={`Details for ${relationship.kind} ${relationship.direction} relationship with ${relationship.other.label}`}\n className={styles.traceDetails}\n state={makeRelationshipDetailRouteState(linkLocation?.state, selectedObject.id, relationship.id)}\n to={relationship.detailsHref}\n >\n Details\n </Link>\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n </section>\n )\n}\n\ninterface RouterLocationParts {\n readonly hash: string\n readonly pathname: string\n readonly search: string\n readonly state: unknown\n}\n\n/** Compatibility name retained for release-workset callers of the shared readable-session policy. */\nexport const releaseWorksetSessionKey = browserReadableSessionKey\n\n/** Render one server-backed release graph without substituting demo relationships. */\nexport const ReleaseWorkset = ({\n release,\n workspaceId\n}: {\n readonly release: PortfolioReleasePresentation\n readonly workspaceId: WorkspaceId\n}): ReactElement => {\n const browserSession = useBrowserSession()\n const location = useLocation()\n const navigate = useNavigate()\n const sessionKey = releaseWorksetSessionKey(browserSession.state)\n const controller = useReleaseWorkset(\n release.id,\n release.targetEnvironmentIds,\n sessionKey,\n browserSession.invalidateSession\n )\n if (sessionKey === null || controller.state._tag === \"idle\" || controller.state._tag === \"loading\") {\n return <LoadingWorkset />\n }\n if (controller.state._tag === \"failed\") {\n return (\n <StatePanel\n action={<Button onClick={controller.retry}>Try again</Button>}\n description=\"Control Center could not read the delivery graph for this release. Saved release facts remain unchanged.\"\n title=\"Release work unavailable\"\n tone=\"caution\"\n />\n )\n }\n\n const workset = presentReleaseWorkset(controller.state.inspection, workspaceId, release.stages)\n const searchParams = new URLSearchParams(location.search)\n const selectedObjectId = searchParams.get(\"object\")\n const selectedRelationshipId = searchParams.get(\"relationship\")\n const selectedObject = selectReleaseWorksetObject(controller.state.inspection, selectedObjectId)\n const selectedTrace = selectReleaseWorksetTrace(controller.state.inspection, workspaceId, selectedObjectId)\n const selectedRelationship = selectReleaseWorksetRelationship(\n controller.state.inspection,\n selectedObjectId,\n selectedRelationshipId\n )\n const selectedEvidenceIds = releaseWorksetRelationshipEvidenceIds(controller.state.inspection, selectedRelationship)\n const selectedEvidenceClaims = releaseWorksetRelationshipEvidenceClaims(\n controller.state.inspection,\n selectedRelationship\n )\n const closeRelationshipDetails = (): void => {\n if (selectedObject === null || selectedRelationship === null) return\n closeRelationshipDetailRoute(navigate, location, selectedObject.id, selectedRelationship.relationshipId)\n }\n return (\n <>\n <div className={styles.root}>\n <div className={styles.context}>\n <div className={styles.contextGroup}>\n <Text as=\"h3\" variant=\"label\">\n Environment\n </Text>\n {release.targetEnvironmentIds.length === 0 ? (\n <Text tone=\"secondary\">No target environment recorded.</Text>\n ) : (\n <div className={styles.tags}>\n {release.targetEnvironmentIds.map((environmentId) => (\n <StateLabel\n key={environmentId}\n label={`Unknown target · ${environmentId.slice(-4)}`}\n size=\"compact\"\n title={`Environment ${environmentId}; provider metadata unavailable`}\n tone=\"neutral\"\n />\n ))}\n </div>\n )}\n </div>\n <div className={styles.contextGroup}>\n <div className={styles.contextHeading}>\n <ServiceMark service=\"confluence\" size=\"compact\" />\n <Text as=\"h3\" variant=\"label\">\n Runbook\n </Text>\n </div>\n {workset.runbooks.length === 0 ? (\n <Text tone=\"secondary\">No runbook linked.</Text>\n ) : (\n <div className={styles.runbooks}>\n {workset.runbooks.map((runbook) => (\n <Link\n className={styles.runbook}\n key={runbook.id}\n state={workspaceEntityStateForHref(runbook.href, location)}\n to={runbook.href}\n >\n <strong>{runbook.title}</strong>\n <span>{runbook.reference}</span>\n </Link>\n ))}\n </div>\n )}\n </div>\n {workset.truncated ? (\n <StateLabel label=\"Bounded view · more records exist\" size=\"compact\" tone=\"caution\" />\n ) : null}\n {selectedObject === null || selectedTrace === null ? null : (\n <SelectedReleaseWorksetObjectPanel\n linkLocation={location}\n selectedObject={selectedObject}\n trace={selectedTrace}\n />\n )}\n </div>\n <LinkProvider component={WorkspaceEntityLink}>\n <WorksetCard\n gaps={workset.gaps}\n heading={`${release.serviceName} release work`}\n jiraItems={workset.jiraItems}\n pipelines={workset.pipelines}\n pullRequestGroups={workset.pullRequestGroups}\n />\n </LinkProvider>\n </div>\n <RelationshipDetailSheet\n claims={selectedEvidenceClaims}\n evidenceIds={selectedEvidenceIds}\n onClose={closeRelationshipDetails}\n onSessionExpired={browserSession.invalidateSession}\n relationship={selectedRelationship}\n sessionKey={sessionKey}\n />\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,n as t,t as n}from"./jsx-runtime-n5LQ9ujS.js";import{E as r,n as i,r as a,t as o,v as s}from"./Dialog-DwSIPb-B-DVn37afM.js";import{i as c,n as l,o as u,r as d,s as f}from"./index-DLoOV6Hp.js";import{v as p}from"./patterns-DEbg7R-A-Cw0A2uKS.js";import{K as m,zt as h}from"./client-OmvShYdC.js";import{a as g,c as _,i as v,n as y,o as b,r as x}from"./serviceOnboarding-B9pvdyWf.js";import{i as S,t as C}from"./connectionTestTransport-c25QXx7A.js";var w=e(t(),1),T={form:`_form_piwc3_1`,intro:`_intro_piwc3_2`,fallback:`_fallback_piwc3_3`,resources:`_resources_piwc3_16`,actions:`_actions_piwc3_22`,error:`_error_piwc3_29`},E=(e,t)=>{switch(e.kind){case`integer`:return{_tag:`integer`,key:e.key,value:Number(t)};case`secret`:return{_tag:`secret`,key:e.key,value:t};case`text`:case`url`:return{_tag:e.kind,key:e.key,value:t}}},D=(e,t)=>e.configurationFields.flatMap(e=>{let n=t.get(e.key)??e.defaultValue;return n===null&&!e.required?[]:[E(e,n??``)]}),O=n(),k=(e,t)=>e.find(e=>e.profileId===t),A=(e,t)=>e.status===`valid`&&(t.preferredSiteId===null||e.cloudId===t.preferredSiteId)&&t.providers.every(t=>e.providers.includes(t)),j=e=>e.status===`expired`?`expired`:e.providers.includes(`jira`)?e.providers.includes(`confluence`)?`Jira + Confluence`:`Jira only`:`Confluence only`,M=({catalogs:e,isSubmitting:t,onCancel:n,onStartOAuth:r,onSubmit:i,profiles:a,profilesState:s,setupIntent:u})=>{let d=e.find(({providerId:e})=>e===`jira`),f=e.find(({providerId:e})=>e===`confluence`),p=u.providers.includes(`jira`),m=u.providers.includes(`confluence`),[h,g]=(0,w.useState)(`Atlassian workspace`),[_,v]=(0,w.useState)(`oauth`),[y,b]=(0,w.useState)(``),[x,C]=(0,w.useState)(``),[E,M]=(0,w.useState)(``),[N,P]=(0,w.useState)(``),[F,ee]=(0,w.useState)(``),[I,L]=(0,w.useState)(``),[R,te]=(0,w.useState)(``),[z,ne]=(0,w.useState)(``),[B,V]=(0,w.useState)(!1),[H,U]=(0,w.useState)(null),[W,G]=(0,w.useState)(``),[K,q]=(0,w.useState)(``),[J,Y]=(0,w.useState)(null),X=(0,w.useRef)(null);(0,w.useEffect)(()=>()=>X.current?.abort(),[]),(0,w.useEffect)(()=>{if(_!==`oauth`)return;let e=k(a,y);if(e!==void 0&&A(e,u))return;let t=u.preferredProfileId===null?void 0:k(a,u.preferredProfileId),n=t!==void 0&&A(t,u)?t:a.find(e=>A(e,u));b(n?.profileId??``)},[_,y,a,u]),(0,w.useEffect)(()=>{u.preferredSiteId!==null&&M(u.preferredSiteId)},[u.preferredSiteId]),(0,w.useEffect)(()=>{if(_!==`oauth`)return;let e=k(a,y);e!==void 0&&(C(e.siteUrl),M(e.cloudId))},[_,y,a]);let Z=e=>{if(e.preventDefault(),Y(null),p&&d===void 0||m&&f===void 0){Y(`The installed Atlassian adapters are unavailable.`);return}let t=h.trim(),n=x.trim(),r=E.trim(),o=N.trim(),s=F.trim(),c=I.trim();if(t.length===0||n.length===0||r.length===0||p&&o.length===0||m&&(s.length===0||c.length===0)){Y(p&&m?`Add the Atlassian site identity, Jira project, Confluence space, and readable health page.`:p?`Add the Atlassian site identity and Jira project.`:`Add the Atlassian site identity, Confluence space, and readable health page.`);return}let l=_===`oauth`?[[`authMode`,`oauth`],[`oauthProfileId`,y]]:[[`authMode`,`api-token`],[`email`,R.trim()],[`apiToken`,z]],g=k(a,y);if(_===`oauth`&&(g===void 0||!A(g,u))){Y(`Choose a valid profile for the products being connected, or use an API token instead.`);return}if(_===`api-token`&&(R.trim().length===0||z.length===0)){Y(`Add the Atlassian email and API token.`);return}if(_===`api-token`&&p&&u.preferredSiteId!==null){Y(`Use a matching OAuth profile to add a Jira project to this Atlassian site.`);return}let v=[...l,[`webBaseUrl`,n],[`siteBaseUrl`,n],[`siteId`,r],[`projectId`,o],[`spaceId`,s],[`probePageId`,c]],b=new Map(v);i([...p&&d!==void 0?[{catalog:d,displayName:`${t} · Jira`,values:D(d,b)}]:[],...m&&f!==void 0?[{catalog:f,displayName:`${t} · Confluence`,values:D(f,b)}]:[]]).then(e=>{e||Y(`Some Atlassian services could not be connected. Review the cards below and retry.`)})},re=e=>{if(u.requestedOAuthProviders===null)return;Y(null),U(null),V(!0),X.current?.abort();let t=new AbortController;X.current=t,r(u.requestedOAuthProviders,t.signal,e).then(e=>{if(!t.signal.aborted){if(e._tag===`configuration-required`){U(e.callbackUrl),Y(`OAuth needs a one-time local client configuration before sign-in.`),V(!1);return}if(!S(e.authorizationUrl,{preferredSiteId:u.preferredSiteId,providers:u.providers})){Y(`Control Center could not preserve this Atlassian setup across sign-in. Try again.`),V(!1);return}window.location.assign(e.authorizationUrl)}},()=>{t.signal.aborted||(Y(`Control Center could not start Atlassian sign-in. Try again.`),V(!1))})},ie=()=>{let e=W.trim();if(e.length===0||K.length===0){Y(`Add the Atlassian OAuth client ID and client secret.`);return}re({clientId:e,clientSecret:K})},Q=()=>{X.current?.abort(),X.current=null,V(!1),v(`api-token`)},$=s===`loading`?`Finding local Atlassian OAuth profiles…`:s===`failed`?`OAuth profile discovery is unavailable. API token fallback remains available.`:s===`ready`?`${a.filter(e=>A(e,u)).length} ${p&&m?`shared `:``}OAuth ${a.filter(e=>A(e,u)).length===1?`profile`:`profiles`} ready`:`OAuth profiles stay on this machine and are shared by Jira and Confluence.`;return(0,O.jsxs)(`form`,{className:T.form,onSubmit:Z,children:[(0,O.jsxs)(`div`,{className:T.intro,children:[(0,O.jsx)(c,{as:`h3`,variant:`card-title`,children:p&&m?`One identity. Jira and Confluence together.`:p?`Connect Jira with your Atlassian identity.`:`Connect Confluence with your Atlassian identity.`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`OAuth is preferred. Control Center reads the selected local profile only inside the server runtime.`}),(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:$})]}),(0,O.jsx)(l,{label:`Account name`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,maxLength:90,onChange:e=>g(e.currentTarget.value),value:h})}),_===`oauth`?(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(o,{disabled:u.requestedOAuthProviders===null,loading:B,onClick:()=>re(),type:`button`,variant:`primary`,children:`Sign in with Atlassian`}),H===null?null:(0,O.jsxs)(`div`,{className:T.fallback,children:[(0,O.jsxs)(c,{as:`p`,tone:`secondary`,variant:`meta`,children:[`Create an OAuth 2.0 integration in Atlassian Developer Console and add `,(0,O.jsx)(`code`,{children:H}),`as its callback URL. The credentials stay on this Control Center machine.`]}),(0,O.jsx)(l,{label:`OAuth client ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,autoComplete:`off`,maxLength:500,onChange:e=>G(e.currentTarget.value),value:W})}),(0,O.jsx)(l,{label:`OAuth client secret`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,autoComplete:`off`,maxLength:16384,onChange:e=>q(e.currentTarget.value),type:`password`,value:K})}),(0,O.jsx)(o,{loading:B,onClick:ie,type:`button`,variant:`primary`,children:`Save OAuth app and continue`})]}),(0,O.jsx)(l,{label:`OAuth profile`,required:!0,size:`compact`,children:e=>(0,O.jsxs)(`select`,{...e,onChange:e=>b(e.currentTarget.value),value:y,children:[(0,O.jsx)(`option`,{value:``,children:`Choose a profile already on this machine`}),a.filter(e=>u.preferredSiteId===null||e.cloudId===u.preferredSiteId).map(e=>(0,O.jsxs)(`option`,{disabled:!A(e,u),value:e.profileId,children:[e.name,` · `,j(e)]},e.profileId))]})}),p&&u.preferredSiteId!==null?null:(0,O.jsx)(o,{onClick:Q,type:`button`,variant:`quiet`,children:`Use API token instead`})]}):(0,O.jsxs)(`div`,{className:T.fallback,children:[(0,O.jsx)(l,{label:`Atlassian email`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,autoComplete:`username`,onChange:e=>te(e.currentTarget.value),type:`email`,value:R})}),(0,O.jsx)(l,{label:`API token`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,autoComplete:`off`,maxLength:16384,onChange:e=>ne(e.currentTarget.value),type:`password`,value:z})}),(0,O.jsx)(o,{onClick:()=>v(`oauth`),type:`button`,variant:`quiet`,children:`Use OAuth profile`})]}),(0,O.jsx)(l,{label:`Atlassian site URL`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,disabled:_===`oauth`,onChange:e=>C(e.currentTarget.value),placeholder:`https://team.atlassian.net/`,type:`url`,value:x})}),(0,O.jsx)(l,{description:`The stable Atlassian cloud ID; filled from OAuth when available.`,label:`Site ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,disabled:_===`oauth`||u.preferredSiteId!==null,onChange:e=>M(e.currentTarget.value),value:E})}),p?(0,O.jsx)(l,{description:`The immutable Jira project ID followed by this connection.`,label:`Jira project ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,onChange:e=>P(e.currentTarget.value),value:N})}):null,m?(0,O.jsxs)(`div`,{className:T.resources,children:[(0,O.jsx)(l,{label:`Confluence space ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,onChange:e=>ee(e.currentTarget.value),value:F})}),(0,O.jsx)(l,{description:`A readable page used only for the connection check.`,label:`Health page ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,onChange:e=>L(e.currentTarget.value),value:I})})]}):null,J===null?null:(0,O.jsx)(c,{as:`p`,className:T.error,role:`alert`,variant:`body`,children:J}),(0,O.jsxs)(`div`,{className:T.actions,children:[(0,O.jsx)(o,{disabled:t,onClick:n,type:`button`,variant:`secondary`,children:`Cancel`}),(0,O.jsx)(o,{loading:t,type:`submit`,variant:`primary`,children:`Connect Atlassian`})]})]})},N={form:`_form_1gjxb_1`,intro:`_intro_1gjxb_6`,resources:`_resources_1gjxb_11`,discoveryActions:`_discoveryActions_1gjxb_22`,resourcePanelHeading:`_resourcePanelHeading_1gjxb_23`,resourcePanel:`_resourcePanel_1gjxb_23`,choiceList:`_choiceList_1gjxb_44`,choice:`_choice_1gjxb_44`,actions:`_actions_1gjxb_58`,error:`_error_1gjxb_65`},P=20,F=e=>[...new Set(e.split(/[\n,]/u).map(e=>e.trim()).filter(e=>e.length>0))],ee=(e,t)=>[...new Set([...e,...F(t)])],I=(e,t)=>[...new Set([...e,...t])].sort((e,t)=>e.localeCompare(t)),L=(e,t)=>{let n=t.trim().toLocaleLowerCase();return n.length===0?e:e.filter(e=>e.toLocaleLowerCase().includes(n))},R=({accountName:e,codeCommit:t,codePipeline:n,pipelineNames:r,profile:i,region:a,repositoryNames:o})=>[...o.map(n=>({catalog:t,displayName:`${e} · ${n}`,values:D(t,new Map([[`profile`,i],[`region`,a],[`repositoryName`,n]]))})),...r.map(t=>({catalog:n,displayName:`${e} · ${t}`,values:D(n,new Map([[`profile`,i],[`region`,a],[`pipelineName`,t]]))}))],te=(e,t)=>{switch(t){case`loading`:return`Discovering local AWS profiles…`;case`ready`:return`${e} local AWS ${e===1?`profile`:`profiles`} detected`;case`failed`:return`Profile discovery unavailable. Enter a profile manually.`;case`idle`:return`AWS profiles are discovered locally by the Control Center server.`}},z=(e,t)=>t===`authorization`?`${e} access was denied. Select names manually or update this profile's permissions.`:`${e} discovery is unavailable (${t}). Select names manually or refresh.`,ne=({label:e,query:t,selected:n,service:r,setQuery:i,setSelected:o})=>{if(r._tag===`failed`){let t=[...n].sort((e,t)=>e.localeCompare(t));return(0,O.jsxs)(`div`,{className:N.resourcePanel,children:[(0,O.jsxs)(`div`,{className:N.resourcePanelHeading,children:[(0,O.jsx)(c,{as:`h4`,variant:`card-title`,children:e}),(0,O.jsx)(a,{label:`${n.size} selected`,size:`compact`,tone:`neutral`})]}),(0,O.jsx)(c,{as:`p`,className:N.error,role:`status`,variant:`body`,children:z(e===`Repositories`?`CodeCommit`:`CodePipeline`,r.failureClass)}),t.length===0?null:(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Preserved from the previous discovery. Clear any resource you no longer want to connect.`}),(0,O.jsx)(`div`,{className:N.choiceList,children:t.map(e=>(0,O.jsxs)(`label`,{className:N.choice,children:[(0,O.jsx)(`input`,{checked:!0,onChange:()=>{let t=new Set(n);t.delete(e),o(t)},type:`checkbox`}),(0,O.jsx)(`span`,{children:e})]},e))})]})]})}let s=I(r.names,n),u=L(s,t);return(0,O.jsxs)(`div`,{className:N.resourcePanel,children:[(0,O.jsxs)(`div`,{className:N.resourcePanelHeading,children:[(0,O.jsx)(c,{as:`h4`,variant:`card-title`,children:e}),(0,O.jsx)(a,{label:`${n.size} selected`,size:`compact`,tone:`neutral`})]}),s.length===0?(0,O.jsxs)(c,{tone:`secondary`,variant:`body`,children:[`No `,e.toLocaleLowerCase(),` were found in this region.`]}):(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(l,{label:`Search ${e.toLocaleLowerCase()}`,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,onChange:e=>i(e.currentTarget.value),type:`search`,value:t})}),(0,O.jsx)(`div`,{className:N.choiceList,children:u.map(e=>(0,O.jsxs)(`label`,{className:N.choice,children:[(0,O.jsx)(`input`,{checked:n.has(e),onChange:t=>{let r=new Set(n);t.currentTarget.checked?r.add(e):r.delete(e),o(r)},type:`checkbox`}),(0,O.jsx)(`span`,{children:e})]},e))}),u.length===0?(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`No matching resources.`}):null,r.truncated?(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Showing the first 20 names. Use manual entry for another name.`}):null]})]})},B=({awsProfiles:e,awsProfilesState:t,catalogs:n,isSubmitting:r,onCancel:i,onDiscover:a,onSubmit:s})=>{let u=n.find(({providerId:e})=>e===`codecommit`),d=n.find(({providerId:e})=>e===`codepipeline`),[f,p]=(0,w.useState)(`AWS account`),[m,h]=(0,w.useState)(`default`),[g,_]=(0,w.useState)(``),[v,y]=(0,w.useState)(``),[b,x]=(0,w.useState)(``),[S,C]=(0,w.useState)(new Set),[T,E]=(0,w.useState)(new Set),[D,k]=(0,w.useState)(``),[A,j]=(0,w.useState)(``),[M,F]=(0,w.useState)(!0),[I,L]=(0,w.useState)({_tag:`idle`}),[z,B]=(0,w.useState)(null),V=(0,w.useRef)(null);(0,w.useEffect)(()=>()=>V.current?.abort(),[]),(0,w.useEffect)(()=>{let t=e.find(e=>e.profile===m)?.region;t!=null&&_(e=>e.trim().length===0?t:e)},[e,m]);let H=()=>{V.current?.abort(),V.current=null,L({_tag:`idle`}),C(new Set),E(new Set)};return(0,O.jsxs)(`form`,{className:N.form,onSubmit:e=>{if(e.preventDefault(),B(null),u===void 0||d===void 0){B(`The installed AWS adapters are unavailable.`);return}let t=f.trim(),n=m.trim(),r=g.trim();if(t.length===0||n.length===0||r.length===0){B(`Add an account name, AWS profile, and region.`);return}let i=ee(S,M?v:``),a=ee(T,M?b:``);if(i.length===0&&a.length===0){B(`Select or manually add at least one repository or pipeline to follow.`);return}if(i.length>P||a.length>P){B(`Follow at most ${P} repositories and pipelines per account.`);return}if([...i,...a].some(e=>e.length>100)){B(`Repository and pipeline names must be 100 characters or fewer.`);return}s(R({accountName:t,codeCommit:u,codePipeline:d,pipelineNames:a,profile:n,region:r,repositoryNames:i})).then(e=>{e||B(`Some AWS resources could not be connected. Review the cards below and retry.`)})},children:[(0,O.jsxs)(`div`,{className:N.intro,children:[(0,O.jsx)(c,{as:`h3`,variant:`card-title`,children:`One account. Many delivery streams.`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`Choose one local AWS profile and region, verify its account, then select CodeCommit repositories and CodePipeline pipelines.`}),(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:te(e.length,t)})]}),(0,O.jsx)(l,{label:`Account name`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,maxLength:90,onChange:e=>p(e.currentTarget.value),value:f})}),(0,O.jsx)(l,{label:`AWS profile`,required:!0,size:`compact`,children:t=>(0,O.jsx)(`input`,{...t,list:e.length>0?`aws-account-profiles`:void 0,maxLength:200,onChange:t=>{let n=t.currentTarget.value,r=e.find(e=>e.profile===n)?.region;h(n),_(r??``),H()},value:m})}),(0,O.jsx)(l,{label:`AWS region`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,maxLength:100,onChange:e=>{_(e.currentTarget.value),H()},value:g})}),(0,O.jsxs)(`div`,{className:N.discoveryActions,children:[(0,O.jsx)(o,{loading:I._tag===`loading`,onClick:()=>{B(null);let e={profile:m.trim(),region:g.trim()};if(e.profile.length===0||e.region.length===0){B(`Add an AWS profile and region before testing discovery.`);return}V.current?.abort();let t=new AbortController;V.current=t,L({_tag:`loading`}),a(e,t.signal).then(e=>{t.signal.aborted||(V.current=null,L({_tag:`ready`,response:e}))},()=>{t.signal.aborted||(V.current=null,L({_tag:`failed`}))})},type:`button`,variant:`secondary`,children:I._tag===`ready`?`Refresh discovery`:`Test & discover`}),I._tag===`ready`?(0,O.jsxs)(c,{tone:`secondary`,variant:`body`,children:[`Verified AWS account `,I.response.accountId]}):I._tag===`failed`?(0,O.jsx)(c,{as:`p`,className:N.error,role:`alert`,variant:`body`,children:`Account verification failed. Check the profile and region, or enter resource names manually.`}):null]}),I._tag===`ready`?(0,O.jsxs)(`div`,{className:N.resources,children:[(0,O.jsx)(ne,{label:`Repositories`,query:D,selected:S,service:I.response.codeCommit,setQuery:k,setSelected:C}),(0,O.jsx)(ne,{label:`Pipelines`,query:A,selected:T,service:I.response.codePipeline,setQuery:j,setSelected:E})]}):null,(0,O.jsx)(`div`,{children:(0,O.jsx)(o,{onClick:()=>F(e=>!e),type:`button`,variant:`quiet`,children:M?`Hide manual name entry`:`Enter resource names manually`})}),M?(0,O.jsxs)(`div`,{className:N.resources,children:[(0,O.jsx)(l,{description:`Comma or line separated. Maximum 20 including selected names.`,label:`Repository names`,size:`compact`,children:e=>(0,O.jsx)(`textarea`,{...e,maxLength:4096,onChange:e=>y(e.currentTarget.value),placeholder:`payments-api\\nrisk-engine`,value:v})}),(0,O.jsx)(l,{description:`Comma or line separated. Maximum 20 including selected names.`,label:`Pipeline names`,size:`compact`,children:e=>(0,O.jsx)(`textarea`,{...e,maxLength:4096,onChange:e=>x(e.currentTarget.value),placeholder:`payments-production\\nrisk-production`,value:b})})]}):null,e.length>0?(0,O.jsx)(`datalist`,{id:`aws-account-profiles`,children:e.map(e=>(0,O.jsx)(`option`,{label:e.region??`Region not configured`,value:e.profile},e.profile))}):null,z===null?null:(0,O.jsx)(c,{as:`p`,className:N.error,role:`alert`,variant:`body`,children:z}),(0,O.jsxs)(`div`,{className:N.actions,children:[(0,O.jsx)(o,{disabled:r,onClick:i,type:`button`,variant:`secondary`,children:`Cancel`}),(0,O.jsx)(o,{loading:r,type:`submit`,variant:`primary`,children:`Connect AWS account`})]})]})},V={page:`_page_1ib7n_1`,heading:`_heading_1ib7n_6`,grid:`_grid_1ib7n_12`,accounts:`_accounts_1ib7n_18`,accountCard:`_accountCard_1ib7n_19`,accountIdentity:`_accountIdentity_1ib7n_20`,resourceList:`_resourceList_1ib7n_21`,resource:`_resource_1ib7n_21`,sectionHeading:`_sectionHeading_1ib7n_23`,accountGrid:`_accountGrid_1ib7n_39`,accountHeading:`_accountHeading_1ib7n_44`,resourceHeading:`_resourceHeading_1ib7n_45`,accountActions:`_accountActions_1ib7n_46`,resourceActions:`_resourceActions_1ib7n_47`,card:`_card_1ib7n_74`,cardHeading:`_cardHeading_1ib7n_80`,cardAction:`_cardAction_1ib7n_81`,synchronization:`_synchronization_1ib7n_88`,syncState:`_syncState_1ib7n_89`,syncActions:`_syncActions_1ib7n_94`,connectionIdentity:`_connectionIdentity_1ib7n_100`,testEvidence:`_testEvidence_1ib7n_107`,identity:`_identity_1ib7n_116`,setupForm:`_setupForm_1ib7n_121`,setupActions:`_setupActions_1ib7n_126`,setupError:`_setupError_1ib7n_133`,identifier:`_identifier_1ib7n_137`},H=e=>m(e.checkedAt),U=({state:e})=>{if(e===void 0||e._tag===`testing`)return null;if(e._tag===`request-failed`)return(0,O.jsxs)(`div`,{"aria-live":`polite`,className:V.testEvidence,role:`status`,children:[(0,O.jsx)(a,{label:`Test failed`,tone:`critical`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`Control Center could not complete the test. Check the server and try again.`})]});let t=e.result,n=H(t);return(0,O.jsxs)(`div`,{"aria-live":`polite`,className:V.testEvidence,role:`status`,children:[(0,O.jsx)(a,{label:t._tag===`healthy`?`Connection healthy`:`Test failed`,tone:t._tag===`healthy`?`positive`:`critical`}),t._tag===`healthy`?(0,O.jsxs)(`div`,{className:V.identity,children:[(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:t.identity.label}),(0,O.jsx)(c,{as:`span`,variant:`card-title`,children:t.identity.displayName}),(0,O.jsx)(c,{className:V.identifier,tone:`secondary`,variant:`body`,children:t.identity.providerImmutableId})]}):(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:t.safeMessage}),(0,O.jsxs)(c,{tone:`secondary`,variant:`meta`,children:[`Checked `,(0,O.jsx)(`time`,{dateTime:n,children:n}),` · `,t.latencyMilliseconds,` ms`]})]})},W=e=>{switch(e){case`never`:return{label:`Never synchronized`,tone:`neutral`};case`running`:return{label:`Synchronizing`,tone:`progress`};case`synchronized`:return{label:`Synchronized`,tone:`positive`};case`source-unavailable`:return{label:`Source unavailable`,tone:`critical`};case`interrupted`:return{label:`Interrupted`,tone:`critical`}}},G=({synchronization:e})=>{let t=W(e.result);return(0,O.jsxs)(`div`,{className:V.syncState,children:[(0,O.jsx)(a,{label:t.label,size:`compact`,tone:t.tone}),(0,O.jsxs)(c,{tone:`secondary`,variant:`meta`,children:[`Last attempt: `,e.lastAttemptAt===null?`never`:String(e.lastAttemptAt),` · Last success: `,e.lastSuccessAt===null?`never`:String(e.lastSuccessAt),` · ${e.pagesCommitted} ${e.pagesCommitted===1?`page`:`pages`}`]})]})},K=({canSynchronize:e,onRefresh:t,onSynchronize:n,state:r})=>{if(r===void 0)return null;let i=r._tag===`ready`?r.synchronization:r._tag===`syncing`?r.previous:null;return(0,O.jsxs)(`div`,{className:V.synchronization,children:[i===null?null:(0,O.jsx)(G,{synchronization:i}),r._tag===`loading`?(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Loading synchronization state…`}):null,r._tag===`failed`?(0,O.jsx)(c,{as:`p`,className:V.setupError,role:`alert`,variant:`body`,children:`Synchronization state is unavailable.`}):null,(0,O.jsxs)(`div`,{className:V.syncActions,children:[(0,O.jsx)(o,{disabled:!e||r._tag===`loading`||r._tag===`syncing`,loading:r._tag===`syncing`,onClick:n,variant:`secondary`,children:`Sync now`}),r._tag===`failed`?(0,O.jsx)(o,{onClick:t,variant:`quiet`,children:`Refresh state`}):null]})]})},q=(e,t)=>{if(!e.isEnabled)return{label:`Disabled`,tone:`neutral`};if(t?._tag===`testing`)return{label:`Checking`,tone:`progress`};if(t?._tag===`result`)return t.result._tag===`healthy`?{label:`Healthy`,tone:`positive`}:{label:`Unavailable`,tone:`critical`};if(e.health===null)return{label:`Not checked`,tone:`neutral`};switch(e.health._tag){case`healthy`:return{label:`Healthy`,tone:`positive`};case`degraded`:return{label:`Degraded`,tone:`caution`};case`unavailable`:return{label:`Unavailable`,tone:`critical`};case`disabled`:return{label:`Not checked`,tone:`neutral`}}},J=e=>{switch(e){case`codecommit`:return`Repository`;case`codepipeline`:return`Pipeline`;case`jira`:return`Project`;case`confluence`:return`Space`;case`clockify`:return`Workspace`}},Y=({account:e,canConfigure:t,connections:n,enablementStates:r,onAdd:i,onRefreshSynchronization:s,onSetEnabled:l,onSynchronize:u,onTest:f,synchronizationStates:m,testStates:h})=>(0,O.jsxs)(d,{as:`article`,className:V.accountCard,padding:`default`,shape:`grouped`,children:[(0,O.jsxs)(`div`,{className:V.accountHeading,children:[(0,O.jsxs)(`div`,{className:V.accountIdentity,children:[(0,O.jsxs)(c,{as:`h2`,variant:`section-title`,children:[e.providerFamily===`aws`?`AWS account`:e.providerFamily===`atlassian`?`Atlassian site`:`Provider account`,` `,e.displayName]}),(0,O.jsxs)(c,{className:V.identifier,tone:`secondary`,variant:`meta`,children:[`Verified identity · `,e.providerImmutableId]})]}),(0,O.jsx)(a,{label:`${e.resources.length} ${e.resources.length===1?`resource`:`resources`}`,size:`compact`,tone:`positive`})]}),(0,O.jsx)(`div`,{className:V.resourceList,children:e.resources.map(e=>{let i=n.find(t=>t.followedResourceId===e.followedResourceId),d=i===void 0?void 0:h.get(i.pluginConnectionId),g=i===void 0?void 0:r.get(i.pluginConnectionId),_=i===void 0?{label:`Followed`,tone:`neutral`}:q(i,d),v=d?._tag===`testing`,y=g===`changing`;return(0,O.jsxs)(`div`,{className:V.resource,children:[(0,O.jsxs)(`div`,{className:V.resourceHeading,children:[(0,O.jsxs)(`div`,{className:V.connectionIdentity,children:[(0,O.jsx)(p,{service:e.providerId,size:`compact`}),(0,O.jsxs)(`div`,{className:V.identity,children:[(0,O.jsx)(c,{as:`h3`,variant:`card-title`,children:e.displayName}),(0,O.jsxs)(c,{className:V.identifier,tone:`secondary`,variant:`meta`,children:[J(e.providerId),` · `,e.providerImmutableId]})]})]}),(0,O.jsx)(a,{label:_.label,size:`compact`,tone:_.tone})]}),i===void 0?null:(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(U,{state:d}),(0,O.jsx)(K,{canSynchronize:t&&i.isEnabled,onRefresh:()=>s(i.pluginConnectionId),onSynchronize:()=>u(i.pluginConnectionId),state:m.get(i.pluginConnectionId)}),(0,O.jsxs)(`div`,{className:V.resourceActions,children:[(0,O.jsx)(o,{disabled:!t||y||v||!i.isEnabled,loading:v,onClick:()=>f(i.pluginConnectionId),variant:`secondary`,children:`Test`}),(0,O.jsx)(o,{disabled:!t||y,loading:y,onClick:()=>l(i.pluginConnectionId,!i.isEnabled),variant:`quiet`,children:i.isEnabled?`Disable`:`Enable`})]}),g===`request-failed`?(0,O.jsx)(c,{as:`p`,className:V.setupError,role:`alert`,variant:`body`,children:`Control Center could not change this service. Refresh and try again.`}):null]})]},e.followedResourceId)})}),e.providerFamily===`aws`?(0,O.jsxs)(`div`,{className:V.accountActions,children:[(0,O.jsx)(o,{disabled:!t,onClick:()=>i(`codecommit`,e.providerImmutableId),variant:`secondary`,children:`Add repository`}),(0,O.jsx)(o,{disabled:!t,onClick:()=>i(`codepipeline`,e.providerImmutableId),variant:`secondary`,children:`Add pipeline`})]}):e.providerFamily===`atlassian`?(0,O.jsxs)(`div`,{className:V.accountActions,children:[(0,O.jsx)(o,{disabled:!t,onClick:()=>i(`jira`,e.providerImmutableId),variant:`secondary`,children:`Add Jira project`}),(0,O.jsx)(o,{disabled:!t,onClick:()=>i(`confluence`,e.providerImmutableId),variant:`secondary`,children:`Add Confluence space`})]}):null]}),X=e=>`${e.catalog.providerId}\0${e.displayName}`,Z=[`jira`,`confluence`],re={preferredProfileId:null,preferredSiteId:null,providers:Z,requestedOAuthProviders:Z},ie=e=>{let t=Z.filter(t=>!e.some(e=>e.providerId===t));return t.length===0?Z:t},Q=(e,t,n)=>n.length===1&&Z.some(r=>!n.includes(r)&&e.some(e=>e.providerId===r)&&t.some(e=>!e.profileId.startsWith(`legacy:`)&&e.providers.includes(r))),$=(e,t)=>t.length===1&&Z.some(n=>!t.includes(n)&&e.some(e=>e.providerId===n)),ae=(e,t)=>({preferredProfileId:null,preferredSiteId:null,providers:t!==void 0&&e.some(({providerId:e})=>e===t)?[t]:ie(e),requestedOAuthProviders:null}),oe=(e,t,n)=>{if(e.requestedOAuthProviders!==null)return e;let r=$(t,e.providers);if(r&&(n._tag===`idle`||n._tag===`loading`))return e;let i=n._tag===`ready`?n.profiles:[];return{...e,requestedOAuthProviders:r&&n._tag===`failed`||Q(t,i,e.providers)?Z:e.providers}},se=({canConfigure:e,canTest:t,connection:n,enablementState:r,onConfigure:i,onRefreshSynchronization:s,onSetEnabled:l,onSynchronize:u,onTest:f,synchronizationState:m,testState:h})=>{let g=h?._tag===`testing`,_=h!==void 0&&h._tag!==`testing`,v=r===`changing`,y=q(n,h);return(0,O.jsxs)(d,{as:`article`,className:V.card,padding:`default`,shape:`grouped`,children:[(0,O.jsxs)(`div`,{className:V.cardHeading,children:[(0,O.jsxs)(`div`,{className:V.connectionIdentity,children:[(0,O.jsx)(p,{service:n.providerId,size:`compact`}),(0,O.jsx)(c,{as:`h2`,variant:`card-title`,children:n.displayName})]}),(0,O.jsx)(a,{label:y.label,size:`compact`,tone:y.tone})]}),(0,O.jsx)(U,{state:h}),(0,O.jsx)(K,{canSynchronize:e&&n.isEnabled,onRefresh:()=>s(n.pluginConnectionId),onSynchronize:()=>u(n.pluginConnectionId),state:m}),(0,O.jsxs)(`div`,{className:V.cardAction,children:[(0,O.jsx)(o,{disabled:!t||v||g||!n.isEnabled,loading:g,onClick:()=>f(n.pluginConnectionId),variant:`secondary`,children:_?`Retry test`:`Test connection`}),(0,O.jsx)(o,{disabled:!e,onClick:i,variant:`secondary`,children:`Add connection`}),(0,O.jsx)(o,{disabled:!e||v,loading:v,onClick:()=>l(n.pluginConnectionId,!n.isEnabled),variant:n.isEnabled?`secondary`:`primary`,children:n.isEnabled?`Disable`:`Enable service`}),t?null:(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Owner access is required.`})]}),r===`request-failed`?(0,O.jsx)(c,{as:`p`,className:V.setupError,role:`alert`,variant:`body`,children:`Control Center could not change this service. Refresh and try again.`}):null]})},ce=({catalog:e,isSubmitting:t,onCancel:n,onSubmit:r})=>{let[i,a]=(0,w.useState)(e.displayName),[s,u]=(0,w.useState)(null),[d,f]=(0,w.useState)(new Map(e.configurationFields.map(e=>[e.key,e.defaultValue??``]))),p=t=>{t.preventDefault(),u(null);let n=e.configurationFields.map(e=>E(e,d.get(e.key)??``));r(i,n).then(t=>{if(!t){u(`Control Center could not create this connection. Check the fields and try again.`);return}f(t=>{let n=new Map(t);for(let t of e.configurationFields)t.kind===`secret`&&n.set(t.key,``);return n})})},m=(e,t)=>{f(n=>new Map(n).set(e,t))};return(0,O.jsxs)(`form`,{className:V.setupForm,onSubmit:p,children:[(0,O.jsx)(l,{label:`Connection name`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,maxLength:200,onChange:e=>a(e.currentTarget.value),value:i})}),e.configurationFields.map(e=>(0,O.jsx)(l,{description:e.description,label:e.label,required:e.required,size:`compact`,children:t=>(0,O.jsx)(`input`,{...t,autoComplete:e.kind===`secret`?`off`:void 0,disabled:e.isReadOnly,max:e.maximum??void 0,maxLength:e.kind===`integer`?void 0:e.kind===`secret`?16384:4096,min:e.minimum??void 0,onChange:t=>m(e.key,t.currentTarget.value),type:e.kind===`secret`?`password`:e.kind===`integer`?`number`:e.kind===`url`?`url`:`text`,value:d.get(e.key)??``})},e.key)),s===null?null:(0,O.jsx)(c,{as:`p`,className:V.setupError,role:`alert`,variant:`body`,children:s}),(0,O.jsxs)(`div`,{className:V.setupActions,children:[(0,O.jsx)(o,{disabled:t,onClick:n,type:`button`,variant:`secondary`,children:`Cancel`}),(0,O.jsx)(o,{loading:t,type:`submit`,variant:`primary`,children:`Enable and test`})]})]})},le=({atlassianProfiles:e,atlassianProfilesState:t,atlassianSetupIntent:n,awsProfiles:r,awsProfilesState:i,canConfigure:s,catalog:l,catalogs:u,isAdditional:f,isOpen:m,isRecovery:h,isSubmitting:g,onCancel:_,onDiscoverAws:v,onOpen:y,onStartAtlassianOAuth:b,onSubmit:x,onSubmitAtlassian:S,onSubmitAws:C})=>{let w=l.providerId===`codecommit`||l.providerId===`codepipeline`,T=l.providerId===`jira`||l.providerId===`confluence`;return(0,O.jsxs)(d,{as:`article`,className:V.card,padding:`default`,shape:`grouped`,children:[(0,O.jsxs)(`div`,{className:V.cardHeading,children:[(0,O.jsxs)(`div`,{className:V.connectionIdentity,children:[(0,O.jsx)(p,{service:l.providerId,size:`compact`}),(0,O.jsx)(c,{as:`h2`,variant:`card-title`,children:l.displayName})]}),(0,O.jsx)(a,{label:h?`Needs correction`:f?`Add another`:`Not configured`,size:`compact`,tone:h?`critical`:`neutral`})]}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:l.description}),m?w?(0,O.jsx)(B,{awsProfiles:r,awsProfilesState:i,catalogs:u,isSubmitting:g,onCancel:_,onDiscover:v,onSubmit:C}):T?(0,O.jsx)(M,{catalogs:u,isSubmitting:g,onCancel:_,onStartOAuth:b,onSubmit:S,profiles:e,profilesState:t,setupIntent:n}):(0,O.jsx)(ce,{catalog:l,isSubmitting:g,onCancel:_,onSubmit:x}):(0,O.jsxs)(`div`,{className:V.cardAction,children:[(0,O.jsx)(o,{disabled:!s,onClick:y,variant:`secondary`,children:w?`Configure AWS account`:f&&l.providerId===`jira`?`Add Jira project`:f&&l.providerId===`confluence`?`Add Confluence space`:T?`Configure Atlassian`:`Enable service`}),s?null:(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Owner access is required.`})]})]})},ue=({actionLabel:e=`Pair to enable`,isActionDisabled:t=!1,onEnable:n,service:r,statusLabel:i=`Available`,statusTone:s=`positive`})=>(0,O.jsxs)(d,{as:`article`,className:V.card,padding:`default`,shape:`grouped`,children:[(0,O.jsxs)(`div`,{className:V.cardHeading,children:[(0,O.jsxs)(`div`,{className:V.connectionIdentity,children:[(0,O.jsx)(p,{service:r.providerId,size:`compact`}),(0,O.jsx)(c,{as:`h2`,variant:`card-title`,children:r.displayName})]}),(0,O.jsx)(a,{label:i,size:`compact`,tone:s})]}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:r.description}),(0,O.jsx)(`div`,{className:V.cardAction,children:(0,O.jsx)(o,{disabled:t,onClick:n,variant:`primary`,children:e})})]}),de=({transport:e=C}={})=>{let t=r(),[n,a]=s(),{invalidateSession:l,state:d}=f(),p=u(d),[m,S]=(0,w.useState)(0),[T,E]=(0,w.useState)({_tag:`idle`}),[D,k]=(0,w.useState)({_tag:`idle`}),[A,j]=(0,w.useState)({_tag:`idle`}),[M,N]=(0,w.useState)(new Map),[P,F]=(0,w.useState)(new Map),[ee,I]=(0,w.useState)(new Map),[L,R]=(0,w.useState)(null),[te,z]=(0,w.useState)(null),[ne,B]=(0,w.useState)(null),H=(0,w.useRef)(new Map),U=(0,w.useRef)(null),W=(0,w.useRef)(new Map),G=(0,w.useRef)(new Map),K=(0,w.useRef)(null),q=(0,w.useRef)(null),J=(0,w.useRef)(new Map),Z=(0,w.useCallback)(t=>{if(p===null||e.synchronization===void 0)return;J.current.get(t)?.abort();let n=new AbortController;J.current.set(t,n),I(e=>new Map(e).set(t,{_tag:`loading`})),e.synchronization(t,n.signal).then(e=>{n.signal.aborted||(J.current.delete(t),I(n=>new Map(n).set(t,{_tag:`ready`,synchronization:e})))},e=>{n.signal.aborted||(J.current.delete(t),h(`UnauthorizedApiError`)(e)&&l(p),I(e=>new Map(e).set(t,{_tag:`failed`})))})},[l,p,e]),ie=(0,w.useCallback)(t=>{if(p===null||e.synchronize===void 0)return;J.current.get(t)?.abort();let n=new AbortController;J.current.set(t,n),I(e=>{let n=e.get(t),r=n?._tag===`ready`?n.synchronization:null;return new Map(e).set(t,{_tag:`syncing`,previous:r})}),e.synchronize(t,n.signal).then(e=>{n.signal.aborted||(J.current.delete(t),I(n=>new Map(n).set(t,{_tag:`ready`,synchronization:e})))},e=>{n.signal.aborted||(J.current.delete(t),h(`UnauthorizedApiError`)(e)&&l(p),I(e=>new Map(e).set(t,{_tag:`failed`})))})},[l,p,e]);(0,w.useEffect)(()=>{if(p===null){E({_tag:`idle`});return}let t=new AbortController;return E({_tag:`loading`}),e.overview(t.signal).then(e=>{t.signal.aborted||E({_tag:`ready`,overview:e})},e=>{t.signal.aborted||(h(`UnauthorizedApiError`)(e)&&l(p),E({_tag:`failed`}))}),()=>t.abort()},[l,m,p,e]),(0,w.useEffect)(()=>{if(T._tag!==`ready`||e.synchronization===void 0)return;let t=T.overview.connections.filter(({supportsSynchronization:e})=>e),n=new Set(t.map(({pluginConnectionId:e})=>e));for(let[e,t]of J.current)n.has(e)||(t.abort(),J.current.delete(e));I(e=>{let t=new Map(e),r=!1;for(let e of t.keys())n.has(e)||(t.delete(e),r=!0);return r?t:e});for(let e of t)Z(e.pluginConnectionId);return()=>{for(let e of t)J.current.get(e.pluginConnectionId)?.abort(),J.current.delete(e.pluginConnectionId)}},[T,Z,e.synchronization]),(0,w.useEffect)(()=>{if(p===null||L!==`codecommit`&&L!==`codepipeline`)return;K.current?.abort();let t=new AbortController;K.current=t,k({_tag:`loading`});let n=e.discoverAwsProfiles;return n===void 0?(k({_tag:`failed`}),()=>t.abort()):(n(t.signal).then(e=>{t.signal.aborted||k({_tag:`ready`,profiles:e})},e=>{t.signal.aborted||(h(`UnauthorizedApiError`)(e)&&l(p),k({_tag:`failed`}))}),()=>t.abort())},[l,L,p,e]),(0,w.useEffect)(()=>{if(p===null||L!==`jira`&&L!==`confluence`)return;q.current?.abort();let t=new AbortController;q.current=t,j({_tag:`loading`});let n=e.discoverAtlassianProfiles;return n===void 0?(j({_tag:`failed`}),()=>t.abort()):(n(t.signal).then(e=>{t.signal.aborted||j({_tag:`ready`,profiles:e})},e=>{t.signal.aborted||(h(`UnauthorizedApiError`)(e)&&l(p),j({_tag:`failed`}))}),()=>t.abort())},[l,L,p,e]),(0,w.useEffect)(()=>(N(new Map),F(new Map),I(new Map),R(null),z(null),B(null),k({_tag:`idle`}),j({_tag:`idle`}),W.current.clear(),()=>{for(let e of H.current.values())e.abort();H.current.clear(),U.current?.abort(),U.current=null,K.current?.abort(),K.current=null,q.current?.abort(),q.current=null;for(let e of J.current.values())e.abort();J.current.clear();for(let e of G.current.values())e.abort();G.current.clear()}),[p]),(0,w.useEffect)(()=>{if(T._tag!==`ready`||d._tag!==`authenticated`||d.session.permission!==`workspace-owner`)return;let e=g(n,`enable`);if(e===null||!T.overview.catalog.some(({providerId:t})=>t===e))return;if(e===`jira`||e===`confluence`){let t=x(n),r=t?.includes(e)===!0;z(r?{preferredProfileId:y(n),preferredSiteId:v(n),providers:t,requestedOAuthProviders:t}:ae(T.overview.connections,e))}R(e);let t=new URLSearchParams(n);t.delete(`enable`),t.delete(`atlassianProfile`),t.delete(`atlassianProvider`),t.delete(`atlassianSite`),a(t,{replace:!0})},[T,n,d,a]);let Q=(0,w.useCallback)(t=>{if(p===null)return;H.current.get(t)?.abort();let n=new AbortController;H.current.set(t,n),N(e=>new Map(e).set(t,{_tag:`testing`})),e.test(t,n.signal).then(e=>{n.signal.aborted||(H.current.delete(t),N(n=>new Map(n).set(t,{_tag:`result`,result:e})))},e=>{n.signal.aborted||(H.current.delete(t),h(`UnauthorizedApiError`)(e)&&l(p),N(e=>new Map(e).set(t,{_tag:`request-failed`})))})},[l,p,e]),$=(0,w.useCallback)(async(t,n)=>{if(p===null)return!1;U.current?.abort();let r=new AbortController;U.current=r,B(n);let i=!1,a=!1,o=!1,s=W.current.get(n)??new Set;W.current.set(n,s);let c=(e,t)=>{s.add(e),i||=t.test._tag!==`healthy`,o||=t.connection.providerAccountId!==null,E(e=>e._tag===`ready`?{_tag:`ready`,overview:{...e.overview,connections:[...e.overview.connections,t.connection]}}:e),N(e=>new Map(e).set(t.connection.pluginConnectionId,{_tag:`result`,result:t.test}))};try{let u=t.filter(e=>!s.has(X(e)));if(e.createBatch!==void 0&&u.length>0){let t=new Map,n=[];for(let r of u){let i=await e.makeConnectionId();t.set(i,X(r)),n.push({pluginConnectionId:i,providerId:r.catalog.providerId,displayName:r.displayName,values:r.values})}let i=await e.createBatch({connections:n},r.signal);if(r.signal.aborted)return!1;let o=new Set;for(let e of i.results){let n=e._tag===`failed`?e.pluginConnectionId:e.response.connection.pluginConnectionId;if(!t.has(n)||o.has(n)){a=!0;continue}if(o.add(n),e._tag===`failed`){a=!0;continue}let r=t.get(e.response.connection.pluginConnectionId);r!==void 0&&c(r,e.response)}a||=o.size!==n.length}else for(let t of u){let n=X(t),i=await e.makeConnectionId(),a=await e.create({pluginConnectionId:i,providerId:t.catalog.providerId,displayName:t.displayName,values:t.values},r.signal);if(r.signal.aborted)return!1;c(n,a)}if(o)try{let t=await e.overview(r.signal);r.signal.aborted||E({_tag:`ready`,overview:t})}catch(e){if(r.signal.aborted)return!1;h(`UnauthorizedApiError`)(e)&&l(p)}return a?W.current.set(n,s):W.current.delete(n),U.current=null,R(i||a?n:null),B(null),!a}catch(e){return r.signal.aborted?!1:(U.current=null,h(`UnauthorizedApiError`)(e)&&l(p),B(null),!1)}},[l,p,e]),ce=(0,w.useCallback)((e,t,n)=>$([{catalog:e,displayName:t,values:n}],e.providerId),[$]),de=(0,w.useCallback)((t,n)=>{if(p===null)return;n||(H.current.get(t)?.abort(),H.current.delete(t),N(e=>{let n=new Map(e);return n.delete(t),n})),G.current.get(t)?.abort();let r=new AbortController;G.current.set(t,r),F(e=>new Map(e).set(t,`changing`)),e.setEnabled(t,n,r.signal).then(e=>{r.signal.aborted||(G.current.delete(t),E(n=>n._tag===`ready`?{_tag:`ready`,overview:{...n.overview,connections:n.overview.connections.map(n=>n.pluginConnectionId===t?e:n)}}:n),F(e=>{let n=new Map(e);return n.delete(t),n}),n?Q(t):N(e=>{let n=new Map(e);return n.delete(t),n}))},e=>{r.signal.aborted||(G.current.delete(t),h(`UnauthorizedApiError`)(e)&&l(p),F(e=>new Map(e).set(t,`request-failed`)))})},[l,p,Q,e]),fe=d._tag===`authenticated`||d._tag===`storage-unavailable`?d.session:null,pe=d._tag===`authenticated`&&d.session.permission===`workspace-owner`;return(0,O.jsxs)(`section`,{"aria-labelledby":`services-title`,className:V.page,children:[(0,O.jsxs)(`header`,{className:V.heading,children:[(0,O.jsx)(c,{as:`h1`,id:`services-title`,variant:`page-title`,children:`Services`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body-large`,children:fe===null||T._tag===`ready`&&T.overview.connections.length===0?`Choose a service below. Control Center will enable it and verify the exact account before using it.`:`Configure first-party providers and verify the exact account each connection represents.`})]}),fe===null&&d._tag!==`checking`?(0,O.jsx)(`div`,{className:V.grid,children:_.map(e=>(0,O.jsx)(ue,{onEnable:()=>t(b(e.providerId)),service:e},e.providerId))}):T._tag===`loading`||T._tag===`idle`?(0,O.jsx)(`div`,{className:V.grid,children:_.map(e=>(0,O.jsx)(ue,{actionLabel:`Loading connections`,isActionDisabled:!0,onEnable:()=>void 0,service:e,statusLabel:`Loading`,statusTone:`progress`},e.providerId))}):T._tag===`failed`?(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(i,{action:(0,O.jsx)(o,{onClick:()=>S(e=>e+1),children:`Try again`}),description:`Control Center could not load connection details. The installed services remain visible below.`,title:`Connections unavailable`}),(0,O.jsx)(`div`,{className:V.grid,children:_.map(e=>(0,O.jsx)(ue,{actionLabel:`Retry connections`,onEnable:()=>S(e=>e+1),service:e,statusLabel:`Installed`,statusTone:`neutral`},e.providerId))})]}):(0,O.jsxs)(O.Fragment,{children:[T.overview.accounts.length===0?null:(0,O.jsxs)(`section`,{"aria-labelledby":`connected-accounts-title`,className:V.accounts,children:[(0,O.jsxs)(`div`,{className:V.sectionHeading,children:[(0,O.jsx)(c,{as:`h2`,id:`connected-accounts-title`,variant:`section-title`,children:`Connected accounts`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`One verified provider identity can own several followed resources.`})]}),(0,O.jsx)(`div`,{className:V.accountGrid,children:T.overview.accounts.map(e=>(0,O.jsx)(Y,{account:e,canConfigure:pe,connections:T.overview.connections,enablementStates:P,onAdd:(e,t)=>{(e===`jira`||e===`confluence`)&&z({preferredProfileId:null,preferredSiteId:t,providers:[e],requestedOAuthProviders:null}),R(e)},onSetEnabled:de,onRefreshSynchronization:Z,onSynchronize:ie,synchronizationStates:ee,onTest:Q,testStates:M},e.providerAccountId))})]}),(0,O.jsx)(`div`,{className:V.grid,children:T.overview.catalog.flatMap(t=>{let n=T.overview.connections.filter(e=>e.providerId===t.providerId),r=new Set(T.overview.accounts.flatMap(({resources:e})=>e.map(({followedResourceId:e})=>e))),i=n.filter(({followedResourceId:e})=>e===null||!r.has(e)),a=ae(T.overview.connections,t.providerId===`jira`||t.providerId===`confluence`?t.providerId:void 0),o=oe(te??a,T.overview.connections,A),s=i.map(e=>(0,O.jsx)(se,{canConfigure:pe,canTest:pe,connection:e,enablementState:P.get(e.pluginConnectionId),onConfigure:()=>{(t.providerId===`jira`||t.providerId===`confluence`)&&z(re),R(t.providerId)},onSetEnabled:de,onRefreshSynchronization:Z,onSynchronize:ie,onTest:Q,synchronizationState:ee.get(e.pluginConnectionId),testState:M.get(e.pluginConnectionId)},e.pluginConnectionId));return n.length>0&&L!==t.providerId&&t.providerId!==`jira`&&t.providerId!==`confluence`?s:[...s,(0,O.jsx)(le,{atlassianProfiles:A._tag===`ready`?A.profiles:[],atlassianProfilesState:A._tag,atlassianSetupIntent:o,awsProfiles:D._tag===`ready`?D.profiles:[],awsProfilesState:D._tag,canConfigure:pe,catalog:t,catalogs:T.overview.catalog,isAdditional:n.length>0&&(t.providerId===`jira`||t.providerId===`confluence`),isOpen:L===t.providerId,isRecovery:i.length>0,isSubmitting:ne===t.providerId,onCancel:()=>{W.current.delete(t.providerId),z(null),R(null)},onDiscoverAws:(t,n)=>{let r=e.discoverAwsResources;return r===void 0?Promise.reject(Error(`AWS resource discovery is unavailable`)):r(t,n).catch(e=>(p!==null&&h(`UnauthorizedApiError`)(e)&&l(p),Promise.reject(e)))},onOpen:()=>{L!==t.providerId&&W.current.delete(t.providerId),(t.providerId===`jira`||t.providerId===`confluence`)&&z(a),R(t.providerId)},onStartAtlassianOAuth:(t,n,r)=>{let i=e.startAtlassianOAuthGrant;return i===void 0?Promise.reject(Error(`Atlassian OAuth is unavailable`)):i(t,n,r)},onSubmit:(e,n)=>ce(t,e,n),onSubmitAtlassian:e=>$(e,t.providerId),onSubmitAws:e=>$(e,t.providerId)},`${t.providerId}-catalog`)]})})]})]})};export{de as ServicesPage};
|
|
2
|
-
//# sourceMappingURL=ServicesPage-
|
|
1
|
+
import{a as e,n as t,t as n}from"./jsx-runtime-n5LQ9ujS.js";import{E as r,n as i,r as a,t as o,v as s}from"./Dialog-DwSIPb-B-DVn37afM.js";import{i as c,n as l,o as u,r as d,s as f}from"./index-DpW_ckau.js";import{v as p}from"./patterns-DEbg7R-A-BhsMyh9D.js";import{K as m,zt as h}from"./client-P7FaPwzJ.js";import{a as g,c as _,i as v,n as y,o as b,r as x}from"./serviceOnboarding-BZ2U_Ugw.js";import{i as S,t as C}from"./connectionTestTransport-C9iPOkKM.js";var w=e(t(),1),T={form:`_form_piwc3_1`,intro:`_intro_piwc3_2`,fallback:`_fallback_piwc3_3`,resources:`_resources_piwc3_16`,actions:`_actions_piwc3_22`,error:`_error_piwc3_29`},E=(e,t)=>{switch(e.kind){case`integer`:return{_tag:`integer`,key:e.key,value:Number(t)};case`secret`:return{_tag:`secret`,key:e.key,value:t};case`text`:case`url`:return{_tag:e.kind,key:e.key,value:t}}},D=(e,t)=>e.configurationFields.flatMap(e=>{let n=t.get(e.key)??e.defaultValue;return n===null&&!e.required?[]:[E(e,n??``)]}),O=n(),k=(e,t)=>e.find(e=>e.profileId===t),A=(e,t)=>e.status===`valid`&&(t.preferredSiteId===null||e.cloudId===t.preferredSiteId)&&t.providers.every(t=>e.providers.includes(t)),j=e=>e.status===`expired`?`expired`:e.providers.includes(`jira`)?e.providers.includes(`confluence`)?`Jira + Confluence`:`Jira only`:`Confluence only`,M=({catalogs:e,isSubmitting:t,onCancel:n,onStartOAuth:r,onSubmit:i,profiles:a,profilesState:s,setupIntent:u})=>{let d=e.find(({providerId:e})=>e===`jira`),f=e.find(({providerId:e})=>e===`confluence`),p=u.providers.includes(`jira`),m=u.providers.includes(`confluence`),[h,g]=(0,w.useState)(`Atlassian workspace`),[_,v]=(0,w.useState)(`oauth`),[y,b]=(0,w.useState)(``),[x,C]=(0,w.useState)(``),[E,M]=(0,w.useState)(``),[N,P]=(0,w.useState)(``),[F,ee]=(0,w.useState)(``),[I,L]=(0,w.useState)(``),[R,te]=(0,w.useState)(``),[z,ne]=(0,w.useState)(``),[B,V]=(0,w.useState)(!1),[H,U]=(0,w.useState)(null),[W,G]=(0,w.useState)(``),[K,q]=(0,w.useState)(``),[J,Y]=(0,w.useState)(null),X=(0,w.useRef)(null);(0,w.useEffect)(()=>()=>X.current?.abort(),[]),(0,w.useEffect)(()=>{if(_!==`oauth`)return;let e=k(a,y);if(e!==void 0&&A(e,u))return;let t=u.preferredProfileId===null?void 0:k(a,u.preferredProfileId),n=t!==void 0&&A(t,u)?t:a.find(e=>A(e,u));b(n?.profileId??``)},[_,y,a,u]),(0,w.useEffect)(()=>{u.preferredSiteId!==null&&M(u.preferredSiteId)},[u.preferredSiteId]),(0,w.useEffect)(()=>{if(_!==`oauth`)return;let e=k(a,y);e!==void 0&&(C(e.siteUrl),M(e.cloudId))},[_,y,a]);let Z=e=>{if(e.preventDefault(),Y(null),p&&d===void 0||m&&f===void 0){Y(`The installed Atlassian adapters are unavailable.`);return}let t=h.trim(),n=x.trim(),r=E.trim(),o=N.trim(),s=F.trim(),c=I.trim();if(t.length===0||n.length===0||r.length===0||p&&o.length===0||m&&(s.length===0||c.length===0)){Y(p&&m?`Add the Atlassian site identity, Jira project, Confluence space, and readable health page.`:p?`Add the Atlassian site identity and Jira project.`:`Add the Atlassian site identity, Confluence space, and readable health page.`);return}let l=_===`oauth`?[[`authMode`,`oauth`],[`oauthProfileId`,y]]:[[`authMode`,`api-token`],[`email`,R.trim()],[`apiToken`,z]],g=k(a,y);if(_===`oauth`&&(g===void 0||!A(g,u))){Y(`Choose a valid profile for the products being connected, or use an API token instead.`);return}if(_===`api-token`&&(R.trim().length===0||z.length===0)){Y(`Add the Atlassian email and API token.`);return}if(_===`api-token`&&p&&u.preferredSiteId!==null){Y(`Use a matching OAuth profile to add a Jira project to this Atlassian site.`);return}let v=[...l,[`webBaseUrl`,n],[`siteBaseUrl`,n],[`siteId`,r],[`projectId`,o],[`spaceId`,s],[`probePageId`,c]],b=new Map(v);i([...p&&d!==void 0?[{catalog:d,displayName:`${t} · Jira`,values:D(d,b)}]:[],...m&&f!==void 0?[{catalog:f,displayName:`${t} · Confluence`,values:D(f,b)}]:[]]).then(e=>{e||Y(`Some Atlassian services could not be connected. Review the cards below and retry.`)})},re=e=>{if(u.requestedOAuthProviders===null)return;Y(null),U(null),V(!0),X.current?.abort();let t=new AbortController;X.current=t,r(u.requestedOAuthProviders,t.signal,e).then(e=>{if(!t.signal.aborted){if(e._tag===`configuration-required`){U(e.callbackUrl),Y(`OAuth needs a one-time local client configuration before sign-in.`),V(!1);return}if(!S(e.authorizationUrl,{preferredSiteId:u.preferredSiteId,providers:u.providers})){Y(`Control Center could not preserve this Atlassian setup across sign-in. Try again.`),V(!1);return}window.location.assign(e.authorizationUrl)}},()=>{t.signal.aborted||(Y(`Control Center could not start Atlassian sign-in. Try again.`),V(!1))})},ie=()=>{let e=W.trim();if(e.length===0||K.length===0){Y(`Add the Atlassian OAuth client ID and client secret.`);return}re({clientId:e,clientSecret:K})},Q=()=>{X.current?.abort(),X.current=null,V(!1),v(`api-token`)},$=s===`loading`?`Finding local Atlassian OAuth profiles…`:s===`failed`?`OAuth profile discovery is unavailable. API token fallback remains available.`:s===`ready`?`${a.filter(e=>A(e,u)).length} ${p&&m?`shared `:``}OAuth ${a.filter(e=>A(e,u)).length===1?`profile`:`profiles`} ready`:`OAuth profiles stay on this machine and are shared by Jira and Confluence.`;return(0,O.jsxs)(`form`,{className:T.form,onSubmit:Z,children:[(0,O.jsxs)(`div`,{className:T.intro,children:[(0,O.jsx)(c,{as:`h3`,variant:`card-title`,children:p&&m?`One identity. Jira and Confluence together.`:p?`Connect Jira with your Atlassian identity.`:`Connect Confluence with your Atlassian identity.`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`OAuth is preferred. Control Center reads the selected local profile only inside the server runtime.`}),(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:$})]}),(0,O.jsx)(l,{label:`Account name`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,maxLength:90,onChange:e=>g(e.currentTarget.value),value:h})}),_===`oauth`?(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(o,{disabled:u.requestedOAuthProviders===null,loading:B,onClick:()=>re(),type:`button`,variant:`primary`,children:`Sign in with Atlassian`}),H===null?null:(0,O.jsxs)(`div`,{className:T.fallback,children:[(0,O.jsxs)(c,{as:`p`,tone:`secondary`,variant:`meta`,children:[`Create an OAuth 2.0 integration in Atlassian Developer Console and add `,(0,O.jsx)(`code`,{children:H}),`as its callback URL. The credentials stay on this Control Center machine.`]}),(0,O.jsx)(l,{label:`OAuth client ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,autoComplete:`off`,maxLength:500,onChange:e=>G(e.currentTarget.value),value:W})}),(0,O.jsx)(l,{label:`OAuth client secret`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,autoComplete:`off`,maxLength:16384,onChange:e=>q(e.currentTarget.value),type:`password`,value:K})}),(0,O.jsx)(o,{loading:B,onClick:ie,type:`button`,variant:`primary`,children:`Save OAuth app and continue`})]}),(0,O.jsx)(l,{label:`OAuth profile`,required:!0,size:`compact`,children:e=>(0,O.jsxs)(`select`,{...e,onChange:e=>b(e.currentTarget.value),value:y,children:[(0,O.jsx)(`option`,{value:``,children:`Choose a profile already on this machine`}),a.filter(e=>u.preferredSiteId===null||e.cloudId===u.preferredSiteId).map(e=>(0,O.jsxs)(`option`,{disabled:!A(e,u),value:e.profileId,children:[e.name,` · `,j(e)]},e.profileId))]})}),p&&u.preferredSiteId!==null?null:(0,O.jsx)(o,{onClick:Q,type:`button`,variant:`quiet`,children:`Use API token instead`})]}):(0,O.jsxs)(`div`,{className:T.fallback,children:[(0,O.jsx)(l,{label:`Atlassian email`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,autoComplete:`username`,onChange:e=>te(e.currentTarget.value),type:`email`,value:R})}),(0,O.jsx)(l,{label:`API token`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,autoComplete:`off`,maxLength:16384,onChange:e=>ne(e.currentTarget.value),type:`password`,value:z})}),(0,O.jsx)(o,{onClick:()=>v(`oauth`),type:`button`,variant:`quiet`,children:`Use OAuth profile`})]}),(0,O.jsx)(l,{label:`Atlassian site URL`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,disabled:_===`oauth`,onChange:e=>C(e.currentTarget.value),placeholder:`https://team.atlassian.net/`,type:`url`,value:x})}),(0,O.jsx)(l,{description:`The stable Atlassian cloud ID; filled from OAuth when available.`,label:`Site ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,disabled:_===`oauth`||u.preferredSiteId!==null,onChange:e=>M(e.currentTarget.value),value:E})}),p?(0,O.jsx)(l,{description:`The immutable Jira project ID followed by this connection.`,label:`Jira project ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,onChange:e=>P(e.currentTarget.value),value:N})}):null,m?(0,O.jsxs)(`div`,{className:T.resources,children:[(0,O.jsx)(l,{label:`Confluence space ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,onChange:e=>ee(e.currentTarget.value),value:F})}),(0,O.jsx)(l,{description:`A readable page used only for the connection check.`,label:`Health page ID`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,onChange:e=>L(e.currentTarget.value),value:I})})]}):null,J===null?null:(0,O.jsx)(c,{as:`p`,className:T.error,role:`alert`,variant:`body`,children:J}),(0,O.jsxs)(`div`,{className:T.actions,children:[(0,O.jsx)(o,{disabled:t,onClick:n,type:`button`,variant:`secondary`,children:`Cancel`}),(0,O.jsx)(o,{loading:t,type:`submit`,variant:`primary`,children:`Connect Atlassian`})]})]})},N={form:`_form_1gjxb_1`,intro:`_intro_1gjxb_6`,resources:`_resources_1gjxb_11`,discoveryActions:`_discoveryActions_1gjxb_22`,resourcePanelHeading:`_resourcePanelHeading_1gjxb_23`,resourcePanel:`_resourcePanel_1gjxb_23`,choiceList:`_choiceList_1gjxb_44`,choice:`_choice_1gjxb_44`,actions:`_actions_1gjxb_58`,error:`_error_1gjxb_65`},P=20,F=e=>[...new Set(e.split(/[\n,]/u).map(e=>e.trim()).filter(e=>e.length>0))],ee=(e,t)=>[...new Set([...e,...F(t)])],I=(e,t)=>[...new Set([...e,...t])].sort((e,t)=>e.localeCompare(t)),L=(e,t)=>{let n=t.trim().toLocaleLowerCase();return n.length===0?e:e.filter(e=>e.toLocaleLowerCase().includes(n))},R=({accountName:e,codeCommit:t,codePipeline:n,pipelineNames:r,profile:i,region:a,repositoryNames:o})=>[...o.map(n=>({catalog:t,displayName:`${e} · ${n}`,values:D(t,new Map([[`profile`,i],[`region`,a],[`repositoryName`,n]]))})),...r.map(t=>({catalog:n,displayName:`${e} · ${t}`,values:D(n,new Map([[`profile`,i],[`region`,a],[`pipelineName`,t]]))}))],te=(e,t)=>{switch(t){case`loading`:return`Discovering local AWS profiles…`;case`ready`:return`${e} local AWS ${e===1?`profile`:`profiles`} detected`;case`failed`:return`Profile discovery unavailable. Enter a profile manually.`;case`idle`:return`AWS profiles are discovered locally by the Control Center server.`}},z=(e,t)=>t===`authorization`?`${e} access was denied. Select names manually or update this profile's permissions.`:`${e} discovery is unavailable (${t}). Select names manually or refresh.`,ne=({label:e,query:t,selected:n,service:r,setQuery:i,setSelected:o})=>{if(r._tag===`failed`){let t=[...n].sort((e,t)=>e.localeCompare(t));return(0,O.jsxs)(`div`,{className:N.resourcePanel,children:[(0,O.jsxs)(`div`,{className:N.resourcePanelHeading,children:[(0,O.jsx)(c,{as:`h4`,variant:`card-title`,children:e}),(0,O.jsx)(a,{label:`${n.size} selected`,size:`compact`,tone:`neutral`})]}),(0,O.jsx)(c,{as:`p`,className:N.error,role:`status`,variant:`body`,children:z(e===`Repositories`?`CodeCommit`:`CodePipeline`,r.failureClass)}),t.length===0?null:(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Preserved from the previous discovery. Clear any resource you no longer want to connect.`}),(0,O.jsx)(`div`,{className:N.choiceList,children:t.map(e=>(0,O.jsxs)(`label`,{className:N.choice,children:[(0,O.jsx)(`input`,{checked:!0,onChange:()=>{let t=new Set(n);t.delete(e),o(t)},type:`checkbox`}),(0,O.jsx)(`span`,{children:e})]},e))})]})]})}let s=I(r.names,n),u=L(s,t);return(0,O.jsxs)(`div`,{className:N.resourcePanel,children:[(0,O.jsxs)(`div`,{className:N.resourcePanelHeading,children:[(0,O.jsx)(c,{as:`h4`,variant:`card-title`,children:e}),(0,O.jsx)(a,{label:`${n.size} selected`,size:`compact`,tone:`neutral`})]}),s.length===0?(0,O.jsxs)(c,{tone:`secondary`,variant:`body`,children:[`No `,e.toLocaleLowerCase(),` were found in this region.`]}):(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(l,{label:`Search ${e.toLocaleLowerCase()}`,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,onChange:e=>i(e.currentTarget.value),type:`search`,value:t})}),(0,O.jsx)(`div`,{className:N.choiceList,children:u.map(e=>(0,O.jsxs)(`label`,{className:N.choice,children:[(0,O.jsx)(`input`,{checked:n.has(e),onChange:t=>{let r=new Set(n);t.currentTarget.checked?r.add(e):r.delete(e),o(r)},type:`checkbox`}),(0,O.jsx)(`span`,{children:e})]},e))}),u.length===0?(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`No matching resources.`}):null,r.truncated?(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Showing the first 20 names. Use manual entry for another name.`}):null]})]})},B=({awsProfiles:e,awsProfilesState:t,catalogs:n,isSubmitting:r,onCancel:i,onDiscover:a,onSubmit:s})=>{let u=n.find(({providerId:e})=>e===`codecommit`),d=n.find(({providerId:e})=>e===`codepipeline`),[f,p]=(0,w.useState)(`AWS account`),[m,h]=(0,w.useState)(`default`),[g,_]=(0,w.useState)(``),[v,y]=(0,w.useState)(``),[b,x]=(0,w.useState)(``),[S,C]=(0,w.useState)(new Set),[T,E]=(0,w.useState)(new Set),[D,k]=(0,w.useState)(``),[A,j]=(0,w.useState)(``),[M,F]=(0,w.useState)(!0),[I,L]=(0,w.useState)({_tag:`idle`}),[z,B]=(0,w.useState)(null),V=(0,w.useRef)(null);(0,w.useEffect)(()=>()=>V.current?.abort(),[]),(0,w.useEffect)(()=>{let t=e.find(e=>e.profile===m)?.region;t!=null&&_(e=>e.trim().length===0?t:e)},[e,m]);let H=()=>{V.current?.abort(),V.current=null,L({_tag:`idle`}),C(new Set),E(new Set)};return(0,O.jsxs)(`form`,{className:N.form,onSubmit:e=>{if(e.preventDefault(),B(null),u===void 0||d===void 0){B(`The installed AWS adapters are unavailable.`);return}let t=f.trim(),n=m.trim(),r=g.trim();if(t.length===0||n.length===0||r.length===0){B(`Add an account name, AWS profile, and region.`);return}let i=ee(S,M?v:``),a=ee(T,M?b:``);if(i.length===0&&a.length===0){B(`Select or manually add at least one repository or pipeline to follow.`);return}if(i.length>P||a.length>P){B(`Follow at most ${P} repositories and pipelines per account.`);return}if([...i,...a].some(e=>e.length>100)){B(`Repository and pipeline names must be 100 characters or fewer.`);return}s(R({accountName:t,codeCommit:u,codePipeline:d,pipelineNames:a,profile:n,region:r,repositoryNames:i})).then(e=>{e||B(`Some AWS resources could not be connected. Review the cards below and retry.`)})},children:[(0,O.jsxs)(`div`,{className:N.intro,children:[(0,O.jsx)(c,{as:`h3`,variant:`card-title`,children:`One account. Many delivery streams.`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`Choose one local AWS profile and region, verify its account, then select CodeCommit repositories and CodePipeline pipelines.`}),(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:te(e.length,t)})]}),(0,O.jsx)(l,{label:`Account name`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,maxLength:90,onChange:e=>p(e.currentTarget.value),value:f})}),(0,O.jsx)(l,{label:`AWS profile`,required:!0,size:`compact`,children:t=>(0,O.jsx)(`input`,{...t,list:e.length>0?`aws-account-profiles`:void 0,maxLength:200,onChange:t=>{let n=t.currentTarget.value,r=e.find(e=>e.profile===n)?.region;h(n),_(r??``),H()},value:m})}),(0,O.jsx)(l,{label:`AWS region`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,maxLength:100,onChange:e=>{_(e.currentTarget.value),H()},value:g})}),(0,O.jsxs)(`div`,{className:N.discoveryActions,children:[(0,O.jsx)(o,{loading:I._tag===`loading`,onClick:()=>{B(null);let e={profile:m.trim(),region:g.trim()};if(e.profile.length===0||e.region.length===0){B(`Add an AWS profile and region before testing discovery.`);return}V.current?.abort();let t=new AbortController;V.current=t,L({_tag:`loading`}),a(e,t.signal).then(e=>{t.signal.aborted||(V.current=null,L({_tag:`ready`,response:e}))},()=>{t.signal.aborted||(V.current=null,L({_tag:`failed`}))})},type:`button`,variant:`secondary`,children:I._tag===`ready`?`Refresh discovery`:`Test & discover`}),I._tag===`ready`?(0,O.jsxs)(c,{tone:`secondary`,variant:`body`,children:[`Verified AWS account `,I.response.accountId]}):I._tag===`failed`?(0,O.jsx)(c,{as:`p`,className:N.error,role:`alert`,variant:`body`,children:`Account verification failed. Check the profile and region, or enter resource names manually.`}):null]}),I._tag===`ready`?(0,O.jsxs)(`div`,{className:N.resources,children:[(0,O.jsx)(ne,{label:`Repositories`,query:D,selected:S,service:I.response.codeCommit,setQuery:k,setSelected:C}),(0,O.jsx)(ne,{label:`Pipelines`,query:A,selected:T,service:I.response.codePipeline,setQuery:j,setSelected:E})]}):null,(0,O.jsx)(`div`,{children:(0,O.jsx)(o,{onClick:()=>F(e=>!e),type:`button`,variant:`quiet`,children:M?`Hide manual name entry`:`Enter resource names manually`})}),M?(0,O.jsxs)(`div`,{className:N.resources,children:[(0,O.jsx)(l,{description:`Comma or line separated. Maximum 20 including selected names.`,label:`Repository names`,size:`compact`,children:e=>(0,O.jsx)(`textarea`,{...e,maxLength:4096,onChange:e=>y(e.currentTarget.value),placeholder:`payments-api\\nrisk-engine`,value:v})}),(0,O.jsx)(l,{description:`Comma or line separated. Maximum 20 including selected names.`,label:`Pipeline names`,size:`compact`,children:e=>(0,O.jsx)(`textarea`,{...e,maxLength:4096,onChange:e=>x(e.currentTarget.value),placeholder:`payments-production\\nrisk-production`,value:b})})]}):null,e.length>0?(0,O.jsx)(`datalist`,{id:`aws-account-profiles`,children:e.map(e=>(0,O.jsx)(`option`,{label:e.region??`Region not configured`,value:e.profile},e.profile))}):null,z===null?null:(0,O.jsx)(c,{as:`p`,className:N.error,role:`alert`,variant:`body`,children:z}),(0,O.jsxs)(`div`,{className:N.actions,children:[(0,O.jsx)(o,{disabled:r,onClick:i,type:`button`,variant:`secondary`,children:`Cancel`}),(0,O.jsx)(o,{loading:r,type:`submit`,variant:`primary`,children:`Connect AWS account`})]})]})},V={page:`_page_1ib7n_1`,heading:`_heading_1ib7n_6`,grid:`_grid_1ib7n_12`,accounts:`_accounts_1ib7n_18`,accountCard:`_accountCard_1ib7n_19`,accountIdentity:`_accountIdentity_1ib7n_20`,resourceList:`_resourceList_1ib7n_21`,resource:`_resource_1ib7n_21`,sectionHeading:`_sectionHeading_1ib7n_23`,accountGrid:`_accountGrid_1ib7n_39`,accountHeading:`_accountHeading_1ib7n_44`,resourceHeading:`_resourceHeading_1ib7n_45`,accountActions:`_accountActions_1ib7n_46`,resourceActions:`_resourceActions_1ib7n_47`,card:`_card_1ib7n_74`,cardHeading:`_cardHeading_1ib7n_80`,cardAction:`_cardAction_1ib7n_81`,synchronization:`_synchronization_1ib7n_88`,syncState:`_syncState_1ib7n_89`,syncActions:`_syncActions_1ib7n_94`,connectionIdentity:`_connectionIdentity_1ib7n_100`,testEvidence:`_testEvidence_1ib7n_107`,identity:`_identity_1ib7n_116`,setupForm:`_setupForm_1ib7n_121`,setupActions:`_setupActions_1ib7n_126`,setupError:`_setupError_1ib7n_133`,identifier:`_identifier_1ib7n_137`},H=e=>m(e.checkedAt),U=({state:e})=>{if(e===void 0||e._tag===`testing`)return null;if(e._tag===`request-failed`)return(0,O.jsxs)(`div`,{"aria-live":`polite`,className:V.testEvidence,role:`status`,children:[(0,O.jsx)(a,{label:`Test failed`,tone:`critical`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`Control Center could not complete the test. Check the server and try again.`})]});let t=e.result,n=H(t);return(0,O.jsxs)(`div`,{"aria-live":`polite`,className:V.testEvidence,role:`status`,children:[(0,O.jsx)(a,{label:t._tag===`healthy`?`Connection healthy`:`Test failed`,tone:t._tag===`healthy`?`positive`:`critical`}),t._tag===`healthy`?(0,O.jsxs)(`div`,{className:V.identity,children:[(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:t.identity.label}),(0,O.jsx)(c,{as:`span`,variant:`card-title`,children:t.identity.displayName}),(0,O.jsx)(c,{className:V.identifier,tone:`secondary`,variant:`body`,children:t.identity.providerImmutableId})]}):(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:t.safeMessage}),(0,O.jsxs)(c,{tone:`secondary`,variant:`meta`,children:[`Checked `,(0,O.jsx)(`time`,{dateTime:n,children:n}),` · `,t.latencyMilliseconds,` ms`]})]})},W=e=>{switch(e){case`never`:return{label:`Never synchronized`,tone:`neutral`};case`running`:return{label:`Synchronizing`,tone:`progress`};case`synchronized`:return{label:`Synchronized`,tone:`positive`};case`source-unavailable`:return{label:`Source unavailable`,tone:`critical`};case`interrupted`:return{label:`Interrupted`,tone:`critical`}}},G=({synchronization:e})=>{let t=W(e.result);return(0,O.jsxs)(`div`,{className:V.syncState,children:[(0,O.jsx)(a,{label:t.label,size:`compact`,tone:t.tone}),(0,O.jsxs)(c,{tone:`secondary`,variant:`meta`,children:[`Last attempt: `,e.lastAttemptAt===null?`never`:String(e.lastAttemptAt),` · Last success: `,e.lastSuccessAt===null?`never`:String(e.lastSuccessAt),` · ${e.pagesCommitted} ${e.pagesCommitted===1?`page`:`pages`}`]})]})},K=({canSynchronize:e,onRefresh:t,onSynchronize:n,state:r})=>{if(r===void 0)return null;let i=r._tag===`ready`?r.synchronization:r._tag===`syncing`?r.previous:null;return(0,O.jsxs)(`div`,{className:V.synchronization,children:[i===null?null:(0,O.jsx)(G,{synchronization:i}),r._tag===`loading`?(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Loading synchronization state…`}):null,r._tag===`failed`?(0,O.jsx)(c,{as:`p`,className:V.setupError,role:`alert`,variant:`body`,children:`Synchronization state is unavailable.`}):null,(0,O.jsxs)(`div`,{className:V.syncActions,children:[(0,O.jsx)(o,{disabled:!e||r._tag===`loading`||r._tag===`syncing`,loading:r._tag===`syncing`,onClick:n,variant:`secondary`,children:`Sync now`}),r._tag===`failed`?(0,O.jsx)(o,{onClick:t,variant:`quiet`,children:`Refresh state`}):null]})]})},q=(e,t)=>{if(!e.isEnabled)return{label:`Disabled`,tone:`neutral`};if(t?._tag===`testing`)return{label:`Checking`,tone:`progress`};if(t?._tag===`result`)return t.result._tag===`healthy`?{label:`Healthy`,tone:`positive`}:{label:`Unavailable`,tone:`critical`};if(e.health===null)return{label:`Not checked`,tone:`neutral`};switch(e.health._tag){case`healthy`:return{label:`Healthy`,tone:`positive`};case`degraded`:return{label:`Degraded`,tone:`caution`};case`unavailable`:return{label:`Unavailable`,tone:`critical`};case`disabled`:return{label:`Not checked`,tone:`neutral`}}},J=e=>{switch(e){case`codecommit`:return`Repository`;case`codepipeline`:return`Pipeline`;case`jira`:return`Project`;case`confluence`:return`Space`;case`clockify`:return`Workspace`}},Y=({account:e,canConfigure:t,connections:n,enablementStates:r,onAdd:i,onRefreshSynchronization:s,onSetEnabled:l,onSynchronize:u,onTest:f,synchronizationStates:m,testStates:h})=>(0,O.jsxs)(d,{as:`article`,className:V.accountCard,padding:`default`,shape:`grouped`,children:[(0,O.jsxs)(`div`,{className:V.accountHeading,children:[(0,O.jsxs)(`div`,{className:V.accountIdentity,children:[(0,O.jsxs)(c,{as:`h2`,variant:`section-title`,children:[e.providerFamily===`aws`?`AWS account`:e.providerFamily===`atlassian`?`Atlassian site`:`Provider account`,` `,e.displayName]}),(0,O.jsxs)(c,{className:V.identifier,tone:`secondary`,variant:`meta`,children:[`Verified identity · `,e.providerImmutableId]})]}),(0,O.jsx)(a,{label:`${e.resources.length} ${e.resources.length===1?`resource`:`resources`}`,size:`compact`,tone:`positive`})]}),(0,O.jsx)(`div`,{className:V.resourceList,children:e.resources.map(e=>{let i=n.find(t=>t.followedResourceId===e.followedResourceId),d=i===void 0?void 0:h.get(i.pluginConnectionId),g=i===void 0?void 0:r.get(i.pluginConnectionId),_=i===void 0?{label:`Followed`,tone:`neutral`}:q(i,d),v=d?._tag===`testing`,y=g===`changing`;return(0,O.jsxs)(`div`,{className:V.resource,children:[(0,O.jsxs)(`div`,{className:V.resourceHeading,children:[(0,O.jsxs)(`div`,{className:V.connectionIdentity,children:[(0,O.jsx)(p,{service:e.providerId,size:`compact`}),(0,O.jsxs)(`div`,{className:V.identity,children:[(0,O.jsx)(c,{as:`h3`,variant:`card-title`,children:e.displayName}),(0,O.jsxs)(c,{className:V.identifier,tone:`secondary`,variant:`meta`,children:[J(e.providerId),` · `,e.providerImmutableId]})]})]}),(0,O.jsx)(a,{label:_.label,size:`compact`,tone:_.tone})]}),i===void 0?null:(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(U,{state:d}),(0,O.jsx)(K,{canSynchronize:t&&i.isEnabled,onRefresh:()=>s(i.pluginConnectionId),onSynchronize:()=>u(i.pluginConnectionId),state:m.get(i.pluginConnectionId)}),(0,O.jsxs)(`div`,{className:V.resourceActions,children:[(0,O.jsx)(o,{disabled:!t||y||v||!i.isEnabled,loading:v,onClick:()=>f(i.pluginConnectionId),variant:`secondary`,children:`Test`}),(0,O.jsx)(o,{disabled:!t||y,loading:y,onClick:()=>l(i.pluginConnectionId,!i.isEnabled),variant:`quiet`,children:i.isEnabled?`Disable`:`Enable`})]}),g===`request-failed`?(0,O.jsx)(c,{as:`p`,className:V.setupError,role:`alert`,variant:`body`,children:`Control Center could not change this service. Refresh and try again.`}):null]})]},e.followedResourceId)})}),e.providerFamily===`aws`?(0,O.jsxs)(`div`,{className:V.accountActions,children:[(0,O.jsx)(o,{disabled:!t,onClick:()=>i(`codecommit`,e.providerImmutableId),variant:`secondary`,children:`Add repository`}),(0,O.jsx)(o,{disabled:!t,onClick:()=>i(`codepipeline`,e.providerImmutableId),variant:`secondary`,children:`Add pipeline`})]}):e.providerFamily===`atlassian`?(0,O.jsxs)(`div`,{className:V.accountActions,children:[(0,O.jsx)(o,{disabled:!t,onClick:()=>i(`jira`,e.providerImmutableId),variant:`secondary`,children:`Add Jira project`}),(0,O.jsx)(o,{disabled:!t,onClick:()=>i(`confluence`,e.providerImmutableId),variant:`secondary`,children:`Add Confluence space`})]}):null]}),X=e=>`${e.catalog.providerId}\0${e.displayName}`,Z=[`jira`,`confluence`],re={preferredProfileId:null,preferredSiteId:null,providers:Z,requestedOAuthProviders:Z},ie=e=>{let t=Z.filter(t=>!e.some(e=>e.providerId===t));return t.length===0?Z:t},Q=(e,t,n)=>n.length===1&&Z.some(r=>!n.includes(r)&&e.some(e=>e.providerId===r)&&t.some(e=>!e.profileId.startsWith(`legacy:`)&&e.providers.includes(r))),$=(e,t)=>t.length===1&&Z.some(n=>!t.includes(n)&&e.some(e=>e.providerId===n)),ae=(e,t)=>({preferredProfileId:null,preferredSiteId:null,providers:t!==void 0&&e.some(({providerId:e})=>e===t)?[t]:ie(e),requestedOAuthProviders:null}),oe=(e,t,n)=>{if(e.requestedOAuthProviders!==null)return e;let r=$(t,e.providers);if(r&&(n._tag===`idle`||n._tag===`loading`))return e;let i=n._tag===`ready`?n.profiles:[];return{...e,requestedOAuthProviders:r&&n._tag===`failed`||Q(t,i,e.providers)?Z:e.providers}},se=({canConfigure:e,canTest:t,connection:n,enablementState:r,onConfigure:i,onRefreshSynchronization:s,onSetEnabled:l,onSynchronize:u,onTest:f,synchronizationState:m,testState:h})=>{let g=h?._tag===`testing`,_=h!==void 0&&h._tag!==`testing`,v=r===`changing`,y=q(n,h);return(0,O.jsxs)(d,{as:`article`,className:V.card,padding:`default`,shape:`grouped`,children:[(0,O.jsxs)(`div`,{className:V.cardHeading,children:[(0,O.jsxs)(`div`,{className:V.connectionIdentity,children:[(0,O.jsx)(p,{service:n.providerId,size:`compact`}),(0,O.jsx)(c,{as:`h2`,variant:`card-title`,children:n.displayName})]}),(0,O.jsx)(a,{label:y.label,size:`compact`,tone:y.tone})]}),(0,O.jsx)(U,{state:h}),(0,O.jsx)(K,{canSynchronize:e&&n.isEnabled,onRefresh:()=>s(n.pluginConnectionId),onSynchronize:()=>u(n.pluginConnectionId),state:m}),(0,O.jsxs)(`div`,{className:V.cardAction,children:[(0,O.jsx)(o,{disabled:!t||v||g||!n.isEnabled,loading:g,onClick:()=>f(n.pluginConnectionId),variant:`secondary`,children:_?`Retry test`:`Test connection`}),(0,O.jsx)(o,{disabled:!e,onClick:i,variant:`secondary`,children:`Add connection`}),(0,O.jsx)(o,{disabled:!e||v,loading:v,onClick:()=>l(n.pluginConnectionId,!n.isEnabled),variant:n.isEnabled?`secondary`:`primary`,children:n.isEnabled?`Disable`:`Enable service`}),t?null:(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Owner access is required.`})]}),r===`request-failed`?(0,O.jsx)(c,{as:`p`,className:V.setupError,role:`alert`,variant:`body`,children:`Control Center could not change this service. Refresh and try again.`}):null]})},ce=({catalog:e,isSubmitting:t,onCancel:n,onSubmit:r})=>{let[i,a]=(0,w.useState)(e.displayName),[s,u]=(0,w.useState)(null),[d,f]=(0,w.useState)(new Map(e.configurationFields.map(e=>[e.key,e.defaultValue??``]))),p=t=>{t.preventDefault(),u(null);let n=e.configurationFields.map(e=>E(e,d.get(e.key)??``));r(i,n).then(t=>{if(!t){u(`Control Center could not create this connection. Check the fields and try again.`);return}f(t=>{let n=new Map(t);for(let t of e.configurationFields)t.kind===`secret`&&n.set(t.key,``);return n})})},m=(e,t)=>{f(n=>new Map(n).set(e,t))};return(0,O.jsxs)(`form`,{className:V.setupForm,onSubmit:p,children:[(0,O.jsx)(l,{label:`Connection name`,required:!0,size:`compact`,children:e=>(0,O.jsx)(`input`,{...e,maxLength:200,onChange:e=>a(e.currentTarget.value),value:i})}),e.configurationFields.map(e=>(0,O.jsx)(l,{description:e.description,label:e.label,required:e.required,size:`compact`,children:t=>(0,O.jsx)(`input`,{...t,autoComplete:e.kind===`secret`?`off`:void 0,disabled:e.isReadOnly,max:e.maximum??void 0,maxLength:e.kind===`integer`?void 0:e.kind===`secret`?16384:4096,min:e.minimum??void 0,onChange:t=>m(e.key,t.currentTarget.value),type:e.kind===`secret`?`password`:e.kind===`integer`?`number`:e.kind===`url`?`url`:`text`,value:d.get(e.key)??``})},e.key)),s===null?null:(0,O.jsx)(c,{as:`p`,className:V.setupError,role:`alert`,variant:`body`,children:s}),(0,O.jsxs)(`div`,{className:V.setupActions,children:[(0,O.jsx)(o,{disabled:t,onClick:n,type:`button`,variant:`secondary`,children:`Cancel`}),(0,O.jsx)(o,{loading:t,type:`submit`,variant:`primary`,children:`Enable and test`})]})]})},le=({atlassianProfiles:e,atlassianProfilesState:t,atlassianSetupIntent:n,awsProfiles:r,awsProfilesState:i,canConfigure:s,catalog:l,catalogs:u,isAdditional:f,isOpen:m,isRecovery:h,isSubmitting:g,onCancel:_,onDiscoverAws:v,onOpen:y,onStartAtlassianOAuth:b,onSubmit:x,onSubmitAtlassian:S,onSubmitAws:C})=>{let w=l.providerId===`codecommit`||l.providerId===`codepipeline`,T=l.providerId===`jira`||l.providerId===`confluence`;return(0,O.jsxs)(d,{as:`article`,className:V.card,padding:`default`,shape:`grouped`,children:[(0,O.jsxs)(`div`,{className:V.cardHeading,children:[(0,O.jsxs)(`div`,{className:V.connectionIdentity,children:[(0,O.jsx)(p,{service:l.providerId,size:`compact`}),(0,O.jsx)(c,{as:`h2`,variant:`card-title`,children:l.displayName})]}),(0,O.jsx)(a,{label:h?`Needs correction`:f?`Add another`:`Not configured`,size:`compact`,tone:h?`critical`:`neutral`})]}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:l.description}),m?w?(0,O.jsx)(B,{awsProfiles:r,awsProfilesState:i,catalogs:u,isSubmitting:g,onCancel:_,onDiscover:v,onSubmit:C}):T?(0,O.jsx)(M,{catalogs:u,isSubmitting:g,onCancel:_,onStartOAuth:b,onSubmit:S,profiles:e,profilesState:t,setupIntent:n}):(0,O.jsx)(ce,{catalog:l,isSubmitting:g,onCancel:_,onSubmit:x}):(0,O.jsxs)(`div`,{className:V.cardAction,children:[(0,O.jsx)(o,{disabled:!s,onClick:y,variant:`secondary`,children:w?`Configure AWS account`:f&&l.providerId===`jira`?`Add Jira project`:f&&l.providerId===`confluence`?`Add Confluence space`:T?`Configure Atlassian`:`Enable service`}),s?null:(0,O.jsx)(c,{tone:`secondary`,variant:`meta`,children:`Owner access is required.`})]})]})},ue=({actionLabel:e=`Pair to enable`,isActionDisabled:t=!1,onEnable:n,service:r,statusLabel:i=`Available`,statusTone:s=`positive`})=>(0,O.jsxs)(d,{as:`article`,className:V.card,padding:`default`,shape:`grouped`,children:[(0,O.jsxs)(`div`,{className:V.cardHeading,children:[(0,O.jsxs)(`div`,{className:V.connectionIdentity,children:[(0,O.jsx)(p,{service:r.providerId,size:`compact`}),(0,O.jsx)(c,{as:`h2`,variant:`card-title`,children:r.displayName})]}),(0,O.jsx)(a,{label:i,size:`compact`,tone:s})]}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:r.description}),(0,O.jsx)(`div`,{className:V.cardAction,children:(0,O.jsx)(o,{disabled:t,onClick:n,variant:`primary`,children:e})})]}),de=({transport:e=C}={})=>{let t=r(),[n,a]=s(),{invalidateSession:l,state:d}=f(),p=u(d),[m,S]=(0,w.useState)(0),[T,E]=(0,w.useState)({_tag:`idle`}),[D,k]=(0,w.useState)({_tag:`idle`}),[A,j]=(0,w.useState)({_tag:`idle`}),[M,N]=(0,w.useState)(new Map),[P,F]=(0,w.useState)(new Map),[ee,I]=(0,w.useState)(new Map),[L,R]=(0,w.useState)(null),[te,z]=(0,w.useState)(null),[ne,B]=(0,w.useState)(null),H=(0,w.useRef)(new Map),U=(0,w.useRef)(null),W=(0,w.useRef)(new Map),G=(0,w.useRef)(new Map),K=(0,w.useRef)(null),q=(0,w.useRef)(null),J=(0,w.useRef)(new Map),Z=(0,w.useCallback)(t=>{if(p===null||e.synchronization===void 0)return;J.current.get(t)?.abort();let n=new AbortController;J.current.set(t,n),I(e=>new Map(e).set(t,{_tag:`loading`})),e.synchronization(t,n.signal).then(e=>{n.signal.aborted||(J.current.delete(t),I(n=>new Map(n).set(t,{_tag:`ready`,synchronization:e})))},e=>{n.signal.aborted||(J.current.delete(t),h(`UnauthorizedApiError`)(e)&&l(p),I(e=>new Map(e).set(t,{_tag:`failed`})))})},[l,p,e]),ie=(0,w.useCallback)(t=>{if(p===null||e.synchronize===void 0)return;J.current.get(t)?.abort();let n=new AbortController;J.current.set(t,n),I(e=>{let n=e.get(t),r=n?._tag===`ready`?n.synchronization:null;return new Map(e).set(t,{_tag:`syncing`,previous:r})}),e.synchronize(t,n.signal).then(e=>{n.signal.aborted||(J.current.delete(t),I(n=>new Map(n).set(t,{_tag:`ready`,synchronization:e})))},e=>{n.signal.aborted||(J.current.delete(t),h(`UnauthorizedApiError`)(e)&&l(p),I(e=>new Map(e).set(t,{_tag:`failed`})))})},[l,p,e]);(0,w.useEffect)(()=>{if(p===null){E({_tag:`idle`});return}let t=new AbortController;return E({_tag:`loading`}),e.overview(t.signal).then(e=>{t.signal.aborted||E({_tag:`ready`,overview:e})},e=>{t.signal.aborted||(h(`UnauthorizedApiError`)(e)&&l(p),E({_tag:`failed`}))}),()=>t.abort()},[l,m,p,e]),(0,w.useEffect)(()=>{if(T._tag!==`ready`||e.synchronization===void 0)return;let t=T.overview.connections.filter(({supportsSynchronization:e})=>e),n=new Set(t.map(({pluginConnectionId:e})=>e));for(let[e,t]of J.current)n.has(e)||(t.abort(),J.current.delete(e));I(e=>{let t=new Map(e),r=!1;for(let e of t.keys())n.has(e)||(t.delete(e),r=!0);return r?t:e});for(let e of t)Z(e.pluginConnectionId);return()=>{for(let e of t)J.current.get(e.pluginConnectionId)?.abort(),J.current.delete(e.pluginConnectionId)}},[T,Z,e.synchronization]),(0,w.useEffect)(()=>{if(p===null||L!==`codecommit`&&L!==`codepipeline`)return;K.current?.abort();let t=new AbortController;K.current=t,k({_tag:`loading`});let n=e.discoverAwsProfiles;return n===void 0?(k({_tag:`failed`}),()=>t.abort()):(n(t.signal).then(e=>{t.signal.aborted||k({_tag:`ready`,profiles:e})},e=>{t.signal.aborted||(h(`UnauthorizedApiError`)(e)&&l(p),k({_tag:`failed`}))}),()=>t.abort())},[l,L,p,e]),(0,w.useEffect)(()=>{if(p===null||L!==`jira`&&L!==`confluence`)return;q.current?.abort();let t=new AbortController;q.current=t,j({_tag:`loading`});let n=e.discoverAtlassianProfiles;return n===void 0?(j({_tag:`failed`}),()=>t.abort()):(n(t.signal).then(e=>{t.signal.aborted||j({_tag:`ready`,profiles:e})},e=>{t.signal.aborted||(h(`UnauthorizedApiError`)(e)&&l(p),j({_tag:`failed`}))}),()=>t.abort())},[l,L,p,e]),(0,w.useEffect)(()=>(N(new Map),F(new Map),I(new Map),R(null),z(null),B(null),k({_tag:`idle`}),j({_tag:`idle`}),W.current.clear(),()=>{for(let e of H.current.values())e.abort();H.current.clear(),U.current?.abort(),U.current=null,K.current?.abort(),K.current=null,q.current?.abort(),q.current=null;for(let e of J.current.values())e.abort();J.current.clear();for(let e of G.current.values())e.abort();G.current.clear()}),[p]),(0,w.useEffect)(()=>{if(T._tag!==`ready`||d._tag!==`authenticated`||d.session.permission!==`workspace-owner`)return;let e=g(n,`enable`);if(e===null||!T.overview.catalog.some(({providerId:t})=>t===e))return;if(e===`jira`||e===`confluence`){let t=x(n),r=t?.includes(e)===!0;z(r?{preferredProfileId:y(n),preferredSiteId:v(n),providers:t,requestedOAuthProviders:t}:ae(T.overview.connections,e))}R(e);let t=new URLSearchParams(n);t.delete(`enable`),t.delete(`atlassianProfile`),t.delete(`atlassianProvider`),t.delete(`atlassianSite`),a(t,{replace:!0})},[T,n,d,a]);let Q=(0,w.useCallback)(t=>{if(p===null)return;H.current.get(t)?.abort();let n=new AbortController;H.current.set(t,n),N(e=>new Map(e).set(t,{_tag:`testing`})),e.test(t,n.signal).then(e=>{n.signal.aborted||(H.current.delete(t),N(n=>new Map(n).set(t,{_tag:`result`,result:e})))},e=>{n.signal.aborted||(H.current.delete(t),h(`UnauthorizedApiError`)(e)&&l(p),N(e=>new Map(e).set(t,{_tag:`request-failed`})))})},[l,p,e]),$=(0,w.useCallback)(async(t,n)=>{if(p===null)return!1;U.current?.abort();let r=new AbortController;U.current=r,B(n);let i=!1,a=!1,o=!1,s=W.current.get(n)??new Set;W.current.set(n,s);let c=(e,t)=>{s.add(e),i||=t.test._tag!==`healthy`,o||=t.connection.providerAccountId!==null,E(e=>e._tag===`ready`?{_tag:`ready`,overview:{...e.overview,connections:[...e.overview.connections,t.connection]}}:e),N(e=>new Map(e).set(t.connection.pluginConnectionId,{_tag:`result`,result:t.test}))};try{let u=t.filter(e=>!s.has(X(e)));if(e.createBatch!==void 0&&u.length>0){let t=new Map,n=[];for(let r of u){let i=await e.makeConnectionId();t.set(i,X(r)),n.push({pluginConnectionId:i,providerId:r.catalog.providerId,displayName:r.displayName,values:r.values})}let i=await e.createBatch({connections:n},r.signal);if(r.signal.aborted)return!1;let o=new Set;for(let e of i.results){let n=e._tag===`failed`?e.pluginConnectionId:e.response.connection.pluginConnectionId;if(!t.has(n)||o.has(n)){a=!0;continue}if(o.add(n),e._tag===`failed`){a=!0;continue}let r=t.get(e.response.connection.pluginConnectionId);r!==void 0&&c(r,e.response)}a||=o.size!==n.length}else for(let t of u){let n=X(t),i=await e.makeConnectionId(),a=await e.create({pluginConnectionId:i,providerId:t.catalog.providerId,displayName:t.displayName,values:t.values},r.signal);if(r.signal.aborted)return!1;c(n,a)}if(o)try{let t=await e.overview(r.signal);r.signal.aborted||E({_tag:`ready`,overview:t})}catch(e){if(r.signal.aborted)return!1;h(`UnauthorizedApiError`)(e)&&l(p)}return a?W.current.set(n,s):W.current.delete(n),U.current=null,R(i||a?n:null),B(null),!a}catch(e){return r.signal.aborted?!1:(U.current=null,h(`UnauthorizedApiError`)(e)&&l(p),B(null),!1)}},[l,p,e]),ce=(0,w.useCallback)((e,t,n)=>$([{catalog:e,displayName:t,values:n}],e.providerId),[$]),de=(0,w.useCallback)((t,n)=>{if(p===null)return;n||(H.current.get(t)?.abort(),H.current.delete(t),N(e=>{let n=new Map(e);return n.delete(t),n})),G.current.get(t)?.abort();let r=new AbortController;G.current.set(t,r),F(e=>new Map(e).set(t,`changing`)),e.setEnabled(t,n,r.signal).then(e=>{r.signal.aborted||(G.current.delete(t),E(n=>n._tag===`ready`?{_tag:`ready`,overview:{...n.overview,connections:n.overview.connections.map(n=>n.pluginConnectionId===t?e:n)}}:n),F(e=>{let n=new Map(e);return n.delete(t),n}),n?Q(t):N(e=>{let n=new Map(e);return n.delete(t),n}))},e=>{r.signal.aborted||(G.current.delete(t),h(`UnauthorizedApiError`)(e)&&l(p),F(e=>new Map(e).set(t,`request-failed`)))})},[l,p,Q,e]),fe=d._tag===`authenticated`||d._tag===`storage-unavailable`?d.session:null,pe=d._tag===`authenticated`&&d.session.permission===`workspace-owner`;return(0,O.jsxs)(`section`,{"aria-labelledby":`services-title`,className:V.page,children:[(0,O.jsxs)(`header`,{className:V.heading,children:[(0,O.jsx)(c,{as:`h1`,id:`services-title`,variant:`page-title`,children:`Services`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body-large`,children:fe===null||T._tag===`ready`&&T.overview.connections.length===0?`Choose a service below. Control Center will enable it and verify the exact account before using it.`:`Configure first-party providers and verify the exact account each connection represents.`})]}),fe===null&&d._tag!==`checking`?(0,O.jsx)(`div`,{className:V.grid,children:_.map(e=>(0,O.jsx)(ue,{onEnable:()=>t(b(e.providerId)),service:e},e.providerId))}):T._tag===`loading`||T._tag===`idle`?(0,O.jsx)(`div`,{className:V.grid,children:_.map(e=>(0,O.jsx)(ue,{actionLabel:`Loading connections`,isActionDisabled:!0,onEnable:()=>void 0,service:e,statusLabel:`Loading`,statusTone:`progress`},e.providerId))}):T._tag===`failed`?(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(i,{action:(0,O.jsx)(o,{onClick:()=>S(e=>e+1),children:`Try again`}),description:`Control Center could not load connection details. The installed services remain visible below.`,title:`Connections unavailable`}),(0,O.jsx)(`div`,{className:V.grid,children:_.map(e=>(0,O.jsx)(ue,{actionLabel:`Retry connections`,onEnable:()=>S(e=>e+1),service:e,statusLabel:`Installed`,statusTone:`neutral`},e.providerId))})]}):(0,O.jsxs)(O.Fragment,{children:[T.overview.accounts.length===0?null:(0,O.jsxs)(`section`,{"aria-labelledby":`connected-accounts-title`,className:V.accounts,children:[(0,O.jsxs)(`div`,{className:V.sectionHeading,children:[(0,O.jsx)(c,{as:`h2`,id:`connected-accounts-title`,variant:`section-title`,children:`Connected accounts`}),(0,O.jsx)(c,{tone:`secondary`,variant:`body`,children:`One verified provider identity can own several followed resources.`})]}),(0,O.jsx)(`div`,{className:V.accountGrid,children:T.overview.accounts.map(e=>(0,O.jsx)(Y,{account:e,canConfigure:pe,connections:T.overview.connections,enablementStates:P,onAdd:(e,t)=>{(e===`jira`||e===`confluence`)&&z({preferredProfileId:null,preferredSiteId:t,providers:[e],requestedOAuthProviders:null}),R(e)},onSetEnabled:de,onRefreshSynchronization:Z,onSynchronize:ie,synchronizationStates:ee,onTest:Q,testStates:M},e.providerAccountId))})]}),(0,O.jsx)(`div`,{className:V.grid,children:T.overview.catalog.flatMap(t=>{let n=T.overview.connections.filter(e=>e.providerId===t.providerId),r=new Set(T.overview.accounts.flatMap(({resources:e})=>e.map(({followedResourceId:e})=>e))),i=n.filter(({followedResourceId:e})=>e===null||!r.has(e)),a=ae(T.overview.connections,t.providerId===`jira`||t.providerId===`confluence`?t.providerId:void 0),o=oe(te??a,T.overview.connections,A),s=i.map(e=>(0,O.jsx)(se,{canConfigure:pe,canTest:pe,connection:e,enablementState:P.get(e.pluginConnectionId),onConfigure:()=>{(t.providerId===`jira`||t.providerId===`confluence`)&&z(re),R(t.providerId)},onSetEnabled:de,onRefreshSynchronization:Z,onSynchronize:ie,onTest:Q,synchronizationState:ee.get(e.pluginConnectionId),testState:M.get(e.pluginConnectionId)},e.pluginConnectionId));return n.length>0&&L!==t.providerId&&t.providerId!==`jira`&&t.providerId!==`confluence`?s:[...s,(0,O.jsx)(le,{atlassianProfiles:A._tag===`ready`?A.profiles:[],atlassianProfilesState:A._tag,atlassianSetupIntent:o,awsProfiles:D._tag===`ready`?D.profiles:[],awsProfilesState:D._tag,canConfigure:pe,catalog:t,catalogs:T.overview.catalog,isAdditional:n.length>0&&(t.providerId===`jira`||t.providerId===`confluence`),isOpen:L===t.providerId,isRecovery:i.length>0,isSubmitting:ne===t.providerId,onCancel:()=>{W.current.delete(t.providerId),z(null),R(null)},onDiscoverAws:(t,n)=>{let r=e.discoverAwsResources;return r===void 0?Promise.reject(Error(`AWS resource discovery is unavailable`)):r(t,n).catch(e=>(p!==null&&h(`UnauthorizedApiError`)(e)&&l(p),Promise.reject(e)))},onOpen:()=>{L!==t.providerId&&W.current.delete(t.providerId),(t.providerId===`jira`||t.providerId===`confluence`)&&z(a),R(t.providerId)},onStartAtlassianOAuth:(t,n,r)=>{let i=e.startAtlassianOAuthGrant;return i===void 0?Promise.reject(Error(`Atlassian OAuth is unavailable`)):i(t,n,r)},onSubmit:(e,n)=>ce(t,e,n),onSubmitAtlassian:e=>$(e,t.providerId),onSubmitAws:e=>$(e,t.providerId)},`${t.providerId}-catalog`)]})})]})]})};export{de as ServicesPage};
|
|
2
|
+
//# sourceMappingURL=ServicesPage-Co6GJHgc.js.map
|