mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 22:51:17 +07:00
[ghai] Add a way to generate a summary of a PR with AI
Add actions: - Generate a summary - Like the generated summary - Dislike the generated summary Adds UI: - A comment in timeline with a purple hover color - buttons for above actions (cherry picked from commit 6f734fb94f53a4efd8dd950b51d427a21f9ab117) (cherry picked from commit 3e0ae846aa29182724b7a350a2567bff89070351) IJ-CR-148445 GitOrigin-RevId: 51e1544114d334edfc5f001f9145e6d4a0c7e0ae
This commit is contained in:
committed by
intellij-monorepo-bot
parent
bc555ebd94
commit
ae3fd256fb
@@ -399,14 +399,16 @@ f:com.intellij.collaboration.api.json.JsonHttpApiHelperKt
|
|||||||
- f:build(com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$ComponentType,kotlin.jvm.functions.Function1,javax.swing.JComponent,kotlin.jvm.functions.Function1):javax.swing.JComponent
|
- f:build(com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$ComponentType,kotlin.jvm.functions.Function1,javax.swing.JComponent,kotlin.jvm.functions.Function1):javax.swing.JComponent
|
||||||
- f:buildDynamic(com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$ComponentType,kotlin.jvm.functions.Function1,javax.swing.JComponent,kotlin.jvm.functions.Function1):javax.swing.JComponent
|
- f:buildDynamic(com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$ComponentType,kotlin.jvm.functions.Function1,javax.swing.JComponent,kotlin.jvm.functions.Function1):javax.swing.JComponent
|
||||||
- f:getTEXT_CONTENT_WIDTH():I
|
- f:getTEXT_CONTENT_WIDTH():I
|
||||||
- f:withHoverHighlight(javax.swing.JComponent):javax.swing.JComponent
|
- f:withHoverHighlight(javax.swing.JComponent,com.intellij.ui.JBColor):javax.swing.JComponent
|
||||||
*f:com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$Builder
|
*f:com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$Builder
|
||||||
- <init>(com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$ComponentType,kotlin.jvm.functions.Function1,javax.swing.JComponent):V
|
- <init>(com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$ComponentType,kotlin.jvm.functions.Function1,javax.swing.JComponent):V
|
||||||
- f:build():javax.swing.JComponent
|
- f:build():javax.swing.JComponent
|
||||||
- f:getHeader():com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$HeaderComponents
|
- f:getHeader():com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$HeaderComponents
|
||||||
|
- f:getHoverHighlight():com.intellij.ui.JBColor
|
||||||
- f:getIconTooltip():java.lang.String
|
- f:getIconTooltip():java.lang.String
|
||||||
- f:getMaxContentWidth():java.lang.Integer
|
- f:getMaxContentWidth():java.lang.Integer
|
||||||
- f:setHeader(com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$HeaderComponents):V
|
- f:setHeader(com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$HeaderComponents):V
|
||||||
|
- f:setHoverHighlight(com.intellij.ui.JBColor):V
|
||||||
- f:setIconTooltip(java.lang.String):V
|
- f:setIconTooltip(java.lang.String):V
|
||||||
- f:setMaxContentWidth(java.lang.Integer):V
|
- f:setMaxContentWidth(java.lang.Integer):V
|
||||||
- f:withHeader(javax.swing.JComponent,javax.swing.JComponent):com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$Builder
|
- f:withHeader(javax.swing.JComponent,javax.swing.JComponent):com.intellij.collaboration.ui.codereview.CodeReviewChatItemUIUtil$Builder
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.intellij.collaboration.ui.VerticalListPanel
|
|||||||
import com.intellij.collaboration.ui.codereview.avatar.Avatar
|
import com.intellij.collaboration.ui.codereview.avatar.Avatar
|
||||||
import com.intellij.collaboration.ui.codereview.comment.CodeReviewCommentUIUtil
|
import com.intellij.collaboration.ui.codereview.comment.CodeReviewCommentUIUtil
|
||||||
import com.intellij.collaboration.ui.util.CodeReviewColorUtil
|
import com.intellij.collaboration.ui.util.CodeReviewColorUtil
|
||||||
|
import com.intellij.ui.JBColor
|
||||||
import com.intellij.ui.hover.HoverStateListener
|
import com.intellij.ui.hover.HoverStateListener
|
||||||
import com.intellij.ui.scale.JBUIScale
|
import com.intellij.ui.scale.JBUIScale
|
||||||
import com.intellij.util.ui.JBUI
|
import com.intellij.util.ui.JBUI
|
||||||
@@ -76,8 +77,8 @@ object CodeReviewChatItemUIUtil {
|
|||||||
SUPER_COMPACT {
|
SUPER_COMPACT {
|
||||||
override val iconSize: Int = Avatar.Sizes.BASE
|
override val iconSize: Int = Avatar.Sizes.BASE
|
||||||
override val iconGap: Int = 10
|
override val iconGap: Int = 10
|
||||||
override val paddingInsets: Insets = Insets(0,0,0,0)
|
override val paddingInsets: Insets = Insets(0, 0, 0, 0)
|
||||||
override val inputPaddingInsets: Insets = Insets(0,0,0,0)
|
override val inputPaddingInsets: Insets = Insets(0, 0, 0, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,16 +114,20 @@ object CodeReviewChatItemUIUtil {
|
|||||||
get() = iconSize + iconGap
|
get() = iconSize + iconGap
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(type: ComponentType,
|
fun build(
|
||||||
iconProvider: (iconSize: Int) -> Icon,
|
type: ComponentType,
|
||||||
content: JComponent,
|
iconProvider: (iconSize: Int) -> Icon,
|
||||||
init: Builder.() -> Unit): JComponent =
|
content: JComponent,
|
||||||
|
init: Builder.() -> Unit,
|
||||||
|
): JComponent =
|
||||||
buildDynamic(type, { iconSize -> SingleValueModel(iconProvider(iconSize)) }, content, init)
|
buildDynamic(type, { iconSize -> SingleValueModel(iconProvider(iconSize)) }, content, init)
|
||||||
|
|
||||||
fun buildDynamic(type: ComponentType,
|
fun buildDynamic(
|
||||||
iconValueProvider: (iconSize: Int) -> SingleValueModel<Icon>,
|
type: ComponentType,
|
||||||
content: JComponent,
|
iconValueProvider: (iconSize: Int) -> SingleValueModel<Icon>,
|
||||||
init: Builder.() -> Unit): JComponent =
|
content: JComponent,
|
||||||
|
init: Builder.() -> Unit,
|
||||||
|
): JComponent =
|
||||||
Builder(type, iconValueProvider, content).apply(init).build()
|
Builder(type, iconValueProvider, content).apply(init).build()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,7 +136,7 @@ object CodeReviewChatItemUIUtil {
|
|||||||
class Builder(
|
class Builder(
|
||||||
private val type: ComponentType,
|
private val type: ComponentType,
|
||||||
private val iconValueProvider: (Int) -> SingleValueModel<Icon>,
|
private val iconValueProvider: (Int) -> SingleValueModel<Icon>,
|
||||||
private val content: JComponent
|
private val content: JComponent,
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Tooltip for a main icon
|
* Tooltip for a main icon
|
||||||
@@ -149,6 +154,11 @@ object CodeReviewChatItemUIUtil {
|
|||||||
*/
|
*/
|
||||||
var header: HeaderComponents? = null
|
var header: HeaderComponents? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color to use as the background color on-hover.
|
||||||
|
*/
|
||||||
|
var hoverHighlight: JBColor = CodeReviewColorUtil.Review.Chat.hover
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper fun to setup [HeaderComponents]
|
* Helper fun to setup [HeaderComponents]
|
||||||
*/
|
*/
|
||||||
@@ -175,7 +185,9 @@ object CodeReviewChatItemUIUtil {
|
|||||||
actionsVisibleOnHover(it, header?.actions)
|
actionsVisibleOnHover(it, header?.actions)
|
||||||
}.apply {
|
}.apply {
|
||||||
border = JBUI.Borders.empty(type.paddingInsets)
|
border = JBUI.Borders.empty(type.paddingInsets)
|
||||||
}.let { withHoverHighlight(it) }
|
}.let {
|
||||||
|
withHoverHighlight(it, hoverHighlight)
|
||||||
|
}
|
||||||
|
|
||||||
private fun <T> JComponent.wrapIfNotNull(value: T?, block: (JComponent, T) -> JComponent): JComponent = let {
|
private fun <T> JComponent.wrapIfNotNull(value: T?, block: (JComponent, T) -> JComponent): JComponent = let {
|
||||||
if (value != null) block(it, value) else it
|
if (value != null) block(it, value) else it
|
||||||
@@ -218,7 +230,7 @@ object CodeReviewChatItemUIUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun withHoverHighlight(comp: JComponent): JComponent {
|
fun withHoverHighlight(comp: JComponent, hoverHighlight: JBColor): JComponent {
|
||||||
val highlighterPanel = JPanelWithBackground(BorderLayout()).apply {
|
val highlighterPanel = JPanelWithBackground(BorderLayout()).apply {
|
||||||
isOpaque = false
|
isOpaque = false
|
||||||
background = null
|
background = null
|
||||||
@@ -228,7 +240,7 @@ object CodeReviewChatItemUIUtil {
|
|||||||
override fun hoverChanged(component: Component, hovered: Boolean) {
|
override fun hoverChanged(component: Component, hovered: Boolean) {
|
||||||
// TODO: extract to theme colors
|
// TODO: extract to theme colors
|
||||||
component.background = if (hovered) {
|
component.background = if (hovered) {
|
||||||
CodeReviewColorUtil.Review.Chat.hover
|
hoverHighlight
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
null
|
null
|
||||||
|
|||||||
@@ -321,6 +321,18 @@ fun <D> Wrapper.bindContentIn(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
|
fun Wrapper.bindContent(
|
||||||
|
debugName: String, contentFlow: Flow<JComponent?>,
|
||||||
|
) {
|
||||||
|
showingScope(debugName) {
|
||||||
|
contentFlow.collect {
|
||||||
|
setContent(it)
|
||||||
|
repaint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun <D> Wrapper.bindContentImpl(
|
private suspend fun <D> Wrapper.bindContentImpl(
|
||||||
dataFlow: Flow<D>,
|
dataFlow: Flow<D>,
|
||||||
componentFactory: CoroutineScope.(D) -> JComponent?,
|
componentFactory: CoroutineScope.(D) -> JComponent?,
|
||||||
|
|||||||
@@ -14,6 +14,10 @@
|
|||||||
interface="org.jetbrains.plugins.github.ai.GHPRAIReviewExtension"
|
interface="org.jetbrains.plugins.github.ai.GHPRAIReviewExtension"
|
||||||
dynamic="true"/>
|
dynamic="true"/>
|
||||||
|
|
||||||
|
<extensionPoint qualifiedName="intellij.vcs.github.aiSummaryExtension"
|
||||||
|
interface="org.jetbrains.plugins.github.ai.GHPRAISummaryExtension"
|
||||||
|
dynamic="true"/>
|
||||||
|
|
||||||
<extensionPoint qualifiedName="com.intellij.vcs.github.gistContentsCollector"
|
<extensionPoint qualifiedName="com.intellij.vcs.github.gistContentsCollector"
|
||||||
interface="org.jetbrains.plugins.github.GithubGistContentsCollector"
|
interface="org.jetbrains.plugins.github.GithubGistContentsCollector"
|
||||||
dynamic="true"/>
|
dynamic="true"/>
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package org.jetbrains.plugins.github.ai
|
||||||
|
|
||||||
|
import com.intellij.collaboration.async.singleExtensionFlow
|
||||||
|
import com.intellij.openapi.extensions.ExtensionPointName
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import org.jetbrains.annotations.ApiStatus
|
||||||
|
import org.jetbrains.annotations.Nls
|
||||||
|
import org.jetbrains.plugins.github.pullrequest.data.GHPRDataContext
|
||||||
|
import org.jetbrains.plugins.github.pullrequest.data.provider.GHPRDataProvider
|
||||||
|
import javax.swing.JComponent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a summary that can be generated at the top of the timeline.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Internal
|
||||||
|
interface GHPRAISummaryViewModel {
|
||||||
|
val isGenerating: StateFlow<Boolean>
|
||||||
|
|
||||||
|
val summaryHtml: StateFlow<GenerationState<String>>
|
||||||
|
|
||||||
|
val rating: StateFlow<Boolean?>
|
||||||
|
val hasKnownActivity: StateFlow<Boolean>
|
||||||
|
|
||||||
|
fun startGenerating()
|
||||||
|
fun stopGenerating()
|
||||||
|
|
||||||
|
fun rate(isUseful: Boolean)
|
||||||
|
|
||||||
|
sealed interface GenerationState<out T> {
|
||||||
|
data object NotStarted : GenerationState<Nothing>
|
||||||
|
data class NotStartedDueToError(val error: @Nls String) : GenerationState<Nothing>
|
||||||
|
data object Loading : GenerationState<Nothing>
|
||||||
|
data class Error(val error: Exception) : GenerationState<Nothing>
|
||||||
|
|
||||||
|
sealed interface WithValue<T> : GenerationState<T> {
|
||||||
|
val value: T
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Step<T>(override val value: T) : WithValue<T>
|
||||||
|
data class Interrupted<T>(override val value: T) : WithValue<T>
|
||||||
|
data class Done<T>(override val value: T) : WithValue<T>
|
||||||
|
|
||||||
|
fun getOrNull(): T? = (this as? WithValue)?.value
|
||||||
|
fun isLoading(): Boolean = this is Loading || this is Step
|
||||||
|
|
||||||
|
fun <R> map(mapper: (T) -> R): GenerationState<R> = when (this) {
|
||||||
|
is Step -> Step(mapper(value))
|
||||||
|
is Interrupted -> Interrupted(mapper(value))
|
||||||
|
is Done -> Done(mapper(value))
|
||||||
|
is NotStarted -> this
|
||||||
|
is NotStartedDueToError -> this
|
||||||
|
is Loading -> this
|
||||||
|
is Error -> this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
|
interface GHPRAISummaryExtension {
|
||||||
|
companion object {
|
||||||
|
private val EP = ExtensionPointName.create<GHPRAISummaryExtension>("intellij.vcs.github.aiSummaryExtension")
|
||||||
|
|
||||||
|
internal val singleFlow: Flow<GHPRAISummaryExtension?>
|
||||||
|
get() = EP.singleExtensionFlow()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun provideSummaryVm(
|
||||||
|
cs: CoroutineScope,
|
||||||
|
project: Project,
|
||||||
|
dataContext: GHPRDataContext,
|
||||||
|
dataProvider: GHPRDataProvider,
|
||||||
|
): GHPRAISummaryViewModel?
|
||||||
|
|
||||||
|
fun createTimelineComponent(vm: GHPRAISummaryViewModel): JComponent
|
||||||
|
}
|
||||||
@@ -16,6 +16,8 @@ import kotlinx.coroutines.flow.*
|
|||||||
import org.jetbrains.annotations.ApiStatus
|
import org.jetbrains.annotations.ApiStatus
|
||||||
import org.jetbrains.plugins.github.ai.GHPRAIReviewExtension
|
import org.jetbrains.plugins.github.ai.GHPRAIReviewExtension
|
||||||
import org.jetbrains.plugins.github.ai.GHPRAIReviewViewModel
|
import org.jetbrains.plugins.github.ai.GHPRAIReviewViewModel
|
||||||
|
import org.jetbrains.plugins.github.ai.GHPRAISummaryExtension
|
||||||
|
import org.jetbrains.plugins.github.ai.GHPRAISummaryViewModel
|
||||||
import org.jetbrains.plugins.github.pullrequest.config.GithubPullRequestsProjectUISettings
|
import org.jetbrains.plugins.github.pullrequest.config.GithubPullRequestsProjectUISettings
|
||||||
import org.jetbrains.plugins.github.pullrequest.data.GHPRDataContext
|
import org.jetbrains.plugins.github.pullrequest.data.GHPRDataContext
|
||||||
import org.jetbrains.plugins.github.pullrequest.data.GHPRIdentifier
|
import org.jetbrains.plugins.github.pullrequest.data.GHPRIdentifier
|
||||||
@@ -36,6 +38,7 @@ import org.jetbrains.plugins.github.pullrequest.ui.toolwindow.model.GHPRToolWind
|
|||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
interface GHPRViewModelContainer {
|
interface GHPRViewModelContainer {
|
||||||
val aiReviewVm: StateFlow<GHPRAIReviewViewModel?>
|
val aiReviewVm: StateFlow<GHPRAIReviewViewModel?>
|
||||||
|
val aiSummaryVm: StateFlow<GHPRAISummaryViewModel?>
|
||||||
|
|
||||||
val infoVm: GHPRInfoViewModel
|
val infoVm: GHPRInfoViewModel
|
||||||
val branchWidgetVm: GHPRBranchWidgetViewModel
|
val branchWidgetVm: GHPRBranchWidgetViewModel
|
||||||
@@ -51,7 +54,7 @@ internal class GHPRViewModelContainerImpl(
|
|||||||
dataContext: GHPRDataContext,
|
dataContext: GHPRDataContext,
|
||||||
private val projectVm: GHPRToolWindowProjectViewModel,
|
private val projectVm: GHPRToolWindowProjectViewModel,
|
||||||
private val pullRequestId: GHPRIdentifier,
|
private val pullRequestId: GHPRIdentifier,
|
||||||
cancelWith: Disposable
|
cancelWith: Disposable,
|
||||||
) : GHPRViewModelContainer {
|
) : GHPRViewModelContainer {
|
||||||
private val cs = parentCs.childScope(javaClass.name).cancelledWith(cancelWith)
|
private val cs = parentCs.childScope(javaClass.name).cancelledWith(cancelWith)
|
||||||
|
|
||||||
@@ -71,6 +74,13 @@ internal class GHPRViewModelContainerImpl(
|
|||||||
GHPRAIReviewExtension.EP.singleExtensionFlow()
|
GHPRAIReviewExtension.EP.singleExtensionFlow()
|
||||||
.mapScoped { it?.provideReviewVm(project, this, dataContext, dataProvider) }
|
.mapScoped { it?.provideReviewVm(project, this, dataContext, dataProvider) }
|
||||||
.stateIn(cs, SharingStarted.Eagerly, null)
|
.stateIn(cs, SharingStarted.Eagerly, null)
|
||||||
|
override val aiSummaryVm: StateFlow<GHPRAISummaryViewModel?> =
|
||||||
|
GHPRAISummaryExtension.singleFlow
|
||||||
|
.mapScoped { extension ->
|
||||||
|
val cs = this@mapScoped
|
||||||
|
extension?.provideSummaryVm(cs, project, dataContext, dataProvider)
|
||||||
|
}
|
||||||
|
.stateIn(cs, SharingStarted.Eagerly, null)
|
||||||
|
|
||||||
private val branchStateVm by lazy {
|
private val branchStateVm by lazy {
|
||||||
GHPRReviewBranchStateSharedViewModel(cs, dataContext, dataProvider)
|
GHPRReviewBranchStateSharedViewModel(cs, dataContext, dataProvider)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import com.intellij.collaboration.ui.codereview.comment.submitActionIn
|
|||||||
import com.intellij.collaboration.ui.codereview.list.error.ErrorStatusPanelFactory
|
import com.intellij.collaboration.ui.codereview.list.error.ErrorStatusPanelFactory
|
||||||
import com.intellij.collaboration.ui.codereview.list.error.ErrorStatusPresenter
|
import com.intellij.collaboration.ui.codereview.list.error.ErrorStatusPresenter
|
||||||
import com.intellij.collaboration.ui.codereview.timeline.comment.CommentTextFieldFactory
|
import com.intellij.collaboration.ui.codereview.timeline.comment.CommentTextFieldFactory
|
||||||
|
import com.intellij.collaboration.ui.util.bindContent
|
||||||
import com.intellij.collaboration.ui.util.bindTextHtmlIn
|
import com.intellij.collaboration.ui.util.bindTextHtmlIn
|
||||||
import com.intellij.collaboration.ui.util.bindTextIn
|
import com.intellij.collaboration.ui.util.bindTextIn
|
||||||
import com.intellij.collaboration.ui.util.bindVisibilityIn
|
import com.intellij.collaboration.ui.util.bindVisibilityIn
|
||||||
@@ -38,6 +39,7 @@ import com.intellij.util.ui.UIUtil
|
|||||||
import com.intellij.util.ui.update.UiNotifyConnector
|
import com.intellij.util.ui.update.UiNotifyConnector
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
import org.jetbrains.plugins.github.ai.GHPRAISummaryExtension
|
||||||
import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException
|
import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException
|
||||||
import org.jetbrains.plugins.github.i18n.GithubBundle
|
import org.jetbrains.plugins.github.i18n.GithubBundle
|
||||||
import org.jetbrains.plugins.github.pullrequest.ui.details.model.GHPRDetailsFull
|
import org.jetbrains.plugins.github.pullrequest.ui.details.model.GHPRDetailsFull
|
||||||
@@ -52,11 +54,13 @@ import javax.swing.JPanel
|
|||||||
import javax.swing.event.ChangeEvent
|
import javax.swing.event.ChangeEvent
|
||||||
import javax.swing.event.ChangeListener
|
import javax.swing.event.ChangeListener
|
||||||
|
|
||||||
internal class GHPRFileEditorComponentFactory(private val cs: CoroutineScope,
|
internal class GHPRFileEditorComponentFactory(
|
||||||
private val project: Project,
|
private val cs: CoroutineScope,
|
||||||
private val projectVm: GHPRToolWindowProjectViewModel,
|
private val project: Project,
|
||||||
private val timelineVm: GHPRTimelineViewModel,
|
private val projectVm: GHPRToolWindowProjectViewModel,
|
||||||
private val initialDetails: GHPRDetailsFull) {
|
private val timelineVm: GHPRTimelineViewModel,
|
||||||
|
private val initialDetails: GHPRDetailsFull,
|
||||||
|
) {
|
||||||
|
|
||||||
private val uiDisposable = cs.nestedDisposable()
|
private val uiDisposable = cs.nestedDisposable()
|
||||||
|
|
||||||
@@ -99,6 +103,18 @@ internal class GHPRFileEditorComponentFactory(private val cs: CoroutineScope,
|
|||||||
border = JBUI.Borders.empty(CodeReviewTimelineUIUtil.VERT_PADDING, 0)
|
border = JBUI.Borders.empty(CodeReviewTimelineUIUtil.VERT_PADDING, 0)
|
||||||
|
|
||||||
add(header)
|
add(header)
|
||||||
|
|
||||||
|
add(Wrapper().apply {
|
||||||
|
val summaryComponent = combine(
|
||||||
|
projectVm.acquireAISummaryViewModel(loadedDetails.value.id, uiDisposable),
|
||||||
|
GHPRAISummaryExtension.singleFlow
|
||||||
|
) { summaryVm, extension ->
|
||||||
|
summaryVm?.let { extension?.createTimelineComponent(it) }
|
||||||
|
}
|
||||||
|
bindVisibilityIn(cs, summaryComponent.map { it != null })
|
||||||
|
bindContent("${javaClass.name}.summaryComponent.content", summaryComponent)
|
||||||
|
})
|
||||||
|
|
||||||
add(description)
|
add(description)
|
||||||
add(timeline)
|
add(timeline)
|
||||||
|
|
||||||
@@ -126,7 +142,8 @@ internal class GHPRFileEditorComponentFactory(private val cs: CoroutineScope,
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
UiNotifyConnector.doWhenFirstShown(scrollPane) {
|
UiNotifyConnector.doWhenFirstShown(scrollPane)
|
||||||
|
{
|
||||||
timelineVm.requestMore()
|
timelineVm.requestMore()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.*
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.jetbrains.annotations.ApiStatus
|
import org.jetbrains.annotations.ApiStatus
|
||||||
import org.jetbrains.plugins.github.ai.GHPRAIReviewViewModel
|
import org.jetbrains.plugins.github.ai.GHPRAIReviewViewModel
|
||||||
|
import org.jetbrains.plugins.github.ai.GHPRAISummaryViewModel
|
||||||
import org.jetbrains.plugins.github.api.GHRepositoryConnection
|
import org.jetbrains.plugins.github.api.GHRepositoryConnection
|
||||||
import org.jetbrains.plugins.github.api.GHRepositoryCoordinates
|
import org.jetbrains.plugins.github.api.GHRepositoryCoordinates
|
||||||
import org.jetbrains.plugins.github.api.data.pullrequest.GHPullRequestShort
|
import org.jetbrains.plugins.github.api.data.pullrequest.GHPullRequestShort
|
||||||
@@ -55,7 +56,7 @@ class GHPRToolWindowProjectViewModel internal constructor(
|
|||||||
private val project: Project,
|
private val project: Project,
|
||||||
parentCs: CoroutineScope,
|
parentCs: CoroutineScope,
|
||||||
private val twVm: GHPRToolWindowViewModel,
|
private val twVm: GHPRToolWindowViewModel,
|
||||||
connection: GHRepositoryConnection
|
connection: GHRepositoryConnection,
|
||||||
) : ReviewToolwindowProjectViewModel<GHPRToolWindowTab, GHPRToolWindowTabViewModel> {
|
) : ReviewToolwindowProjectViewModel<GHPRToolWindowTab, GHPRToolWindowTabViewModel> {
|
||||||
private val cs = parentCs.childScope(javaClass.name)
|
private val cs = parentCs.childScope(javaClass.name)
|
||||||
|
|
||||||
@@ -161,6 +162,9 @@ class GHPRToolWindowProjectViewModel internal constructor(
|
|||||||
fun acquireAIReviewViewModel(id: GHPRIdentifier, disposable: Disposable): StateFlow<GHPRAIReviewViewModel?> =
|
fun acquireAIReviewViewModel(id: GHPRIdentifier, disposable: Disposable): StateFlow<GHPRAIReviewViewModel?> =
|
||||||
pullRequestsVms[id].acquireValue(disposable).aiReviewVm
|
pullRequestsVms[id].acquireValue(disposable).aiReviewVm
|
||||||
|
|
||||||
|
fun acquireAISummaryViewModel(id: GHPRIdentifier, disposable: Disposable): StateFlow<GHPRAISummaryViewModel?> =
|
||||||
|
pullRequestsVms[id].acquireValue(disposable).aiSummaryVm
|
||||||
|
|
||||||
fun acquireInfoViewModel(id: GHPRIdentifier, disposable: Disposable): GHPRInfoViewModel =
|
fun acquireInfoViewModel(id: GHPRIdentifier, disposable: Disposable): GHPRInfoViewModel =
|
||||||
pullRequestsVms[id].acquireValue(disposable).infoVm
|
pullRequestsVms[id].acquireValue(disposable).infoVm
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user