[space] Upgrade space-idea-sdk to 1.1.63274
[idea/community.git] / plugins / space / src / main / kotlin / com / intellij / space / vcs / review / details / SpaceReviewDetailsVm.kt
1 // Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.space.vcs.review.details
3
4 import circlet.client.api.ProjectKey
5 import circlet.client.api.TD_MemberProfile
6 import circlet.client.api.identifier
7 import circlet.code.api.*
8 import circlet.code.codeReview
9 import circlet.platform.api.Ref
10 import circlet.platform.api.TID
11 import circlet.platform.client.*
12 import circlet.workspaces.Workspace
13 import com.intellij.openapi.project.Project
14 import com.intellij.space.utils.SpaceUrls
15 import com.intellij.space.vcs.SpaceProjectInfo
16 import com.intellij.space.vcs.SpaceRepoInfo
17 import com.intellij.space.vcs.review.details.diff.SpaceDiffVm
18 import com.intellij.space.vcs.review.details.diff.SpaceDiffVmImpl
19 import com.intellij.space.vcs.review.details.diff.SpaceReviewDiffLoader
20 import com.intellij.space.vcs.review.details.process.SpaceReviewStateUpdater
21 import com.intellij.space.vcs.review.details.process.SpaceReviewStateUpdaterImpl
22 import libraries.coroutines.extra.Lifetime
23 import libraries.coroutines.extra.Lifetimed
24 import runtime.reactive.*
25 import runtime.reactive.property.map
26 import runtime.reactive.property.mapInit
27
28 internal sealed class SpaceReviewDetailsVm<R : CodeReviewRecord>(
29   final override val lifetime: Lifetime,
30   val ideaProject: Project,
31   val spaceProjectInfo: SpaceProjectInfo,
32   spaceReposInfo: Set<SpaceRepoInfo>,
33   val reviewRef: Ref<R>,
34   val workspace: Workspace
35 ) : Lifetimed {
36   val client: KCircletClient = workspace.client
37
38   val review: Property<R> = reviewRef.property()
39
40   val projectKey: ProjectKey = review.value.project
41   val reviewKey: String? = review.value.key
42
43   val reviewUrl: String = SpaceUrls.review(projectKey, review.value.number)
44
45   val reviewId: TID = review.value.id
46
47   val title: Property<String> = cellProperty { review.live.title }
48
49   val state: Property<CodeReviewState> = cellProperty { review.live.state }
50
51   val createdAt: Property<Long> = cellProperty { review.live.createdAt }
52
53   val createdBy: Property<TD_MemberProfile> = cellProperty { review.live.createdBy!!.resolve() }
54
55   val turnBased: Property<Boolean?> = cellProperty { review.live.turnBased }
56
57   val reviewStateUpdater: SpaceReviewStateUpdater = SpaceReviewStateUpdaterImpl(workspace, review.value)
58
59   private val infoByRepos = spaceReposInfo.associateBy(SpaceRepoInfo::name)
60
61   private val participantsProperty: Property<LoadingValue<Ref<CodeReviewParticipants>>> = load {
62     client.arena.resolveRefsOrFetch {
63       reviewRef.extensionRef(CodeReviewParticipants::class)
64     }
65   }
66
67   private val participantsRef: Property<Ref<CodeReviewParticipants>?> = lastLoadedValueOrNull(participantsProperty)
68   private val pendingCounterRef: Property<Ref<CodeReviewPendingMessageCounter>?> = lastLoadedValueOrNull(pendingCounterAsync(client))
69
70   val participantsVm: Property<SpaceReviewParticipantsVm?> = map(participantsRef, pendingCounterRef) { participantsRef, pendingCounterRef ->
71     if (participantsRef != null && pendingCounterRef != null) {
72       SpaceReviewParticipantsVmImpl(lifetime, projectKey, reviewRef, participantsRef, pendingCounterRef, review.value.identifier, workspace)
73     }
74     else null
75   }
76
77   private val detailedInfo: Property<CodeReviewDetailedInfo?> = mapInit(review, null) {
78     client.codeReview.getReviewDetails(review.value.project.identifier, review.value.identifier)
79   }
80
81   val commits: Property<List<SpaceReviewCommitListItem>> = mapInit(detailedInfo, emptyList()) { detailedInfo ->
82     val revisions: List<RevisionsInReview> = detailedInfo?.commits ?: emptyList()
83
84     revisions.flatMap { revInReview ->
85       val repo = revInReview.repository
86       val repoInfo = infoByRepos[repo.name]
87       val commitsInRepository = revInReview.commits.size
88
89       revInReview.commits
90         .filterNot(GitCommitWithGraph::unreachable)
91         .mapIndexed { index, gitCommitWithGraph -> SpaceReviewCommitListItem(gitCommitWithGraph, repo, index, commitsInRepository, repoInfo) }
92     }
93   }
94
95   val selectedTab: MutableProperty<SelectedTab> = mutableProperty(SelectedTab.INFO)
96
97   val commitChangesVm: SpaceReviewChangesVm = SpaceReviewChangesVmImpl(
98     lifetime, client, projectKey, review.value.identifier,
99     reviewId, commits, participantsVm, infoByRepos
100   )
101
102   val allChangesVm: SpaceReviewChangesVmImpl = SpaceReviewChangesVmImpl(
103     lifetime, client, projectKey, review.value.identifier,
104     reviewId, commits, participantsVm, infoByRepos
105   )
106
107   val selectedChangesVm: Property<SpaceReviewChangesVm> = map(selectedTab) { tab ->
108     selectedOrAll(tab, commitChangesVm, allChangesVm)
109   }
110
111   val spaceDiffVm: SpaceDiffVm = SpaceDiffVmImpl(client,
112                                                  reviewId,
113                                                  reviewKey as String,
114                                                  projectKey,
115                                                  selectedChangesVm,
116                                                  SpaceReviewDiffLoader(lifetime, client),
117                                                  participantsVm)
118 }
119
120 private fun <T> selectedOrAll(tab: SelectedTab, selected: T, all: T): T = when (tab) {
121   SelectedTab.INFO -> all
122   SelectedTab.COMMITS -> selected
123 }
124
125 internal class MergeRequestDetailsVm(
126   lifetime: Lifetime,
127   ideaProject: Project,
128   spaceProjectInfo: SpaceProjectInfo,
129   spaceReposInfo: Set<SpaceRepoInfo>,
130   refMrRecord: Ref<MergeRequestRecord>,
131   workspace: Workspace
132 ) : SpaceReviewDetailsVm<MergeRequestRecord>(lifetime, ideaProject, spaceProjectInfo, spaceReposInfo, refMrRecord, workspace) {
133
134   private val branchPair: Property<MergeRequestBranchPair> = cellProperty { review.live.branchPair }
135
136   val repository: Property<String> = cellProperty { branchPair.live.repository }
137   val targetBranchInfo: Property<MergeRequestBranch?> = cellProperty { branchPair.live.targetBranchInfo }
138   val sourceBranchInfo: Property<MergeRequestBranch?> = cellProperty { branchPair.live.sourceBranchInfo }
139 }
140
141 internal class CommitSetReviewDetailsVm(
142   lifetime: Lifetime,
143   ideaProject: Project,
144   spaceProjectInfo: SpaceProjectInfo,
145   spaceReposInfo: Set<SpaceRepoInfo>,
146   refMrRecord: Ref<CommitSetReviewRecord>,
147   workspace: Workspace
148 ) : SpaceReviewDetailsVm<CommitSetReviewRecord>(lifetime, ideaProject, spaceProjectInfo, spaceReposInfo, refMrRecord, workspace)
149
150 internal fun createReviewDetailsVm(lifetime: Lifetime,
151                                    project: Project,
152                                    workspace: Workspace,
153                                    spaceProjectInfo: SpaceProjectInfo,
154                                    spaceReposInfo: Set<SpaceRepoInfo>,
155                                    codeReviewListItem: CodeReviewListItem): SpaceReviewDetailsVm<out CodeReviewRecord> {
156   val client = workspace.client
157   return when (val codeReviewRecord = codeReviewListItem.review.resolve()) {
158     is MergeRequestRecord -> MergeRequestDetailsVm(
159       lifetime,
160       project,
161       spaceProjectInfo,
162       spaceReposInfo,
163       codeReviewRecord.toRef(client.arena),
164       workspace
165     )
166     is CommitSetReviewRecord -> CommitSetReviewDetailsVm(
167       lifetime,
168       project,
169       spaceProjectInfo,
170       spaceReposInfo,
171       codeReviewRecord.toRef(client.arena),
172       workspace
173     )
174     else -> throw IllegalArgumentException("Unable to resolve CodeReviewRecord")
175   }
176 }
177
178 enum class SelectedTab {
179   INFO,
180   COMMITS
181 }
182
183 private fun SpaceReviewDetailsVm<*>.pendingCounterAsync(client: KCircletClient): LoadingProperty<Ref<CodeReviewPendingMessageCounter>> {
184   return load {
185     client.arena.resolveRefsOrFetch {
186       reviewRef.extensionRef(CodeReviewPendingMessageCounter::class)
187     }
188   }
189 }