382eb2e49e5695ec3f2526a009677c2c2134808e
[idea/community.git] / plugins / space / src / main / kotlin / com / intellij / space / vcs / review / details / SpaceReviewParticipantsVmImpl.kt
1 // Copyright 2000-2020 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.client.KCircletClient
11 import circlet.platform.client.property
12 import circlet.platform.client.resolve
13 import circlet.workspaces.Workspace
14 import libraries.coroutines.extra.Lifetime
15 import runtime.reactive.Property
16 import runtime.reactive.cellProperty
17 import runtime.reactive.live
18 import runtime.reactive.property.combineLatest
19
20 internal class SpaceReviewParticipantsVmImpl(
21   override val lifetime: Lifetime,
22   private val projectKey: ProjectKey,
23   val review: Ref<CodeReviewRecord>,
24   participantsRef: Ref<CodeReviewParticipants>,
25   private val pendingCounterRef: Ref<CodeReviewPendingMessageCounter>,
26   private val reviewIdentifier: ReviewIdentifier,
27   private val workspace: Workspace
28 ) : SpaceReviewParticipantsVm {
29   private val client: KCircletClient = workspace.client
30
31   private val participants = participantsRef.property()
32   override val codeReviewRecord: CodeReviewRecord = review.resolve()
33
34   override val authors: Property<List<CodeReviewParticipant>> = cellProperty {
35     participants.live.participants?.filter { it.role == CodeReviewParticipantRole.Author } ?: emptyList()
36   }
37
38   override val reviewers: Property<List<CodeReviewParticipant>> = cellProperty {
39     participants.live.participants?.filter { it.role == CodeReviewParticipantRole.Reviewer } ?: emptyList()
40   }
41   override val me: TD_MemberProfile
42     get() = workspace.me.value
43
44   override val controlVm: Property<ParticipantStateControlVM> = combineLatest(
45     review.property(),
46     reviewers,
47     authors)
48   { reviewRecord, reviewers, authors ->
49     if (reviewRecord.state != CodeReviewState.Opened) return@combineLatest ParticipantStateControlVM.WithoutControls
50
51     createControlVm(reviewers, authors, reviewRecord)
52   }
53
54   private fun createControlVm(reviewers: List<CodeReviewParticipant>,
55                               authors: List<CodeReviewParticipant>,
56                               reviewRecord: CodeReviewRecord): ParticipantStateControlVM {
57     val meReviewer = reviewers.me()
58     val meAuthor = authors.me()
59     val isTurnBased = reviewRecord.turnBased == true
60
61     when {
62       meReviewer != null -> return when {
63         meReviewer.theirTurn == true && isTurnBased -> {
64           ParticipantStateControlVM.ReviewerDropdown(turnBased = true, pendingCounterRef)
65         }
66         (meReviewer.theirTurn == null || !isTurnBased) && meReviewer.reviewerState == null -> {
67           ParticipantStateControlVM.ReviewerDropdown(turnBased = false, pendingCounterRef)
68         }
69         meReviewer.theirTurn == false && isTurnBased -> {
70           ParticipantStateControlVM.ReviewerResumeReviewButton(meReviewer.state)
71         }
72         (meReviewer.theirTurn == null || !isTurnBased) && meReviewer.reviewerState != null -> {
73           ParticipantStateControlVM.ReviewerResumeReviewButton(meReviewer.state)
74         }
75         else -> ParticipantStateControlVM.WithoutControls
76       }
77
78       meAuthor != null -> return when {
79         !isTurnBased -> ParticipantStateControlVM.WithoutControls
80         meAuthor.theirTurn == true -> {
81           ParticipantStateControlVM.AuthorEndTurnButton(
82             canPassTurn = !reviewers.all { it.reviewerState == ReviewerState.Accepted },
83             canFinishReview = reviewers.any { it.reviewerState == ReviewerState.Accepted } &&
84                               reviewers.none { it.reviewerState == null && it.theirTurn == false }
85           )
86         }
87         meAuthor.theirTurn == false && reviewers.isNotEmpty() -> {
88           ParticipantStateControlVM.AuthorResumeReviewButton
89         }
90         else -> ParticipantStateControlVM.WithoutControls
91       }
92       else -> return ParticipantStateControlVM.WithoutControls
93     }
94   }
95
96   private fun List<CodeReviewParticipant>.me() = singleOrNull { it.user.id == me.id }
97
98   override suspend fun addReviewer(profile: TD_MemberProfile) {
99     client.codeReview.addReviewParticipant(
100       projectKey.identifier,
101       reviewIdentifier,
102       profile.identifier,
103       CodeReviewParticipantRole.Reviewer
104     )
105   }
106
107   override suspend fun removeReviewer(profile: TD_MemberProfile) {
108     client.codeReview.removeReviewParticipant(
109       projectKey.identifier,
110       reviewIdentifier,
111       profile.identifier,
112       CodeReviewParticipantRole.Reviewer
113     )
114   }
115 }
116