diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 18f0d3db2404..793a4e82789d 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -51,11 +51,6 @@
-
-
-
-
-
diff --git a/.idea/libraries/jackson_datatype_joda.xml b/.idea/libraries/jackson_datatype_joda.xml
deleted file mode 100644
index f9d777e89990..000000000000
--- a/.idea/libraries/jackson_datatype_joda.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/ktor_websockets.xml b/.idea/libraries/ktor_websockets.xml
deleted file mode 100644
index ae60e89a4dbc..000000000000
--- a/.idea/libraries/ktor_websockets.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/space_idea_sdk.xml b/.idea/libraries/space_idea_sdk.xml
deleted file mode 100644
index 52da14468cdd..000000000000
--- a/.idea/libraries/space_idea_sdk.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index f40e16c86c94..6bd97b66290d 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -530,7 +530,6 @@
-
@@ -819,7 +818,6 @@
-
diff --git a/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy b/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy
index 8c02fcbba93d..60ad9a253669 100644
--- a/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy
+++ b/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy
@@ -1,4 +1,4 @@
-// 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.
+// 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.
package org.jetbrains.intellij.build
import groovy.transform.CompileStatic
@@ -85,7 +85,6 @@ abstract class BaseIdeaProperties extends JetBrainsProductProperties {
"intellij.webp",
"intellij.grazie",
"intellij.featuresTrainer",
- "intellij.space",
"intellij.lombok"
]
diff --git a/intellij.idea.community.main.iml b/intellij.idea.community.main.iml
index 4e445ec593b4..c899d56ae6ad 100644
--- a/intellij.idea.community.main.iml
+++ b/intellij.idea.community.main.iml
@@ -142,7 +142,6 @@
-
diff --git a/intellij.idea.community.main.space.iml b/intellij.idea.community.main.space.iml
deleted file mode 100644
index 3b59ca6cd12c..000000000000
--- a/intellij.idea.community.main.space.iml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy
index a934f8043b09..0b3258009e9e 100644
--- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy
+++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy
@@ -336,9 +336,6 @@ class CommunityLibraryLicenses {
new LibraryLicense(name: "Jackson", libraryName: "jackson", url: "https://github.com/FasterXML/jackson").apache(),
new LibraryLicense(name: "Jackson Databind", libraryName: "jackson-databind",
url: "https://github.com/FasterXML/jackson-databind").apache(),
- new LibraryLicense(name: "Jackson Datatype Joda",
- libraryName: "jackson-datatype-joda",
- url: "https://github.com/FasterXML/jackson-datatype-joda").apache(),
new LibraryLicense(name: "Jackson Module Kotlin", libraryName: "jackson-module-kotlin",
url: "https://github.com/FasterXML/jackson-module-kotlin").apache(),
new LibraryLicense(name: "Jakarta ORO", libraryName: "OroMatcher",
@@ -449,15 +446,6 @@ class CommunityLibraryLicenses {
new LibraryLicense(name: "Kryo", libraryName: "Kryo",
url: "https://github.com/EsotericSoftware/kryo",
licenseUrl: "https://github.com/EsotericSoftware/kryo/blob/master/LICENSE.md").newBsd(),
- new LibraryLicense(name: "ktor-client-apache",
- libraryName: "space-ktor-client-apache",
- url: "https://github.com/ktorio/ktor").apache(),
- new LibraryLicense(name: "ktor-server-netty",
- libraryName: "space-ktor-server-netty",
- url: "https://github.com/ktorio/ktor").apache(),
- new LibraryLicense(name: "ktor-websockets",
- libraryName: "ktor-websockets",
- url: "https://github.com/ktorio/ktor").apache(),
new LibraryLicense(name: "kXML2", libraryName: "kxml2", license: "BSD", url: "http://sourceforge.net/projects/kxml/"),
new LibraryLicense(name: "Language Tool", libraryName: "org.languagetool:languagetool-core:5.2",
license: "LGPL 2.1",
@@ -693,7 +681,6 @@ class CommunityLibraryLicenses {
jetbrainsLibrary("rd-framework"),
jetbrainsLibrary("rd-swing"),
jetbrainsLibrary("rd-text"),
- jetbrainsLibrary("space-idea-sdk"),
jetbrainsLibrary("tcServiceMessages"),
jetbrainsLibrary("tips-idea-ce"),
jetbrainsLibrary("tips-pycharm-community"),
diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy
index 61edcb1eaf4c..2626935973e8 100644
--- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy
+++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy
@@ -268,10 +268,6 @@ final class CommunityRepositoryModules {
bundlingRestrictions.includeInEapOnly = true
},
plugin("intellij.jps.cache"),
- plugin("intellij.space") {
- withProjectLibrary("space-idea-sdk")
- withProjectLibrary("jackson-datatype-joda")
- },
plugin("intellij.lombok") {
withModule("intellij.lombok.generated")
},
diff --git a/plugins/space/intellij.space.iml b/plugins/space/intellij.space.iml
deleted file mode 100644
index ea93302237c9..000000000000
--- a/plugins/space/intellij.space.iml
+++ /dev/null
@@ -1,235 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/SpaceVmWithClient.kt b/plugins/space/src/main/kotlin/com/intellij/space/SpaceVmWithClient.kt
deleted file mode 100644
index 1e2aa9fc46c7..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/SpaceVmWithClient.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.
-package com.intellij.space
-
-import circlet.platform.client.KCircletClient
-
-interface SpaceVmWithClient {
- val client: KCircletClient
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceActionUtils.kt b/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceActionUtils.kt
deleted file mode 100644
index ac3b1ba1d8f1..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceActionUtils.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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.
-package com.intellij.space.actions
-
-import com.intellij.openapi.actionSystem.ActionPlaces
-import com.intellij.openapi.actionSystem.AnActionEvent
-import icons.SpaceIcons
-
-object SpaceActionUtils {
- fun showIconInActionSearch(e: AnActionEvent) {
- e.presentation.icon = if (e.place == ActionPlaces.ACTION_SEARCH) SpaceIcons.Main else null
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceLoginAction.kt b/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceLoginAction.kt
deleted file mode 100644
index 4098bd0ff471..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceLoginAction.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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.
-package com.intellij.space.actions
-
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.project.DumbAwareAction
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.settings.SpaceSettingsPanel
-
-class SpaceLoginAction : DumbAwareAction() {
- override fun update(e: AnActionEvent) {
- e.presentation.isEnabledAndVisible = SpaceWorkspaceComponent.getInstance().workspace.value == null
- SpaceActionUtils.showIconInActionSearch(e)
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- SpaceSettingsPanel.openSettings(e.project)
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceLoginPromoPanel.kt b/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceLoginPromoPanel.kt
deleted file mode 100644
index 0120450e1b39..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceLoginPromoPanel.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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.
-package com.intellij.space.actions
-
-import com.intellij.ide.BrowserUtil
-import com.intellij.ide.ui.fullRow
-import com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI
-import com.intellij.openapi.util.NlsContexts
-import com.intellij.openapi.util.SystemInfo
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.promo.*
-import com.intellij.space.settings.SpaceLoginState
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.LoginComponents.errorText
-import com.intellij.space.ui.LoginComponents.loginButton
-import com.intellij.space.ui.LoginComponents.organizationUrlTextField
-import com.intellij.ui.ComponentUtil
-import com.intellij.ui.SimpleTextAttributes
-import com.intellij.ui.components.ActionLink
-import com.intellij.ui.components.BrowserLink
-import com.intellij.ui.components.JBLabel
-import com.intellij.ui.components.panels.Wrapper
-import com.intellij.ui.layout.*
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.components.BorderLayoutPanel
-import javax.swing.JButton
-import javax.swing.JComponent
-
-internal fun prettyBorder() = JBUI.Borders.empty(16, 20, 4, 20)
-
-internal fun buildLoginPanelWithPromo(
- state: SpaceLoginState.Disconnected,
- statsExplorePlace: SpaceStatsCounterCollector.ExplorePlace,
- statsLoginPlace: SpaceStatsCounterCollector.LoginPlace,
- packParent: () -> Unit,
- loginAction: (String) -> Unit
-): JComponent {
- val wrapper = Wrapper().apply {
- val loginPanel = loginPanel(statsLoginPlace, state, loginAction).apply {
- border = prettyBorder()
- }
- val promoPanel = promoPanel(statsExplorePlace) {
- SpaceStatsCounterCollector.ADV_LOG_IN_LINK.log()
- setContent(loginPanel)
- packParent()
- repaint()
- }.apply {
- border = prettyBorder()
- }
-
- val content = if (state.server.isNotBlank() || state.error?.isNotBlank() == true) loginPanel else promoPanel
- setContent(content)
- repaint()
- }
- val borderLayoutPanel = BorderLayoutPanel().addToCenter(wrapper)
- toolbarPromoBanner()?.let { borderLayoutPanel.addToTop(it) }
- return borderLayoutPanel
-}
-
-private fun promoPanel(statsExplorePlace: SpaceStatsCounterCollector.ExplorePlace, loginAction: () -> Unit) = panel {
- fullRow { createSpaceByJetbrainsLabel()() }
- fullRow { promoText(if (SystemInfo.isMac) 60 else 52)() }
- fullRow {
- JButton(SpaceBundle.message("space.promo.explore.space.button")).apply {
- addActionListener {
- SpaceStatsCounterCollector.EXPLORE_SPACE.log(statsExplorePlace)
- BrowserUtil.browse(EXPLORE_SPACE_PROMO_URL)
- }
- }.apply {
- ComponentUtil.putClientProperty(this, DarculaButtonUI.DEFAULT_STYLE_KEY, true)
- }()
- }
- fullRow {
- grayTextLabel(SpaceBundle.message("login.already.have.account.label"))()
- loginLabel(loginAction)()
- }
-}
-
-private fun loginPanel(
- statsLoginPlace: SpaceStatsCounterCollector.LoginPlace,
- state: SpaceLoginState.Disconnected,
- loginAction: (String) -> Unit
-) = panel {
- val serverField = organizationUrlTextField(state.server)
- val loginButton = loginButton(statsLoginPlace, default = true) {
- it.isEnabled = false
- loginAction(serverField.text.trim())
- }
-
- fullRow { label(SpaceBundle.message("login.panel.organization.url.label")) }
- fullRow { serverField() }
- fullRow { loginButton() }
-
- state.error?.let {
- val errorText = errorText(it)
- fullRow { errorText() }
- }
-
- fullRow {
- grayTextLabel(SpaceBundle.message("login.dont.have.account.label"))()
- singUpLabel()()
- }
-}
-
-private fun grayTextLabel(@NlsContexts.Label text: String) = JBLabel(text).apply {
- foreground = SimpleTextAttributes.GRAYED_SMALL_ATTRIBUTES.fgColor
-}
-
-private fun loginLabel(loginAction: () -> Unit) = ActionLink(SpaceBundle.message("login.panel.log.in.button")) {
- loginAction()
-}
-
-private fun singUpLabel(): BrowserLink = BrowserLink(SpaceBundle.message("login.sign.up"), SIGN_UP_SPACE_URL).apply {
- addActionListener {
- SpaceStatsCounterCollector.SIGN_UP_LINK.log()
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceLogoutAction.kt b/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceLogoutAction.kt
deleted file mode 100644
index df6bb8aa00b9..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceLogoutAction.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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.
-package com.intellij.space.actions
-
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.project.DumbAwareAction
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.stats.SpaceStatsCounterCollector
-
-class SpaceLogoutAction : DumbAwareAction() {
- override fun update(e: AnActionEvent) {
- e.presentation.isEnabledAndVisible = SpaceWorkspaceComponent.getInstance().workspace.value != null
- SpaceActionUtils.showIconInActionSearch(e)
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- SpaceWorkspaceComponent.getInstance().signOut(SpaceStatsCounterCollector.LogoutPlace.ACTION)
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceMainToolBarAction.kt b/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceMainToolBarAction.kt
deleted file mode 100644
index 9584ef26e959..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/actions/SpaceMainToolBarAction.kt
+++ /dev/null
@@ -1,157 +0,0 @@
-// 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.
-package com.intellij.space.actions
-
-import circlet.client.api.englishFullName
-import circlet.platform.client.ConnectionStatus
-import circlet.workspaces.Workspace
-import com.intellij.openapi.actionSystem.ActionPlaces
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.RightAlignedToolbarAction
-import com.intellij.openapi.project.DumbAwareAction
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.popup.JBPopupFactory
-import com.intellij.space.components.SpaceUserAvatarProvider
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.settings.SpaceLoginState
-import com.intellij.space.settings.SpaceSettings
-import com.intellij.space.settings.SpaceSettingsPanel
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.*
-import com.intellij.space.ui.LoginComponents.buildConnectingPanel
-import com.intellij.space.utils.SpaceUrls
-import com.intellij.space.vcs.SpaceProjectContext
-import com.intellij.space.vcs.clone.SpaceCloneAction
-import com.intellij.space.vcs.review.SpaceShowReviewsAction
-import com.intellij.ui.AnimatedIcon
-import com.intellij.ui.awt.RelativePoint
-import com.intellij.ui.components.panels.Wrapper
-import com.intellij.util.ui.cloneDialog.VcsCloneDialogUiSpec
-import libraries.coroutines.extra.Lifetime
-import runtime.reactive.view
-import java.awt.Component
-import java.awt.Point
-import javax.swing.Icon
-import javax.swing.JComponent
-
-class SpaceMainToolBarAction : DumbAwareAction(), RightAlignedToolbarAction {
- private val settings = SpaceSettings.getInstance()
-
- override fun update(e: AnActionEvent) {
- val isOnNavBar = e.place == ActionPlaces.NAVIGATION_BAR_TOOLBAR
- val isOnMainBar = e.place == ActionPlaces.MAIN_TOOLBAR
- if (!isOnNavBar && !isOnMainBar) {
- e.presentation.isEnabledAndVisible = false
- return
- }
- e.presentation.isEnabledAndVisible = true
-
- val space = SpaceWorkspaceComponent.getInstance()
- val avatars = SpaceUserAvatarProvider.getInstance().avatars.value
- val isOnline = space.workspace.value?.client?.connectionStatus?.value is ConnectionStatus.Connected
- val isConnecting = space.loginState.value is SpaceLoginState.Connecting
- e.presentation.icon = when {
- isOnline -> avatars.online
- isConnecting -> AnimatedIcon.Default.INSTANCE
- else -> avatars.offline
- }
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- val component = e.inputEvent.component
- val space = SpaceWorkspaceComponent.getInstance()
- val workspace = space.workspace.value
- SpaceStatsCounterCollector.OPEN_MAIN_TOOLBAR_POPUP.log(SpaceStatsCounterCollector.LoginState.convert(space.loginState.value))
- if (workspace != null) {
- buildMenu(workspace, SpaceUserAvatarProvider.getInstance().avatars.value.circle, e.project!!)
- .showUnderneathOf(component)
- }
- else {
- val wrapper = Wrapper()
- val popup = JBPopupFactory.getInstance().createComponentPopupBuilder(wrapper, wrapper)
- .setRequestFocus(true)
- .setFocusable(true)
- .createPopup()
- space.loginState.view(space.lifetime) { _: Lifetime, st: SpaceLoginState ->
- val view = createView(st, component) { popup.pack(true, true) }
- if (view == null) {
- popup.cancel()
- return@view
- }
-
- wrapper.setContent(view)
- wrapper.repaint()
- if (st is SpaceLoginState.Disconnected) {
- popup.pack(true, true)
- }
- }
- popup.show(RelativePoint(component, Point(-wrapper.preferredSize.width + component.width, component.height)))
- }
- }
-
- private fun createView(st: SpaceLoginState, component: Component, packPopup: () -> Unit): JComponent? {
- return when (st) {
- is SpaceLoginState.Connected -> null
-
- is SpaceLoginState.Connecting -> buildConnectingPanel(st, SpaceStatsCounterCollector.LoginPlace.MAIN_TOOLBAR, prettyBorder()) {
- st.cancel()
- }
-
- is SpaceLoginState.Disconnected -> buildLoginPanelWithPromo(
- st,
- SpaceStatsCounterCollector.ExplorePlace.MAIN_TOOLBAR,
- SpaceStatsCounterCollector.LoginPlace.MAIN_TOOLBAR,
- packPopup
- ) { serverName ->
- val space = SpaceWorkspaceComponent.getInstance()
- space.signInManually(serverName, space.lifetime, component)
- }
- }
- }
-
- private fun buildMenu(workspace: Workspace, icon: Icon, project: Project): AccountsMenuListPopup {
- val host = settings.serverSettings.server
- val serverUrl = cleanupUrl(host)
- val menuItems: MutableList = mutableListOf()
- menuItems += AccountMenuItem.Account(
- workspace.me.value.englishFullName(), // NON-NLS
- serverUrl,
- resizeIcon(icon, VcsCloneDialogUiSpec.Components.popupMenuAvatarSize),
- listOf(browseAction(SpaceBundle.message("main.toolbar.open.server", serverUrl), host, true)))
- menuItems += AccountMenuItem.Action(SpaceBundle.message("action.com.intellij.space.vcs.clone.SpaceCloneAction.text"),
- { SpaceCloneAction.runClone(project) },
- showSeparatorAbove = true)
- val projectContext = SpaceProjectContext.getInstance(project)
- val context = projectContext.currentContext
- if (context.isAssociatedWithSpaceRepository) {
- val descriptions = context.reposInProject.keys
- menuItems += AccountMenuItem.Action(SpaceBundle.message("action.show.code.reviews.text"), {
- SpaceShowReviewsAction.showCodeReviews(project)
- })
- if (descriptions.size > 1) {
- menuItems += AccountMenuItem.Group(SpaceBundle.message("open.in.browser.group.checklists"), descriptions.map {
- val checklistsUrl = SpaceUrls.checklists(it.key)
- browseAction(SpaceBundle.message("open.in.browser.open.for.project.action", it.project.name), checklistsUrl)
- }.toList())
-
- menuItems += AccountMenuItem.Group(SpaceBundle.message("open.in.browser.group.issues"), descriptions.map {
- val issuesUrl = SpaceUrls.issues(it.key)
- browseAction(SpaceBundle.message("open.in.browser.open.for.project.action", it.project.name), issuesUrl)
- }.toList())
- }
- else if (descriptions.isNotEmpty()) {
- val projectKey = descriptions.first().key
- menuItems += browseAction(SpaceBundle.message("main.toolbar.checklists.action"), SpaceUrls.checklists(projectKey))
- menuItems += browseAction(SpaceBundle.message("main.toolbar.issues.action"), SpaceUrls.issues(projectKey))
- }
- }
- menuItems += AccountMenuItem.Action(SpaceBundle.message("main.toolbar.settings.action"),
- { SpaceSettingsPanel.openSettings(project) },
- showSeparatorAbove = true)
- menuItems += AccountMenuItem.Action(SpaceBundle.message("main.toolbar.log.out.action"), {
- SpaceWorkspaceComponent.getInstance().signOut(SpaceStatsCounterCollector.LogoutPlace.MAIN_TOOLBAR)
- })
-
- return AccountsMenuListPopup(project, AccountMenuPopupStep(menuItems))
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/actions/internal/SpaceReceivedPacketsAction.kt b/plugins/space/src/main/kotlin/com/intellij/space/actions/internal/SpaceReceivedPacketsAction.kt
deleted file mode 100644
index 82419f27207c..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/actions/internal/SpaceReceivedPacketsAction.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.
-package com.intellij.space.actions.internal
-
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.project.DumbAwareAction
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.messages.SpaceBundle
-import libraries.klogging.logger
-
-internal class SpaceReceivedPacketsAction : DumbAwareAction() {
- companion object {
- private val LOG = logger()
- }
-
- override fun update(e: AnActionEvent) {
- val presentation = e.presentation
- val workspace = SpaceWorkspaceComponent.getInstance().workspace.value
- if (workspace == null) {
- presentation.isEnabledAndVisible = false
- return
- }
-
- presentation.isEnabledAndVisible = true
- if (workspace.client.logReceivedPackets) {
- presentation.text = SpaceBundle.message("action.internal.stop.log.packets.text")
- }
- else {
- presentation.text = SpaceBundle.message("action.internal.start.log.packets.text")
- }
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- val client = SpaceWorkspaceComponent.getInstance().workspace.value?.client ?: return
- if (client.logReceivedPackets) {
- LOG.info { "Logging packets is stopped" }
- client.logReceivedPackets = false
- }
- else {
- LOG.info { "Logging packets is started" }
- client.logReceivedPackets = true
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/auth/SpaceAuthNotifier.kt b/plugins/space/src/main/kotlin/com/intellij/space/auth/SpaceAuthNotifier.kt
deleted file mode 100644
index 941ea5e1965f..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/auth/SpaceAuthNotifier.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.
-package com.intellij.space.auth
-
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.project.DumbAwareAction
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.messages.SpaceBundleExtensions
-import com.intellij.space.settings.SpaceSettingsPanel
-import com.intellij.space.utils.notify
-
-internal object SpaceAuthNotifier {
- fun authFailed() {
- val tryAgainAction = object : DumbAwareAction(SpaceBundleExtensions.messagePointer("auth.notification.failed.login.again.action")) {
- override fun actionPerformed(e: AnActionEvent) {
- SpaceSettingsPanel.openSettings(null)
- }
- }
- notify(SpaceBundle.message("auth.notification.failed.message"), listOf(tryAgainAction))
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/auth/SpaceOAuthRedirectHandler.kt b/plugins/space/src/main/kotlin/com/intellij/space/auth/SpaceOAuthRedirectHandler.kt
deleted file mode 100644
index 6c3f7a9f393b..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/auth/SpaceOAuthRedirectHandler.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-package com.intellij.space.auth
-
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.util.concurrency.AppExecutorUtil
-import io.ktor.application.call
-import io.ktor.http.ContentType
-import io.ktor.request.uri
-import io.ktor.response.respondText
-import io.ktor.routing.get
-import io.ktor.routing.routing
-import io.ktor.server.engine.embeddedServer
-import io.ktor.server.netty.Netty
-import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.Runnable
-import kotlinx.coroutines.asCoroutineDispatcher
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.launch
-import java.io.IOException
-
-private val ioDispatcher = AppExecutorUtil.getAppExecutorService().asCoroutineDispatcher()
-
-internal suspend fun startRedirectHandling(lifetime: Lifetime, server: String, ports: Collection): SpaceRedirectHandlingInfo? {
- val info = CompletableDeferred()
- launch(lifetime, ioDispatcher) {
- for (port in ports.distinct().shuffled()) {
- try {
- val redirectUrl = startAuthServerAsync(lifetime, server, port)
- info.complete(SpaceRedirectHandlingInfo(port, redirectUrl))
- break
- }
- catch (e: IOException) {
- // check next port
- }
- }
- info.complete(null)
- }
- return info.await()
-}
-
-private fun startAuthServerAsync(lifetime: Lifetime, serverUrl: String, port: Int): Deferred {
- val redirectUrl = CompletableDeferred()
- val server = embeddedServer(Netty, port = port, host = "localhost") {
- routing {
- get("/auth") {
- call.respondText(
- createAuthPage(serverUrl),
- contentType = ContentType.Text.Html
- )
- redirectUrl.complete(call.request.uri)
- }
- }
- }
- server.start(wait = false)
-
- fun stopServer() {
- ApplicationManager.getApplication().executeOnPooledThread(Runnable {
- server.stop(1000, 1000)
- })
- }
- lifetime.addOrCallImmediately {
- stopServer()
- }
- redirectUrl.invokeOnCompletion {
- stopServer()
- }
-
- return redirectUrl
-}
-
-internal data class SpaceRedirectHandlingInfo(val port: Int, val redirectUrl: Deferred)
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/auth/authPage.kt b/plugins/space/src/main/kotlin/com/intellij/space/auth/authPage.kt
deleted file mode 100644
index a76d8fad3208..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/auth/authPage.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-package com.intellij.space.auth
-
-import com.intellij.ide.plugins.PluginManagerCore
-import com.intellij.openapi.extensions.PluginId
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.openapi.util.text.HtmlChunk.*
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.ui.AppUIUtil
-import java.io.File
-
-internal fun createAuthPage(server: String): String = html()
- .child(
- head()
- .child(styleTag(loadAuthResourceFileContent("spaceAuthPage.css")))
- )
- .child(
- body().child(
- div().attr("class", "central-div")
- .child(
- div().attr("class", "central-div-header")
- .child(
- div().attr("class", "central-div-header-icon").addRaw(loadAuthResourceFileContent("spaceAuthIcon.svg"))
- )
- .child(
- div().attr("class", "central-div-header-text").addText(SpaceBundle.message("auth.page.jetbrains.space.header.text"))
- )
- )
- .child(
- div().attr("class", "central-div-content")
- .child(
- div().attr("class", "central-div-content-icon").addRaw(loadProductSvg() ?: "")
- )
- .child(
- div().attr("class", "central-div-content-text").addText(SpaceBundle.message("auth.page.content.text"))
- )
- )
- .child(
- link(server, SpaceBundle.message("auth.page.go.to.space.link")).attr("class", "central-div-content-link")
- )
- )
- )
- .toString()
-
-@NlsSafe
-private fun loadAuthResourceFileContent(fileName: String): String {
- val plugin = PluginManagerCore.getPlugin(PluginId.getId("com.jetbrains.space"))
- ?: throw IllegalStateException("Couldn't find space plugin descriptor")
- val loader = plugin.pluginClassLoader
- return loader.getResourceAsStream("auth/$fileName")!!.bufferedReader(Charsets.UTF_8).readText()
-}
-
-@NlsSafe
-private fun loadProductSvg(): String? {
- AppUIUtil.findIcon().takeIf { it?.endsWith(".svg") ?: false }?.let { iconPath ->
- val iconFile = File(iconPath)
- if (iconFile.exists() && iconFile.isFile) {
- return iconFile.readText(Charsets.UTF_8)
- }
- }
- return null
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/editor/SpaceChatEditor.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/editor/SpaceChatEditor.kt
deleted file mode 100644
index 32f034a15f91..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/editor/SpaceChatEditor.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.
-package com.intellij.space.chat.editor
-
-import com.intellij.diff.util.FileEditorBase
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.fileEditor.FileEditor
-import com.intellij.openapi.fileEditor.FileEditorPolicy
-import com.intellij.openapi.fileEditor.FileEditorProvider
-import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.space.chat.ui.SpaceChatPanel
-import com.intellij.space.messages.SpaceBundle
-import libraries.coroutines.extra.LifetimeSource
-import javax.swing.JComponent
-
-private class SpaceChatEditor(private val project: Project, private val spaceChatFile: SpaceChatFile) : FileEditorBase() {
- private val editorLifetime = LifetimeSource()
-
- init {
- Disposer.register(this, Disposable { editorLifetime.terminate() })
- }
-
- val component by lazy {
- val headerDetails = spaceChatFile.headerDetailsBuilder(editorLifetime)
- SpaceChatPanel(project, editorLifetime, this, spaceChatFile.channelsVm, spaceChatFile.chatRecord, headerDetails)
- }
-
- override fun getComponent(): JComponent = component
-
- override fun getPreferredFocusedComponent(): JComponent? = null
-
- override fun getName(): String = SpaceBundle.message("chat.editor.name")
-
- override fun getFile() = spaceChatFile
-}
-
-internal class SpaceChatEditorProvider : FileEditorProvider, DumbAware {
- override fun accept(project: Project, file: VirtualFile): Boolean = file is SpaceChatFile
-
- override fun createEditor(project: Project, file: VirtualFile): FileEditor = SpaceChatEditor(project, file as SpaceChatFile)
-
- override fun getEditorTypeId(): String = "SpaceChatEditor"
-
- override fun getPolicy(): FileEditorPolicy = FileEditorPolicy.HIDE_DEFAULT_EDITOR
-
- override fun disposeEditor(editor: FileEditor) {
- if (editor.file?.getUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN) != true) {
- Disposer.dispose(editor)
- }
-
- super.disposeEditor(editor)
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/editor/SpaceChatFile.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/editor/SpaceChatFile.kt
deleted file mode 100644
index 486a4150b136..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/editor/SpaceChatFile.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-// 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.
-package com.intellij.space.chat.editor
-
-import circlet.client.api.M2ChannelRecord
-import circlet.m2.ChannelsVm
-import circlet.platform.api.Ref
-import com.intellij.ide.FileIconProvider
-import com.intellij.ide.actions.SplitAction
-import com.intellij.openapi.fileEditor.impl.EditorTabTitleProvider
-import com.intellij.openapi.fileTypes.FileType
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.NlsContexts
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.openapi.vfs.VirtualFilePathWrapper
-import com.intellij.space.chat.model.api.SpaceChatHeaderDetails
-import com.intellij.space.editor.SpaceChatComplexPathVirtualFileSystem
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.testFramework.LightVirtualFile
-import icons.SpaceIcons
-import libraries.coroutines.extra.Lifetime
-import javax.swing.Icon
-
-/**
- * @param id is used only for equals and hashcode to avoid multiple editor tabs the same [SpaceChatFile]
- */
-internal class SpaceChatFile(
- private val sessionId: String,
- private val projectHash: String,
- @NlsSafe val id: String,
- @NlsSafe path: String,
- @NlsContexts.TabTitle val displayName: String,
- @NlsContexts.Tooltip val tabTooltip: String,
- val channelsVm: ChannelsVm,
- val chatRecord: Ref,
- val headerDetailsBuilder: (Lifetime) -> SpaceChatHeaderDetails
-) : LightVirtualFile(path, SpaceChatFileType.instance, ""), VirtualFilePathWrapper {
-
- init {
- putUserData(SplitAction.FORBID_TAB_SPLIT, true)
- isWritable = false
- }
-
- override fun getFileSystem() = SpaceChatComplexPathVirtualFileSystem.getInstance()
-
- override fun getPath(): String = try {
- fileSystem.getPath(sessionId, projectHash, id)
- }
- catch (e: Exception) {
- name
- }
-
- override fun enforcePresentableName(): Boolean = true
-
- override fun getPresentablePath(): String = name
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
-
- other as SpaceChatFile
-
- if (id != other.id) return false
-
- return true
- }
-
- override fun hashCode(): Int = id.hashCode()
-}
-
-internal class SpaceChatFileTabTitleProvider : EditorTabTitleProvider {
- override fun getEditorTabTitle(project: Project, file: VirtualFile): String? = (file as? SpaceChatFile)?.displayName
-
- override fun getEditorTabTooltipText(project: Project, virtualFile: VirtualFile): String? = (virtualFile as? SpaceChatFile)?.tabTooltip
-}
-
-internal class SpaceChatIconProvider : FileIconProvider {
- override fun getIcon(file: VirtualFile, flags: Int, project: Project?): Icon? {
- if (file !is SpaceChatFile) {
- return null
- }
- return SpaceIcons.Main
- }
-}
-
-private class SpaceChatFileType private constructor(): FileType {
-
- override fun getName(): String = "SpaceChat"
-
- override fun getDescription(): String = SpaceBundle.message("filetype.chat.description")
-
- override fun getDefaultExtension(): String = ""
-
- override fun getIcon(): Icon = SpaceIcons.Main
-
- override fun isBinary(): Boolean = true
-
- override fun isReadOnly(): Boolean = true
-
- companion object {
- val instance = SpaceChatFileType()
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/markdown/markdownConverter.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/markdown/markdownConverter.kt
deleted file mode 100644
index 0d1d7c135c87..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/markdown/markdownConverter.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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.
-package com.intellij.space.chat.markdown
-
-import org.intellij.markdown.IElementType
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.intellij.markdown.flavours.gfm.GFMElementTypes
-import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor
-import org.intellij.markdown.flavours.gfm.GFMTokenTypes
-import org.intellij.markdown.flavours.gfm.StrikeThroughParser
-import org.intellij.markdown.html.GeneratingProvider
-import org.intellij.markdown.html.HtmlGenerator
-import org.intellij.markdown.html.SimpleInlineTagProvider
-import org.intellij.markdown.parser.LinkMap
-import org.intellij.markdown.parser.MarkdownParser
-import org.intellij.markdown.parser.sequentialparsers.RangesListBuilder
-import org.intellij.markdown.parser.sequentialparsers.SequentialParser
-import org.intellij.markdown.parser.sequentialparsers.SequentialParserManager
-import org.intellij.markdown.parser.sequentialparsers.TokensCache
-import org.intellij.markdown.parser.sequentialparsers.impl.*
-import org.jetbrains.annotations.Contract
-import java.net.URI
-
-@Contract(pure = true)
-internal fun convertToHtml(markdownText: String, server: String? = null): String {
- val flavour = SpaceFlavourDescriptor()
- val parsedTree = MarkdownParser(flavour).buildMarkdownTreeFromString(markdownText)
- val providers = flavour.createHtmlGeneratingProviders(
- linkMap = LinkMap.buildLinkMap(parsedTree, markdownText),
- baseURI = server?.let { URI(it) }
- )
- val htmlText = HtmlGenerator(markdownText, parsedTree, providers, false).generateHtml()
- return htmlText.removePrefix("").removeSuffix("")
-}
-
-private class SpaceFlavourDescriptor : GFMFlavourDescriptor() {
- override val sequentialParserManager = object : SequentialParserManager() {
- override fun getParserSequence(): List = listOf(
- AutolinkParser(listOf(MarkdownTokenTypes.AUTOLINK, GFMTokenTypes.GFM_AUTOLINK)),
- BacktickParser(),
- ImageParser(),
- InlineLinkParser(),
- ReferenceLinkParser(),
- LineBreaksParser(), // difference with super
- StrikeThroughParser(),
- EmphStrongParser()
- )
- }
-
- override fun createHtmlGeneratingProviders(linkMap: LinkMap, baseURI: URI?): Map {
- val parentProviders = super.createHtmlGeneratingProviders(linkMap, baseURI).toMutableMap()
- parentProviders[MarkdownElementTypes.EMPH] = SimpleInlineTagProvider("i", 1, -1)
- parentProviders[MarkdownElementTypes.STRONG] = SimpleInlineTagProvider("b", 2, -2)
- parentProviders[GFMElementTypes.STRIKETHROUGH] = SimpleInlineTagProvider("strike", 2, -2)
- return parentProviders
- }
-}
-
-private class LineBreaksParser : SequentialParser {
- override fun parse(tokens: TokensCache, rangesToGlue: List): SequentialParser.ParsingResult {
- val result = SequentialParser.ParsingResultBuilder()
- val delegateIndices = RangesListBuilder()
- var iterator = tokens.RangesListIterator(rangesToGlue)
-
- while (iterator.type != null) {
- if (iterator.type == MarkdownTokenTypes.EOL) {
- result.withNode(SequentialParser.Node(iterator.index..iterator.index + 1, MarkdownTokenTypes.HARD_LINE_BREAK))
- }
- else {
- delegateIndices.put(iterator.index)
- }
-
- iterator = iterator.advance()
- }
-
- return result.withFurtherProcessing(delegateIndices.get())
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/markdown/markdownUnfurlProcessor.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/markdown/markdownUnfurlProcessor.kt
deleted file mode 100644
index 8c5bc0da25b8..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/markdown/markdownUnfurlProcessor.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.
-package com.intellij.space.chat.markdown
-
-import circlet.client.api.UnfurlAttachment
-import circlet.client.api.UnfurlDetailsDateTime
-import circlet.client.api.UnfurlDetailsProfile
-import circlet.client.api.fullName
-import circlet.platform.client.resolve
-import com.intellij.openapi.util.text.HtmlChunk.link
-import com.intellij.space.utils.formatPrettyDateTime
-import platform.common.Unfurl
-
-internal fun processUnfurls(markdown: String, unfurls: List): String {
- var result = markdown
- unfurls.map { it.unfurl }.forEach { unfurl ->
- result = result.replace(unfurl.link, unfurl.createNewLink())
- }
- return result
-}
-
-private fun Unfurl.createNewLink(): String = when (val unfurlDetails = details) {
- is UnfurlDetailsProfile -> link(link, unfurlDetails.profile.resolve().name.fullName()).toString() // NON-NLS
- is UnfurlDetailsDateTime -> unfurlDetails.utcMilliseconds.formatPrettyDateTime()
- else -> link
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatHeaderDetails.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatHeaderDetails.kt
deleted file mode 100644
index 52eddb8d0a38..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatHeaderDetails.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.api
-
-internal interface SpaceChatHeaderDetails
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatItem.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatItem.kt
deleted file mode 100644
index 5cbb6cf1e698..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatItem.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.api
-
-import circlet.client.api.AttachmentInfo
-import circlet.client.api.CPrincipal
-import circlet.client.api.ChannelItemRecord
-import circlet.client.api.M2ChannelRecord
-import circlet.m2.M2MessageEditingVm
-import circlet.m2.channel.M2ChannelVm
-import circlet.m2.threads.M2ThreadPreviewVm
-import circlet.platform.api.KDateTime
-import circlet.platform.api.Ref
-import circlet.platform.api.TID
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.util.ui.codereview.timeline.TimelineItem
-import kotlinx.coroutines.CompletableDeferred
-import libraries.coroutines.extra.Lifetime
-import runtime.reactive.MutableProperty
-import runtime.reactive.Property
-
-internal interface SpaceChatItem : TimelineItem {
- val id: TID
-
- val chat: M2ChannelVm
-
- val author: CPrincipal
-
- val text: @NlsSafe String
-
- val created: KDateTime
-
- val type: SpaceChatItemType
-
- val thread: Ref?
-
- /**
- * hack to prevent threads collapsing when SpaceChatItem is recreated
- */
- val loadingThread: MutableProperty?>
-
- val delivered: Boolean
-
- val link: String?
-
- val canDelete: Boolean
-
- val isEdited: Boolean
-
- val editingVm: Property
-
- val isEditing: Property
-
- val canEdit: Boolean
-
- val startThreadVm: SpaceChatStartThreadVm
-
- val pending: Boolean?
-
- val attachments: List
-
- val additionalFeatures: Set
-
- val projectedItem: Property?
-
- val threadPreview: M2ThreadPreviewVm?
-
- fun startEditing()
-
- fun stopEditing()
-
- suspend fun delete()
-
- suspend fun loadThread(lifetime: Lifetime): M2ChannelVm?
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatItemAdditionalFeature.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatItemAdditionalFeature.kt
deleted file mode 100644
index 78a5ffded375..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatItemAdditionalFeature.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.api
-
-import runtime.reactive.Property
-
-internal sealed class SpaceChatItemAdditionalFeature {
- class ShowResolvedState(val resolved: Property) : SpaceChatItemAdditionalFeature()
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatItemType.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatItemType.kt
deleted file mode 100644
index f3443cf07d45..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatItemType.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.api
-
-import circlet.client.api.M2ItemContentDetails
-import circlet.client.api.M2TextItemContent
-import circlet.client.api.TD_MemberProfile
-import circlet.client.api.mc.ChatMessage
-import circlet.client.api.mc.toMessage
-import circlet.code.api.*
-import circlet.platform.api.Ref
-import com.intellij.space.chat.model.api.SpaceChatItemType.*
-import com.intellij.space.chat.model.impl.toMCMessageContent
-
-internal fun M2ItemContentDetails?.toType(): SpaceChatItemType = when (this) {
- is CodeDiscussionAddedFeedEvent -> CodeDiscussion(codeDiscussion)
- is M2TextItemContent -> SimpleText
- is ReviewCompletionStateChangedEvent -> ReviewCompletionStateChanged
- is ReviewerChangedEvent -> ReviewerChanged(changeType, uid)
- is MergeRequestMergedEvent -> MergeRequestMerged(sourceBranch, targetBranch)
- is MergeRequestBranchDeletedEvent -> MergeRequestBranchDeleted(branch)
- is ReviewTitleChangedEvent -> ReviewTitleChanged(oldTitle, newTitle)
- is circlet.client.api.mc.MCMessage -> when (val chatMessage = toMessage()) {
- is ChatMessage.Text -> SimpleText
- is ChatMessage.Block -> MCMessage(chatMessage.toMCMessageContent())
- }
- null -> Deleted
- else -> Unknown
-}
-
-internal sealed class SpaceChatItemType {
- class CodeDiscussion(val discussion: Ref) : SpaceChatItemType()
-
- object SimpleText : SpaceChatItemType()
-
- object ReviewCompletionStateChanged : SpaceChatItemType()
-
- class ReviewerChanged(val changeType: ReviewerChangedType, val uid: Ref) : SpaceChatItemType()
-
- class MergeRequestMerged(val sourceBranch: String, val targetBranch: String) : SpaceChatItemType()
-
- class MergeRequestBranchDeleted(val branch: String) : SpaceChatItemType()
-
- class ReviewTitleChanged(val oldTitle: String, val newTitle: String) : SpaceChatItemType()
-
- class MCMessage(val content: SpaceMCMessageContent) : SpaceChatItemType()
-
- object Deleted : SpaceChatItemType()
-
- object Unknown : SpaceChatItemType()
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatStartThreadVm.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatStartThreadVm.kt
deleted file mode 100644
index 8a968b2f8ff3..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceChatStartThreadVm.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.api
-
-import runtime.reactive.Property
-
-internal interface SpaceChatStartThreadVm {
- val canStartThread: Property
-
- val isWritingFirstMessage: Property
-
- fun startWritingFirstMessage()
-
- fun stopWritingFirstMessage()
-
- suspend fun startThread(message: String)
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceMCMessageContent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceMCMessageContent.kt
deleted file mode 100644
index e12ddee47f3d..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/api/SpaceMCMessageContent.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.api
-
-import circlet.client.api.mc.MessageOutline
-import circlet.client.api.mc.MessageStyle
-import javax.swing.Icon
-
-internal interface SpaceMCMessageContent {
- val outline: MessageOutline?
-
- val sections: List
-
- val style: MessageStyle
-}
-
-internal sealed class SpaceMCMessageSection {
- class Section(val header: String?, val elements: List, val footer: String?) : SpaceMCMessageSection()
- object Divider : SpaceMCMessageSection()
-}
-
-internal sealed class SpaceMCMessageElement {
- class Text(val icon: Icon?, val content: String) : SpaceMCMessageElement()
- object MessageDivider : SpaceMCMessageElement()
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceChatItemImpl.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceChatItemImpl.kt
deleted file mode 100644
index 09b2b2581668..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceChatItemImpl.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.impl
-
-import circlet.m2.M2MessageVm
-import circlet.m2.channel.M2ChannelVm
-import circlet.platform.client.property
-import com.intellij.space.chat.model.api.SpaceChatItem
-import com.intellij.space.chat.model.api.SpaceChatItemAdditionalFeature
-import com.intellij.space.chat.model.api.toType
-import com.intellij.space.chat.ui.awaitFullLoad
-import kotlinx.coroutines.CompletableDeferred
-import libraries.coroutines.extra.Lifetime
-import runtime.reactive.mutableProperty
-
-internal class SpaceChatItemImpl private constructor(
- private val messageVm: M2MessageVm,
- override val link: String?,
- override val additionalFeatures: Set = setOf()
-) : SpaceChatItem {
- private val record = messageVm.message
-
- override val id = record.id
-
- override val thread = messageVm.message.thread
-
- override val loadingThread = mutableProperty?>(null)
-
- override val threadPreview = messageVm.thread
-
- override val chat = messageVm.channelVm
-
- override val author = record.author
-
- override val created = record.created
-
- override val type = record.details.toType()
-
- override val delivered = messageVm.delivered
-
- override val canDelete = messageVm.canDelete
-
- override val text = record.text
-
- override val editingVm = messageVm.editingVm
-
- override val isEditing = messageVm.isEditing
-
- override val canEdit = messageVm.canEdit
-
- override val isEdited = record.edited != null
-
- override val startThreadVm = SpaceChatStartThreadVmImpl(messageVm, threadPreview, loadingThread)
-
- override val pending = record.pending
-
- override val attachments = record.attachments ?: listOf()
-
- override val projectedItem = record.projectedItem?.property()
-
- override fun startEditing() {
- messageVm.startEditing()
- }
-
- override fun stopEditing() {
- messageVm.stopEditing()
- }
-
- override suspend fun delete() {
- chat.deleteCurrentOrOriginalMessage(id)
- }
-
- override suspend fun loadThread(lifetime: Lifetime): M2ChannelVm? {
- threadPreview ?: return null
- val loadingThreadDeferred = CompletableDeferred()
- loadingThread.value = loadingThreadDeferred
- return chat.channelsVm.thread(lifetime, chat, threadPreview, null).also {
- it.awaitFullLoad(lifetime)
- loadingThreadDeferred.complete(it)
- }
- }
-
- override fun equals(other: Any?): Boolean {
- if (this === other) {
- return true
- }
-
- if (other !is SpaceChatItemImpl) {
- return false
- }
-
- if (record != other.record) {
- return false
- }
-
- return true
- }
-
- override fun hashCode(): Int = record.hashCode()
-
- companion object {
- internal fun M2MessageVm.convertToChatItem(
- link: String?,
- additionalFeatures: Set = setOf()
- ): SpaceChatItem = SpaceChatItemImpl(this, link, additionalFeatures = additionalFeatures)
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceChatReviewHeaderDetails.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceChatReviewHeaderDetails.kt
deleted file mode 100644
index 533925362194..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceChatReviewHeaderDetails.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.impl
-
-import circlet.code.api.CodeReviewState
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.space.chat.model.api.SpaceChatHeaderDetails
-import com.intellij.space.vcs.SpaceProjectInfo
-import org.jetbrains.annotations.Nls
-import runtime.reactive.Property
-
-internal class SpaceChatReviewHeaderDetails(
- val spaceProject: SpaceProjectInfo,
- val state: Property,
- @Nls val title: Property,
- @NlsSafe val reviewKey: String?,
-) : SpaceChatHeaderDetails
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceChatStartThreadVmImpl.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceChatStartThreadVmImpl.kt
deleted file mode 100644
index 7ec63173aa93..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceChatStartThreadVmImpl.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.impl
-
-import circlet.m2.M2MessageVm
-import circlet.m2.channel.M2ChannelVm
-import circlet.m2.threads.M2ThreadPreviewVm
-import com.intellij.space.chat.model.api.SpaceChatStartThreadVm
-import com.intellij.space.chat.ui.awaitFullLoad
-import kotlinx.coroutines.CompletableDeferred
-import runtime.reactive.MutableProperty
-import runtime.reactive.mutableProperty
-import runtime.reactive.property
-import runtime.reactive.property.map
-
-internal class SpaceChatStartThreadVmImpl(
- private val messageVm: M2MessageVm,
- private val threadPreview: M2ThreadPreviewVm?,
- private val loadingThread: MutableProperty?>
-) : SpaceChatStartThreadVm {
- private val lifetime = messageVm.lifetime
-
- override val isWritingFirstMessage = mutableProperty(false)
-
- override val canStartThread = lifetime.map(
- messageVm.canOpenThread,
- isWritingFirstMessage,
- threadPreview?.messageCount ?: property(null)
- ) { canOpenThread, writingFirstMessage, messagesCount ->
- canOpenThread && !writingFirstMessage && (messagesCount == null || messagesCount == 0)
- }
-
- override fun startWritingFirstMessage() {
- isWritingFirstMessage.value = true
-
- }
-
- override fun stopWritingFirstMessage() {
- isWritingFirstMessage.value = false
- }
-
- override suspend fun startThread(message: String) {
- val threadChannelDeferred = CompletableDeferred()
- loadingThread.value = threadChannelDeferred
-
- val newThreadPreview = threadPreview ?: messageVm.makeThreadPreview()
-
- val channelsVm = messageVm.channelsVm
- val viewerLifetime = messageVm.lifetime
-
- val threadChannel = channelsVm.thread(viewerLifetime, messageVm.channelVm, newThreadPreview, null)
- threadChannel.awaitFullLoad(viewerLifetime)
- threadChannel.sendMessage(message)
- threadChannelDeferred.complete(threadChannel)
- stopWritingFirstMessage()
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceMCMessageContentImpl.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceMCMessageContentImpl.kt
deleted file mode 100644
index 84e84fa6cdde..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/model/impl/SpaceMCMessageContentImpl.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.
-package com.intellij.space.chat.model.impl
-
-import circlet.client.api.mc.*
-import com.intellij.icons.AllIcons
-import com.intellij.space.chat.model.api.SpaceMCMessageContent
-import com.intellij.space.chat.model.api.SpaceMCMessageElement
-import com.intellij.space.chat.model.api.SpaceMCMessageSection
-import javax.swing.Icon
-
-internal fun ChatMessage.Block.toMCMessageContent(): SpaceMCMessageContent =
- SpaceMCMessageContentImpl(outline, sections.mapNotNull { it.convert() }, style ?: MessageStyle.PRIMARY)
-
-private fun MessageSectionElement.convert(): SpaceMCMessageSection? = when (this) {
- is MessageSection -> SpaceMCMessageSection.Section(header, elements.mapNotNull { it.convert() }, footer)
- is MessageDivider -> SpaceMCMessageSection.Divider
- else -> null
-}
-
-private fun MessageElement.convert(): SpaceMCMessageElement? = when (this) {
- is MessageText -> {
- val icon = (accessory as? MessageIcon)?.icon?.toIcon()
- SpaceMCMessageElement.Text(icon, content)
- }
- is MessageDivider -> SpaceMCMessageElement.MessageDivider
- else -> null
-}
-
-private fun ApiIcon.toIcon(): Icon? = when (icon) {
- "commits", "commits-small" -> AllIcons.Vcs.CommitNode
- else -> null
-}
-
-private class SpaceMCMessageContentImpl(
- override val outline: MessageOutline?,
- override val sections: List,
- override val style: MessageStyle
-) : SpaceMCMessageContent
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/HoverableJPanel.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/HoverableJPanel.kt
deleted file mode 100644
index 3f89ae2a27af..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/HoverableJPanel.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import javax.swing.JPanel
-
-internal abstract class HoverableJPanel : JPanel(null) {
- abstract fun hoverStateChanged(isHovered: Boolean)
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatAvatarType.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatAvatarType.kt
deleted file mode 100644
index a27578866c29..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatAvatarType.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import com.intellij.util.ui.JBValue
-
-internal enum class SpaceChatAvatarType(val size: JBValue) {
- MAIN_CHAT(JBValue.UIInteger("space.chat.avatar.size", 30)),
- THREAD(JBValue.UIInteger("space.chat.thread.avatar.size", 20))
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatContentPanel.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatContentPanel.kt
deleted file mode 100644
index 26d7669a0c02..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatContentPanel.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import circlet.client.api.M2ChannelRecord
-import circlet.client.api.TD_MemberProfile
-import circlet.client.api.fullName
-import circlet.m2.ChannelsVm
-import circlet.m2.M2MessageVm
-import circlet.m2.channel.M2ChannelVm
-import circlet.platform.api.Ref
-import circlet.platform.api.isTemporary
-import com.intellij.ide.plugins.newui.VerticalLayout
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.openapi.util.text.HtmlChunk
-import com.intellij.space.chat.model.impl.SpaceChatItemImpl.Companion.convertToChatItem
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.SpaceAvatarProvider
-import com.intellij.space.utils.SpaceUrls
-import com.intellij.ui.ColorUtil
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.UIUtil
-import com.intellij.util.ui.codereview.timeline.TimelineComponent
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.delay
-import org.jetbrains.annotations.Nls
-import runtime.reactive.awaitTrue
-import javax.swing.JPanel
-
-internal class SpaceChatContentPanel(
- private val project: Project,
- private val lifetime: Lifetime,
- parent: Disposable,
- channelsVm: ChannelsVm,
- chatRecord: Ref
-) : SpaceChatContentPanelBase(lifetime, parent, channelsVm, chatRecord) {
- private val server = channelsVm.client.server
-
- override fun onChatLoad(chatVm: M2ChannelVm) {
- val itemsListModel = SpaceChatItemListModel()
- val contentPanel = createContentPanel(itemsListModel, chatVm)
- chatVm.mvms.forEach(lifetime) { messagesViewModel ->
- val chatItems = messagesViewModel.messages.map { messageViewModel ->
- messageViewModel.convertToChatItem(messageViewModel.getLink())
- }
- itemsListModel.messageListUpdated(chatItems)
- stopLoadingContent(contentPanel)
- }
- }
-
- private fun createContentPanel(model: SpaceChatItemListModel, chatVM: M2ChannelVm): JPanel {
- val avatarSize = SpaceChatAvatarType.MAIN_CHAT.size
- val avatarProvider = SpaceAvatarProvider(lifetime, this, avatarSize)
- val itemComponentFactory = SpaceChatItemComponentFactory(project, lifetime, server, avatarProvider)
- val timeline = TimelineComponent(model, itemComponentFactory, offset = 0).apply {
- border = JBUI.Borders.emptyBottom(10)
- }
-
- return JPanel(VerticalLayout(0)).apply {
- isOpaque = false
- add(timeline, VerticalLayout.FILL_HORIZONTAL)
- add(createNewMessageField(chatVM, SpaceChatAvatarType.MAIN_CHAT, SpaceStatsCounterCollector.SendMessagePlace.MAIN_CHAT),
- VerticalLayout.FILL_HORIZONTAL)
- }
- }
-}
-
-internal suspend fun M2ChannelVm.awaitFullLoad(lifetime: Lifetime) {
- ready.awaitTrue(lifetime)
- val messages = mvms.prop
- while (messages.value.hasPrev) {
- // TODO: remove this temporary fix when it will be fixed in platform
- delay(1)
- loadPrev()
- }
- while (messages.value.hasNext) {
- delay(1)
- loadNext()
- }
-}
-
-internal fun M2MessageVm.getLink(): String? =
- if (canCopyLink && !message.isTemporary()) {
- SpaceUrls.message(channelVm.key.value, message)
- }
- else {
- null
- }
-
-@Nls
-internal fun TD_MemberProfile.link(): HtmlChunk =
- HtmlChunk.link(SpaceUrls.member(username), name.fullName()) // NON-NLS
-
-@NlsSafe
-internal fun getGrayTextHtml(@Nls text: String): String =
- HtmlChunk.span("color: ${ColorUtil.toHtmlColor(UIUtil.getContextHelpForeground())}").addRaw(text).toString()
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatContentPanelBase.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatContentPanelBase.kt
deleted file mode 100644
index 51ca65478a06..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatContentPanelBase.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import circlet.client.api.M2ChannelRecord
-import circlet.m2.ChannelsVm
-import circlet.m2.channel.M2ChannelVm
-import circlet.platform.api.Ref
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.editor.colors.EditorColorsManager
-import com.intellij.ui.ComponentUtil
-import com.intellij.ui.components.JBLoadingPanel
-import com.intellij.util.concurrency.annotations.RequiresEdt
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.UIUtil
-import com.intellij.util.ui.components.BorderLayoutPanel
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.launch
-import org.jetbrains.annotations.Nls
-import runtime.Ui
-import java.awt.BorderLayout
-import java.awt.Dimension
-import java.awt.event.MouseEvent
-import java.awt.event.MouseMotionAdapter
-import javax.swing.JComponent
-
-internal abstract class SpaceChatContentPanelBase(
- private val lifetime: Lifetime,
- parent: Disposable,
- private val channelsVm: ChannelsVm,
- private val chatRecord: Ref
-) : BorderLayoutPanel() {
- private val loadingPanel = object : JBLoadingPanel(BorderLayout(), parent) {
- init {
- startLoading()
- isOpaque = false
- }
-
- override fun getPreferredSize(): Dimension {
- val size = super.getPreferredSize()
- return Dimension(size.width, size.height.takeIf { it != 0 } ?: JBUI.scale(80))
- }
- }
-
- init {
- isOpaque = true
- background = EditorColorsManager.getInstance().globalScheme.defaultBackground
-
- addToCenter(loadingPanel)
-
- addHoveringSupport()
- launch(lifetime, Ui) {
- val chatVM = loadChatVM()
- onChatLoad(chatVM)
- }
- }
-
- private fun addHoveringSupport() {
- var lastHoveredMessagePanel: HoverableJPanel? = null
- addMouseMotionListener(object : MouseMotionAdapter() {
- override fun mouseMoved(e: MouseEvent?) {
- e ?: return
- val component = UIUtil.getDeepestComponentAt(this@SpaceChatContentPanelBase, e.x, e.y) ?: return
- val messageComponent = ComponentUtil.getParentOfType(HoverableJPanel::class.java, component)
- if (messageComponent != lastHoveredMessagePanel) {
- lastHoveredMessagePanel?.hoverStateChanged(false)
- lastHoveredMessagePanel = messageComponent
- messageComponent?.hoverStateChanged(true)
- }
- }
- })
- }
-
- private suspend fun loadChatVM(): M2ChannelVm = channelsVm.channel(lifetime, chatRecord).also {
- it.awaitFullLoad(lifetime)
- }
-
- protected abstract fun onChatLoad(chatVm: M2ChannelVm)
-
- @RequiresEdt
- protected fun stopLoadingContent(contentComponent: JComponent) {
- if (loadingPanel.isLoading) {
- loadingPanel.add(contentComponent, BorderLayout.CENTER)
- loadingPanel.stopLoading()
- loadingPanel.revalidate()
- loadingPanel.repaint()
- }
- }
-
- fun setLoadingText(@Nls text: String) {
- loadingPanel.setLoadingText(text)
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatEditableComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatEditableComponent.kt
deleted file mode 100644
index 83026c13d5d0..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatEditableComponent.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import com.intellij.openapi.application.runWriteAction
-import com.intellij.openapi.project.Project
-import com.intellij.space.chat.model.api.SpaceChatItem
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.util.ui.codereview.SingleValueModel
-import com.intellij.util.ui.codereview.SingleValueModelImpl
-import com.intellij.util.ui.codereview.ToggleableContainer
-import com.intellij.util.ui.codereview.timeline.comment.SubmittableTextField
-import com.intellij.util.ui.codereview.timeline.comment.SubmittableTextFieldModelBase
-import com.intellij.util.ui.components.BorderLayoutPanel
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import runtime.reactive.awaitLoaded
-import javax.swing.JComponent
-
-internal class SpaceChatEditableComponent(
- project: Project,
- lifetime: Lifetime,
- content: JComponent,
- message: SpaceChatItem
-) : BorderLayoutPanel() {
- val editingModel: SingleValueModel = SingleValueModelImpl(false)
-
- init {
- isOpaque = false
- val submittableModel = object : SubmittableTextFieldModelBase("") {
- override fun submit() {
- val editingVm = message.editingVm.value
- val newText = document.text
- if (editingVm != null) {
- val id = editingVm.message.id
- launch(lifetime, Ui) {
- val chat = editingVm.channel.awaitLoaded(lifetime)
- if (newText.isBlank()) {
- SpaceStatsCounterCollector.SEND_EDIT_MESSAGE.log(project, true)
- chat?.deleteMessage(id)
- }
- else {
- SpaceStatsCounterCollector.SEND_EDIT_MESSAGE.log(project, false)
- chat?.alterMessage(id, newText)
- }
- }
- }
- message.stopEditing()
- }
- }
-
- message.editingVm.forEach(lifetime) { editingVm ->
- if (editingVm == null) {
- editingModel.value = false
- return@forEach
- }
- val workspace = SpaceWorkspaceComponent.getInstance().workspace.value ?: return@forEach
- runWriteAction {
- submittableModel.document.setText(workspace.completion.editable(editingVm.message.text))
- }
- editingModel.value = true
- SpaceStatsCounterCollector.START_EDIT_MESSAGE.log(project)
- }
- addToCenter(
- ToggleableContainer.create(editingModel, { content }, {
- SubmittableTextField(SpaceBundle.message("chat.message.edit.action.text"), submittableModel, onCancel = {
- SpaceStatsCounterCollector.DISCARD_EDIT_MESSAGE.log(project)
- message.stopEditing()
- })
- })
- )
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatItemComponentFactory.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatItemComponentFactory.kt
deleted file mode 100644
index e5989c5b4ae8..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatItemComponentFactory.kt
+++ /dev/null
@@ -1,262 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import circlet.code.api.ReviewerChangedType
-import circlet.platform.client.resolve
-import circlet.principals.asUser
-import com.intellij.icons.AllIcons
-import com.intellij.ide.plugins.newui.VerticalLayout
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.text.HtmlChunk
-import com.intellij.openapi.util.text.HtmlChunk.html
-import com.intellij.space.chat.model.api.SpaceChatItem
-import com.intellij.space.chat.model.api.SpaceChatItemType.*
-import com.intellij.space.chat.ui.discussion.SpaceChatCodeDiscussionComponentFactory
-import com.intellij.space.chat.ui.message.MessageTitleComponent
-import com.intellij.space.chat.ui.message.SpaceChatMessagePendingHeader
-import com.intellij.space.chat.ui.message.SpaceMCMessageComponent
-import com.intellij.space.chat.ui.message.SpaceStyledMessageComponent
-import com.intellij.space.chat.ui.thread.createCollapsedThreadComponent
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.SpaceAvatarProvider
-import com.intellij.space.ui.resizeIcon
-import com.intellij.ui.components.JBLabel
-import com.intellij.ui.scale.JBUIScale
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.codereview.SingleValueModelImpl
-import com.intellij.util.ui.codereview.ToggleableContainer
-import com.intellij.util.ui.codereview.timeline.TimelineItemComponentFactory
-import com.intellij.util.ui.codereview.timeline.comment.SubmittableTextFieldModelBase
-import com.intellij.util.ui.components.BorderLayoutPanel
-import icons.SpaceIcons
-import icons.VcsCodeReviewIcons
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import javax.swing.*
-
-internal class SpaceChatItemComponentFactory(
- private val project: Project,
- private val lifetime: Lifetime,
- private val server: String,
- private val avatarProvider: SpaceAvatarProvider
-) : TimelineItemComponentFactory {
-
- private val codeDiscussionComponentFactory = SpaceChatCodeDiscussionComponentFactory(project, lifetime, server)
-
- /**
- * Method should return [HoverableJPanel] because it is used to implement hovering properly
- *
- * @see SpaceChatPanel
- */
- override fun createComponent(item: SpaceChatItem): HoverableJPanel {
- val component =
- when (val type = item.type) {
- is CodeDiscussion ->
- codeDiscussionComponentFactory.createComponent(item, type.discussion) ?: createUnsupportedMessageTypePanel(item.link)
- is SimpleText -> SpaceChatEditableComponent(project, lifetime, createSimpleMessageComponent(item), item)
- is ReviewCompletionStateChanged -> SpaceStyledMessageComponent(createSimpleMessageComponent(item))
- is ReviewerChanged -> {
- val user = type.uid.resolve().link()
- val text = when (type.changeType) {
- ReviewerChangedType.Joined -> SpaceBundle.message("chat.reviewer.added", user)
- ReviewerChangedType.Left -> SpaceBundle.message("chat.reviewer.removed", user)
- }
- SpaceStyledMessageComponent(SpaceChatMarkdownTextComponent(server, text))
- }
- is MergeRequestMerged -> SpaceStyledMessageComponent(
- SpaceChatMarkdownTextComponent(
- server,
- HtmlChunk.raw(
- SpaceBundle.message(
- "chat.review.merged",
- HtmlChunk.text(type.sourceBranch).bold(), // NON-NLS
- HtmlChunk.text(type.targetBranch).bold() // NON-NLS
- )
- ).wrapWith(html()).toString()
- )
- )
- is MergeRequestBranchDeleted -> SpaceStyledMessageComponent(
- SpaceChatMarkdownTextComponent(
- server,
- HtmlChunk.raw(
- SpaceBundle.message("chat.review.deleted.branch", HtmlChunk.text(type.branch).bold()) // NON-NLS
- ).wrapWith(html()).toString()
- )
- )
- is ReviewTitleChanged -> SpaceStyledMessageComponent(
- SpaceChatMarkdownTextComponent(
- server,
- HtmlChunk.raw(
- SpaceBundle.message(
- "chat.review.title.changed",
- HtmlChunk.text(type.oldTitle).bold(), // NON-NLS
- HtmlChunk.text(type.newTitle).bold() // NON-NLS
- )
- ).wrapWith(html()).toString()
- )
- )
- is MCMessage -> SpaceMCMessageComponent(server, type.content, item.attachments)
- is Deleted -> SpaceChatMarkdownTextComponent(server, getGrayTextHtml(SpaceBundle.message("chat.message.removed.text")))
- is Unknown -> createUnsupportedMessageTypePanel(item.link)
- }
- return Item(
- createAvatarIcon(item),
- createTitleComponent(item),
- SpaceChatMessagePendingHeader(item),
- component.addThreadComponentIfNeeded(item).addStartThreadField(item)
- )
- }
-
- private fun createTitleComponent(item: SpaceChatItem): MessageTitleComponent? {
- if (item.type == Deleted) {
- return null
- }
- return MessageTitleComponent(project, lifetime, item)
- }
-
- private fun createAvatarIcon(item: SpaceChatItem): Icon {
- val user = item.author.asUser
- if (user != null) {
- return avatarProvider.getIcon(user)
- }
- if (item.type == Deleted) {
- return resizeIcon(VcsCodeReviewIcons.Delete)
- }
- return resizeIcon(SpaceIcons.Main)
- }
-
- private fun resizeIcon(icon: Icon) = resizeIcon(icon, avatarProvider.iconSize.get())
-
- private fun createUnsupportedMessageTypePanel(messageLink: String?): JComponent {
- val description = if (messageLink != null) {
- SpaceBundle.message("chat.unsupported.message.type.with.link", messageLink)
- }
- else {
- SpaceBundle.message("chat.unsupported.message.type")
- }
- return JBLabel(description, AllIcons.General.Warning, SwingConstants.LEFT).setCopyable(true)
- }
-
- private fun JComponent.addThreadComponentIfNeeded(message: SpaceChatItem): JComponent {
- return if (message.type is CodeDiscussion) {
- this
- }
- else {
- val threadComponent = createCollapsedThreadComponent(project, lifetime, message, null)
- JPanel(VerticalLayout(0)).apply {
- isOpaque = false
- add(this@addThreadComponentIfNeeded, VerticalLayout.FILL_HORIZONTAL)
- add(threadComponent, VerticalLayout.FILL_HORIZONTAL)
- }
- }
- }
-
- private fun JComponent.addStartThreadField(message: SpaceChatItem): JComponent {
- val startThreadVm = message.startThreadVm
-
- val isWritingFirstMessageModel = SingleValueModelImpl(false)
- startThreadVm.isWritingFirstMessage.forEach(lifetime) {
- isWritingFirstMessageModel.value = it
- }
- val emptyPanel = JPanel().apply {
- isOpaque = false
- border = JBUI.Borders.empty()
- }
- val statsPlace = SpaceStatsCounterCollector.SendMessagePlace.NEW_THREAD
- val firstThreadMessageField = ToggleableContainer.create(isWritingFirstMessageModel, { emptyPanel }, {
- val submittableModel = object : SubmittableTextFieldModelBase("") {
- override fun submit() {
- isBusy = true
- SpaceStatsCounterCollector.SEND_MESSAGE.log(statsPlace, false)
- launch(lifetime, Ui) {
- startThreadVm.startThread(document.text)
- isBusy = false
- }
- }
- }
- val newMessageComponent = SpaceChatNewMessageWithAvatarComponent(
- lifetime,
- SpaceChatAvatarType.THREAD,
- submittableModel,
- statsPlace,
- onCancel = { startThreadVm.stopWritingFirstMessage() }
- )
- BorderLayoutPanel().apply {
- isOpaque = false
- border = JBUI.Borders.emptyTop(10)
- addToCenter(newMessageComponent)
- }
- })
- return JPanel(VerticalLayout(0)).apply {
- isOpaque = false
- border = JBUI.Borders.empty()
- add(this@addStartThreadField, VerticalLayout.FILL_HORIZONTAL)
- add(firstThreadMessageField, VerticalLayout.FILL_HORIZONTAL)
- }
- }
-
- private fun createSimpleMessageComponent(message: SpaceChatItem): SpaceChatMarkdownTextComponent =
- SpaceChatMarkdownTextComponent(server, message.text, message.isEdited)
-
- internal class Item(
- avatar: Icon,
- private val title: MessageTitleComponent?,
- header: JComponent,
- content: JComponent
- ) : HoverableJPanel() {
- companion object {
- val AVATAR_GAP: Int
- get() = JBUIScale.scale(8)
- }
-
- init {
- val headerPart = BorderLayoutPanel().apply {
- isOpaque = false
- border = JBUI.Borders.emptyLeft(avatar.iconWidth + AVATAR_GAP)
- addToCenter(header)
- }
-
- val avatarPanel = BorderLayoutPanel().apply {
- isOpaque = false
- border = JBUI.Borders.empty()
- addToTop(userAvatar(avatar))
- }
- val rightPart = JPanel(VerticalLayout(JBUI.scale(5))).apply {
- isOpaque = false
- border = JBUI.Borders.emptyLeft(AVATAR_GAP)
- title?.let { add(it, VerticalLayout.FILL_HORIZONTAL) }
- val contentWrapper = BorderLayoutPanel().apply {
- isOpaque = false
- if (title == null) {
- border = JBUI.Borders.emptyTop(avatar.iconHeight / 4)
- }
- addToCenter(content)
- }
- add(contentWrapper, VerticalLayout.FILL_HORIZONTAL)
- }
- val messagePanel = BorderLayoutPanel().apply {
- isOpaque = false
- addToLeft(avatarPanel)
- addToCenter(rightPart)
- }
-
- layout = VerticalLayout(JBUI.scale(3))
- isOpaque = false
- border = JBUI.Borders.emptyTop(15)
-
- add(headerPart, VerticalLayout.FILL_HORIZONTAL)
- add(messagePanel, VerticalLayout.FILL_HORIZONTAL)
- }
-
- private fun userAvatar(avatar: Icon) = JLabel(avatar)
-
- override fun hoverStateChanged(isHovered: Boolean) {
- title ?: return
- title.actionsPanel.isVisible = isHovered
- title.revalidate()
- title.repaint()
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatItemListModel.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatItemListModel.kt
deleted file mode 100644
index 74de19d34f1f..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatItemListModel.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import com.intellij.space.chat.model.api.SpaceChatItem
-import javax.swing.AbstractListModel
-import kotlin.math.min
-
-internal class SpaceChatItemListModel : AbstractListModel() {
- private val items = mutableListOf()
-
- override fun getElementAt(index: Int): SpaceChatItem = items[index]
-
- override fun getSize() = items.size
-
- fun messageListUpdated(new: List) {
- val newItems = keepOldItemsState(new)
- val oldItems = ArrayList(items)
-
- items.clear()
- items.addAll(newItems)
-
- for (i in 0 until min(oldItems.size, newItems.size)) {
- if (oldItems[i] != newItems[i]) {
- fireContentsChanged(this, i, i)
- }
- }
- if (newItems.size < oldItems.size) {
- fireIntervalRemoved(this, newItems.size, oldItems.size - 1)
- }
- if (newItems.size > oldItems.size) {
- fireIntervalAdded(this, oldItems.size, newItems.size - 1)
- }
- }
-
- private fun keepOldItemsState(new: List): List {
- val oldItems = items.associateBy { it.id }
- return List(new.size) { i ->
- val newItem = new[i]
- val oldItem = oldItems[newItem.id]
- if (oldItem == newItem) {
- // if nothing changed, keep old reference
- oldItem
- }
- else {
- if (oldItem != null) {
- // if smth changed, keep loadingThread state
- newItem.loadingThread.value = oldItem.loadingThread.value
- }
- newItem
- }
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatMarkdownTextComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatMarkdownTextComponent.kt
deleted file mode 100644
index ef39319addbe..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatMarkdownTextComponent.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import circlet.client.api.UnfurlAttachment
-import circlet.completion.mentions.MentionConverter
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.space.chat.markdown.convertToHtml
-import com.intellij.space.chat.markdown.processUnfurls
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.vcs.review.HtmlEditorPane
-import com.intellij.util.ui.UIUtil
-import org.jetbrains.annotations.NonNls
-
-internal class SpaceChatMarkdownTextComponent(
- private val server: @NonNls String,
- initialText: @NlsSafe String? = null,
- initialIsEdited: Boolean = false,
- initialUnfurls: List = emptyList()
-) : HtmlEditorPane() {
- init {
- putClientProperty(UIUtil.HIDE_EDITOR_FROM_DATA_CONTEXT_PROPERTY, true)
- initialText?.let { setMarkdownText(it, initialIsEdited, initialUnfurls) }
- }
-
- fun setMarkdownText(text: @NlsSafe String, isEdited: Boolean, unfurls: List = emptyList()) {
- setBody(processItemText(server, text, isEdited, unfurls))
- }
-}
-
-@NlsSafe
-private fun processItemText(
- server: @NonNls String,
- @NlsSafe text: String,
- isEdited: Boolean,
- unfurls: List
-): String {
- val markdown = MentionConverter.markdown(text, server).let {
- if (isEdited) {
- it + " " + getGrayTextHtml(SpaceBundle.message("chat.message.edited.text"))
- }
- else {
- it
- }
- }
- return convertToHtml(processUnfurls(markdown, unfurls), server)
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatPanel.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatPanel.kt
deleted file mode 100644
index a69a76c480e2..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceChatPanel.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import circlet.client.api.M2ChannelRecord
-import circlet.m2.ChannelsVm
-import circlet.platform.api.Ref
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.editor.colors.EditorColorsManager
-import com.intellij.openapi.project.Project
-import com.intellij.space.chat.model.api.SpaceChatHeaderDetails
-import com.intellij.space.chat.ui.header.createComponent
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.ui.ScrollPaneFactory
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.components.BorderLayoutPanel
-import libraries.coroutines.extra.Lifetime
-import net.miginfocom.layout.AC
-import net.miginfocom.layout.CC
-import net.miginfocom.layout.LC
-import net.miginfocom.swing.MigLayout
-import javax.swing.JComponent
-import javax.swing.JPanel
-import javax.swing.ScrollPaneConstants
-
-internal class SpaceChatPanel(
- private val project: Project,
- private val lifetime: Lifetime,
- private val parent: Disposable,
- private val channelsVm: ChannelsVm,
- private val chatRecord: Ref,
- private val headerDetails: SpaceChatHeaderDetails
-) : BorderLayoutPanel() {
-
- init {
- isOpaque = true
- background = EditorColorsManager.getInstance().globalScheme.defaultBackground
-
- val contentComponent = createContentComponent()
- val scrollableContentPanel = ScrollPaneFactory.createScrollPane(
- contentComponent,
- ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
- ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
- ).apply {
- border = JBUI.Borders.empty()
- isOpaque = false
- viewport.isOpaque = false
- }
- addToCenter(scrollableContentPanel)
- }
-
- private fun createContentComponent(): JComponent {
- val contentPanel = SpaceChatContentPanel(project, lifetime, parent, channelsVm, chatRecord).apply {
- setLoadingText(SpaceBundle.message("chat.loading.text"))
- }
-
- return JPanel(null).apply {
- isOpaque = false
- border = JBUI.Borders.empty(5, 20)
-
- val maxWidth = JBUI.scale(600)
-
- layout = MigLayout(LC().gridGap("0", "${JBUI.scale(10)}")
- .insets("0", "0", "0", "0")
- .flowY(),
- AC().size(":$maxWidth:$maxWidth").gap("push"))
- add(headerDetails.createComponent(lifetime), CC().growX().minWidth(""))
- add(contentPanel, CC().grow().push().minWidth(""))
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceNewMessageField.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceNewMessageField.kt
deleted file mode 100644
index 2de529152d76..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/SpaceNewMessageField.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui
-
-import circlet.m2.channel.M2ChannelVm
-import com.intellij.openapi.application.runWriteAction
-import com.intellij.openapi.ui.MessageDialogBuilder
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.SpaceAvatarProvider
-import com.intellij.ui.components.JBLabel
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.codereview.timeline.comment.SubmittableTextField
-import com.intellij.util.ui.codereview.timeline.comment.SubmittableTextFieldModel
-import com.intellij.util.ui.codereview.timeline.comment.SubmittableTextFieldModelBase
-import libraries.coroutines.extra.Lifetime
-import net.miginfocom.layout.CC
-import net.miginfocom.layout.LC
-import net.miginfocom.swing.MigLayout
-import javax.swing.JComponent
-import javax.swing.JPanel
-
-internal fun createNewMessageField(
- chatVM: M2ChannelVm,
- avatarType: SpaceChatAvatarType,
- statsPlace: SpaceStatsCounterCollector.SendMessagePlace,
- pendingStateProvider: () -> Boolean = { false },
- onCancel: (() -> Unit)? = null,
- onSend: (() -> Unit)? = null
-): JComponent {
- val submittableModel = object : SubmittableTextFieldModelBase("") {
- override fun submit() {
- val isPending = pendingStateProvider()
- SpaceStatsCounterCollector.SEND_MESSAGE.log(statsPlace, isPending)
- chatVM.sendMessage(document.text, pending = isPending)
- runWriteAction {
- document.setText("")
- }
- onSend?.invoke()
- }
- }
- return SpaceChatNewMessageWithAvatarComponent(chatVM.lifetime, avatarType, submittableModel, statsPlace, onCancel)
-}
-
-internal class SpaceChatNewMessageWithAvatarComponent(
- avatarProviderLifetime: Lifetime,
- avatarType: SpaceChatAvatarType,
- submittableModel: SubmittableTextFieldModel,
- statsPlace: SpaceStatsCounterCollector.SendMessagePlace,
- onCancel: (() -> Unit)?
-) : JPanel(null) {
- init {
- isOpaque = false
- layout = MigLayout(LC().gridGap("0", "0")
- .insets("0", "0", "0", "0")
- .fill()).apply {
- columnConstraints = "[][]"
- }
- val avatarProvider = SpaceAvatarProvider(avatarProviderLifetime, this, avatarType.size)
- val avatar = avatarProvider.getIcon(SpaceWorkspaceComponent.getInstance().workspace.value!!.me.value)
- val avatarComponent = JBUI.Panels.simplePanel(JBLabel(avatar)).apply {
- isOpaque = false
- border = JBUI.Borders.emptyRight(SpaceChatItemComponentFactory.Item.AVATAR_GAP)
- }
- val submittableTextField = SubmittableTextField(
- SpaceBundle.message("chat.comment.action.text"),
- submittableModel,
- onCancel = {
- if (
- submittableModel.document.text.isBlank() ||
- MessageDialogBuilder.yesNo(
- SpaceBundle.message("chat.message.new.discard.changes.title"),
- SpaceBundle.message("chat.message.new.discard.changes.text")
- ).ask(this)
- ) {
- SpaceStatsCounterCollector.DISCARD_SEND_MESSAGE.log(statsPlace)
- onCancel?.invoke()
- }
- }
- )
- add(avatarComponent, CC().pushY())
- add(submittableTextField, CC().growX().pushX().alignY("center"))
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceChatCodeDiscussionComponentFactory.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceChatCodeDiscussionComponentFactory.kt
deleted file mode 100644
index 5449c747fb8f..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceChatCodeDiscussionComponentFactory.kt
+++ /dev/null
@@ -1,258 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.discussion
-
-import circlet.code.api.CodeDiscussionRecord
-import circlet.code.api.CodeDiscussionSnippet
-import circlet.platform.api.Ref
-import circlet.platform.client.property
-import circlet.platform.client.resolve
-import com.intellij.icons.AllIcons
-import com.intellij.ide.plugins.newui.HorizontalLayout
-import com.intellij.ide.plugins.newui.VerticalLayout
-import com.intellij.openapi.application.runWriteAction
-import com.intellij.openapi.editor.colors.EditorColorsManager
-import com.intellij.openapi.project.Project
-import com.intellij.space.chat.model.api.SpaceChatItem
-import com.intellij.space.chat.ui.SpaceChatAvatarType
-import com.intellij.space.chat.ui.SpaceChatEditableComponent
-import com.intellij.space.chat.ui.SpaceChatMarkdownTextComponent
-import com.intellij.space.chat.ui.SpaceChatNewMessageWithAvatarComponent
-import com.intellij.space.chat.ui.message.createResolvedComponent
-import com.intellij.space.chat.ui.thread.createCollapsedThreadComponent
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.ui.IdeBorderFactory
-import com.intellij.ui.RoundedLineBorder
-import com.intellij.ui.SideBorder
-import com.intellij.ui.components.ActionLink
-import com.intellij.ui.components.JBLabel
-import com.intellij.ui.components.panels.NonOpaquePanel
-import com.intellij.ui.scale.JBUIScale
-import com.intellij.util.PathUtil
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.UIUtil
-import com.intellij.util.ui.codereview.InlineIconButton
-import com.intellij.util.ui.codereview.SingleValueModel
-import com.intellij.util.ui.codereview.SingleValueModelImpl
-import com.intellij.util.ui.codereview.ToggleableContainer
-import com.intellij.util.ui.codereview.timeline.comment.SubmittableTextFieldModelBase
-import com.intellij.util.ui.components.BorderLayoutPanel
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.launch
-import net.miginfocom.layout.CC
-import net.miginfocom.layout.LC
-import net.miginfocom.swing.MigLayout
-import runtime.Ui
-import runtime.reactive.Property
-import runtime.reactive.property.map
-import java.awt.event.ActionListener
-import javax.swing.JComponent
-import javax.swing.JPanel
-import javax.swing.SwingConstants
-
-internal class SpaceChatCodeDiscussionComponentFactory(
- private val project: Project,
- private val lifetime: Lifetime,
- private val server: String,
-) {
- fun createComponent(message: SpaceChatItem, codeDiscussion: Ref): JComponent? {
- val discussionMessage = message.projectedItem ?: return null
- val discussion = codeDiscussion.resolve()
- val discussionProperty = codeDiscussion.property()
- val resolved = lifetime.map(discussionProperty) { it.resolved }
- val collapseButton = InlineIconButton(AllIcons.General.CollapseComponent, AllIcons.General.CollapseComponentHover)
- val expandButton = InlineIconButton(AllIcons.General.ExpandComponent, AllIcons.General.ExpandComponentHover)
-
- val filePath = discussion.anchor.filename ?: return null
- val fileNameComponent = JBUI.Panels.simplePanel(
- createFileNameComponent(filePath, collapseButton, expandButton, resolved)
- ).apply {
- isOpaque = false
- border = JBUI.Borders.empty(8)
- }
- val snippet = discussion.snippet ?: return null
- val diffEditorComponent = when (snippet) {
- is CodeDiscussionSnippet.PlainSnippet -> {
- return null
- }
- is CodeDiscussionSnippet.InlineDiffSnippet -> createDiffComponent(project, discussion.anchor, snippet)
- }.apply {
- border = IdeBorderFactory.createBorder(SideBorder.TOP)
- }
-
- val snapshotComponent = JPanel(VerticalLayout(0)).apply {
- isOpaque = true
- background = EditorColorsManager.getInstance().globalScheme.defaultBackground
- border = RoundedLineBorder(UIUtil.CONTRAST_BORDER_COLOR, IdeBorderFactory.BORDER_ROUNDNESS)
- add(fileNameComponent)
- add(diffEditorComponent, VerticalLayout.FILL_HORIZONTAL)
- }
- val reviewCommentComponent = SpaceChatMarkdownTextComponent(server)
-
- val collapseModel = SingleValueModelImpl(true)
- val panel = JPanel(VerticalLayout(JBUIScale.scale(4))).apply {
- isOpaque = false
- add(snapshotComponent, VerticalLayout.FILL_HORIZONTAL)
- add(createEditableReviewCommentComponent(reviewCommentComponent, message, collapseModel), VerticalLayout.FILL_HORIZONTAL)
- }
-
- val outerReplyComponent = createOuterReplyComponent(discussionProperty, message)
- val threadComponent = createThreadComponent(discussionProperty, message)
- val component = JPanel(VerticalLayout(0)).apply {
- isOpaque = false
- add(panel, VerticalLayout.FILL_HORIZONTAL)
- add(threadComponent, VerticalLayout.FILL_HORIZONTAL)
- add(outerReplyComponent, VerticalLayout.FILL_HORIZONTAL)
- addDiscussionExpandCollapseHandling(
- this,
- collapseModel,
- listOf(outerReplyComponent, threadComponent, reviewCommentComponent, diffEditorComponent),
- collapseButton,
- expandButton,
- resolved
- )
- }
-
- discussionMessage.forEach(lifetime) {
- reviewCommentComponent.setMarkdownText(it.text, it.edited != null)
- reviewCommentComponent.repaint()
- }
-
- return component
- }
-
- private fun createOuterReplyComponent(discussion: Property, message: SpaceChatItem): JComponent {
- val newMessageStateModel = SingleValueModelImpl(false)
- val replyAction = ActionLink(SpaceBundle.message("chat.reply.action")) {
- newMessageStateModel.value = true
- }
- val resolveComponent = createResolveComponent(lifetime, message.chat.client, discussion)
- val actionsComponent = JPanel(HorizontalLayout(JBUI.scale(5))).apply {
- isOpaque = false
- border = JBUI.Borders.emptyTop(8)
- add(replyAction)
- add(resolveComponent)
- }
- val outerReplyComponent = ToggleableContainer.create(
- newMessageStateModel,
- mainComponentSupplier = { actionsComponent },
- toggleableComponentSupplier = {
- val statsPlace = SpaceStatsCounterCollector.SendMessagePlace.FIRST_DISCUSSION_ANSWER
- val submittableModel = object : SubmittableTextFieldModelBase("") {
- override fun submit() {
- val isPending = false
- SpaceStatsCounterCollector.SEND_MESSAGE.log(statsPlace, isPending)
- launch(lifetime, Ui) {
- val thread = message.loadThread(lifetime)
- thread?.sendMessage(document.text, pending = isPending)
- runWriteAction {
- document.setText("")
- }
- newMessageStateModel.value = false
- }
- }
- }
- SpaceChatNewMessageWithAvatarComponent(lifetime, SpaceChatAvatarType.THREAD, submittableModel, statsPlace,
- onCancel = {
- newMessageStateModel.value = false
- })
- }
- )
- message.threadPreview!!.messageCount.forEach(lifetime) { count ->
- actionsComponent.isVisible = count == 0
- }
- return BorderLayoutPanel().apply {
- isOpaque = false
- addToCenter(outerReplyComponent)
- }
- }
-
- private fun createThreadComponent(discussionProperty: Property, message: SpaceChatItem): JComponent {
- val threadActionsFactory = SpaceChatDiscussionActionsFactory(
- lifetime,
- message.chat.client,
- discussionProperty
- )
- return BorderLayoutPanel().apply {
- isOpaque = false
- addToCenter(createCollapsedThreadComponent(project, lifetime, message, threadActionsFactory, withFirst = false))
- }
- }
-
- private fun createEditableReviewCommentComponent(
- reviewCommentContent: JComponent,
- message: SpaceChatItem,
- collapseModel: SingleValueModel
- ): JComponent {
- val editableReviewCommentComponent = SpaceChatEditableComponent(project, lifetime, reviewCommentContent, message)
- editableReviewCommentComponent.editingModel.addValueUpdatedListener { isEditing ->
- if (isEditing) {
- collapseModel.value = false
- }
- }
- return editableReviewCommentComponent
- }
-
- private fun createFileNameComponent(
- filePath: String,
- collapseButton: InlineIconButton,
- expandButton: InlineIconButton,
- resolved: Property
- ): JComponent {
- val name = PathUtil.getFileName(filePath)
- val parentPath = PathUtil.getParentPath(filePath)
- val nameLabel = JBLabel(name, null, SwingConstants.LEFT).setCopyable(true)
-
- val resolvedLabel = createResolvedComponent(lifetime, resolved)
- return NonOpaquePanel(MigLayout(LC().insets("0").gridGap("${JBUI.scale(5)}", "0").fill().noGrid())).apply {
- add(nameLabel, CC().minWidth("0").shrinkPrio(9))
-
- if (parentPath.isNotBlank()) {
- add(JBLabel(parentPath).apply {
- foreground = UIUtil.getContextHelpForeground()
- setCopyable(true)
- }, CC().minWidth("0").shrinkPrio(10))
- }
- add(resolvedLabel, CC().hideMode(3).shrinkPrio(0))
- add(collapseButton, CC().hideMode(3).shrinkPrio(0))
- add(expandButton, CC().hideMode(3).shrinkPrio(0))
- }
- }
-
- // TODO: Extract it to code-review module
- private fun addDiscussionExpandCollapseHandling(
- parentComponent: JComponent,
- collapseModel: SingleValueModel,
- componentsToHide: Collection,
- collapseButton: InlineIconButton,
- expandButton: InlineIconButton,
- resolved: Property
- ) {
- collapseButton.actionListener = ActionListener {
- collapseModel.value = true
- SpaceStatsCounterCollector.COLLAPSE_DISCUSSION.log(project)
- }
- expandButton.actionListener = ActionListener {
- collapseModel.value = false
- SpaceStatsCounterCollector.EXPAND_DISCUSSION.log(project)
- }
-
- fun stateUpdated(collapsed: Boolean) {
- collapseButton.isVisible = resolved.value && !collapsed
- expandButton.isVisible = resolved.value && collapsed
-
- val areComponentsVisible = !resolved.value || !collapsed
- componentsToHide.forEach { it.isVisible = areComponentsVisible }
- parentComponent.revalidate()
- parentComponent.repaint()
- }
-
- collapseModel.addValueUpdatedListener {
- stateUpdated(it)
- }
-
- resolved.forEach(lifetime) {
- collapseModel.value = it
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceChatDiffComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceChatDiffComponent.kt
deleted file mode 100644
index 79f5ac34e212..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceChatDiffComponent.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.discussion
-
-import circlet.code.api.CodeDiscussionAnchor
-import circlet.code.api.CodeDiscussionSnippet
-import com.intellij.diff.util.DiffDrawUtil
-import com.intellij.diff.util.TextDiffType
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.editor.EditorFactory
-import com.intellij.openapi.editor.LineNumberConverter
-import com.intellij.openapi.editor.ex.EditorEx
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.ui.JBColor
-import com.intellij.ui.JBColor.namedColor
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.codereview.timeline.TimelineDiffComponentFactory
-import org.jetbrains.annotations.Nls
-import runtime.code.DiffLineType
-import runtime.code.InlineDiffLine
-import runtime.text.TextRange
-import runtime.text.end
-import java.awt.Color
-import javax.swing.JComponent
-
-internal fun createDiffComponent(
- project: Project,
- anchor: CodeDiscussionAnchor,
- snippet: CodeDiscussionSnippet.InlineDiffSnippet
-): JComponent {
- val lines = snippet.lines
- val lineSeparator = "\n"
- val text = lines.joinToString(lineSeparator) { line ->
- line.text
- }
- val anchorLine = lines.findAnchorLine(anchor)
- val editorFactory = EditorFactory.getInstance()
- return TimelineDiffComponentFactory(project, editorFactory).createDiffComponent(text) { editor ->
- editor
- .addLinesHighlighting(lines, anchorLine, lineSeparator)
- .convertLinesNumber(lines)
- editor.scrollPane.border = JBUI.Borders.empty()
- }
-}
-
-private fun EditorEx.convertLinesNumber(lines: List): EditorEx {
- if (lines.any { it.newLineNum != null && it.oldLineNum != null }) {
- gutter.setLineNumberConverter(
- object : LineNumberConverter {
- override fun convert(editor: Editor, lineNumber: Int) = lines[lineNumber - 1].oldLineNum?.plus(1)
-
- override fun getMaxLineNumber(editor: Editor): Int? = lines.mapNotNull { it.oldLineNum }.maxOrNull()
- },
- object : LineNumberConverter {
- override fun convert(editor: Editor, lineNumber: Int) = lines[lineNumber - 1].newLineNum?.plus(1)
-
- override fun getMaxLineNumber(editor: Editor): Int? = lines.mapNotNull { it.newLineNum }.maxOrNull()
- }
- )
- }
- else {
- gutter.setLineNumberConverter(object : LineNumberConverter {
- override fun convert(editor: Editor, lineNumber: Int) = lines[lineNumber - 1].newLineNum?.plus(1)
-
- override fun getMaxLineNumber(editor: Editor): Int? = lines.last().newLineNum
- })
- }
- return this
-}
-
-private fun EditorEx.addLinesHighlighting(
- lines: List,
- anchorLine: InlineDiffLine?,
- @NlsSafe separator: String
-): EditorEx {
- val prefixLengths = ArrayList()
- prefixLengths.add(0)
- for (i in lines.indices) {
- prefixLengths.add(prefixLengths[i] + lines[i].text.length + separator.length)
- }
- lines.forEachIndexed { i, line ->
- addFullLineHighlighting(line, i, anchorLine)
- val prefixLength = prefixLengths[i]
- line.inserts?.let { ranges -> addInlineHighlighting(line, prefixLength, ranges, TextDiffType.INSERTED) }
- line.deletes?.let { ranges -> addInlineHighlighting(line, prefixLength, ranges, TextDiffType.DELETED) }
- }
- return this
-}
-
-private fun EditorEx.addFullLineHighlighting(line: InlineDiffLine, lineIndex: Int, anchorLine: InlineDiffLine?) {
- if (anchorLine != null && anchorLine == line) {
- DiffDrawUtil.createHighlighter(this, lineIndex, lineIndex + 1, AnchorLine, false)
- }
- else {
- val diffType = when (line.type) {
- DiffLineType.ADDED -> TextDiffType.INSERTED
- DiffLineType.DELETED -> TextDiffType.DELETED
- DiffLineType.MODIFIED -> TextDiffType.MODIFIED
- DiffLineType.CONFLICT_OLD -> TextDiffType.CONFLICT
- DiffLineType.CONFLICT_NEW -> TextDiffType.CONFLICT
- DiffLineType.FILTERED_ADDED -> TextDiffType.INSERTED
- DiffLineType.FILTERED_DELETED -> TextDiffType.DELETED
- DiffLineType.FILTERED_MODIFIED -> TextDiffType.MODIFIED
- null -> null
- }
- val ignored = (line.deletes?.any { range -> !isFullLineRange(line, range) } ?: false) ||
- (line.inserts?.any { range -> !isFullLineRange(line, range) } ?: false)
- if (diffType != null) {
- DiffDrawUtil.createHighlighter(this, lineIndex, lineIndex + 1, diffType, ignored)
- }
- }
-}
-
-private fun isFullLineRange(line: InlineDiffLine, range: TextRange): Boolean = line.text.length == range.length
-
-private fun EditorEx.addInlineHighlighting(line: InlineDiffLine, prefixLength: Int, ranges: List, diffType: TextDiffType) {
- ranges.forEach { range ->
- if (!isFullLineRange(line, range)) {
- DiffDrawUtil.createInlineHighlighter(this, prefixLength + range.start, prefixLength + range.end, diffType)
- }
- }
-}
-
-private fun List.findAnchorLine(anchor: CodeDiscussionAnchor): InlineDiffLine? =
- this.find { line ->
- line.oldLineNum != null && anchor.oldLine == line.oldLineNum ||
- line.newLineNum != null && anchor.line == line.newLineNum
- }
-
-private object AnchorLine : TextDiffType {
- @Nls
- override fun getName() = SpaceBundle.message("review.diff.type.anchor.name")
-
- override fun getColor(editor: Editor?): Color = namedColor(
- "Space.Review.diffAnchorBackground",
- JBColor(0xFBF1D1, 0x544B2D)
- )
-
- override fun getIgnoredColor(editor: Editor?) = getColor(editor)
-
- override fun getMarkerColor(editor: Editor?) = getColor(editor)
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceChatDiscussionActionsFactory.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceChatDiscussionActionsFactory.kt
deleted file mode 100644
index 4b7fd2446d08..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceChatDiscussionActionsFactory.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.discussion
-
-import circlet.code.api.CodeDiscussionRecord
-import circlet.platform.client.KCircletClient
-import com.intellij.space.chat.ui.thread.SpaceChatThreadActionsFactory
-import libraries.coroutines.extra.Lifetime
-import runtime.reactive.Property
-import javax.swing.JComponent
-
-internal class SpaceChatDiscussionActionsFactory(
- private val lifetime: Lifetime,
- private val client: KCircletClient,
- private val discussion: Property
-) : SpaceChatThreadActionsFactory {
- override fun createActionsComponent(): JComponent = createResolveComponent(lifetime, client, discussion)
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceResolveActionComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceResolveActionComponent.kt
deleted file mode 100644
index b7da039dfc79..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/discussion/SpaceResolveActionComponent.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.discussion
-
-import circlet.code.api.CodeDiscussionRecord
-import circlet.code.codeReview
-import circlet.platform.client.KCircletClient
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.ui.components.ActionLink
-import com.intellij.util.ui.UIUtil
-import com.intellij.util.ui.codereview.SingleValueModel
-import com.intellij.util.ui.codereview.SingleValueModelImpl
-import com.intellij.util.ui.components.BorderLayoutPanel
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.delay
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import runtime.reactive.Property
-import javax.swing.JComponent
-import javax.swing.JLabel
-
-internal fun createResolveComponent(
- lifetime: Lifetime,
- client: KCircletClient,
- discussion: Property,
-): JComponent {
- val resolvingLabel = JLabel(SpaceBundle.message("chat.resolving.action.state")).apply {
- foreground = UIUtil.getContextHelpForeground()
- }
- val reopeningLabel = JLabel(SpaceBundle.message("chat.reopening.action.state")).apply {
- foreground = UIUtil.getContextHelpForeground()
- }
- val resolvingModel = SingleValueModelImpl(ResolvingState.READY)
- val resolveReopenLabel = createResolveReopenLabel(lifetime, client, discussion, resolvingModel)
- val contentPanel = BorderLayoutPanel().apply {
- isOpaque = false
- addToCenter(resolveReopenLabel)
- }
- resolvingModel.addValueUpdatedListener { newState ->
- val stateLabel = when (newState) {
- ResolvingState.RESOLVING -> resolvingLabel
- ResolvingState.REOPENING -> reopeningLabel
- ResolvingState.READY -> resolveReopenLabel
- }
- contentPanel.removeAll()
- contentPanel.addToCenter(stateLabel)
- contentPanel.revalidate()
- contentPanel.repaint()
- }
- return contentPanel
-}
-
-private fun createResolveReopenLabel(
- lifetime: Lifetime,
- client: KCircletClient,
- discussion: Property,
- resolvingModel: SingleValueModel
-): JComponent {
- val reviewService = client.codeReview
- fun resolve() {
- val currentDiscussion = discussion.value
- launch(lifetime, Ui) {
- if (!currentDiscussion.resolved) {
- SpaceStatsCounterCollector.RESOLVE_DISCUSSION.log()
- resolvingModel.value = ResolvingState.RESOLVING
- }
- else {
- SpaceStatsCounterCollector.REOPEN_DISCUSSION.log()
- resolvingModel.value = ResolvingState.REOPENING
- }
- delay(200) // reduce status label blinking
- reviewService.resolveCodeDiscussion(currentDiscussion.id, !currentDiscussion.resolved)
- resolvingModel.value = ResolvingState.READY
- }
- }
-
- val label = ActionLink(SpaceBundle.message("chat.resolve.action")) {
- resolve()
- }
- discussion.forEach(lifetime) {
- label.text = if (it.resolved) {
- SpaceBundle.message("chat.reopen.action")
- }
- else {
- SpaceBundle.message("chat.resolve.action")
- }
- }
-
- return label
-}
-
-private enum class ResolvingState {
- RESOLVING,
- REOPENING,
- READY
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/header/SpaceChatHeaderComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/header/SpaceChatHeaderComponent.kt
deleted file mode 100644
index d68fbe4f3f6f..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/header/SpaceChatHeaderComponent.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.header
-
-import com.intellij.space.chat.model.api.SpaceChatHeaderDetails
-import com.intellij.space.chat.model.impl.SpaceChatReviewHeaderDetails
-import libraries.coroutines.extra.Lifetime
-import javax.swing.JComponent
-
-internal fun SpaceChatHeaderDetails.createComponent(lifetime: Lifetime): JComponent = when (this) {
- is SpaceChatReviewHeaderDetails -> SpaceChatReviewHeaderComponent(lifetime, this)
- else -> throw IllegalArgumentException("This chat header type is not supported")
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/header/SpaceChatReviewHeaderComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/header/SpaceChatReviewHeaderComponent.kt
deleted file mode 100644
index 25321973678b..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/header/SpaceChatReviewHeaderComponent.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.header
-
-import circlet.code.api.CodeReviewState
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.openapi.util.text.HtmlBuilder
-import com.intellij.space.chat.model.impl.SpaceChatReviewHeaderDetails
-import com.intellij.space.chat.ui.SpaceChatAvatarType
-import com.intellij.space.chat.ui.getGrayTextHtml
-import com.intellij.space.ui.resizeIcon
-import com.intellij.space.vcs.review.HtmlEditorPane
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.components.BorderLayoutPanel
-import icons.VcsCodeReviewIcons
-import libraries.coroutines.extra.Lifetime
-import net.miginfocom.layout.CC
-import net.miginfocom.layout.LC
-import net.miginfocom.swing.MigLayout
-import org.jetbrains.annotations.Nls
-import javax.swing.JComponent
-import javax.swing.JLabel
-import javax.swing.JPanel
-
-internal class SpaceChatReviewHeaderComponent(
- lifetime: Lifetime,
- details: SpaceChatReviewHeaderDetails
-) : JPanel() {
- companion object {
- private const val STATE_ICON_FACTOR: Double = 2.0 / 3
-
- private const val STATE_ICON_GAP_FACTOR: Double = 0.5
- }
-
- private val stateIconSize: Int
- get() = (SpaceChatAvatarType.MAIN_CHAT.size.get() * STATE_ICON_FACTOR).toInt()
-
- init {
- isOpaque = false
- layout = MigLayout(LC().gridGap("0", "0")
- .insets("0", "0", "0", "0")
- .fill()).apply {
- columnConstraints = "[][]"
- }
-
- val reviewStateIconPanel = BorderLayoutPanel().apply {
- isOpaque = false
- border = JBUI.Borders.emptyRight((stateIconSize * STATE_ICON_GAP_FACTOR).toInt())
- }
- val headerContent = HtmlEditorPane().apply {
- font = font.deriveFont((font.size * 1.5).toFloat())
- }
-
- add(reviewStateIconPanel, CC().pushY())
- add(headerContent, CC().pushX().alignY("center"))
-
- details.title.forEach(lifetime) { newTitle ->
- headerContent.setBody(getHeaderHtml(newTitle, details.reviewKey))
- }
- details.state.forEach(lifetime) { newState ->
- if (reviewStateIconPanel.components.isNotEmpty()) {
- reviewStateIconPanel.remove(0)
- }
- reviewStateIconPanel.add(getReviewStateIcon(newState), 0)
- reviewStateIconPanel.revalidate()
- reviewStateIconPanel.repaint()
- }
- }
-
- private fun getReviewStateIcon(state: CodeReviewState): JComponent {
- val icon = when (state) {
- CodeReviewState.Opened -> VcsCodeReviewIcons.PullRequestOpen
- CodeReviewState.Closed, CodeReviewState.Deleted -> VcsCodeReviewIcons.PullRequestClosed
- }
- return JLabel(resizeIcon(icon, stateIconSize))
- }
-
- @Nls
- private fun getHeaderHtml(@Nls title: String, @NlsSafe reviewKey: String?): String {
- val builder = HtmlBuilder().append(title)
- if (reviewKey != null) {
- builder
- .nbsp()
- .appendRaw(getGrayTextHtml(reviewKey))
- }
- return builder.toString()
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/MessageTitleComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/MessageTitleComponent.kt
deleted file mode 100644
index 90edc0de6aa7..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/MessageTitleComponent.kt
+++ /dev/null
@@ -1,151 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.message
-
-import circlet.client.api.CApplicationPrincipalDetails
-import circlet.client.api.CPrincipal
-import circlet.client.api.CUserPrincipalDetails
-import circlet.platform.client.resolve
-import com.intellij.icons.AllIcons
-import com.intellij.ide.plugins.newui.HorizontalLayout
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.MessageDialogBuilder
-import com.intellij.openapi.util.text.HtmlChunk
-import com.intellij.space.chat.model.api.SpaceChatItem
-import com.intellij.space.chat.model.api.SpaceChatItemAdditionalFeature
-import com.intellij.space.chat.ui.link
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.SpaceAutoUpdatableComponentService
-import com.intellij.space.utils.SpaceUrls
-import com.intellij.space.utils.formatPrettyDateTime
-import com.intellij.space.vcs.review.HtmlEditorPane
-import com.intellij.ui.AnimatedIcon
-import com.intellij.ui.components.JBLabel
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.UIUtil
-import com.intellij.util.ui.codereview.InlineIconButton
-import icons.VcsCodeReviewIcons
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.delay
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import java.awt.event.ActionListener
-import javax.swing.JComponent
-import javax.swing.JPanel
-
-internal class MessageTitleComponent(
- private val project: Project,
- private val lifetime: Lifetime,
- message: SpaceChatItem
-) : JPanel(HorizontalLayout(JBUI.scale(5))) {
- val actionsPanel = JPanel(HorizontalLayout(JBUI.scale(5))).apply {
- isOpaque = false
- isVisible = false
- add(createStartThreadButton(message))
- createEditButton(message)?.let { add(it) }
- createDeleteButton(message)?.let { add(it) }
- }
-
- init {
- val authorPanel = HtmlEditorPane().apply {
- putClientProperty(UIUtil.HIDE_EDITOR_FROM_DATA_CONTEXT_PROPERTY, true)
- setBody(createMessageAuthorChunk(message.author).bold().toString())
- }
- val timePanel = SpaceAutoUpdatableComponentService.createAutoUpdatableComponent {
- HtmlEditorPane().apply {
- putClientProperty(UIUtil.HIDE_EDITOR_FROM_DATA_CONTEXT_PROPERTY, true)
- foreground = UIUtil.getContextHelpForeground()
- setBody(HtmlChunk.text(message.created.formatPrettyDateTime()).toString()) // NON-NLS
- }
- }
-
- isOpaque = false
- add(authorPanel)
- add(timePanel)
- val showResolvedStateFeature = message.additionalFeatures.filterIsInstance().singleOrNull()
- if (showResolvedStateFeature != null) {
- add(createResolvedComponent(lifetime, showResolvedStateFeature.resolved))
- }
- add(actionsPanel)
- launch(lifetime, Ui) {
- delay(2000)
- if (!message.delivered) {
- add(JBLabel(AnimatedIcon.Default.INSTANCE))
- revalidate()
- repaint()
- }
- }
- }
-
- private fun createMessageAuthorChunk(author: CPrincipal): HtmlChunk =
- when (val details = author.details) {
- is CUserPrincipalDetails -> {
- val user = details.user.resolve()
- user.link()
- }
- is CApplicationPrincipalDetails -> {
- val app = details.app.resolve()
- HtmlChunk.link(SpaceUrls.app(app), app.name) // NON-NLS
- }
- else -> {
- HtmlChunk.text(author.name) // NON-NLS
- }
- }
-
- private fun createDeleteButton(message: SpaceChatItem): JComponent? {
- if (!message.canDelete) {
- return null
- }
- return InlineIconButton(
- VcsCodeReviewIcons.Delete,
- VcsCodeReviewIcons.DeleteHovered,
- tooltip = SpaceBundle.message("chat.message.action.delete.tooltip")
- ).apply {
- actionListener = ActionListener {
- if (
- MessageDialogBuilder.yesNo(
- SpaceBundle.message("chat.message.delete.dialog.title"),
- SpaceBundle.message("chat.message.delete.dialog.message")
- ).ask(this)
- ) {
- SpaceStatsCounterCollector.DELETE_MESSAGE.log(project)
- launch(lifetime, Ui) {
- message.delete()
- }
- }
- }
- }
- }
-
- private fun createEditButton(message: SpaceChatItem): JComponent? {
- if (!message.canEdit) {
- return null
- }
- return InlineIconButton(
- AllIcons.General.Inline_edit,
- AllIcons.General.Inline_edit_hovered,
- tooltip = SpaceBundle.message("chat.message.action.edit.tooltip")
- ).apply {
- actionListener = ActionListener {
- message.startEditing()
- }
- }
- }
-
- private fun createStartThreadButton(message: SpaceChatItem): JComponent {
- val startThreadVm = message.startThreadVm
- val button = InlineIconButton(
- VcsCodeReviewIcons.Comment,
- VcsCodeReviewIcons.CommentHovered,
- tooltip = SpaceBundle.message("chat.message.action.start.thread.tooltip")
- ).apply {
- actionListener = ActionListener {
- startThreadVm.startWritingFirstMessage()
- }
- }
- startThreadVm.canStartThread.forEach(lifetime) {
- button.isVisible = it
- }
- return button
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceChatMessagePendingHeader.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceChatMessagePendingHeader.kt
deleted file mode 100644
index 07216f725b3d..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceChatMessagePendingHeader.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.message
-
-import com.intellij.icons.AllIcons
-import com.intellij.space.chat.model.api.SpaceChatItem
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.ui.components.ActionLink
-import com.intellij.ui.components.JBLabel
-import com.intellij.ui.components.panels.HorizontalLayout
-import com.intellij.util.ui.UIUtil
-import javax.swing.JPanel
-import javax.swing.SwingConstants
-
-internal class SpaceChatMessagePendingHeader(private val item: SpaceChatItem) : JPanel(HorizontalLayout(5)) {
- init {
- isOpaque = false
- isVisible = item.pending == true
-
- val infoLabel = JBLabel(SpaceBundle.message("chat.message.pending.text"), AllIcons.General.Note, SwingConstants.LEFT).apply {
- foreground = UIUtil.getContextHelpForeground()
- }
- val postNowLabel = ActionLink(SpaceBundle.message("chat.message.pending.post.action")) {
- item.chat.publishMessage(item.id)
- }
- add(infoLabel)
- add(postNowLabel)
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceMCMessageComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceMCMessageComponent.kt
deleted file mode 100644
index 43bd568cebae..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceMCMessageComponent.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.message
-
-import circlet.client.api.AttachmentInfo
-import circlet.client.api.UnfurlAttachment
-import com.intellij.ide.plugins.newui.VerticalLayout
-import com.intellij.openapi.ui.OnePixelDivider
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.space.chat.model.api.SpaceMCMessageContent
-import com.intellij.space.chat.model.api.SpaceMCMessageElement
-import com.intellij.space.chat.model.api.SpaceMCMessageSection
-import com.intellij.space.chat.ui.SpaceChatMarkdownTextComponent
-import com.intellij.space.chat.ui.getGrayTextHtml
-import com.intellij.ui.IdeBorderFactory
-import com.intellij.ui.SideBorder
-import com.intellij.ui.components.JBLabel
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.components.BorderLayoutPanel
-import org.jetbrains.annotations.NonNls
-import javax.swing.JComponent
-import javax.swing.JPanel
-
-internal class SpaceMCMessageComponent(
- @NonNls private val server: String,
- message: SpaceMCMessageContent,
- attachments: List
-) : BorderLayoutPanel() {
- companion object {
- private const val SMALL_FONT_SCALING = 0.9
- private const val HEADER_FONT_SCALING = 1.2
- }
-
- private val unfurls = attachments.mapNotNull { it.details }.filterIsInstance()
-
- init {
- isOpaque = false
-
- message.outline?.let { outline ->
- addToTop(SpaceChatMarkdownTextComponent(server, outline.text, initialUnfurls = unfurls).withSmallFont())
- }
-
- val sectionsComponent = message.sections.map { it.createComponent() }.wrapToSingleComponent()
- addToCenter(SpaceStyledMessageComponent(sectionsComponent, style = message.style))
- }
-
- private fun SpaceMCMessageSection.createComponent(): JComponent =
- when (this) {
- is SpaceMCMessageSection.Divider -> createDividerPanel()
- is SpaceMCMessageSection.Section -> createComponent()
- }
-
- private fun SpaceMCMessageSection.Section.createComponent(): JComponent = JPanel(VerticalLayout(JBUI.scale(10))).apply {
- isOpaque = false
-
- header?.let { add(createHeaderComponent(it), VerticalLayout.FILL_HORIZONTAL) }
-
- val elementsComponent = elements.map { it.createComponent() }.wrapToSingleComponent()
- add(elementsComponent, VerticalLayout.FILL_HORIZONTAL)
-
- footer?.let { add(createFooterComponent(it), VerticalLayout.FILL_HORIZONTAL) }
- }
-
- private fun SpaceMCMessageElement.createComponent(): JComponent =
- when (this) {
- is SpaceMCMessageElement.Text -> createComponent()
- is SpaceMCMessageElement.MessageDivider -> createDividerPanel()
- }
-
- private fun SpaceMCMessageElement.Text.createComponent(): JComponent {
- val textComponent = SpaceChatMarkdownTextComponent(server, content, initialUnfurls = unfurls)
-
- return BorderLayoutPanel().apply {
- isOpaque = false
- createIconComponent()?.let { iconComponent ->
- addToLeft(
- BorderLayoutPanel().apply {
- isOpaque = false
- border = JBUI.Borders.emptyRight(3)
- addToTop(iconComponent)
- }
- )
- }
- addToCenter(textComponent)
- }
- }
-
- private fun SpaceMCMessageElement.Text.createIconComponent(): JComponent? = icon?.let { JBLabel(icon) }
-
- private fun createHeaderComponent(@NlsSafe text: String) = SpaceChatMarkdownTextComponent(server, text, initialUnfurls = unfurls).apply {
- scaleFont(HEADER_FONT_SCALING)
- }
-
- private fun createFooterComponent(@NlsSafe text: String) =
- SpaceChatMarkdownTextComponent(server, getGrayTextHtml(text), initialUnfurls = unfurls).withSmallFont()
-
- private fun JComponent.withSmallFont(): JComponent = scaleFont(SMALL_FONT_SCALING)
-
- private fun JComponent.scaleFont(scaling: Double): JComponent = apply {
- font = font.deriveFont((font.size * scaling).toFloat())
- }
-
- private fun createDividerPanel() = JPanel().apply {
- isOpaque = false
- border = IdeBorderFactory.createBorder(OnePixelDivider.BACKGROUND, SideBorder.TOP)
- }
-
- private fun List.wrapToSingleComponent(): JComponent {
- val wrapper = JPanel(VerticalLayout(JBUI.scale(10)))
- forEach { component ->
- wrapper.add(component, VerticalLayout.FILL_HORIZONTAL)
- }
- return wrapper.apply {
- isOpaque = false
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceResolvedTagComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceResolvedTagComponent.kt
deleted file mode 100644
index 351e557db4d6..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceResolvedTagComponent.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.message
-
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.ui.components.JBLabel
-import com.intellij.util.ui.UIUtil
-import libraries.coroutines.extra.Lifetime
-import runtime.reactive.Property
-import javax.swing.JComponent
-
-internal fun createResolvedComponent(lifetime: Lifetime, resolved: Property): JComponent {
- val resolvedLabel = JBLabel(SpaceBundle.message("chat.message.resolved.text"), UIUtil.ComponentStyle.SMALL).apply {
- foreground = UIUtil.getContextHelpForeground()
- background = UIUtil.getPanelBackground()
- isOpaque = true
- }
- resolved.forEach(lifetime) {
- resolvedLabel.isVisible = it
- }
- return resolvedLabel
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceStyledMessageComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceStyledMessageComponent.kt
deleted file mode 100644
index 3bb200136a90..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/message/SpaceStyledMessageComponent.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.message
-
-import circlet.client.api.mc.MessageStyle
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.components.BorderLayoutPanel
-import java.awt.*
-import javax.swing.JComponent
-
-internal class SpaceStyledMessageComponent(content: JComponent, style: MessageStyle = MessageStyle.PRIMARY) : BorderLayoutPanel() {
- // TODO: create colors for Darcula
- private val lineColor = when (style) {
- MessageStyle.PRIMARY -> Color(0xB3D8F8)
- MessageStyle.SECONDARY -> Color(0xB5B9BD)
- MessageStyle.SUCCESS -> Color(0xC7E3D4)
- MessageStyle.ERROR -> Color(0xECC5C6)
- MessageStyle.WARNING -> Color(0xF1E4C9)
- }
-
- private val lineWidth
- get() = JBUI.scale(6)
- private val lineCenterX
- get() = lineWidth / 2
- private val yRoundOffset
- get() = lineWidth / 2
-
- init {
- addToCenter(content)
- isOpaque = false
- border = JBUI.Borders.empty(yRoundOffset, 15, yRoundOffset, 0)
- }
-
- override fun paint(g: Graphics?) {
- super.paint(g)
-
- with(g as Graphics2D) {
- setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
-
- color = lineColor
- stroke = BasicStroke(lineWidth.toFloat() / 2 + 1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)
-
- drawLine(lineCenterX, yRoundOffset, lineCenterX, height - yRoundOffset)
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatCollapsedThreadComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatCollapsedThreadComponent.kt
deleted file mode 100644
index af858b0189f5..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatCollapsedThreadComponent.kt
+++ /dev/null
@@ -1,182 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.thread
-
-import circlet.m2.threads.M2ThreadPreviewVm
-import circlet.platform.api.toKDateTime
-import circlet.platform.client.resolve
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.text.HtmlChunk
-import com.intellij.space.chat.model.api.SpaceChatItem
-import com.intellij.space.chat.ui.SpaceChatAvatarType
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.SpaceAutoUpdatableComponentService
-import com.intellij.space.ui.SpaceAvatarProvider
-import com.intellij.space.utils.formatPrettyDateTime
-import com.intellij.ui.components.JBLabel
-import com.intellij.ui.components.labels.LinkLabel
-import com.intellij.ui.components.panels.HorizontalLayout
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.UIUtil
-import com.intellij.util.ui.components.BorderLayoutPanel
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import runtime.reactive.Property
-import runtime.reactive.SequentialLifetimes
-import javax.swing.JComponent
-import javax.swing.JPanel
-
-internal fun createCollapsedThreadComponent(
- project: Project,
- lifetime: Lifetime,
- message: SpaceChatItem,
- threadActionsFactory: SpaceChatThreadActionsFactory?,
- withFirst: Boolean = true
-): JComponent {
- val contentPanel = BorderLayoutPanel().apply {
- isOpaque = false
- border = JBUI.Borders.emptyTop(8)
- }
- val threadPreview = message.threadPreview
- val loadingThreadsSqLifetime = SequentialLifetimes(lifetime)
- message.loadingThread.forEach(lifetime) { loadingThread ->
- val loadingThreadLifetime = loadingThreadsSqLifetime.next()
- contentPanel.removeAll()
- if (loadingThread != null) {
- if (!loadingThread.isCompleted) {
- val loadingThreadLabel = JBLabel(SpaceBundle.message("chat.message.loading.thread.label")).apply {
- foreground = UIUtil.getContextHelpForeground()
- }
- contentPanel.addToCenter(loadingThreadLabel)
- contentPanel.revalidate()
- contentPanel.repaint()
- }
- launch(lifetime, Ui) {
- val threadValue = loadingThread.await()
- val threadComponent = createThreadComponent(
- project, lifetime, threadValue,
- pendingStateProvider = { false },
- threadActionsFactory = threadActionsFactory,
- folded = false,
- withFirst = withFirst
- )
- threadValue.mvms.forEach(loadingThreadLifetime) { messages ->
- contentPanel.isVisible = messages.messages.size > if (withFirst) 0 else 1
- }
- contentPanel.removeAll()
- contentPanel.addToCenter(threadComponent)
- contentPanel.revalidate()
- contentPanel.repaint()
- }
- }
- else {
- if (threadPreview != null) {
- val actionsComponent = createActionsComponent(project, lifetime, message, threadPreview, threadActionsFactory)
- contentPanel.addToCenter(actionsComponent)
- threadPreview.messageCount.forEach(loadingThreadLifetime) { count ->
- contentPanel.isVisible = count > 0
- }
- }
- else {
- contentPanel.isVisible = false
- }
- contentPanel.revalidate()
- contentPanel.repaint()
- }
- }
- return contentPanel
-}
-
-private fun createActionsComponent(
- project: Project,
- lifetime: Lifetime,
- message: SpaceChatItem,
- threadPreview: M2ThreadPreviewVm,
- threadActionsFactory: SpaceChatThreadActionsFactory?
-): JComponent {
- val authorsPanel = createThreadAuthorAvatarsComponent(lifetime, threadPreview)
- val dateComponent = createDateComponent(lifetime, threadPreview.lastReplyTime)
- val repliesComponent = createRepliesLink(project, lifetime, threadPreview.messageCount) {
- launch(lifetime, Ui) {
- message.loadThread(lifetime)
- }
- }
- return JPanel(HorizontalLayout(JBUI.scale(5))).apply {
- isOpaque = false
- add(authorsPanel)
- add(repliesComponent)
- add(dateComponent)
- threadActionsFactory?.createActionsComponent()?.let { add(it) }
- }
-}
-
-private fun createThreadAuthorAvatarsComponent(lifetime: Lifetime, threadPreview: M2ThreadPreviewVm): JComponent {
- val contentPanel = BorderLayoutPanel().apply {
- isOpaque = false
- }
- val avatarsProvider = SpaceAvatarProvider(lifetime, contentPanel, SpaceChatAvatarType.THREAD.size)
- threadPreview.authors.forEach(lifetime) { authors ->
- contentPanel.removeAll()
- if (authors.isNullOrEmpty()) {
- contentPanel.border = JBUI.Borders.emptyLeft(10)
- }
- else {
- contentPanel.border = JBUI.Borders.empty()
- val icons = authors.take(3).map { avatarsProvider.getIcon(it.resolve()) }
- val iconsPanel = JPanel(HorizontalLayout(1)).apply {
- isOpaque = false
- for (icon in icons) {
- add(JBLabel(icon))
- }
- }
- contentPanel.addToCenter(iconsPanel)
- contentPanel.revalidate()
- contentPanel.repaint()
- }
- }
- return contentPanel
-}
-
-private fun createDateComponent(lifetime: Lifetime, lastReplyTime: Property): JComponent {
- val contentPanel = BorderLayoutPanel().apply {
- isOpaque = false
- }
- lastReplyTime.forEach(lifetime) { time ->
- contentPanel.removeAll()
- if (time == null) {
- contentPanel.isVisible = false
- }
- else {
- contentPanel.isVisible = true
- val dateComponent = SpaceAutoUpdatableComponentService.createAutoUpdatableComponent {
- JBLabel(HtmlChunk.text(time.toKDateTime().formatPrettyDateTime()).toString()).apply { // NON-NLS
- putClientProperty(UIUtil.HIDE_EDITOR_FROM_DATA_CONTEXT_PROPERTY, true)
- foreground = UIUtil.getContextHelpForeground()
- setCopyable(true)
- }
- }
- contentPanel.addToCenter(dateComponent)
- }
- contentPanel.revalidate()
- contentPanel.repaint()
- }
- return contentPanel
-}
-
-private fun createRepliesLink(project: Project, lifetime: Lifetime, messagesCount: Property, action: () -> Unit): JComponent {
- val contentPanel = BorderLayoutPanel().apply {
- isOpaque = false
- }
- messagesCount.forEach(lifetime) { count ->
- val repliesLink = LinkLabel.create(SpaceBundle.message("chat.message.replies.link", count)) {
- SpaceStatsCounterCollector.OPEN_THREAD.log(project)
- action()
- }
- contentPanel.removeAll()
- contentPanel.addToCenter(repliesLink)
- contentPanel.revalidate()
- contentPanel.repaint()
- }
- return contentPanel
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatStandaloneThreadComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatStandaloneThreadComponent.kt
deleted file mode 100644
index 253b4b165159..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatStandaloneThreadComponent.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.thread
-
-import circlet.client.api.M2ChannelRecord
-import circlet.m2.ChannelsVm
-import circlet.m2.M2MessageVm
-import circlet.m2.channel.M2ChannelVm
-import circlet.platform.api.Ref
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.project.Project
-import com.intellij.space.chat.model.api.SpaceChatItem
-import com.intellij.space.chat.model.impl.SpaceChatItemImpl.Companion.convertToChatItem
-import com.intellij.space.chat.ui.SpaceChatContentPanelBase
-import com.intellij.space.chat.ui.getLink
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import libraries.coroutines.extra.Lifetime
-
-internal class SpaceChatStandaloneThreadComponent(
- private val project: Project,
- private val lifetime: Lifetime,
- parent: Disposable,
- channelsVm: ChannelsVm,
- chatRecord: Ref,
- private val pendingStateProvider: () -> Boolean,
- private val threadActionsFactory: SpaceChatThreadActionsFactory,
- private val statsPlace: SpaceStatsCounterCollector.SendMessagePlace = SpaceStatsCounterCollector.SendMessagePlace.THREAD,
- private val messageConverter: (index: Int, message: M2MessageVm) -> SpaceChatItem = { _, message ->
- message.convertToChatItem(message.getLink())
- }
-) : SpaceChatContentPanelBase(lifetime, parent, channelsVm, chatRecord) {
- override fun onChatLoad(chatVm: M2ChannelVm) {
- stopLoadingContent(
- createThreadComponent(project, lifetime, chatVm, pendingStateProvider, threadActionsFactory, statsPlace = statsPlace,
- messageConverter = messageConverter)
- )
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatThreadActionsFactory.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatThreadActionsFactory.kt
deleted file mode 100644
index daebb41f3de2..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatThreadActionsFactory.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.thread
-
-import javax.swing.JComponent
-
-internal interface SpaceChatThreadActionsFactory {
- fun createActionsComponent(): JComponent
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatThreadComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatThreadComponent.kt
deleted file mode 100644
index db02b923ef05..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/chat/ui/thread/SpaceChatThreadComponent.kt
+++ /dev/null
@@ -1,109 +0,0 @@
-// 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.
-package com.intellij.space.chat.ui.thread
-
-import circlet.m2.M2MessageVm
-import circlet.m2.channel.M2ChannelVm
-import com.intellij.ide.plugins.newui.HorizontalLayout
-import com.intellij.ide.plugins.newui.VerticalLayout
-import com.intellij.openapi.project.Project
-import com.intellij.space.chat.model.api.SpaceChatItem
-import com.intellij.space.chat.model.impl.SpaceChatItemImpl.Companion.convertToChatItem
-import com.intellij.space.chat.ui.*
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.SpaceAvatarProvider
-import com.intellij.ui.components.ActionLink
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.codereview.SingleValueModelImpl
-import com.intellij.util.ui.codereview.ToggleableContainer
-import com.intellij.util.ui.codereview.timeline.TimelineComponent
-import com.intellij.util.ui.codereview.timeline.thread.TimelineThreadCommentsPanel
-import libraries.coroutines.extra.Lifetime
-import javax.swing.JComponent
-import javax.swing.JPanel
-
-internal fun createThreadComponent(
- project: Project,
- lifetime: Lifetime,
- thread: M2ChannelVm,
- pendingStateProvider: () -> Boolean,
- threadActionsFactory: SpaceChatThreadActionsFactory? = null,
- withFirst: Boolean = true,
- folded: Boolean = true,
- statsPlace: SpaceStatsCounterCollector.SendMessagePlace = SpaceStatsCounterCollector.SendMessagePlace.THREAD,
- messageConverter: (index: Int, message: M2MessageVm) -> SpaceChatItem = { _, message -> message.convertToChatItem(message.getLink()) }
-): JComponent {
- val threadComponent = JPanel(VerticalLayout(0)).apply {
- isOpaque = false
- }
- val server = thread.client.server
- val avatarSize = SpaceChatAvatarType.THREAD.size
- val avatarProvider = SpaceAvatarProvider(lifetime, threadComponent, avatarSize)
-
- val itemsListModel = SpaceChatItemListModel()
-
- thread.mvms.forEach(lifetime) { messageList ->
- val messages = messageList.messages
- itemsListModel.messageListUpdated(
- messages
- .drop(if (withFirst) 0 else 1)
- .mapIndexed { index, message -> messageConverter(index, message) }
- )
- threadComponent.isVisible = messages.size > if (withFirst) 0 else 1
- }
-
- val itemComponentFactory = SpaceChatItemComponentFactory(project, lifetime, server, avatarProvider)
- val threadTimeline = if (folded) {
- TimelineThreadCommentsPanel(
- itemsListModel,
- commentComponentFactory = itemComponentFactory::createComponent,
- offset = 0
- ).apply {
- border = JBUI.Borders.emptyBottom(5)
- }
- }
- else {
- TimelineComponent(itemsListModel, itemComponentFactory, offset = 0).apply {
- border = JBUI.Borders.emptyBottom(5)
- }
- }
-
- val actionsComponent = createActionsComponent(thread, threadActionsFactory, statsPlace, pendingStateProvider)
- return threadComponent.apply {
- add(threadTimeline, VerticalLayout.FILL_HORIZONTAL)
- add(actionsComponent, VerticalLayout.FILL_HORIZONTAL)
- }
-}
-
-private fun createActionsComponent(
- thread: M2ChannelVm,
- threadActionsFactory: SpaceChatThreadActionsFactory?,
- statsPlace: SpaceStatsCounterCollector.SendMessagePlace,
- pendingStateProvider: () -> Boolean
-): JComponent {
- val newMessageStateModel = SingleValueModelImpl(false)
- val label = ActionLink(SpaceBundle.message("chat.reply.action")) {
- newMessageStateModel.value = true
- }
-
- val additionalActions = threadActionsFactory?.createActionsComponent()
- val actionsComponent = JPanel(HorizontalLayout(JBUI.scale(5))).apply {
- isOpaque = false
- border = JBUI.Borders.emptyLeft(SpaceChatAvatarType.THREAD.size.get() + SpaceChatItemComponentFactory.Item.AVATAR_GAP)
- add(label)
- additionalActions?.let { add(it) }
- }
- return ToggleableContainer.create(
- newMessageStateModel,
- mainComponentSupplier = { actionsComponent },
- toggleableComponentSupplier = {
- createNewMessageField(
- thread,
- statsPlace = statsPlace,
- onCancel = { newMessageStateModel.value = false },
- avatarType = SpaceChatAvatarType.THREAD,
- pendingStateProvider = pendingStateProvider
- )
- }
- )
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/components/SpaceUserAvatarProvider.kt b/plugins/space/src/main/kotlin/com/intellij/space/components/SpaceUserAvatarProvider.kt
deleted file mode 100644
index c9a41fbfea1f..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/components/SpaceUserAvatarProvider.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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.
-package com.intellij.space.components
-
-import circlet.client.api.englishFullName
-import circlet.platform.client.ConnectionStatus
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.service
-import com.intellij.space.ui.SpaceAvatarUtils
-import com.intellij.space.ui.SpaceAvatars
-import com.intellij.space.ui.SpaceImageLoader
-import kotlinx.coroutines.CancellationException
-import libraries.coroutines.extra.LifetimeSource
-import libraries.klogging.logger
-import runtime.reactive.Property
-import runtime.reactive.awaitFirst
-import runtime.reactive.filter
-import runtime.reactive.property.mapInit
-
-@Service
-class SpaceUserAvatarProvider : Disposable {
- companion object {
- private val LOG = logger()
-
- fun getInstance(): SpaceUserAvatarProvider = service()
- }
-
- private val lifetime: LifetimeSource = LifetimeSource()
-
- private val avatarPlaceholders: SpaceAvatars = SpaceAvatars.MainIcon
-
- val avatars: Property = lifetime.mapInit(SpaceWorkspaceComponent.getInstance().workspace, avatarPlaceholders) { ws ->
- ws ?: return@mapInit avatarPlaceholders
- val id = ws.me.value.username
- val name = ws.me.value.englishFullName()
-
- val avatarTID = ws.me.value.smallAvatar ?: return@mapInit SpaceAvatarUtils.generateAvatars(id, name)
- val imageLoader = SpaceImageLoader.getInstance()
-
- // await connected state before trying to load image.
- ws.client.connectionStatus.filter { it is ConnectionStatus.Connected }.awaitFirst(ws.lifetime)
-
- try {
- LOG.info { "loading user avatar: $avatarTID" }
- val loadedImage = imageLoader.loadImageAsync(avatarTID)?.await()
- if (loadedImage == null) {
- SpaceAvatarUtils.generateAvatars(id, name)
- }
- else {
- SpaceAvatarUtils.createAvatars(loadedImage)
- }
- }
- catch (th: CancellationException) {
- throw th
- }
- catch (e: Exception) {
- LOG.error { "user avatar not loaded: $e" }
- avatarPlaceholders
- }
- }
-
- override fun dispose() {
- lifetime.terminate()
- }
-}
-
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/components/SpaceWorkspaceComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/components/SpaceWorkspaceComponent.kt
deleted file mode 100644
index 8507601da26c..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/components/SpaceWorkspaceComponent.kt
+++ /dev/null
@@ -1,262 +0,0 @@
-// 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.
-package com.intellij.space.components
-
-import circlet.arenas.initCircletArenas
-import circlet.client.api.impl.ApiClassesDeserializer
-import circlet.client.api.impl.tombstones.registerArenaTombstones
-import circlet.code.api.CodeReviewArena
-import circlet.code.api.CodeReviewParticipantsArena
-import circlet.code.api.ReviewPendingMessageCounterArena
-import circlet.common.oauth.IdeaOAuthConfig
-import circlet.permissions.FeatureFlagsVmPersistenceKey
-import circlet.platform.api.oauth.OAuthTokenResponse
-import circlet.platform.api.oauth.toTokenInfo
-import circlet.platform.api.serialization.ExtendableSerializationRegistry
-import circlet.platform.client.ClientArenaRegistry
-import circlet.platform.workspaces.CodeFlowConfig
-import circlet.platform.workspaces.WorkspaceConfiguration
-import circlet.platform.workspaces.WorkspaceManagerHost
-import circlet.workspaces.Workspace
-import circlet.workspaces.WorkspaceManager
-import com.intellij.ide.browsers.BrowserLauncher
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.Service.Level
-import com.intellij.openapi.components.service
-import com.intellij.openapi.wm.IdeFrame
-import com.intellij.space.auth.SpaceAuthNotifier
-import com.intellij.space.auth.startRedirectHandling
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.runtime.ApplicationDispatcher
-import com.intellij.space.settings.SpaceLoginState
-import com.intellij.space.settings.SpaceServerSettings
-import com.intellij.space.settings.SpaceSettings
-import com.intellij.space.settings.log
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.utils.IdeaPasswordSafePersistence
-import com.intellij.space.utils.LifetimedDisposable
-import com.intellij.space.utils.LifetimedDisposableImpl
-import com.intellij.ui.AppIcon
-import com.intellij.util.concurrency.AppExecutorUtil
-import kotlinx.coroutines.asCoroutineDispatcher
-import kotlinx.coroutines.withContext
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.launch
-import libraries.coroutines.extra.usingSource
-import libraries.klogging.KLogger
-import libraries.klogging.assert
-import libraries.klogging.logger
-import runtime.Ui
-import runtime.mutableUiDispatch
-import runtime.persistence.InMemoryPersistence
-import runtime.persistence.PersistenceConfiguration
-import runtime.persistence.PersistenceKey
-import runtime.reactive.MutableProperty
-import runtime.reactive.Property
-import runtime.reactive.SequentialLifetimes
-import runtime.reactive.mutableProperty
-import runtime.reactive.property.map
-import java.awt.Component
-import java.net.URI
-import java.net.URL
-import java.util.concurrent.CancellationException
-import javax.swing.JFrame
-import javax.swing.SwingUtilities
-
-/**
- * The main plugin's component that allows to log in to the Space server or disconnect from it.
- * If possible, the component is automatically authorized when the app starts
- */
-@Service(Level.APP)
-internal class SpaceWorkspaceComponent : WorkspaceManagerHost(), LifetimedDisposable by LifetimedDisposableImpl() {
- companion object {
- internal fun getInstance(): SpaceWorkspaceComponent = service()
- private val LOG: KLogger = logger()
- }
-
- private val workspacesLifetimes = SequentialLifetimes(lifetime)
-
- private val manager = mutableProperty(null)
-
- val workspace: Property = map(manager) { wm ->
- wm?.workspace?.value
- }
-
- val loginState: MutableProperty = mutableProperty(getInitialState())
-
- init {
- initApp()
- val wsLifetime = workspacesLifetimes.next()
-
- // sign in automatically on application startup.
- launch(wsLifetime, Ui) {
- val signInResult = autoSignIn(wsLifetime)
- if (signInResult == AutoSignInResult.NOT_AUTHORIZED) {
- authFailed()
- }
- }
-
- workspace.forEach(lifetime) { ws ->
- loginState.value = if (ws == null) {
- SpaceLoginState.Disconnected(SpaceSettings.getInstance().serverSettings.server)
- }
- else {
- SpaceLoginState.Connected(ws.client.server, ws)
- }
- }
- }
-
- private fun initApp() {
- val application = ApplicationManager.getApplication()
-
- mutableUiDispatch = ApplicationDispatcher(this, application)
-
- initCircletArenas()
- registerArenaTombstones(ExtendableSerializationRegistry.global)
-
- ApiClassesDeserializer(ExtendableSerializationRegistry.global).registerDeserializers()
-
- // code review
- ClientArenaRegistry.register(CodeReviewArena)
- ClientArenaRegistry.register(CodeReviewParticipantsArena)
- ClientArenaRegistry.register(ReviewPendingMessageCounterArena)
- circlet.code.api.impl.ApiClassesDeserializer(ExtendableSerializationRegistry.global).registerDeserializers()
- }
-
-
- override suspend fun authFailed() {
- signOut(SpaceStatsCounterCollector.LogoutPlace.AUTH_FAIL)
- SpaceAuthNotifier.authFailed()
- }
-
- private suspend fun signIn(lifetime: Lifetime, server: String): OAuthTokenResponse {
- LOG.assert(manager.value == null, "manager.value == null")
-
- val lt = workspacesLifetimes.next()
- val newManager = createWorkspaceManager(lt, server)
-
- val portsMapping: Map = IdeaOAuthConfig.redirectURIs.map { rawUri -> URL(rawUri).let { url -> url.port to url } }.toMap()
- val ports = portsMapping.keys
- val (port, redirectUrl) = startRedirectHandling(lifetime, server, ports)
- ?: return OAuthTokenResponse.Error(server, "", SpaceBundle.message("auth.error.ports.busy.label"))
-
- val authUrl = portsMapping.getValue(port)
- val codeFlow = CodeFlowConfig(newManager.wsConfig, authUrl.toExternalForm())
- val uri = URI(codeFlow.codeFlowURL())
- try {
- BrowserLauncher.instance.browse(uri)
- }
- catch (th: Throwable) {
- return OAuthTokenResponse.Error(server, "", SpaceBundle.message("auth.error.cant.open.browser.label", server))
- }
-
- val response = withContext(AppExecutorUtil.getAppExecutorService().asCoroutineDispatcher()) {
- codeFlow.handleCodeFlowRedirect(redirectUrl.await())
- }
- if (response is OAuthTokenResponse.Success) {
- LOG.info { "A personal token was received" }
- newManager.signInWithToken(response.toTokenInfo())
- SpaceSettings.getInstance().serverSettings = SpaceServerSettings(true, server)
- manager.value = newManager
- }
- return response
- }
-
- fun signInManually(server:String, uiLifetime: Lifetime, component: Component) {
- var serverName = server
- if (serverName.isBlank()) {
- val error = SpaceBundle.message("login.panel.error.organization.url.should.not.be.empty")
- loginState.value = SpaceLoginState.Disconnected("", error)
- return
- }
- serverName = normalizeUrl(serverName)
- launch(uiLifetime, Ui) {
- uiLifetime.usingSource { connectLt ->
- try {
- loginState.value = SpaceLoginState.Connecting(serverName) {
- connectLt.terminate()
- loginState.value = SpaceLoginState.Disconnected(serverName)
- }
- when (val response = signIn(connectLt, serverName)) {
- is OAuthTokenResponse.Error -> {
- val error = response.description // NON-NLS
- loginState.value = SpaceLoginState.Disconnected(serverName, error)
- }
- }
- }
- catch (th: CancellationException) {
- throw th
- }
- catch (th: Throwable) {
- log.error(th)
- loginState.value = SpaceLoginState.Disconnected(
- serverName,
- th.message ?: SpaceBundle.message("auth.error.unknown.label", th.javaClass.simpleName)
- )
- }
- val frame = SwingUtilities.getAncestorOfClass(JFrame::class.java, component)
- AppIcon.getInstance().requestFocus(frame as IdeFrame?)
- }
- }
- }
-
- private fun normalizeUrl(serverName: String): String {
- var result = serverName
- result = if (result.startsWith("https://") || result.startsWith("http://")) result else "https://$result"
- result = result.removeSuffix("/")
- return result
- }
-
- fun signOut(statsPlace: SpaceStatsCounterCollector.LogoutPlace) {
- SpaceStatsCounterCollector.LOG_OUT.log(statsPlace)
- val oldManager = manager.value
- oldManager?.signOut(true)
- workspacesLifetimes.clear()
- manager.value = null
- val settings = SpaceSettings.getInstance()
- settings.serverSettings = settings.serverSettings.copy(enabled = false)
- }
-
- private suspend fun autoSignIn(wsLifetime: Lifetime): AutoSignInResult {
- val serverSettings = SpaceSettings.getInstance().serverSettings
- val server = serverSettings.server
- if (!serverSettings.enabled || server.isBlank()) {
- return AutoSignInResult.NOT_AUTHORIZED_BEFORE
- }
- val newManager = createWorkspaceManager(wsLifetime, server)
- return try {
- if (newManager.signInNonInteractive()) {
- manager.value = newManager
- AutoSignInResult.AUTHORIZED
- }
- else {
- AutoSignInResult.NOT_AUTHORIZED
- }
- }
- catch (th: Throwable) {
- LOG.info(th, "Couldn't authorize interactively")
- AutoSignInResult.NOT_AUTHORIZED
- }
- }
-
- private fun createWorkspaceManager(lifetime: Lifetime, server: String): WorkspaceManager {
- val persistenceConfig = PersistenceConfiguration(
- FeatureFlagsVmPersistenceKey,
- PersistenceKey.AllArenas
- )
- val workspaceConfig = WorkspaceConfiguration(server, IdeaOAuthConfig.clientId, IdeaOAuthConfig.clientSecret)
- return WorkspaceManager(lifetime, null, this, InMemoryPersistence(), IdeaPasswordSafePersistence, persistenceConfig, workspaceConfig)
- }
-
- private fun getInitialState(): SpaceLoginState {
- val workspace = workspace.value ?: return SpaceLoginState.Disconnected("")
- return SpaceLoginState.Connected(workspace.client.server, workspace)
- }
-
- private enum class AutoSignInResult {
- NOT_AUTHORIZED_BEFORE,
- NOT_AUTHORIZED,
- AUTHORIZED
- }
-}
-
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/editor/SpaceChatComplexPathVirtualFileSystem.kt b/plugins/space/src/main/kotlin/com/intellij/space/editor/SpaceChatComplexPathVirtualFileSystem.kt
deleted file mode 100644
index c4e4e3d7eb2e..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/editor/SpaceChatComplexPathVirtualFileSystem.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-package com.intellij.space.editor
-
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.vcs.editor.ComplexPathVirtualFileSystem
-import com.intellij.vcs.editor.GsonComplexPathSerializer
-
-internal class SpaceChatComplexPathVirtualFileSystem : ComplexPathVirtualFileSystem(
- GsonComplexPathSerializer(ComplexPath::class.java)
-) {
-
- fun getPath(sessionId: String, projectHash: String, id: String): String {
- return getPath(ComplexPath(sessionId, projectHash, id))
- }
-
- data class ComplexPath(override val sessionId: String,
- override val projectHash: String,
- val id: String) : ComplexPathVirtualFileSystem.ComplexPath
-
- override fun getProtocol(): String = PROTOCOL
-
- override fun findOrCreateFile(project: Project, path: ComplexPath): VirtualFile? {
- return project.service().findChatFile(path.id)
- }
-
- companion object {
- private const val PROTOCOL = "space-chat"
-
- @JvmStatic
- fun getInstance() = service().getFileSystem(PROTOCOL) as SpaceChatComplexPathVirtualFileSystem
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/editor/SpaceDiffComplexPathVirtualFileSystem.kt b/plugins/space/src/main/kotlin/com/intellij/space/editor/SpaceDiffComplexPathVirtualFileSystem.kt
deleted file mode 100644
index bcde153904a1..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/editor/SpaceDiffComplexPathVirtualFileSystem.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-package com.intellij.space.editor
-
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.space.vcs.review.details.diff.SpaceDiffFileId
-import com.intellij.vcs.editor.ComplexPathVirtualFileSystem
-import com.intellij.vcs.editor.GsonComplexPathSerializer
-
-internal class SpaceDiffComplexPathVirtualFileSystem : ComplexPathVirtualFileSystem(
- GsonComplexPathSerializer(ComplexPath::class.java)
-) {
-
- fun getPath(sessionId: String, projectHash: String, fileId: SpaceDiffFileId): String {
- return getPath(ComplexPath(sessionId, projectHash, fileId))
- }
-
- data class ComplexPath(override val sessionId: String,
- override val projectHash: String,
- val fileId: SpaceDiffFileId) : ComplexPathVirtualFileSystem.ComplexPath
-
- override fun getProtocol(): String = PROTOCOL
-
- override fun findOrCreateFile(project: Project, path: ComplexPath): VirtualFile? {
- return project.service().findDiffFile(path.fileId)
- }
-
- companion object {
- private const val PROTOCOL = "space-diff"
-
- @JvmStatic
- fun getInstance() = service().getFileSystem(PROTOCOL) as SpaceDiffComplexPathVirtualFileSystem
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/editor/SpaceVirtualFilesManager.kt b/plugins/space/src/main/kotlin/com/intellij/space/editor/SpaceVirtualFilesManager.kt
deleted file mode 100644
index 7c7cfef84816..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/editor/SpaceVirtualFilesManager.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.
-package com.intellij.space.editor
-
-import circlet.client.api.M2ChannelRecord
-import circlet.m2.ChannelsVm
-import circlet.platform.api.Ref
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.NlsContexts
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.space.chat.editor.SpaceChatFile
-import com.intellij.space.chat.model.api.SpaceChatHeaderDetails
-import com.intellij.space.vcs.review.details.SpaceReviewChangesVm
-import com.intellij.space.vcs.review.details.diff.SpaceDiffFile
-import com.intellij.space.vcs.review.details.diff.SpaceDiffFileData
-import com.intellij.space.vcs.review.details.diff.SpaceDiffFileId
-import com.intellij.space.vcs.review.details.diff.SpaceDiffVm
-import com.intellij.util.containers.ContainerUtil.createWeakValueMap
-import libraries.coroutines.extra.Lifetime
-
-@Service
-internal class SpaceVirtualFilesManager(private val project: Project) : Disposable {
- // current time should be enough to distinguish the manager between launches
- private val sessionId = System.currentTimeMillis().toString()
-
- private val chatFiles = createWeakValueMap()
- private val diffFiles = createWeakValueMap()
-
- fun findChatFile(id: String) = chatFiles[id]
- fun findDiffFile(fileId: SpaceDiffFileId) = diffFiles[fileId]
-
- fun findOrCreateChatFile(
- @NlsSafe id: String,
- @NlsSafe path: String,
- @NlsContexts.TabTitle displayName: String,
- @NlsContexts.Tooltip tabTooltip: String,
- channelsVm: ChannelsVm,
- chatRecord: Ref,
- headerDetailsBuilder: (Lifetime) -> SpaceChatHeaderDetails
- ): SpaceChatFile = chatFiles.getOrPut(id) {
- SpaceChatFile(sessionId, project.locationHash, id, path, displayName, tabTooltip, channelsVm, chatRecord, headerDetailsBuilder)
- }
-
- fun findOrCreateDiffFile(
- changesVm: runtime.reactive.Property,
- diffVm: SpaceDiffVm
- ): SpaceDiffFile = SpaceDiffFileId(diffVm.projectKey.key, diffVm.reviewKey, diffVm.reviewId).let { fileId ->
- diffFiles.getOrPut(fileId) { SpaceDiffFile(sessionId, project.locationHash, fileId, diffVm.reviewKey) }
- .apply { updateDiffPresentation(changesVm, diffVm) }
- }
-
- fun updateDiffPresentation(changesVm: runtime.reactive.Property,
- diffVm: SpaceDiffVm) {
- val fileId = SpaceDiffFileId(diffVm.projectKey.key, diffVm.reviewKey, diffVm.reviewId)
- diffFiles[fileId]?.updateDiffFileData(SpaceDiffFileData(changesVm, diffVm))
- }
-
- override fun dispose() {
- chatFiles.clear()
- diffFiles.clear()
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/klogging/impl/ApplicationLogger.kt b/plugins/space/src/main/kotlin/com/intellij/space/klogging/impl/ApplicationLogger.kt
deleted file mode 100644
index 66ddee69b5d7..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/klogging/impl/ApplicationLogger.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.
-package com.intellij.space.klogging.impl
-
-import com.intellij.openapi.diagnostic.Logger
-import libraries.klogging.BaseLogger
-
-class ApplicationLogger(private val logger: Logger) : BaseLogger {
-
- override val isTraceEnabled: Boolean get() = logger.isTraceEnabled
- override val isDebugEnabled: Boolean get() = logger.isDebugEnabled
- override val isInfoEnabled: Boolean get() = true
- override val isWarnEnabled: Boolean get() = true
- override val isErrorEnabled: Boolean get() = true
-
- override fun trace(message: Any?) {
- logger.trace(message.toString())
- }
-
- override fun debug(message: Any?) {
- logger.debug(message.toString())
- }
-
- override fun info(message: Any?) {
- logger.info(message.toString())
- }
-
- override fun warn(message: Any?) {
- logger.warn(message.toString())
- }
-
- override fun trace(t: Throwable, message: Any?) {
- logger.trace(message.toString())
- logger.trace(t)
- }
-
- override fun debug(t: Throwable, message: Any?) {
- logger.debug(message.toString(), t)
- }
-
- override fun info(t: Throwable, message: Any?) {
- logger.info(message.toString(), t)
- }
-
- override fun warn(t: Throwable, message: Any?) {
- logger.warn(message.toString(), t)
- }
-
- override fun error(message: Any?) {
- logger.error(message.toString())
- }
-
- override fun error(t: Throwable, message: Any?) {
- logger.error(message.toString(), t)
- }
-
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/klogging/impl/KLoggerFactoryIdea.kt b/plugins/space/src/main/kotlin/com/intellij/space/klogging/impl/KLoggerFactoryIdea.kt
deleted file mode 100644
index e6b855269c35..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/klogging/impl/KLoggerFactoryIdea.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-package com.intellij.space.klogging.impl
-
-import com.intellij.openapi.diagnostic.Logger
-import libraries.klogging.KLogger
-import libraries.klogging.KLoggerFactory
-import libraries.klogging.LoggerNameSource
-import libraries.klogging.loggerNameFromSource
-import kotlin.reflect.KClass
-
-object KLoggerFactoryIdea : KLoggerFactory {
- override fun logger(owner: KClass<*>): KLogger = wrapLogger(Logger.getInstance(owner.java))
-
- override fun logger(owner: Any): KLogger = logger(owner.javaClass.kotlin)
-
- override fun logger(name: String): KLogger = wrapLogger(Logger.getInstance(name))
-
- override fun logger(nameSource: LoggerNameSource): KLogger = logger(loggerNameFromSource(nameSource))
-
- private fun wrapLogger(logger: Logger) = KLogger(wrapWithApplicationLogger(logger))
-
- fun wrapWithApplicationLogger(logger: Logger): ApplicationLogger = ApplicationLogger(logger)
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/messages/SpaceBundle.java b/plugins/space/src/main/kotlin/com/intellij/space/messages/SpaceBundle.java
deleted file mode 100644
index 1e4667809488..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/messages/SpaceBundle.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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.
-package com.intellij.space.messages;
-
-import com.intellij.DynamicBundle;
-import org.jetbrains.annotations.Nls;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.PropertyKey;
-
-import java.util.function.Supplier;
-
-public class SpaceBundle extends DynamicBundle {
- @NonNls public static final String BUNDLE = "messages.SpaceBundle";
- private static final SpaceBundle INSTANCE = new SpaceBundle();
-
- private SpaceBundle() {
- super(BUNDLE);
- }
-
- @NotNull
- public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
- return INSTANCE.getMessage(key, params);
- }
-
- @NotNull
- public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key,
- Object @NotNull ... params) {
- return INSTANCE.getLazyMessage(key, params);
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/messages/SpaceBundleExtensions.kt b/plugins/space/src/main/kotlin/com/intellij/space/messages/SpaceBundleExtensions.kt
deleted file mode 100644
index ac8d224e6ff4..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/messages/SpaceBundleExtensions.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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.
-package com.intellij.space.messages
-
-import org.jetbrains.annotations.Nls
-import org.jetbrains.annotations.PropertyKey
-
-internal object SpaceBundleExtensions {
- fun messagePointer(@PropertyKey(resourceBundle = SpaceBundle.BUNDLE) key: String, vararg params: Any): () -> @Nls String = {
- SpaceBundle.message(key, *params)
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/notification/SpaceNotificationIdsHolder.kt b/plugins/space/src/main/kotlin/com/intellij/space/notification/SpaceNotificationIdsHolder.kt
deleted file mode 100644
index 050f64d6870d..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/notification/SpaceNotificationIdsHolder.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.
-package com.intellij.space.notification
-
-import com.intellij.notification.impl.NotificationIdsHolder
-
-class SpaceNotificationIdsHolder : NotificationIdsHolder {
- override fun getNotificationIds(): List {
- return listOf(
- GIT_REPO_INIT_ERROR,
- PROJECT_SHARED_SUCCESSFULLY,
- SHARING_NOT_FINISHED
- )
- }
-
- companion object {
- const val GIT_REPO_INIT_ERROR = "space.git.repo.init.error"
- const val PROJECT_SHARED_SUCCESSFULLY = "space.project.shared.successfully"
- const val SHARING_NOT_FINISHED = "space.sharing.not.finished"
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/BuildLogPublisher.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/BuildLogPublisher.kt
deleted file mode 100644
index d280a52a104a..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/BuildLogPublisher.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services
-
-import com.intellij.build.DefaultBuildDescriptor
-import com.intellij.build.events.BuildEvent
-import com.intellij.build.events.MessageEvent
-import com.intellij.build.events.impl.FinishBuildEventImpl
-import com.intellij.build.events.impl.MessageEventImpl
-import com.intellij.build.events.impl.StartBuildEventImpl
-import com.intellij.build.events.impl.SuccessResultImpl
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.components.ServiceManager
-import com.intellij.openapi.project.Project
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.plugins.pipelines.viewmodel.LogData
-import runtime.reactive.ObservableList
-
-fun publishBuildLog(project: Project, data: LogData) {
- if (!ApplicationManager.getApplication().isUnitTestMode && !ApplicationManager.getApplication().isHeadlessEnvironment) {
- val descriptor = DefaultBuildDescriptor(data.buildId, SpaceBundle.message("build.log.title"), project.basePath!!,
- System.currentTimeMillis())
-
- val view = ServiceManager.getService(project, SyncDslViewManager::class.java)
-
- view.onEvent(data.buildId, StartBuildEventImpl(descriptor, SpaceBundle.message("build.log.message.started", project.name)))
-
- view.onEvent(data.buildId, MessageEventImpl(data.buildId, MessageEvent.Kind.INFO, null,
- SpaceBundle.message("build.log.message.process"), null))
-
- if (!data.lifetime.isTerminated) {
- data.messages.change.forEach(data.lifetime) { change ->
- when (change) {
- is ObservableList.Change.Add -> {
- val message = change.newValue
- view.onEvent(data.buildId, message)
- }
- else -> {
- }
- }
- }
- }
-
- data.lifetime.addOrCallImmediately {
- view.onEvent(data.buildId,
- FinishBuildEventImpl(descriptor.id, null, System.currentTimeMillis(), SpaceBundle.message("build.log.message.finished"),
- SuccessResultImpl(false)))
- }
-
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/ScriptKtsPersistentState.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/ScriptKtsPersistentState.kt
deleted file mode 100644
index 48802ce4078e..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/ScriptKtsPersistentState.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services
-
-import circlet.automation.bootstrap.AutomationDslEvaluationBootstrap
-import circlet.pipelines.config.idea.api.IdeaScriptConfig
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.project.getProjectCachePath
-import com.intellij.util.io.safeOutputStream
-import libraries.klogging.logger
-import java.io.IOException
-import java.nio.file.FileSystemException
-import java.nio.file.Files
-import java.nio.file.NoSuchFileException
-import java.nio.file.Path
-import java.nio.file.attribute.BasicFileAttributes
-
-private val log = logger()
-
-class ScriptKtsPersistentState(val project: Project) {
-
- // not for load failure
- fun load(): IdeaScriptConfig? {
-
- val path = getCacheFile(project)
-
- val fileAttributes = try {
- Files.readAttributes(path, BasicFileAttributes::class.java)
- }
- catch (ignored: FileSystemException) {
- return null
- }
-
- if (fileAttributes == null || !fileAttributes.isRegularFile) {
- return null
- }
-
- return try {
- Files.newBufferedReader(path, Charsets.UTF_8).use { reader ->
- val evalService = AutomationDslEvaluationBootstrap(log, getAutomationConfigurationWithFallback()).loadEvaluatorForIdea()
- if (evalService == null) {
- log.error("DSL evaluation service not found, cannot deserialize automation DSL model")
- return null
- }
- evalService.deserializeJsonConfig(reader.readLine())
- }
- }
- catch (e: NoSuchFileException) {
- null
- }
- catch (e: IOException) {
- log.error(e)
- null
- }
- }
-
- private fun getCacheFile(project: Project): Path {
- return project.getProjectCachePath("space_automation").resolve(".space.kts.dat")
- }
-
- fun save(config: IdeaScriptConfig) {
- val path = getCacheFile(project)
- path.safeOutputStream().use {
- it.write(config.printJson().toByteArray(Charsets.UTF_8))
- }
- }
-
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceKtsCompilationConfiguration.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceKtsCompilationConfiguration.kt
deleted file mode 100644
index 3ccffa932508..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceKtsCompilationConfiguration.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services
-
-import circlet.pipelines.config.dsl.scriptdefinition.ProjectScriptCompilationConfiguration
-import circlet.pipelines.config.dsl.scriptdefinition.resolveScriptArtifact
-import circlet.pipelines.config.ivy.resolver.ivyResolver
-import com.intellij.openapi.diagnostic.logger
-import com.intellij.space.messages.SpaceBundle
-import kotlin.script.experimental.api.*
-import kotlin.script.experimental.jvm.updateClasspath
-
-internal class SpaceKtsCompilationConfiguration : ScriptCompilationConfiguration(ProjectScriptCompilationConfiguration(), body = {
- refineConfiguration {
- beforeCompiling { context ->
- addAutomationRuntimeToClasspath(context)
- }
- }
-
- ide {
- acceptedLocations(ScriptAcceptedLocation.Everywhere)
- }
-}) {
- companion object {
- private val LOG = logger()
-
- private val AUTH_ERROR = ResultWithDiagnostics.Failure(
- ScriptDiagnostic(4, SpaceBundle.message("kts.file.login.error"))
- )
-
- private val DEPENDENCIES_LOADING_ERROR = ResultWithDiagnostics.Failure(
- ScriptDiagnostic(4, SpaceBundle.message("kts.file.dependencies.error"))
- )
-
- private fun addAutomationRuntimeToClasspath(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics {
- val config = getAutomationConfigurationOrNull()
- if (config == null) {
- LOG.debug("[space-kts] User not logged in to Space, cannot fetch Automation runtime")
- return AUTH_ERROR
- }
-
- try {
- LOG.debug("[space-kts] Resolving space-automation-runtime from ${config.locationDescription}")
-
- return config.ivyResolver
- .resolveScriptArtifact("com.jetbrains", "space-automation-runtime", "latest.integration")
- .onSuccess { jars ->
- LOG.debug("[space-kts] Successfully resolved space-automation-runtime: ${jars.joinToString()}")
- ScriptCompilationConfiguration(context.compilationConfiguration) { updateClasspath(jars) }.asSuccess()
- }
- .onFailure { diagnostics ->
- LOG.warn("[space-kts] Failure while downloading dependencies for .space.kts file: $diagnostics")
- DEPENDENCIES_LOADING_ERROR
- }
- }
- catch (th: Throwable) {
- LOG.warn("[space-kts] Couldn't download dependencies for .space.kts file", th)
- return DEPENDENCIES_LOADING_ERROR
- }
- }
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceKtsFileDetector.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceKtsFileDetector.kt
deleted file mode 100644
index 4b6711fb0ad8..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceKtsFileDetector.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services
-
-import com.intellij.space.plugins.pipelines.utils.DslFileFinder
-import com.intellij.space.tools.spaceKtsToolwindow
-import com.intellij.space.utils.LifetimedDisposable
-import com.intellij.space.utils.LifetimedDisposableImpl
-import com.intellij.space.vcs.PostStartupActivity
-import com.intellij.openapi.application.runReadAction
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vfs.*
-import libraries.klogging.logger
-import runtime.reactive.Property
-import runtime.reactive.mutableProperty
-
-private val log = logger()
-
-class SpaceKtsFileDetectorActivator : PostStartupActivity() {
- override fun runActivity(project: Project) {
- project.service()
- }
-}
-
-// listens to file system and exposes script dsl file
-@Service
-class SpaceKtsFileDetector(val project: Project) : LifetimedDisposable by LifetimedDisposableImpl() {
-
- val dslFile: Property get() = _dslFile
-
- private val _dslFile = mutableProperty(null)
-
- private val fileListener = object : VirtualFileListener {
- override fun propertyChanged(event: VirtualFilePropertyEvent) {
- if (event.propertyName == "name") {
- handleFileChanged(event.oldValue.toString())
- handleFileChanged(event.newValue.toString())
- }
- }
-
- override fun fileCreated(event: VirtualFileEvent) {
- handleFileChanged(event.fileName)
- }
-
- override fun fileDeleted(event: VirtualFileEvent) {
- handleFileChanged(event.fileName)
- }
-
- override fun fileMoved(event: VirtualFileMoveEvent) {
- handleFileChanged(event.fileName)
- }
- }
-
- init {
- log.info("SpaceKtsFileDetector")
-
- refreshScript()
-
- LocalFileSystem.getInstance().addVirtualFileListener(fileListener)
-
- lifetime.add {
- LocalFileSystem.getInstance().removeVirtualFileListener(fileListener)
- }
-
- _dslFile.forEach(lifetime) { file ->
- project.spaceKtsToolwindow?.setAvailable(file != null, null)
- }
- }
-
-
- fun refreshScript() {
- runReadAction {
- if (!project.isDisposed) {
- _dslFile.value = checkIsDslFileExists()
- }
- }
- }
-
- fun handleFileChanged(name: String) {
- if (DslFileFinder.checkFileNameIsApplicable(name)) {
- refreshScript()
- }
- }
-
- private fun checkIsDslFileExists(): VirtualFile? {
- return DslFileFinder.find(project)
- }
-
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceKtsModelBuilder.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceKtsModelBuilder.kt
deleted file mode 100644
index b321913b263b..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceKtsModelBuilder.kt
+++ /dev/null
@@ -1,247 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services
-
-import circlet.automation.bootstrap.AutomationCompilerBootstrap
-import circlet.automation.bootstrap.AutomationDslEvaluationBootstrap
-import circlet.automation.bootstrap.embeddedMavenServer
-import circlet.automation.bootstrap.publicMavenServer
-import circlet.pipelines.config.idea.api.IdeaScriptConfig
-import circlet.pipelines.config.utils.AutomationCompilerConfiguration
-import circlet.platform.client.backgroundDispatcher
-import com.intellij.openapi.application.ModalityState
-import com.intellij.openapi.application.invokeAndWaitIfNeeded
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.service
-import com.intellij.openapi.fileEditor.FileDocumentManager
-import com.intellij.openapi.progress.ProgressIndicator
-import com.intellij.openapi.progress.ProgressManager
-import com.intellij.openapi.progress.Task
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.plugins.pipelines.utils.ObservableQueue
-import com.intellij.space.plugins.pipelines.viewmodel.LogData
-import com.intellij.space.plugins.pipelines.viewmodel.ScriptModel
-import com.intellij.space.plugins.pipelines.viewmodel.ScriptState
-import com.intellij.space.utils.LifetimedDisposable
-import com.intellij.space.utils.LifetimedDisposableImpl
-import kotlinx.coroutines.withContext
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.launch
-import libraries.coroutines.extra.using
-import libraries.klogging.*
-import org.slf4j.event.Level
-import org.slf4j.event.SubstituteLoggingEvent
-import org.slf4j.helpers.SubstituteLogger
-import runtime.Ui
-import runtime.reactive.*
-import runtime.reactive.property.flatMap
-import runtime.reactive.property.map
-import java.nio.file.Files
-import java.nio.file.Paths
-import kotlin.io.path.name
-
-private val log = logger()
-
-@Service
-class SpaceKtsModelBuilder(val project: Project) : LifetimedDisposable by LifetimedDisposableImpl(), KLogging() {
- private val persistentState = ScriptKtsPersistentState(project)
-
- private val _model = mutableProperty(null)
- private val _modelBuildIsRequested = mutableProperty(false)
-
- // script is null when no build file is found in project
- @Suppress("USELESS_CAST")
- val script = map(_model) { it as ScriptModel? }
-
- val config = flatMap(_model) { (it?.config ?: mutableProperty(null)) }
-
- init {
- launch(lifetime, backgroundDispatcher) {
- val saved = log.catch { persistentState.load() }
- withContext(Ui) {
- project.service().dslFile.view(lifetime) { lt, file ->
- _model.value = file?.let { ScriptModelHolder(lt, file, _modelBuildIsRequested, saved) }
- }
- config.skip(1).view(lifetime) { lt, config ->
- if (config != null) {
- launch(lt, backgroundDispatcher) {
- persistentState.save(config)
- }
- }
- }
- }
- }
- }
-
-
- fun requestModel() {
- _modelBuildIsRequested.value = true
- }
-
- fun rebuildModel() {
- _model.value?.rebuildModel()
- }
-
- // this class is created per automation script file found and it is responsible for building model content
- private inner class ScriptModelHolder(val lifetime: Lifetime,
- val scriptFile: VirtualFile,
- modelBuildIsRequested: Property,
- loadedConfig: IdeaScriptConfig?) : ScriptModel {
-
- val sync = Any()
-
- private val _config = mutableProperty(loadedConfig)
- private val _error = mutableProperty(null)
- private val _state = mutableProperty(if (loadedConfig == null) ScriptState.NotInitialised else ScriptState.Ready)
-
- override val config: Property get() = _config
- override val error: Property get() = _error
- override val state: Property get() = _state
-
- private val logBuildData = mutableProperty(null)
-
- init {
-
- // push to IDE build log
- logBuildData.view(lifetime) { lt, log ->
- if (log != null) {
- publishBuildLog(project, log)
- }
- }
-
- modelBuildIsRequested.whenTrue(lifetime) { lt ->
- if (_state.value == ScriptState.NotInitialised)
- rebuildModel()
- }
-
- }
-
- fun rebuildModel() {
- ProgressManager.getInstance().run(object : Task.Backgroundable(
- project,
- SpaceBundle.message("kts.progress.title.building.dsl.model"),
- false
- ) {
- override fun run(pi: ProgressIndicator) {
- // todo: implement build cancellation and re-building
- synchronized(sync) {
- if (_state.value == ScriptState.Building)
- return
- _state.value = ScriptState.Building
- }
- val data = LogData()
- try {
- logBuildData.value = data
- build(data)
- }
- finally {
- data.close()
- _state.value = ScriptState.Ready
- }
- }
- })
- }
-
- private fun build(logData: LogData) {
- lifetime.using { lt ->
- invokeAndWaitIfNeeded(ModalityState.NON_MODAL) {
- // We need to save the automation script to disk before compiling, to take into account the most recent changes.
- // The script might have dependencies on other files in the project, so we also save other files.
- FileDocumentManager.getInstance().saveAllDocuments()
- }
- compileAndEvaluate(logData.asLogger(lt), logData)
- }
- }
-
- private fun compileAndEvaluate(eventLogger: KLogger, logData: LogData) {
- val outputDir = createTempDir("space-automation-temp")
- try {
- val outputDirPath = outputDir.toPath()
- val compiledJarPath = outputDirPath.resolve("compiledJar.jar")
- val scriptRuntimePath = outputDirPath.resolve("space-automation-runtime.jar")
-
- val configuration = getAutomationConfigurationWithFallback()
-
- val compiler = AutomationCompilerBootstrap(log = eventLogger, configuration = configuration)
- val compileResultCode = compiler.compile(script = Paths.get(scriptFile.path), jar = compiledJarPath)
-
- if (compileResultCode != 0) {
- _config.value = null
- _error.value = SpaceBundle.message("kts.toolwindow.error.compilation.failed.code", compileResultCode)
- return
- }
- if (!Files.isRegularFile(compiledJarPath)) {
- _config.value = null
- _error.value = SpaceBundle.message("kts.toolwindow.error.missing.compiled.jar", compiledJarPath.name)
- return
- }
- // See AutomationCompiler.kt (in space project) where we copy the runtime jar into the output folder for all resolver types
- if (!Files.exists(scriptRuntimePath)) {
- _config.value = null
- _error.value = SpaceBundle.message("kts.toolwindow.error.missing.runtime.jar", scriptRuntimePath.name)
- return
- }
-
- val evaluator = AutomationDslEvaluationBootstrap(log = eventLogger, configuration = configuration).loadEvaluatorForIdea()
- if (evaluator == null) {
- _config.value = null
- _error.value = SpaceBundle.message("kts.toolwindow.error.evaluation.service.not.found")
- return
- }
-
- val evalResult = evaluator.evaluateAndValidate(compiledJarPath, scriptRuntimePath)
- if (evalResult.validationErrors.any()) {
- val validationErrorsPrefix = SpaceBundle.message("kts.toolwindow.validation.errors.prefix")
- val message = evalResult.validationErrors.joinToString("\n", prefix = "$validationErrorsPrefix\n")
- logData.error(message)
- _config.value = null
- _error.value = message
- return
- }
-
- _config.value = evalResult.config
- _error.value = null
- }
- catch (th: Throwable) {
- val stackTraceText = th.stackTraceToString()
- val logMessage = "${th.message}.\n$stackTraceText"
- logData.error(logMessage)
- // do not touch last config, just update the error state.
- _error.value = stackTraceText
- }
- finally {
- outputDir.deleteRecursively()
- }
- }
- }
-}
-
-internal fun getAutomationConfigurationOrNull(): AutomationCompilerConfiguration? =
- SpaceWorkspaceComponent.getInstance().workspace.value?.client?.server?.let {
- AutomationCompilerConfiguration.Remote(server = embeddedMavenServer(it))
- }
-
-
-// Primary option is to download from currently connected server, fallback to the public maven
-internal fun getAutomationConfigurationWithFallback(): AutomationCompilerConfiguration =
- getAutomationConfigurationOrNull() ?: AutomationCompilerConfiguration.Remote(server = publicMavenServer)
-
-private fun LogData.asLogger(lifetime: Lifetime): KLogger {
- val queue = ObservableQueue.mutable()
-
- queue.change.forEach(lifetime) {
- val ev = it.index
- when (ev.level) {
- Level.INFO -> message(ev.message)
- Level.DEBUG -> message(ev.message)
- Level.WARN -> message(ev.message)
- Level.ERROR -> error(ev.message)
- Level.TRACE -> {
- }
- }
- }
- // slf4j's SubstituteLogger mechanism allows us to put logs as events in a queue (even though not initially made for this)
- return KLogger(JVMLogger(SubstituteLogger("ScriptModelBuilderLogger", queue, false)))
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceScriptDefinitionsProvider.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceScriptDefinitionsProvider.kt
deleted file mode 100644
index 5facfa9f4372..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceScriptDefinitionsProvider.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services
-
-import java.io.File
-import kotlin.script.experimental.api.ScriptEvaluationConfiguration
-import kotlin.script.experimental.host.ScriptDefinition
-import kotlin.script.experimental.host.ScriptingHostConfiguration
-import kotlin.script.experimental.intellij.ScriptDefinitionsProvider
-
-private class SpaceScriptDefinitionsProvider : ScriptDefinitionsProvider {
- override val id = "SpaceScriptDefinitionsProvider"
-
- override fun getDefinitionClasses(): Iterable = listOf()
- override fun getDefinitionsClassPath(): Iterable = listOf()
-
- override fun provideDefinitions(
- baseHostConfiguration: ScriptingHostConfiguration,
- loadedScriptDefinitions: List
- ): Iterable = listOf(
- ScriptDefinition(
- SpaceKtsCompilationConfiguration(),
- ScriptEvaluationConfiguration.Default
- )
- )
-
- override fun useDiscovery() = false
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceScriptRunLineMarkerProvider.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceScriptRunLineMarkerProvider.kt
deleted file mode 100644
index c01df8290b10..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SpaceScriptRunLineMarkerProvider.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services
-
-import com.intellij.execution.lineMarker.RunLineMarkerContributor
-import com.intellij.psi.PsiElement
-
-class SpaceScriptRunLineMarkerProvider : RunLineMarkerContributor() {
-
- override fun getInfo(element: PsiElement): Info? {
- val refs = element.references
- refs.forEach {
- // TODO: optimize it!!!
- /*
- if (it is KtSimpleNameReference) {
- val resolveResult = it.resolve()
- if (resolveResult != null) {
- val fqnName = resolveResult.getKotlinFqName()
- if (fqnName != null) {
- if (fqnName.asString() == "circlet.pipelines.config.dsl.api.Project.job") {
- val valueArgumentList = element.nextSibling as KtValueArgumentList
- val taskName = valueArgumentList.arguments.firstOrNull()?.children?.firstOrNull()?.reference?.canonicalText
- if (taskName != null) {
- val runAction = object : AnAction(ExecutionBundle.message("run.configurable.display.name"), null, AllIcons.RunConfigurations.TestState.Run) {
- override fun actionPerformed(e: AnActionEvent) {
- CircletRunConfigurationUtils.run(taskName, element.project)
- }
- }
- return Info(runAction)
- }
- }
- }
- }
- }
- */
- }
-
- return null
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SyncDslViewManager.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SyncDslViewManager.kt
deleted file mode 100644
index 3404c356fb60..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/SyncDslViewManager.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services
-
-import com.intellij.build.AbstractViewManager
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.project.Project
-import com.intellij.space.messages.SpaceBundle
-
-@Service
-class SyncDslViewManager(project: Project) : AbstractViewManager(project) {
- public override fun getViewName() = SpaceBundle.message("tab.title.space.automation.dsl")
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/execution/SpaceTaskRunner.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/execution/SpaceTaskRunner.kt
deleted file mode 100644
index e373d21cf971..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/execution/SpaceTaskRunner.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services.execution
-
-import com.intellij.execution.process.ProcessHandler
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.project.Project
-import libraries.io.random.Random
-import libraries.klogging.KLogging
-import java.io.OutputStream
-
-@Service
-class SpaceTaskRunner(val project: Project) {
- companion object : KLogging()
-
- private val ideaLocalRunnerLabel = "SpaceTaskRunner_${Random.nextString(10)}"
-
- fun run(taskName: String): ProcessHandler {
- // todo: implement using local run from the SDK.
- return TaskProcessHandler(taskName)
- }
-
- private val newLine: String = System.getProperty("line.separator", "\n")
-}
-
-class TaskProcessHandler(private val taskName: String) : ProcessHandler() {
-
- companion object : KLogging()
-
- override fun getProcessInput(): OutputStream? {
- return null
- }
-
- override fun detachIsDefault(): Boolean {
- return false
- }
-
- override fun detachProcessImpl() {
- logger.info("detachProcessImpl for task $taskName")
- }
-
- override fun destroyProcessImpl() {
- logger.info("destroyProcessImpl for task $taskName")
- notifyProcessTerminated(0)
- }
-
- fun dispose() {
- notifyProcessTerminated(0)
- }
-
-
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunConfiguration.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunConfiguration.kt
deleted file mode 100644
index e30c0c09633e..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunConfiguration.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services.run
-
-import com.intellij.execution.Executor
-import com.intellij.execution.configurations.ConfigurationFactory
-import com.intellij.execution.configurations.LocatableConfigurationBase
-import com.intellij.execution.configurations.RunConfiguration
-import com.intellij.execution.configurations.RunProfileState
-import com.intellij.execution.runners.ExecutionEnvironment
-import com.intellij.openapi.options.SettingsEditor
-import com.intellij.openapi.project.Project
-
-class SpaceRunConfiguration(project: Project, factory: ConfigurationFactory)
- : LocatableConfigurationBase(project, factory, "Run") {
-
- override fun getConfigurationEditor(): SettingsEditor {
- return SpaceRunTaskConfigurationEditor()
- }
-
- override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? {
- return SpaceRunTaskState(options, environment)
- }
-
- public override fun getOptions(): SpaceRunTaskConfigurationOptions {
- return super.getOptions() as SpaceRunTaskConfigurationOptions
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunConfigurationType.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunConfigurationType.kt
deleted file mode 100644
index 687e1000c427..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunConfigurationType.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services.run
-
-import com.intellij.execution.configurations.RunConfiguration
-import com.intellij.execution.configurations.SimpleConfigurationType
-import com.intellij.openapi.components.BaseState
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.NotNullLazyValue
-import com.intellij.space.messages.SpaceBundle
-import icons.SpaceIcons
-import platform.common.ProductName
-
-class SpaceRunConfigurationType : SimpleConfigurationType(
- "SpaceRunConfiguration",
- SpaceBundle.message("space.task.run.configuration.name"),
- SpaceBundle.message("run.configuration.description", ProductName),
- NotNullLazyValue.createValue { SpaceIcons.Main }
-) {
-
- override fun createTemplateConfiguration(project: Project): RunConfiguration {
- return SpaceRunConfiguration(project, this)
- }
-
- override fun getOptionsClass(): Class? {
- return SpaceRunTaskConfigurationOptions::class.java
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunConfigurationUtils.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunConfigurationUtils.kt
deleted file mode 100644
index 1143932602a4..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunConfigurationUtils.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services.run
-
-import com.intellij.execution.ProgramRunnerUtil
-import com.intellij.execution.RunManager
-import com.intellij.execution.executors.DefaultRunExecutor
-import com.intellij.openapi.project.Project
-
-object SpaceRunConfigurationUtils {
- fun run(taskName: String, project: Project) {
- val runManager = RunManager.getInstance(project)
- val settings = runManager.createConfiguration("Run task $taskName", SpaceRunConfigurationType::class.java)
- val configuration = settings.configuration as SpaceRunConfiguration
- configuration.options.taskName = taskName
- runManager.addConfiguration(settings)
- runManager.selectedConfiguration = settings
- ProgramRunnerUtil.executeConfiguration(settings, DefaultRunExecutor.getRunExecutorInstance())
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunTaskConfigurationEditor.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunTaskConfigurationEditor.kt
deleted file mode 100644
index b06908fe3d08..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunTaskConfigurationEditor.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services.run
-
-import com.intellij.openapi.options.SettingsEditor
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.ui.components.JBTextField
-import javax.swing.BoxLayout
-import javax.swing.JComponent
-import javax.swing.JLabel
-import javax.swing.JPanel
-
-class SpaceRunTaskConfigurationEditor : SettingsEditor() {
- private val taskNameField = JBTextField()
- override fun resetEditorFrom(s: SpaceRunConfiguration) {
- val options = s.options
- taskNameField.text = options.taskName
- }
-
- override fun createEditor(): JComponent {
- val panel = JPanel()
- panel.layout = BoxLayout(panel, BoxLayout.LINE_AXIS)
- panel.add(JLabel(SpaceBundle.message("run.configuration.editor.task.name.label")))
- panel.add(taskNameField)
- return panel
- }
-
- override fun applyEditorTo(s: SpaceRunConfiguration) {
- val options = s.options
- options.taskName = taskNameField.text
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunTaskConfigurationOptions.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunTaskConfigurationOptions.kt
deleted file mode 100644
index 80b4c1222fc1..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunTaskConfigurationOptions.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services.run
-
-import com.intellij.execution.configurations.LocatableRunConfigurationOptions
-import com.intellij.util.xmlb.annotations.OptionTag
-
-class SpaceRunTaskConfigurationOptions : LocatableRunConfigurationOptions() {
- @get:OptionTag("TASK_NAME")
- var taskName by string("")
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunTaskState.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunTaskState.kt
deleted file mode 100644
index 0c66df982c36..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/services/run/SpaceRunTaskState.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.services.run
-
-import com.intellij.execution.ExecutionException
-import com.intellij.execution.configurations.CommandLineState
-import com.intellij.execution.process.ProcessHandler
-import com.intellij.execution.runners.ExecutionEnvironment
-import com.intellij.openapi.components.service
-import com.intellij.space.plugins.pipelines.services.execution.SpaceTaskRunner
-
-class SpaceRunTaskState(private val settings: SpaceRunTaskConfigurationOptions, environment: ExecutionEnvironment) : CommandLineState(
- environment) {
-
- override fun startProcess(): ProcessHandler {
- val project = environment.project
- val runner = project.service()
- val taskName = settings.taskName
- if (taskName == null) {
- throw ExecutionException("TaskName is null") // NON-NLS
- }
- else {
- return runner.run(taskName)
- }
- }
-
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/ui/SpaceScriptsViewFactory.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/ui/SpaceScriptsViewFactory.kt
deleted file mode 100644
index 7f545db1cb53..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/ui/SpaceScriptsViewFactory.kt
+++ /dev/null
@@ -1,390 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.ui
-
-import circlet.pipelines.DefaultDslFileName
-import circlet.pipelines.config.idea.api.*
-import circlet.pipelines.config.idea.api.ProcessExecutable.*
-import circlet.pipelines.config.idea.api.ScriptStep.CompositeStep
-import circlet.pipelines.config.idea.api.ScriptStep.SimpleStep
-import com.intellij.icons.AllIcons
-import com.intellij.ide.IdeBundle
-import com.intellij.ide.util.PsiNavigationSupport
-import com.intellij.openapi.actionSystem.ActionToolbarPosition
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vfs.LocalFileSystem
-import com.intellij.openapi.vfs.VfsUtil
-import com.intellij.openapi.wm.ToolWindow
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.plugins.pipelines.services.SpaceKtsModelBuilder
-import com.intellij.space.plugins.pipelines.viewmodel.ScriptState
-import com.intellij.space.plugins.pipelines.viewmodel.SpaceModelTreeNode
-import com.intellij.space.utils.LifetimedDisposable
-import com.intellij.space.utils.LifetimedDisposableImpl
-import com.intellij.ui.DumbAwareActionButton
-import com.intellij.ui.ToggleActionButton
-import com.intellij.ui.ToolbarDecorator
-import com.intellij.ui.components.ActionLink
-import com.intellij.ui.components.Panel
-import com.intellij.ui.content.ContentFactory
-import com.intellij.ui.treeStructure.Tree
-import com.intellij.util.ui.JBEmptyBorder
-import com.intellij.util.ui.tree.TreeUtil
-import libraries.coroutines.extra.Lifetime
-import libraries.klogging.KLogging
-import runtime.reactive.bind
-import runtime.reactive.mutableProperty
-import runtime.reactive.view
-import java.awt.CardLayout
-import java.awt.Component
-import java.awt.GridBagConstraints
-import java.awt.GridBagLayout
-import javax.swing.BoxLayout
-import javax.swing.JComponent
-import javax.swing.JLabel
-import javax.swing.JPanel
-import javax.swing.tree.DefaultMutableTreeNode
-import javax.swing.tree.DefaultTreeModel
-import javax.swing.tree.TreeSelectionModel
-import kotlin.reflect.full.isSubtypeOf
-import kotlin.reflect.jvm.javaType
-import kotlin.reflect.typeOf
-
-class SpaceToolWindowViewModel(val lifetime: Lifetime) {
- val taskIsRunning = mutableProperty(false)
- val selectedNode = mutableProperty(null)
- val extendedViewModeEnabled = mutableProperty(true)
-}
-
-@Service
-class SpaceToolWindowService(val project: Project) : LifetimedDisposable by LifetimedDisposableImpl(), KLogging() {
- val modelBuilder = project.service()
-
- val viewModel = SpaceToolWindowViewModel(lifetime)
-
- fun createToolWindowContent(toolWindow: ToolWindow) {
-
- // ping script builder first so that it starts building the model for the first time.
- modelBuilder.requestModel()
-
- val panel = Panel(title = null).apply {
- add(createView())
- }
-
- val content = ContentFactory.SERVICE.getInstance().createContent(panel, "", false).apply {
- isCloseable = false
- }
-
- toolWindow.contentManager.addContent(content)
- }
-
- fun createView(): JComponent {
- logger.debug("createView. begin")
- val layout = CardLayout()
- val panel = JPanel(layout)
- val treeCompName = "tree"
- val missedDslCompName = "empty"
- val treeView = createModelTreeView(lifetime, project)
-
- panel.add(treeView, treeCompName)
- panel.add(createViewForMissedDsl(project), missedDslCompName)
-
- modelBuilder.script.view(lifetime) { lt, script ->
- if (script == null) {
- layout.show(panel, missedDslCompName)
- }
- else {
- layout.show(panel, treeCompName)
- }
- }
-
- logger.debug("createView. end")
- return panel
- }
-
- private fun createModelTreeView(lifetime: Lifetime, project: Project): JComponent {
- val tree = Tree()
-
- tree.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION
-
- val root = tree.model.root as DefaultMutableTreeNode
-
- tree.selectionModel.addTreeSelectionListener {
- val selectedNode = it.path.lastPathComponent
- viewModel.selectedNode.value = if (selectedNode is SpaceModelTreeNode) selectedNode else null
- }
-
- TreeUtil.expandAll(tree)
- tree.isRootVisible = false
-
- lifetime.bind(modelBuilder.script) { script ->
- bind(viewModel.extendedViewModeEnabled) { extendedViewModeEnabled ->
- if (script != null) {
- bind(script.config) { config ->
- bind(script.error) { error ->
- bind(script.state) { state ->
- resetNodes(root, config, error, state, viewModel.extendedViewModeEnabled.value)
- (tree.model as DefaultTreeModel).reload()
- }
- }
- }
- }
- else {
- // seems unreachable state.
- root.removeAllChildren()
- }
- }
- }
-
-
- val refreshAction = object : DumbAwareActionButton(IdeBundle.message("action.refresh"), AllIcons.Actions.Refresh) {
- override fun actionPerformed(e: AnActionEvent) {
- modelBuilder.rebuildModel()
- }
- }
-
- val expandAllAction = object : DumbAwareActionButton(IdeBundle.message("action.expand.all"), AllIcons.Actions.Expandall) {
- override fun actionPerformed(e: AnActionEvent) {
- if (modelBuilder.script.value?.state?.value == ScriptState.Building) {
- return
- }
- TreeUtil.expandAll(tree)
- }
- }
-
- val collapseAllAction = object : DumbAwareActionButton(IdeBundle.message("action.collapse.all"), AllIcons.Actions.Collapseall) {
- override fun actionPerformed(e: AnActionEvent) {
- if (modelBuilder.script.value?.state?.value == ScriptState.Building) {
- return
- }
- TreeUtil.collapseAll(tree, 0)
- }
- }
-
- val showExtendedInfoAction = object : ToggleActionButton(SpaceBundle.message("show.details"), AllIcons.Actions.Show) {
- override fun isSelected(e: AnActionEvent?): Boolean {
- return viewModel.extendedViewModeEnabled.value
- }
-
- override fun setSelected(e: AnActionEvent?, state: Boolean) {
- viewModel.extendedViewModeEnabled.value = state
- }
- }
-
- fun updateActionsIsEnabledStates() {
- val smthIsRunning = modelBuilder.script.value?.state?.value == ScriptState.Building || viewModel.taskIsRunning.value
- refreshAction.isEnabled = !smthIsRunning
- }
-
- viewModel.selectedNode.forEach(lifetime) {
- updateActionsIsEnabledStates()
- }
-
- modelBuilder.script.view(lifetime) { lt, script ->
- script?.state?.forEach(lt) {
- updateActionsIsEnabledStates()
- }
- }
-
- viewModel.taskIsRunning.forEach(lifetime) {
- updateActionsIsEnabledStates()
- }
-
- val panel = ToolbarDecorator
- .createDecorator(tree)
- .addExtraAction(refreshAction)
- // .addExtraAction(runAction)
- .addExtraAction(expandAllAction)
- .addExtraAction(collapseAllAction)
- .addExtraAction(showExtendedInfoAction)
- .setToolbarPosition(ActionToolbarPosition.TOP)
- .createPanel()
- panel.border = JBEmptyBorder(0)
- return panel
- }
-
- private fun resetNodes(root: DefaultMutableTreeNode,
- config: IdeaScriptConfig?,
- error: String?,
- state: ScriptState,
- extendedViewModeEnabled: Boolean) {
- root.removeAllChildren()
- if (config == null) {
- if (error != null) {
- root.add(SpaceModelTreeNode(error))
- return
- }
- if (state == ScriptState.Building) {
- root.add(SpaceModelTreeNode("Compiling script..."))
- return
- }
- return
- }
-
- val jobs = config.jobs
- val targets = config.targets
- val pipelines = config.pipelines
-
- var jobsTypesCount = 0
- if (jobs.any()) {
- jobsTypesCount++
- }
- if (targets.any()) {
- jobsTypesCount++
- }
- if (pipelines.any()) {
- jobsTypesCount++
- }
- val shouldAddGroupingNodes = jobsTypesCount > 1
- if (jobs.any()) {
- val jobsCollectionNode = getGroupingNode(root, "jobs", shouldAddGroupingNodes)
- config.jobs.forEach { job ->
- val jobNode = job.toTreeNode(showChildren = extendedViewModeEnabled)
- jobsCollectionNode.add(jobNode)
- }
- }
-
- targets.forEach {
- val child = SpaceModelTreeNode("target + ${it.name}. not implemented in UI yet")
- root.add(child)
- }
- pipelines.forEach {
- val child = SpaceModelTreeNode("pipelines + ${it.name}. not implemented in UI yet")
- root.add(child)
- }
- }
-
- private fun createViewForMissedDsl(project: Project): JComponent {
- val panel = JPanel()
- panel.layout = BoxLayout(panel, BoxLayout.Y_AXIS)
-
- val infoText = JLabel(SpaceBundle.message("kts.toolwindow.automation.is.not.configured.label"))
- infoText.isEnabled = false
- infoText.alignmentX = Component.CENTER_ALIGNMENT
- panel.add(infoText)
-
- val createDslLink = ActionLink(SpaceBundle.message("kts.toolwindow.add.automation.script.link")) {
- val basePath = project.basePath
- if (basePath != null) {
- val baseDirFile = LocalFileSystem.getInstance().findFileByPath(basePath)
- if (baseDirFile != null) {
- val application = ApplicationManager.getApplication()
- application.runWriteAction {
- val file = baseDirFile.createChildData(this, DefaultDslFileName)
- val newLine = System.getProperty("line.separator", "\n")
- val newFileContent =
- "// Write your automation script $newLine" +
- "// Once the script is ready, commit the changes to the repository $newLine" +
- "// Use full DSL reference when needed https://jetbrains.team/help/space/automation-dsl.html $newLine" +
- "job(\"My First Job\") {$newLine " +
- "container(\"hello-world\")$newLine" +
- "}"
- VfsUtil.saveText(file, newFileContent)
- PsiNavigationSupport.getInstance().createNavigatable(project, file, -1).navigate(true)
- }
- }
- }
- }
-
- createDslLink.alignmentX = Component.CENTER_ALIGNMENT
- panel.add(createDslLink)
-
- val rootPanel = JPanel()
- rootPanel.layout = GridBagLayout()
- rootPanel.add(panel, GridBagConstraints())
- return rootPanel
- }
-
- private fun getGroupingNode(root: DefaultMutableTreeNode, name: String, shouldAddGroupingNodes: Boolean): DefaultMutableTreeNode {
- if (shouldAddGroupingNodes) {
- val res = SpaceModelTreeNode(name, true)
- root.add(res)
- return res
- }
-
- return root
- }
-}
-
-private fun ScriptJob.toTreeNode(showChildren: Boolean) = SpaceModelTreeNode(name, true).apply {
- if (showChildren) {
- if (triggers.any()) {
- add(triggers.toTreeNode())
- }
- add(steps.toTreeNode())
- }
-}
-
-private fun List.toTreeNode() = SpaceModelTreeNode("triggers").apply {
- forEach { trigger ->
- add(trigger.toTreeNode())
- }
-}
-
-private fun Trigger.toTreeNode() = SpaceModelTreeNode(usefulSubTypeName() ?: "other trigger")
-
-private fun StepSequence.toTreeNode() = SpaceModelTreeNode("steps").apply {
- forEach { step ->
- add(step.toTreeNode())
- }
-}
-
-private fun ScriptStep.toTreeNode(): SpaceModelTreeNode = when (val step = this) {
- is CompositeStep -> SpaceModelTreeNode(step.treeNodeText).apply {
- step.children.forEach { subStep ->
- add(subStep.toTreeNode())
- }
- }
- is SimpleStep.Process.Container -> SpaceModelTreeNode("container: ${step.image}").apply {
- add(step.data.exec.toTreeNode())
- }
- is SimpleStep.DockerComposeStep -> SpaceModelTreeNode("compose: ${step.mainService}")
- else -> SpaceModelTreeNode(step.usefulSubTypeName())
-}
-
-private val CompositeStep.treeNodeText: String get() = when(this) {
- is CompositeStep.Fork -> "parallel"
- is CompositeStep.Sequence -> "sequence"
- else -> usefulSubTypeName() ?: "composite step"
-}
-
-private fun ProcessExecutable.toTreeNode() = DefaultMutableTreeNode(treeNodeText)
-
-private val ProcessExecutable.treeNodeText: String
- get() = when (this) {
- is ContainerExecutable.DefaultCommand -> "exec: defaultCommand${args.presentArgs()}"
- is ContainerExecutable.OverrideEntryPoint -> "exec: overrideEntryPoint: $entryPoint${args.presentArgs()}"
- is KotlinScript -> "exec: kts script"
- is ShellScript -> "exec: shell script"
- else -> "exec: ${usefulSubTypeName()}"
- }
-
-private fun List.presentArgs(): String {
- return if (this.any()) ". args: ${this.joinToString()}" else ""
-}
-
-/**
- * Returns the name of this object's dynamic type (which is a subtype of its static type [T]).
- * If this object is of an anonymous type, this method falls back to the name of the closest supertype of the runtime type of this object
- * that implements/extends its static type [T].
- * If this object is a direct anonymous implementation of the static type [T], this method returns `null` to allow other fallbacks.
- *
- * Most instances of the interfaces are anonymous classes at the moment in the space project.
- * For instance, the [Trigger] interface may have subinterfaces that we don't know of at compile time here, but could be added in the
- * future.
- * Since the object is of an anonymous class, we should use the name of the closest supertype that implements [Trigger], e.g. GitPush.
- */
-@OptIn(ExperimentalStdlibApi::class)
-private inline fun T.usefulSubTypeName(): String? {
- val simpleClassName = this::class.simpleName
- if (simpleClassName != null) { // false for anonymous classes
- return simpleClassName
- }
- // There is always at least one supertype (T), because we know this is an anonymous class that is also an instance of T
- val subTypeOfT = this::class.supertypes.first { it.isSubtypeOf(typeOf()) }
- val simpleSubtypeName = subTypeOfT.javaType.typeName.substringAfterLast('.')
- return simpleSubtypeName.takeIf { it != T::class.simpleName }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/utils/DslFileFinder.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/utils/DslFileFinder.kt
deleted file mode 100644
index 566048f16266..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/utils/DslFileFinder.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.utils
-
-import circlet.pipelines.DefaultDslFileName
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vfs.LocalFileSystem
-import com.intellij.openapi.vfs.VirtualFile
-
-object DslFileFinder {
-
- fun find(project: Project): VirtualFile? {
- val basePath = project.basePath ?: return null
- val baseDirFile = LocalFileSystem.getInstance().findFileByPath(basePath) ?: return null
- return find(baseDirFile)
- }
-
- fun checkFileNameIsApplicable(name: String): Boolean {
- return DefaultDslFileName.equals(name, true)
- }
-
- private fun find(baseDirFile: VirtualFile): VirtualFile? {
- return baseDirFile.children.firstOrNull {
- checkFileNameIsApplicable(it.name)
- }
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/utils/ObservableQueue.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/utils/ObservableQueue.kt
deleted file mode 100644
index 99d2e255327f..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/utils/ObservableQueue.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.utils
-
-import runtime.reactive.Signal
-import runtime.reactive.Source
-import java.util.*
-
-interface ObservableQueue : Queue {
- @Suppress("unused")
- sealed class Change(val index: T) {
- class Add(val value: T) : Change(value)
- }
-
- val change: Source>
-
- companion object {
- fun mutable(): ObservableQueue = ObservableMutableQueue()
- }
-}
-
-class ObservableMutableQueue : ObservableQueue, Queue {
-
- private val storage = ArrayDeque()
-
- override val change = Signal.create>()
-
- override fun contains(element: T): Boolean {
- return storage.contains(element)
- }
-
- override fun addAll(elements: Collection): Boolean {
- return storage.addAll(elements)
- }
-
- override fun clear() {
- TODO("not implemented") //return storage.clear()
- }
-
- override fun element(): T {
- TODO("not implemented") //return storage.element()
- }
-
- override fun isEmpty(): Boolean {
- return storage.isEmpty()
- }
-
- override fun remove(): T {
- TODO("not implemented") //return storage.remove()
- }
-
- override fun remove(element: T): Boolean {
- TODO("not implemented") //return storage.remove(element)
- }
-
- override fun containsAll(elements: Collection): Boolean {
- TODO("not implemented") //return storage.containsAll(elements)
- }
-
- override fun removeAll(elements: Collection): Boolean {
- TODO("not implemented") //return storage.removeAll(elements)
- }
-
- override fun add(element: T): Boolean {
- storage.add(element)
- change.fire(ObservableQueue.Change.Add(element))
- return true
- }
-
- override fun offer(e: T): Boolean {
- TODO("not implemented") //return storage.offer(e)
- }
-
- override fun iterator(): MutableIterator {
- TODO("not implemented") //return storage.iterator()
- }
-
- override fun retainAll(elements: Collection): Boolean {
- TODO("not implemented") //return storage.retainAll(elements)
- }
-
- override fun peek(): T {
- TODO("not implemented") //return storage.peek()
- }
-
- override fun poll(): T {
- TODO("not implemented") //return storage.poll()
- }
-
- override val size: Int
- get() = storage.size
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/viewmodel/ScriptModel.kt b/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/viewmodel/ScriptModel.kt
deleted file mode 100644
index c406b1f6b558..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/plugins/pipelines/viewmodel/ScriptModel.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-package com.intellij.space.plugins.pipelines.viewmodel
-
-import circlet.pipelines.config.idea.api.IdeaScriptConfig
-import com.intellij.build.events.BuildEvent
-import com.intellij.build.events.BuildEventsNls
-import com.intellij.build.events.impl.OutputBuildEventImpl
-import libraries.coroutines.extra.LifetimeSource
-import libraries.coroutines.extra.assertNotTerminated
-import libraries.io.random.Random
-import runtime.reactive.ObservableList
-import runtime.reactive.Property
-import javax.swing.tree.DefaultMutableTreeNode
-
-enum class ScriptState { NotInitialised, Building, Ready }
-
-interface ScriptModel {
- val config: Property
- val error: Property
- val state: Property
-}
-
-class LogData {
-
- // lifetime corresponding to the entire build process, it terminates when this build finishes
- val lifetime get() = _buildLifetime
-
- val buildId = Random.nextUID()
-
- val messages = ObservableList.mutable()
-
- private val _buildLifetime = LifetimeSource()
-
- fun message(@BuildEventsNls.Message message: String) {
- _buildLifetime.assertNotTerminated()
- messages.add(OutputBuildEventImpl(buildId, message + "\n", true))
- }
-
- fun error(@BuildEventsNls.Message message: String) {
- _buildLifetime.assertNotTerminated()
- messages.add(OutputBuildEventImpl(buildId, message + "\n", false))
- }
-
- fun close() {
- _buildLifetime.terminate()
- }
-
-}
-
-class SpaceModelTreeNode(text: String? = null, val isRunnable: Boolean = false) : DefaultMutableTreeNode(text)
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/promo/promo.kt b/plugins/space/src/main/kotlin/com/intellij/space/promo/promo.kt
deleted file mode 100644
index 491b9909250b..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/promo/promo.kt
+++ /dev/null
@@ -1,194 +0,0 @@
-// 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.
-package com.intellij.space.promo
-
-import com.intellij.ide.BrowserUtil
-import com.intellij.ide.ui.fullRow
-import com.intellij.openapi.ui.panel.ComponentPanelBuilder
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.ui.components.BrowserLink
-import com.intellij.ui.layout.*
-import com.intellij.ui.scale.ScaleContext
-import com.intellij.ui.scale.ScaleType
-import com.intellij.util.FontUtil
-import com.intellij.util.JBHiDPIScaledImage
-import com.intellij.util.SVGLoader
-import com.intellij.util.ui.*
-import icons.SpaceIcons
-import libraries.klogging.logger
-import java.awt.Color
-import java.awt.Cursor
-import java.awt.Dimension
-import java.awt.Image
-import java.awt.event.MouseAdapter
-import java.awt.event.MouseEvent
-import javax.imageio.ImageIO
-import javax.swing.JComponent
-import javax.swing.JLabel
-import javax.swing.JLayeredPane
-
-internal const val SPACE_PROMO_VIDEO_URL: String = "https://www.jetbrains.com/space/?show-overview=from-ide&switch-to-branch=JS-14525-space-overview-video-qs-parameter"
-internal const val EXPLORE_SPACE_PROMO_URL: String = "https://www.jetbrains.com/space/?fromIDEplugin"
-internal const val SIGN_UP_SPACE_URL: String = "https://www.jetbrains.com/space/?fromIDEplugin#sign-up"
-
-internal const val SPACE_TOOLBAR_PROMO_BANNER_PATH = "/images/spacePromo.png"
-internal const val SPACE_TOOLBAR_PROMO_BANNER_PATH_RETINA = "/images/spacePromo@2x.png"
-
-internal const val SPACE_BIG_PROMO_BANNER_NAME = "/images/spaceVideoPreview"
-internal const val DARK_POSTFIX = "_dark"
-internal const val HIDPI_POSTFIX = "@2x"
-
-internal const val JETBRAINS_SPACE_LOGO = "/images/jetbrainsSpace.svg"
-internal const val JETBRAINS_SPACE_LOGO_DARK = "/images/jetbrainsSpaceDark.svg"
-
-internal fun LayoutBuilder.promoPanel(statsExplorePlace: SpaceStatsCounterCollector.ExplorePlace) {
- fullRow { createSpaceByJetbrainsLabel()() }
- fullRow { promoText(76)() }
- fullRow { exploreSpaceLink(statsExplorePlace)() }.largeGapAfter()
-}
-
-internal fun toolbarPromoBanner(): JComponent? {
- val imagePath = if (StartupUiUtil.isJreHiDPI()) SPACE_TOOLBAR_PROMO_BANNER_PATH_RETINA else SPACE_TOOLBAR_PROMO_BANNER_PATH
- val image = ImageLoader.loadImage(imagePath, 364, 199) ?: return null
-
- return wrapWithWatchSpaceOverviewLabelOverlay(JLabel(JBImageIcon(image)), SpaceStatsCounterCollector.OverviewPlace.MAIN_TOOLBAR)
-}
-
-internal fun bigPromoBanner(statsOverviewPlace: SpaceStatsCounterCollector.OverviewPlace): JComponent? =
- bigPromoBanner(500, 285, statsOverviewPlace)
-
-internal fun bigPromoBanner(width: Int, height: Int, statsOverviewPlace: SpaceStatsCounterCollector.OverviewPlace): JComponent? {
- val isDarcula = StartupUiUtil.isUnderDarcula()
- val themePart = if (isDarcula) DARK_POSTFIX else ""
- val retinaPart = if (StartupUiUtil.isJreHiDPI()) HIDPI_POSTFIX else ""
- val imagePath = "${SPACE_BIG_PROMO_BANNER_NAME}${retinaPart}${themePart}.png"
-
- val image = ImageLoader.loadImage(imagePath, width, height) ?: return null
-
- return wrapWithWatchSpaceOverviewLabelOverlay(
- JLabel(JBImageIcon(image)),
- statsOverviewPlace,
- alwaysDisplayLabel = true,
- useDarkLabel = isDarcula
- )
-}
-
-internal fun exploreSpaceLink(statsExplorePlace: SpaceStatsCounterCollector.ExplorePlace): BrowserLink =
- BrowserLink(
- SpaceBundle.message("space.promo.explore.space.button"),
- EXPLORE_SPACE_PROMO_URL
- ).apply {
- addActionListener {
- SpaceStatsCounterCollector.EXPLORE_SPACE.log(statsExplorePlace)
- }
- isFocusPainted = false
- }
-
-private fun wrapWithWatchSpaceOverviewLabelOverlay(
- component: JComponent,
- statsOverviewPlace: SpaceStatsCounterCollector.OverviewPlace,
- alwaysDisplayLabel: Boolean = false,
- useDarkLabel: Boolean = true
-): JComponent {
- @NlsSafe val text = "\u25B6${FontUtil.spaceAndThinSpace()}${SpaceBundle.message("space.promo.watch.space.overview.label")}"
- val labelBackground = if (useDarkLabel) Color(0, 0, 0, 180) else Color(255, 255, 255, 180)
- val labelForeground = if (useDarkLabel) Color.WHITE else Color.BLACK
-
- val watchVideoButton = JLabel(text).apply {
- isFocusable = false
- isOpaque = true
- isVisible = alwaysDisplayLabel
- background = labelBackground
- foreground = labelForeground
- border = JBUI.Borders.empty(8)
- }
-
- return JComponentOverlay.createCentered(component, watchVideoButton).apply {
- cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
-
- addMouseListener(object : MouseAdapter() {
- override fun mouseEntered(e: MouseEvent?) {
- if (!alwaysDisplayLabel) watchVideoButton.isVisible = true
- }
-
- override fun mouseExited(e: MouseEvent?) {
- if (!alwaysDisplayLabel) watchVideoButton.isVisible = false
- }
-
- override fun mouseClicked(e: MouseEvent?) {
- SpaceStatsCounterCollector.WATCH_OVERVIEW.log(statsOverviewPlace)
- watchPromoVideo()
- }
- })
- }
-}
-
-internal fun createSpaceByJetbrainsLabel(): JComponent = JLabel().apply {
- val jbSpaceSvgLogo = SvgLoader.loadSvg(if (StartupUiUtil.isUnderDarcula()) JETBRAINS_SPACE_LOGO_DARK else JETBRAINS_SPACE_LOGO, this)
- if (jbSpaceSvgLogo != null) {
- icon = jbSpaceSvgLogo
- }
- else {
- icon = SpaceIcons.Main
- text = SpaceBundle.message("product.name.jetbrains.space")
- }
-}
-
-internal fun promoText(maxLineLength: Int = 0): JLabel = ComponentPanelBuilder.createCommentComponent(
- SpaceBundle.message("space.promo.text.full"), true, maxLineLength).apply {
- foreground = JBUI.CurrentTheme.Label.foreground()
- font = JBUI.Fonts.label()
-}
-
-private fun watchPromoVideo() {
- BrowserUtil.browse(SPACE_PROMO_VIDEO_URL)
-}
-
-private object JComponentOverlay {
- fun createCentered(component: JComponent, centeredOverlay: JComponent): JLayeredPane {
- val pane = object : JLayeredPane() {
- override fun getPreferredSize(): Dimension = component.preferredSize
-
- override fun doLayout() {
- super.doLayout()
- component.setBounds(0, 0, width, height)
- centeredOverlay.bounds = SingleComponentCenteringLayout.getBoundsForCentered(component, centeredOverlay)
- }
- }
- pane.isFocusable = false
- pane.add(component, JLayeredPane.DEFAULT_LAYER, 1)
- pane.add(centeredOverlay, JLayeredPane.DEFAULT_LAYER, 0)
- return pane
- }
-}
-
-val log = logger()
-
-private object ImageLoader {
-
- fun loadImage(path: String, width: Int, height: Int): Image? {
- return try {
- val img = ImageIO.read(javaClass.getResourceAsStream(path))
- JBHiDPIScaledImage(img, width, height, img.type)
- }
- catch (e: Exception) {
- log.error { "Image ${path} is not loaded" }
- null
- }
- }
-}
-
-private object SvgLoader {
- fun loadSvg(path: String, comp: JComponent): JBImageIcon? = try {
- val bytes = javaClass.getResourceAsStream(path)?.readAllBytes()
- val ctx = ScaleContext.create(comp)
- val image = SVGLoader.loadWithoutCache(bytes, ctx.getScale(ScaleType.SYS_SCALE).toFloat())
- val hiDpi = ImageUtil.ensureHiDPI(image, ctx)
- JBImageIcon(hiDpi)
- }
- catch (e: Exception) {
- log.error { "Svg ${path} is not loaded" }
- null
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/runtime/ApplicationDispatcher.kt b/plugins/space/src/main/kotlin/com/intellij/space/runtime/ApplicationDispatcher.kt
deleted file mode 100644
index baad52d697e0..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/runtime/ApplicationDispatcher.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-// 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.
-package com.intellij.space.runtime
-
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.application.Application
-import com.intellij.openapi.application.ModalityState
-import com.intellij.openapi.util.Disposer
-import com.intellij.util.concurrency.AppExecutorUtil
-import kotlinx.coroutines.*
-import libraries.klogging.logger
-import runtime.Cancellable
-import runtime.CoroutineExceptionLogger
-import runtime.Dispatcher
-import runtime.TaskCancellable
-import java.util.concurrent.Future
-import java.util.concurrent.ScheduledExecutorService
-import java.util.concurrent.TimeUnit
-import kotlin.coroutines.CoroutineContext
-
-private val log = logger()
-
-internal class ApplicationDispatcher(disposable: Disposable, private val application: Application) : Dispatcher {
- private val executor = AppExecutorUtil.createBoundedScheduledExecutorService("Application Auxiliary Scheduler", 1)
-
- private val context = ApplicationCoroutineContext(application, executor)
-
- private val contextWithLog = context + CoroutineExceptionLogger.create(log)
-
- override val coroutineContext: CoroutineContext
- get() = contextWithLog
-
- init {
- Disposer.register(disposable, Disposable {
- executor.shutdown()
- try {
- executor.awaitTermination(5, TimeUnit.SECONDS)
- }
- catch (e: InterruptedException) {
- log.warn { "Executor was not properly terminated" }
- }
- })
- }
-
- override fun dispatch(fn: () -> Unit) {
- application.invokeLater(fn, ModalityState.any())
- }
-
- override fun dispatch(delay: Int, fn: () -> Unit): Cancellable {
- val invoke = java.lang.Runnable {
- application.invokeLater(fn, ModalityState.any())
- }
- val disposable = executor.schedule(invoke, delay.toLong(), TimeUnit.MILLISECONDS)
-
- return TaskCancellable(disposable)
- }
-
- override fun dispatchInterval(delay: Int, interval: Int, fn: () -> Unit): Cancellable {
- val invoke = java.lang.Runnable {
- application.invokeLater(fn, ModalityState.any())
- }
- val disposable = executor.scheduleWithFixedDelay(invoke, delay.toLong(), interval.toLong(), TimeUnit.MILLISECONDS)
-
- return TaskCancellable(disposable)
- }
-}
-
-@UseExperimental(InternalCoroutinesApi::class)
-private class ApplicationCoroutineContext(
- private val application: Application,
- private val executor: ScheduledExecutorService
-) : CoroutineDispatcher(), Delay {
-
- override fun dispatch(context: CoroutineContext, block: Runnable) {
- application.invokeLater(block, ModalityState.any())
- }
-
- override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) {
- val toResume = java.lang.Runnable {
- application.invokeLater({ with(continuation) { this@ApplicationCoroutineContext.resumeUndispatched(Unit) } }, ModalityState.any())
- }
-
- executor.schedule(toResume, timeMillis, TimeUnit.MILLISECONDS)
- }
-
- override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle {
- val toResume = java.lang.Runnable {
- application.invokeLater({
- block.run()
- }, ModalityState.any())
- }
-
- return DisposableFutureHandle(executor.schedule(toResume, timeMillis, TimeUnit.MILLISECONDS))
- }
-}
-
-private class DisposableFutureHandle(private val future: Future<*>) : DisposableHandle {
- override fun dispose() {
- future.cancel(false)
- }
-
- override fun toString(): String = "DisposableFutureHandle[$future]"
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceLoginState.kt b/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceLoginState.kt
deleted file mode 100644
index 9502155313ef..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceLoginState.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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.
-package com.intellij.space.settings
-
-import circlet.workspaces.Workspace
-import com.intellij.openapi.util.NlsContexts.DetailedDescription
-
-sealed class SpaceLoginState(val server: String) {
- class Disconnected(server: String, @DetailedDescription val error: String? = null) : SpaceLoginState(server)
- class Connected(server: String, val workspace: Workspace) : SpaceLoginState(server)
- class Connecting(server: String, private val cancelationHandler: () -> Unit) : SpaceLoginState(server) {
- fun cancel() = cancelationHandler()
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceServerSettings.kt b/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceServerSettings.kt
deleted file mode 100644
index 1a9640ae6f47..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceServerSettings.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-// 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.
-package com.intellij.space.settings
-
-data class SpaceServerSettings(
- var enabled: Boolean = false,
- var server: String = ""
-)
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceSettings.kt b/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceSettings.kt
deleted file mode 100644
index 09314a8d02c1..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceSettings.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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.
-package com.intellij.space.settings
-
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.components.*
-
-@State(
- name = "SpaceServerConfigurable",
- storages = [Storage(value = "SpaceServer.xml", roamingType = RoamingType.DEFAULT)]
-)
-class SpaceSettings : SimplePersistentStateComponent(SpaceSettingsState()) {
- var serverSettings: SpaceServerSettings
- get() = state.serverSettings
- set(value) {
- state.serverSettings = value
- }
-
- var cloneType: CloneType
- get() = state.cloneType
- set(value) {
- state.cloneType = value
- }
-
- companion object {
- fun getInstance(): SpaceSettings = ApplicationManager.getApplication().getService(SpaceSettings::class.java)
- }
-}
-
-class SpaceSettingsState : BaseState() {
- var serverSettings: SpaceServerSettings by this.property(SpaceServerSettings()) {
- it.enabled.not() && it.server.isBlank()
- }
-
- var cloneType: CloneType by enum(CloneType.HTTPS)
-}
-
-enum class CloneType {
- HTTPS,
- SSH
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceSettingsPanel.kt b/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceSettingsPanel.kt
deleted file mode 100644
index 06b4f487db69..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/settings/SpaceSettingsPanel.kt
+++ /dev/null
@@ -1,173 +0,0 @@
-// 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.
-package com.intellij.space.settings
-
-import circlet.client.api.englishFullName
-import com.intellij.ide.ui.fullRow
-import com.intellij.openapi.options.BoundConfigurable
-import com.intellij.openapi.options.SearchableConfigurable
-import com.intellij.openapi.options.ShowSettingsUtil
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.DialogPanel
-import com.intellij.space.components.SpaceUserAvatarProvider
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.promo.bigPromoBanner
-import com.intellij.space.promo.promoPanel
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.LoginComponents.buildConnectingPanel
-import com.intellij.space.ui.LoginComponents.loginPanel
-import com.intellij.space.ui.LoginComponents.separatorRow
-import com.intellij.space.ui.cleanupUrl
-import com.intellij.space.ui.resizeIcon
-import com.intellij.space.utils.LifetimedDisposable
-import com.intellij.space.utils.LifetimedDisposableImpl
-import com.intellij.space.utils.SpaceUrls
-import com.intellij.ui.EnumComboBoxModel
-import com.intellij.ui.SimpleTextAttributes
-import com.intellij.ui.components.BrowserLink
-import com.intellij.ui.components.panels.VerticalLayout
-import com.intellij.ui.layout.*
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.UIUtil
-import com.intellij.util.ui.components.BorderLayoutPanel
-import libraries.klogging.logger
-import net.miginfocom.layout.CC
-import net.miginfocom.layout.LC
-import net.miginfocom.swing.MigLayout
-import runtime.reactive.SequentialLifetimes
-import javax.swing.JButton
-import javax.swing.JComponent
-import javax.swing.JLabel
-import javax.swing.JPanel
-
-val log = logger()
-
-class SpaceSettingsPanel :
- BoundConfigurable(SpaceBundle.message("configurable.name"), null),
- SearchableConfigurable,
- LifetimedDisposable by LifetimedDisposableImpl() {
- private val sqLifetime = SequentialLifetimes(lifetime)
-
- override fun getId(): String = "settings.space"
-
- override fun createPanel(): DialogPanel = panel {
- val panelLifetime = sqLifetime.next()
- val accountPanel = BorderLayoutPanel()
- row {
- cell(isFullWidth = true) { accountPanel(pushX, growX) }
- }
- val separatorRow = separatorRow()
- val cloneTypeRow = row {
- cell(isFullWidth = true) {
- label(SpaceBundle.message("settings.panel.clone.repositories.with.label"))
- comboBox(EnumComboBoxModel(CloneType::class.java), SpaceSettings.getInstance()::cloneType)
- createConfigureHttpAndSshLink()().withLargeLeftGap()
- }
- }
-
- SpaceWorkspaceComponent.getInstance().loginState.forEach(panelLifetime) { loginState ->
- accountPanel.removeAll()
- accountPanel.addToCenter(createView(accountPanel, loginState))
- accountPanel.revalidate()
- accountPanel.repaint()
-
- val rowsVisibility = when (loginState) {
- is SpaceLoginState.Connected -> true
- else -> false
- }
- separatorRow.visible = rowsVisibility
- cloneTypeRow.visible = rowsVisibility
- }
- }
-
- private fun createView(wrapper: JComponent, st: SpaceLoginState): JComponent {
- when (st) {
- is SpaceLoginState.Disconnected -> return buildSettingsLoginPanel(st) { server ->
- SpaceWorkspaceComponent.getInstance().signInManually(server, lifetime, wrapper)
- }
-
- is SpaceLoginState.Connecting -> return buildConnectingPanel(st, SpaceStatsCounterCollector.LoginPlace.SETTINGS) {
- st.cancel()
- }
-
- is SpaceLoginState.Connected -> {
- val serverComponent = JLabel(cleanupUrl(st.server)).apply {
- foreground = SimpleTextAttributes.GRAYED_ATTRIBUTES.fgColor
- font = font.deriveFont((font.size * 0.9).toFloat())
- }
- val logoutButton = JButton(SpaceBundle.message("settings.panel.log.out.button.text")).apply {
- addActionListener {
- SpaceWorkspaceComponent.getInstance().signOut(SpaceStatsCounterCollector.LogoutPlace.SETTINGS)
- }
- }
-
- val namePanel = JPanel(VerticalLayout(UIUtil.DEFAULT_VGAP)).apply {
- add(JLabel(st.workspace.me.value.englishFullName())) // NON-NLS
- add(serverComponent)
- }
-
- val infoPanel = JPanel(VerticalLayout(UIUtil.DEFAULT_VGAP)).apply {
- add(namePanel)
- val logoutButtonPanel = BorderLayoutPanel().addToLeft(logoutButton).apply {
- border = JBUI.Borders.emptyTop(5)
- }
- add(logoutButtonPanel)
- }
-
- val avatarLabel = JLabel()
- SpaceUserAvatarProvider.getInstance().avatars.forEach(lifetime) { avatars ->
- avatarLabel.icon = resizeIcon(avatars.circle, 64)
- }
- return JPanel().apply {
- layout = MigLayout(LC().gridGap("${JBUI.scale(10)}", "0")
- .insets("0", "0", "0", "0")
- .fill()).apply {
- columnConstraints = "[][]"
- }
- add(avatarLabel, CC().pushY().alignY("center"))
- add(infoPanel, CC().push())
- }
- }
- }
- }
-
- private fun createConfigureHttpAndSshLink(): JComponent {
- val contentPanel = BorderLayoutPanel().apply {
- isOpaque = false
- }
- SpaceWorkspaceComponent.getInstance().workspace.forEach(lifetime) {
- contentPanel.removeAll()
- if (it != null) {
- val url = SpaceUrls.git(it.me.value.username)
- val browserLink = BrowserLink(SpaceBundle.message("settings.panel.configure.git.ssh.keys.http.password.link"), url).apply {
- addActionListener {
- SpaceStatsCounterCollector.OPEN_GIT_SETTINGS_IN_SPACE.log()
- }
- }
- contentPanel.addToCenter(browserLink)
- }
- contentPanel.revalidate()
- contentPanel.repaint()
- }
- return contentPanel
- }
-
- companion object {
- fun openSettings(project: Project?) {
- ShowSettingsUtil.getInstance().showSettingsDialog(project, SpaceSettingsPanel::class.java)
- }
- }
-}
-
-internal fun buildSettingsLoginPanel(st: SpaceLoginState.Disconnected,
- loginAction: (String) -> Unit
-): DialogPanel {
- return panel {
- loginPanel(st, SpaceStatsCounterCollector.LoginPlace.SETTINGS, isLoginActionDefault = false, withOrganizationsUrlLabel = true,
- loginAction)
- promoPanel(SpaceStatsCounterCollector.ExplorePlace.SETTINGS)
- bigPromoBanner(SpaceStatsCounterCollector.OverviewPlace.SETTINGS)?.let {
- fullRow { it() }
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/stats/SpaceStatsCounterCollector.kt b/plugins/space/src/main/kotlin/com/intellij/space/stats/SpaceStatsCounterCollector.kt
deleted file mode 100644
index da562cf70abb..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/stats/SpaceStatsCounterCollector.kt
+++ /dev/null
@@ -1,363 +0,0 @@
-// 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.
-package com.intellij.space.stats
-
-import circlet.code.api.CodeReviewParticipantRole
-import com.intellij.internal.statistic.eventLog.EventLogGroup
-import com.intellij.internal.statistic.eventLog.events.EventFields
-import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
-import com.intellij.space.settings.SpaceLoginState
-import com.intellij.space.vcs.review.list.ReviewListQuickFilter
-
-internal class SpaceStatsCounterCollector : CounterUsagesCollector() {
- override fun getGroup(): EventLogGroup = GROUP
-
- companion object {
- @JvmField
- val GROUP = EventLogGroup("space", 1)
-
-
- // --------------------
- // General
- // --------------------
-
- @JvmField
- val LOGIN_STATUS = EventFields.Enum("login_status")
-
- @JvmField
- val OPEN_MAIN_TOOLBAR_POPUP = GROUP.registerEvent("open_main_toolbar_popup", LOGIN_STATUS)
-
- @JvmField
- val OPEN_GIT_SETTINGS_IN_SPACE = GROUP.registerEvent("open_git_settings_in_space")
-
- // --------------------
- // Advertisement
- // --------------------
-
- @JvmField
- val EXPLORE_PLACE = EventFields.Enum("adv_explore_place")
-
- @JvmField
- val OVERVIEW_PLACE = EventFields.Enum("adv_overview_place")
-
- @JvmField
- val EXPLORE_SPACE = GROUP.registerEvent("adv_explore_space", EXPLORE_PLACE)
-
- @JvmField
- val WATCH_OVERVIEW = GROUP.registerEvent("adv_watch_overview", OVERVIEW_PLACE)
-
- @JvmField
- val ADV_LOG_IN_LINK = GROUP.registerEvent("adv_log_in_link")
-
- @JvmField
- val SIGN_UP_LINK = GROUP.registerEvent("adv_sign_up_link")
-
- // --------------------
- // Clone
- // --------------------
-
- @JvmField
- val OPEN_SPACE_CLONE_TAB = GROUP.registerEvent("open_space_clone_tab", LOGIN_STATUS)
-
- @JvmField
- val CLONE_REPO = GROUP.registerEvent("clone_repo")
-
- // --------------------
- // Share project
- // --------------------
-
- @JvmField
- val OPEN_SHARE_PROJECT = GROUP.registerEvent("open_share_project", LOGIN_STATUS)
-
- @JvmField
- val START_CREATING_NEW_PROJECT = GROUP.registerEvent("start_creating_new_project")
-
- @JvmField
- val CREATE_NEW_PROJECT = GROUP.registerEvent("create_new_project")
-
- @JvmField
- val SHARE_PROJECT = GROUP.registerEvent("share_project")
-
- // --------------------
- // Chat
- // --------------------
-
- @JvmField
- val SEND_MESSAGE_PLACE = EventFields.Enum("new_message_place")
-
- @JvmField
- val SEND_MESSAGE_IS_PENDING = EventFields.Boolean("new_message_is_pending")
-
- @JvmField
- val EDIT_MESSAGE_IS_EMPTY = EventFields.Boolean("edit_message_is_empty")
-
- @JvmField
- val SEND_MESSAGE = GROUP.registerEvent("chat_send_message", SEND_MESSAGE_PLACE, SEND_MESSAGE_IS_PENDING)
-
- @JvmField
- val DISCARD_SEND_MESSAGE = GROUP.registerEvent("chat_discard_send_message", SEND_MESSAGE_PLACE)
-
- @JvmField
- val START_EDIT_MESSAGE = GROUP.registerEvent("chat_start_edit_message")
-
- @JvmField
- val DISCARD_EDIT_MESSAGE = GROUP.registerEvent("chat_discard_edit_message")
-
- @JvmField
- val SEND_EDIT_MESSAGE = GROUP.registerEvent("chat_send_edit_message", EDIT_MESSAGE_IS_EMPTY)
-
- @JvmField
- val OPEN_THREAD = GROUP.registerEvent("chat_open_thread")
-
- @JvmField
- val DELETE_MESSAGE = GROUP.registerEvent("chat_delete_message")
-
- @JvmField
- val EXPAND_DISCUSSION = GROUP.registerEvent("chat_expand_discussion")
-
- @JvmField
- val COLLAPSE_DISCUSSION = GROUP.registerEvent("chat_collapse_discussion")
-
- @JvmField
- val RESOLVE_DISCUSSION = GROUP.registerEvent("chat_resolve_discussion")
-
- @JvmField
- val REOPEN_DISCUSSION = GROUP.registerEvent("chat_reopen_discussion")
-
- // --------------------
- // Login
- // --------------------
-
- @JvmField
- val LOGIN_PLACE = EventFields.Enum("login_place")
-
- @JvmField
- val LOGOUT_PLACE = EventFields.Enum("logout_place")
-
- @JvmField
- val LOG_IN = GROUP.registerEvent("button_log_in", LOGIN_PLACE)
-
- @JvmField
- val LOG_OUT = GROUP.registerEvent("button_log_out", LOGOUT_PLACE)
-
- @JvmField
- val CANCEL_LOGIN = GROUP.registerEvent("cancel_login", LOGIN_PLACE)
-
- // --------------------
- // ReviewsList
- // --------------------
-
- @JvmField
- val QUICK_FILTER = EventFields.Enum("quick_filter", transform = { it.name })
-
- @JvmField
- val OPEN_REVIEW_TYPE = EventFields.Enum("open_review_type")
-
- @JvmField
- val FILTER_TEXT_EMPTY = EventFields.Boolean("filter_text_empty")
-
- @JvmField
- val REFRESH_REVIEWS_PLACE = EventFields.Enum("refresh_reviews_place")
-
- @JvmField
- val REVIEWS_LOG_IN_LINK = GROUP.registerEvent("reviews_list_log_in_link")
-
- @JvmField
- val CHANGE_QUICK_FILTER = GROUP.registerEvent("reviews_list_change_quick_filter", QUICK_FILTER)
-
- @JvmField
- val CHANGE_TEXT_FILTER = GROUP.registerEvent("reviews_list_change_text_filter", FILTER_TEXT_EMPTY)
-
- @JvmField
- val OPEN_REVIEW = GROUP.registerEvent("reviews_list_open_review", OPEN_REVIEW_TYPE)
-
- @JvmField
- val REFRESH_REVIEWS_ACTION = GROUP.registerEvent("reviews_list_refresh_action", REFRESH_REVIEWS_PLACE)
-
- // --------------------
- // ReviewDetails
- // --------------------
-
- @JvmField
- val PARTICIPANT_ROLE = EventFields.Enum("participant_role", transform = { it.name })
-
- @JvmField
- val PARTICIPANT_EDIT_TYPE = EventFields.Enum("participant_edit_type")
-
- @JvmField
- val COMMITS_SELECTION_TYPE = EventFields.Enum("commits_selection_type")
-
- @JvmField
- val DETAILS_TAB_TYPE = EventFields.Enum("details_tab_type")
-
- @JvmField
- val REVIEW_DIFF_PLACE = EventFields.Enum("review_diff_place")
-
- @JvmField
- val EDIT_PARTICIPANT = GROUP.registerEvent("review_details_edit_participant", PARTICIPANT_ROLE, PARTICIPANT_EDIT_TYPE)
-
- @JvmField
- val EDIT_PARTICIPANT_ICON = GROUP.registerEvent("review_details_add_participant_icon", PARTICIPANT_ROLE)
-
- @JvmField
- val SHOW_TIMELINE = GROUP.registerEvent("review_details_show_timeline")
-
- @JvmField
- val OPEN_PROJECT_IN_SPACE = GROUP.registerEvent("review_details_open_project_in_space")
-
- @JvmField
- val OPEN_REVIEW_IN_SPACE = GROUP.registerEvent("review_details_open_review_in_space")
-
- @JvmField
- val BACK_TO_LIST = GROUP.registerEvent("review_details_back_to_list", DETAILS_TAB_TYPE)
-
- @JvmField
- val CHANGE_COMMITS_SELECTION = GROUP.registerEvent("review_details_change_commits_selection", COMMITS_SELECTION_TYPE)
-
- @JvmField
- val SELECT_DETAILS_TAB = GROUP.registerEvent("review_details_select_details_tab", DETAILS_TAB_TYPE)
-
- @JvmField
- val OPEN_REVIEW_DIFF = GROUP.registerEvent("review_details_open_review_diff", REVIEW_DIFF_PLACE)
-
- @JvmField
- val CHECKOUT_BRANCH = GROUP.registerEvent("review_details_checkout_branch")
-
- @JvmField
- val UPDATE_BRANCH = GROUP.registerEvent("review_details_update_branch")
-
- @JvmField
- val ACCEPT_CHANGES = GROUP.registerEvent("review_details_accept_changes")
-
- @JvmField
- val WAIT_FOR_RESPONSE = GROUP.registerEvent("review_details_wait_for_response")
-
- @JvmField
- val RESUME_REVIEW = GROUP.registerEvent("review_details_resume_review")
-
- // --------------------
- // ReviewDiff
- // --------------------
-
- @JvmField
- val LOADER_TYPE = EventFields.Enum("loader_type")
-
- @JvmField
- val LEAVE_COMMENT = GROUP.registerEvent("review_diff_leave_comment")
-
- @JvmField
- val CLOSE_LEAVE_COMMENT = GROUP.registerEvent("review_diff_close_leave_comment")
-
- @JvmField
- val DIFF_LOADED = GROUP.registerEvent("review_diff_loaded", LOADER_TYPE)
- }
-
-
- // helper classes should be outside the companion to get rid of Companion class in imports and usages
-
- enum class LoginState {
- CONNECTED,
- CONNECTING,
- DISCONNECTED;
-
- companion object {
- fun convert(state: SpaceLoginState) = when (state) {
- is SpaceLoginState.Connected -> CONNECTED
- is SpaceLoginState.Connecting -> CONNECTING
- is SpaceLoginState.Disconnected -> DISCONNECTED
- }
- }
- }
-
- enum class ExplorePlace {
- MAIN_TOOLBAR,
- SETTINGS,
- SHARE,
- CLONE
- }
-
- enum class OverviewPlace {
- MAIN_TOOLBAR,
- SETTINGS,
- CLONE
- }
-
- enum class SendMessagePlace {
- MAIN_CHAT,
- THREAD,
- DIFF,
- NEW_THREAD,
- FIRST_DISCUSSION_ANSWER,
- NEW_DISCUSSION
- }
-
- enum class LoginPlace {
- MAIN_TOOLBAR,
- SETTINGS,
- SHARE,
- CLONE
- }
-
- enum class LogoutPlace {
- ACTION,
- SETTINGS,
- MAIN_TOOLBAR,
- CLONE,
- AUTH_FAIL,
- }
-
- enum class OpenReviewActionType {
- ENTER,
- DOUBLE_CLICK,
- ARROW
- }
-
- enum class RefreshReviewsPlace {
- EMPTY_LIST,
- CONTEXT_MENU
- }
-
- enum class ParticipantEditType {
- ADD,
- REMOVE
- }
-
- enum class CommitsSelectionType {
- SINGLE,
- ALL,
- SUBSET_CONNECTED,
- SUBSET_SPLIT;
-
- companion object {
- fun calculateSelectionType(newSelection: List, commitsCount: Int): CommitsSelectionType =
- when (newSelection.size) {
- commitsCount -> ALL
- 1 -> SINGLE
- else -> calculateSubsetType(newSelection)
- }
-
- private fun calculateSubsetType(newSelection: List): CommitsSelectionType {
- for (i in 1 until newSelection.size) {
- if (newSelection[i - 1] + 1 != newSelection[i]) {
- return SUBSET_SPLIT
- }
- }
- return SUBSET_CONNECTED
- }
- }
- }
-
- enum class DetailsTabType {
- DETAILS,
- COMMITS
- }
-
- enum class ReviewDiffPlace {
- EDITOR,
- DIALOG
- }
-
- enum class LoaderType {
- GIT,
- SPACE
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/stats/SpaceStatsStateCollector.kt b/plugins/space/src/main/kotlin/com/intellij/space/stats/SpaceStatsStateCollector.kt
deleted file mode 100644
index 17204d6d658c..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/stats/SpaceStatsStateCollector.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-package com.intellij.space.stats
-
-import com.intellij.internal.statistic.beans.MetricEvent
-import com.intellij.internal.statistic.eventLog.EventLogGroup
-import com.intellij.internal.statistic.eventLog.events.EventFields
-import com.intellij.internal.statistic.service.fus.collectors.ProjectUsagesCollector
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.Project
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.plugins.pipelines.services.SpaceKtsFileDetector
-import com.intellij.space.settings.CloneType
-import com.intellij.space.settings.SpaceSettings
-import com.intellij.space.stats.SpaceStatsCounterCollector.Companion.LOGIN_STATUS
-import com.intellij.space.vcs.SpaceProjectContext
-
-internal class SpaceStatsStateCollector : ProjectUsagesCollector() {
- override fun getGroup() = GROUP
-
- override fun getMetrics(project: Project): MutableSet {
- val result = HashSet()
- val workspace = SpaceWorkspaceComponent.getInstance()
- result.add(LOGIN_STATE.metric(SpaceStatsCounterCollector.LoginState.convert(workspace.loginState.value)))
-
- val context = SpaceProjectContext.getInstance(project)
- result.add(ASSOCIATED_REPOS_STATE.metric(
- context.currentContext.isAssociatedWithSpaceRepository,
- context.probablyContainsSpaceRepo.value
- ))
-
- val automationScriptDetector = project.service()
- result.add(AUTOMATION_FILE_STATE.metric(automationScriptDetector.dslFile.value != null))
-
- val cloneType = SpaceSettings.getInstance().cloneType
- result.add(GIT_CLONE_TYPE_STATE.metric(cloneType))
-
- return result
- }
-
- companion object {
- @JvmField
- val GROUP = EventLogGroup("space.state", 1)
-
- @JvmField
- val IS_ASSOCIATED_WITH_SPACE_REPO = EventFields.Boolean("is_associated_with_space_repo")
-
- @JvmField
- val IS_PROBABLY_CONTAINS_SPACE_REPO = EventFields.Boolean("is_probably_contains_space_repo")
-
- @JvmField
- val AUTOMATION_FILE_EXISTS = EventFields.Boolean("automation_file_exists")
-
- @JvmField
- val GIT_CLONE_TYPE = EventFields.Enum("type")
-
- @JvmField
- val LOGIN_STATE = GROUP.registerEvent("login_status", LOGIN_STATUS)
-
- @JvmField
- val ASSOCIATED_REPOS_STATE = GROUP.registerEvent(
- "associated_repos_state",
- IS_ASSOCIATED_WITH_SPACE_REPO,
- IS_PROBABLY_CONTAINS_SPACE_REPO
- )
-
- @JvmField
- val AUTOMATION_FILE_STATE = GROUP.registerEvent("automation_file_state", AUTOMATION_FILE_EXISTS)
-
- @JvmField
- val GIT_CLONE_TYPE_STATE = GROUP.registerEvent("git_clone_type", GIT_CLONE_TYPE)
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/tools/SpaceToolWindowFactory.kt b/plugins/space/src/main/kotlin/com/intellij/space/tools/SpaceToolWindowFactory.kt
deleted file mode 100644
index 913c674158a9..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/tools/SpaceToolWindowFactory.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-package com.intellij.space.tools
-
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.wm.ToolWindow
-import com.intellij.openapi.wm.ToolWindowFactory
-import com.intellij.space.plugins.pipelines.ui.SpaceToolWindowService
-import com.intellij.space.utils.computeSafe
-
-class SpaceToolWindowFactory : ToolWindowFactory, DumbAware {
-
- override fun shouldBeAvailable(project: Project): Boolean {
- return false
- }
-
- override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
- val service = project.service()
- service.createToolWindowContent(toolWindow)
- }
-
- override fun isDoNotActivateOnStart(): Boolean {
- return true
- }
-
- companion object {
- const val TOOL_WINDOW_ID = "Space Automation" // NON-NLS
- }
-
-}
-
-val Project.spaceKtsToolwindow: ToolWindow?
- get() = computeSafe {
- toolWindowManager.getToolWindow(SpaceToolWindowFactory.TOOL_WINDOW_ID)
- }
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/tools/Utilities.kt b/plugins/space/src/main/kotlin/com/intellij/space/tools/Utilities.kt
deleted file mode 100644
index 05a2d05334d1..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/tools/Utilities.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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.
-package com.intellij.space.tools
-
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.wm.ToolWindowManager
-import com.intellij.openapi.wm.ex.ToolWindowManagerEx
-
-val Project.toolWindowManager: ToolWindowManager get() = ToolWindowManager.getInstance(this)
-val Project.toolWindowManagerEx: ToolWindowManagerEx get() = ToolWindowManagerEx.getInstanceEx(this)
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/ui/AvatarProvider.kt b/plugins/space/src/main/kotlin/com/intellij/space/ui/AvatarProvider.kt
deleted file mode 100644
index 98e74dcf9350..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/ui/AvatarProvider.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-// 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.
-package com.intellij.space.ui
-
-import circlet.client.api.TD_MemberProfile
-import circlet.client.api.englishFullName
-import circlet.platform.api.TID
-import com.intellij.ui.scale.ScaleContext
-import com.intellij.util.concurrency.annotations.RequiresEdt
-import com.intellij.util.ui.AvatarUtils.generateColoredAvatar
-import com.intellij.util.ui.ImageUtil
-import com.intellij.util.ui.JBImageIcon
-import com.intellij.util.ui.JBValue
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import java.awt.Component
-import java.awt.Graphics
-import javax.swing.Icon
-
-class SpaceAvatarProvider(
- private val lifetime: Lifetime,
- private val component: Component,
- val iconSize: JBValue
-) {
- private val scaleContext = ScaleContext.create(component)
-
- private val avatarIconsCache: MutableMap = HashMap()
-
- private val imageLoader: SpaceImageLoader = SpaceImageLoader.getInstance()
-
- @RequiresEdt
- fun getIcon(user: TD_MemberProfile): Icon {
- val iconSize = iconSize.get()
-
- // so that icons are rescaled when any scale changes (be it font size or current DPI)
- if (scaleContext.update(ScaleContext.create(component))) {
- avatarIconsCache.clear()
- }
-
- return avatarIconsCache.getOrPut(user.id) {
- val gradientIcon = resizeIcon(JBImageIcon(ImageUtil.createCircleImage(
- generateColoredAvatar(
- user.username,
- user.englishFullName()
- )
- )), iconSize)
- val icon = DelegatingIcon(gradientIcon)
-
- user.smallAvatar?.let { tid ->
- launch(lifetime, Ui) {
- val image = imageLoader.loadImageAsync(tid)?.await()
- if (image != null) {
- val circleImage = ImageUtil.createCircleImage(image)
- icon.delegate = resizeIcon(JBImageIcon(circleImage), iconSize)
- component.repaint()
- }
- }
- }
-
- icon
- }
- }
-}
-
-private class DelegatingIcon(var delegate: Icon) : Icon {
- override fun getIconHeight() = delegate.iconHeight
- override fun getIconWidth() = delegate.iconWidth
- override fun paintIcon(c: Component?, g: Graphics?, x: Int, y: Int) = delegate.paintIcon(c, g, x, y)
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/ui/LoginComponents.kt b/plugins/space/src/main/kotlin/com/intellij/space/ui/LoginComponents.kt
deleted file mode 100644
index 89f726523366..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/ui/LoginComponents.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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.
-package com.intellij.space.ui
-
-import com.intellij.execution.ui.FragmentedSettingsUtil
-import com.intellij.ide.IdeBundle
-import com.intellij.ide.ui.fullRow
-import com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI
-import com.intellij.openapi.ui.DialogPanel
-import com.intellij.openapi.ui.OnePixelDivider
-import com.intellij.openapi.ui.panel.ComponentPanelBuilder
-import com.intellij.openapi.util.NlsContexts
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.settings.SpaceLoginState
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.ui.ComponentUtil
-import com.intellij.ui.JBColor
-import com.intellij.ui.SeparatorComponent
-import com.intellij.ui.components.JBLabel
-import com.intellij.ui.components.JBTextField
-import com.intellij.ui.layout.*
-import com.intellij.util.ui.JBFont
-import com.intellij.util.ui.UIUtil
-import javax.swing.JButton
-import javax.swing.JLabel
-import javax.swing.border.Border
-
-internal object LoginComponents {
- @NlsSafe private const val organizationUrlPlaceholder: String = "company.jetbrains.space"
-
- fun LayoutBuilder.loginPanel(
- state: SpaceLoginState.Disconnected,
- statsLoginPlace: SpaceStatsCounterCollector.LoginPlace,
- isLoginActionDefault: Boolean = false,
- withOrganizationsUrlLabel: Boolean = false,
- loginAction: (String) -> Unit
- ) {
- val serverField = organizationUrlTextField(
- state.server,
- 30,
- if (withOrganizationsUrlLabel) organizationUrlPlaceholder
- else SpaceBundle.message("login.input.field.organizations.url.large.placeholder", organizationUrlPlaceholder)
- )
-
- val loginButton = loginButton(statsLoginPlace, default = isLoginActionDefault, onClick = {
- it.isEnabled = false
- loginAction(serverField.text.trim())
- })
-
- fullRow { logIntoSpaceLabel()() }
-
- if (withOrganizationsUrlLabel) {
- row(SpaceBundle.message("login.panel.organization.url.label")) { serverField() }
- row("") { loginButton() }
- }
- else {
- fullRow { serverField() }
- fullRow { loginButton() }
- }
-
- state.error?.let {
- val errorText = errorText(it)
- if (withOrganizationsUrlLabel) {
- fullRow { errorText(growX, pushX) }
- }
- else {
- row("") {
- errorText(growX, pushX)
- }
- }
- }
-
- separatorRow().largeGapAfter()
- }
-
- internal fun organizationUrlTextField(
- @NlsSafe initialText: String = "",
- columns: Int = 0,
- @NlsContexts.StatusText placeholderText: String = organizationUrlPlaceholder
- ): JBTextField {
- return JBTextField(initialText, columns).apply {
- emptyText.text = placeholderText
- accessibleContext.accessibleName = placeholderText
- FragmentedSettingsUtil.setupPlaceholderVisibility(this)
- }
- }
-
- internal fun loginButton(
- statsLoginPlace: SpaceStatsCounterCollector.LoginPlace,
- default: Boolean = false,
- onClick: (JButton) -> Unit
- ): JButton =
- JButton(SpaceBundle.message("login.panel.log.in.button")).apply {
- addActionListener {
- SpaceStatsCounterCollector.LOG_IN.log(statsLoginPlace)
- onClick(this)
- }
- ComponentUtil.putClientProperty(this, DarculaButtonUI.DEFAULT_STYLE_KEY, default)
- }
-
- internal fun logIntoSpaceLabel(): JBLabel = JBLabel(SpaceBundle.message("login.panel.log.in.to.space.label"),
- UIUtil.ComponentStyle.LARGE).apply {
- font = JBFont.label().biggerOn(3.0f)
- }
-
- internal fun errorText(@NlsContexts.DetailedDescription error: String): JLabel =
- ComponentPanelBuilder.createCommentComponent(error, true).apply {
- foreground = JBColor.RED
- }
-
- internal fun RowBuilder.separatorRow(): Row = row {
- SeparatorComponent(0, OnePixelDivider.BACKGROUND, null)()
- }
-
- internal fun buildConnectingPanel(
- st: SpaceLoginState.Connecting,
- statsLoginPlace: SpaceStatsCounterCollector.LoginPlace,
- customBorder: Border? = null,
- cancelAction: () -> Unit
- ): DialogPanel {
- return panel {
- val cancelButton = JButton(IdeBundle.message("button.cancel")).apply {
- addActionListener {
- SpaceStatsCounterCollector.CANCEL_LOGIN.log(statsLoginPlace)
- cancelAction()
- }
- }
- row(SpaceBundle.message("login.panel.connecting.to.server.label", st.server)) {
- cancelButton()
- }
- }.apply {
- customBorder?.let { border = it }
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/ui/ScrollUtils.kt b/plugins/space/src/main/kotlin/com/intellij/space/ui/ScrollUtils.kt
deleted file mode 100644
index fbfef0656820..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/ui/ScrollUtils.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.
-package com.intellij.space.ui
-
-import circlet.platform.client.XPagedListOnFlux
-import com.intellij.ui.components.JBList
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.delay
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import runtime.reactive.Property
-import runtime.reactive.SequentialLifetimes
-import java.awt.event.AdjustmentEvent
-import javax.swing.JScrollPane
-
-
-fun bindScroll(
- lifetime: Lifetime,
- scrollableList: JScrollPane,
- vm: LoadableListVm,
- list: JBList
-) {
- val slVisibility = SequentialLifetimes(lifetime)
-
- fun updateScroll(force: Boolean) {
- if (!lifetime.isTerminated) {
- // run element visibility updater, tracks elements in a view port and set visible to true.
- launch(slVisibility.next(), Ui) {
- delay(300)
- while (vm.isLoading.value) {
- delay(300)
- }
- }
- val last = list.lastVisibleIndex
- if (force || !vm.isLoading.value) {
- vm.xList.value?.let { value ->
- if ((last == -1 || list.model.size < last + 10) && value.hasMore()) {
- launch(lifetime, Ui) {
- value.more()
- updateScroll(true)
- }
- }
- }
- }
- }
- }
-
- val listener: (e: AdjustmentEvent) -> Unit = {
- updateScroll(false)
- }
-
- scrollableList.verticalScrollBar.addAdjustmentListener(listener)
- lifetime.add {
- scrollableList.verticalScrollBar.removeAdjustmentListener(listener)
- }
-}
-
-interface LoadableListVm {
- val isLoading: Property
-
- val xList: Property
-}
-
-data class LoadableListVmImpl(
- override val isLoading: Property,
- override val xList: Property
-) : LoadableListVm
-
-interface LoadableListAdapter {
- fun hasMore(): Boolean
-
- suspend fun more()
-}
-
-fun Property?>.toLoadable(): Property {
- val lla = object : LoadableListAdapter {
- override fun hasMore(): Boolean {
- return this@toLoadable.value?.hasMore?.value ?: false
- }
-
- override suspend fun more() {
- this@toLoadable.value?.more()
- }
- }
- return Property.create(lla)
-}
-
-
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceAccountMenu.kt b/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceAccountMenu.kt
deleted file mode 100644
index 3d2a607c9e9e..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceAccountMenu.kt
+++ /dev/null
@@ -1,241 +0,0 @@
-// 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.
-package com.intellij.space.ui
-
-import com.intellij.icons.AllIcons
-import com.intellij.ide.BrowserUtil
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.popup.PopupStep
-import com.intellij.openapi.ui.popup.util.BaseListPopupStep
-import com.intellij.ui.ColorUtil
-import com.intellij.ui.SimpleTextAttributes
-import com.intellij.ui.awt.RelativePoint
-import com.intellij.ui.components.JBLabel
-import com.intellij.ui.popup.WizardPopup
-import com.intellij.ui.popup.list.ListPopupImpl
-import com.intellij.util.ui.EmptyIcon
-import com.intellij.util.ui.GridBag
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.UIUtil
-import org.jetbrains.annotations.Nls
-import org.jetbrains.annotations.NonNls
-import java.awt.Component
-import java.awt.GridBagLayout
-import java.awt.Point
-import javax.swing.*
-
-sealed class AccountMenuItem(val showSeparatorAbove: Boolean) {
- class Account(
- @Nls val title: String,
- @Nls val info: String,
- val icon: Icon,
- val actions: List = emptyList(),
- showSeparatorAbove: Boolean = false
- ) : AccountMenuItem(showSeparatorAbove)
-
- class Action(
- @Nls val text: String,
- val runnable: () -> Unit,
- val rightIcon: Icon = EmptyIcon.create(AllIcons.Ide.External_link_arrow),
- showSeparatorAbove: Boolean = false
- ) : AccountMenuItem(showSeparatorAbove)
-
- class Group(
- @Nls val text: String,
- val actions: List = emptyList(),
- showSeparatorAbove: Boolean = false
- ) : AccountMenuItem(showSeparatorAbove)
-}
-
-class AccountMenuPopupStep(items: List) : BaseListPopupStep(null, items) {
- override fun hasSubstep(selectedValue: AccountMenuItem?): Boolean {
- val hasSubActions = selectedValue is AccountMenuItem.Account && selectedValue.actions.size > 1
- return hasSubActions
- }
-
- override fun onChosen(selectedValue: AccountMenuItem, finalChoice: Boolean): PopupStep<*>? = when (selectedValue) {
- is AccountMenuItem.Action -> doFinalStep(selectedValue.runnable)
- is AccountMenuItem.Account -> when {
- selectedValue.actions.isEmpty() -> null
- selectedValue.actions.size == 1 -> doFinalStep((selectedValue.actions.first() as AccountMenuItem.Action).runnable)
- else -> AccountMenuPopupStep(selectedValue.actions)
- }
- is AccountMenuItem.Group -> AccountMenuPopupStep(selectedValue.actions)
- }
-
- override fun getBackgroundFor(value: AccountMenuItem?) = UIUtil.getPanelBackground()
-}
-
-class AccountsMenuListPopup(
- project: Project? = null,
- accountMenuPopupStep: AccountMenuPopupStep,
- parent: WizardPopup? = null,
- parentObject: Any? = null
-) : ListPopupImpl(project,
- parent,
- accountMenuPopupStep,
- parentObject
-) {
- override fun getListElementRenderer() = AccountMenuItemRenderer()
-
- override fun createPopup(parent: WizardPopup?, step: PopupStep<*>?, parentValue: Any?) = AccountsMenuListPopup(
- parent?.project,
- step as AccountMenuPopupStep,
- parent,
- parentValue)
-
- override fun showUnderneathOf(aComponent: Component) {
- show(RelativePoint(aComponent, Point(-this.component.preferredSize.width + aComponent.width, aComponent.height)))
- }
-}
-
-class AccountMenuItemRenderer : ListCellRenderer {
- private val leftInset = 12
- private val innerInset = 8
- private val emptyMenuRightArrowIcon = EmptyIcon.create(AllIcons.General.ArrowRight)
- private val separatorBorder = JBUI.Borders.customLine(JBUI.CurrentTheme.Popup.separatorColor(), 1, 0, 0, 0)
-
- private val listSelectionBackground = UIUtil.getListSelectionBackground(true)
-
- private val accountRenderer = AccountItemRenderer()
- private val actionRenderer = ActionItemRenderer()
- private val groupRenderer = GroupItemRenderer()
-
- override fun getListCellRendererComponent(list: JList?,
- value: AccountMenuItem,
- index: Int,
- selected: Boolean,
- focused: Boolean): Component {
- val renderer = when (value) {
- is AccountMenuItem.Account -> accountRenderer.getListCellRendererComponent(null, value, index, selected, focused)
- is AccountMenuItem.Action -> actionRenderer.getListCellRendererComponent(null, value, index, selected, focused)
- is AccountMenuItem.Group -> groupRenderer.getListCellRendererComponent(null, value, index, selected, focused)
- }
- UIUtil.setBackgroundRecursively(renderer, if (selected) listSelectionBackground else UIUtil.getPanelBackground())
- renderer.border = if (value.showSeparatorAbove) separatorBorder else null
- return renderer
- }
-
- private inner class AccountItemRenderer : JPanel(GridBagLayout()), ListCellRenderer {
- private val listSelectionForeground = UIUtil.getListSelectionForeground(true)
-
- val avatarLabel = JLabel()
- val titleComponent = JLabel().apply {
- font = JBUI.Fonts.label().asBold()
- }
- val link = JBLabel().apply {
- font = JBUI.Fonts.smallFont()
- }
- val nextStepIconLabel = JLabel()
-
- init {
- val insets = JBUI.insets(innerInset, leftInset, innerInset, innerInset)
- var gbc = GridBag().setDefaultAnchor(GridBag.WEST)
-
- gbc = gbc.nextLine().next() // 1, |
- .weightx(0.0).fillCellVertically().insets(insets).coverColumn()
- add(avatarLabel, gbc)
-
- gbc = gbc.next() // 2, 1
- .weightx(1.0).weighty(0.5).fillCellHorizontally().anchor(GridBag.LAST_LINE_START)
- add(titleComponent, gbc)
-
- gbc = gbc.next() // 3, |
- .weightx(0.0).insets(insets).coverColumn()
- add(nextStepIconLabel, gbc)
-
- gbc = gbc.nextLine().next().next() // 2, 2
- .weightx(1.0).weighty(0.5).fillCellHorizontally().anchor(GridBag.FIRST_LINE_START)
- add(link, gbc)
- }
-
- override fun getListCellRendererComponent(list: JList?,
- value: AccountMenuItem.Account,
- index: Int,
- selected: Boolean,
- focused: Boolean): JComponent {
- avatarLabel.icon = value.icon
-
- titleComponent.apply {
- text = value.title
- foreground = if (selected) listSelectionForeground else SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES.fgColor
- }
-
- link.apply {
- text = value.info
- foreground = if (selected) listSelectionForeground else SimpleTextAttributes.GRAYED_SMALL_ATTRIBUTES.fgColor
- }
-
- nextStepIconLabel.apply {
- icon = when {
- value.actions.size < 2 -> emptyMenuRightArrowIcon
- selected && ColorUtil.isDark(listSelectionBackground) -> AllIcons.Icons.Ide.NextStepInverted
- else -> AllIcons.Icons.Ide.NextStep
- }
- }
- return this
- }
- }
-
- private inner class ActionItemRenderer : JPanel(GridBagLayout()), ListCellRenderer {
- val actionTextLabel = JLabel()
- val rightIconLabel = JLabel()
-
- init {
- val topBottom = 3
- val insets = JBUI.insets(topBottom, leftInset, topBottom, 0)
-
- var gbc = GridBag().setDefaultAnchor(GridBag.WEST)
- gbc = gbc.nextLine().next().insets(insets)
- add(actionTextLabel, gbc)
- gbc = gbc.next()
- add(rightIconLabel, gbc)
- gbc = gbc.next().fillCellHorizontally().weightx(1.0).anchor(GridBag.EAST)
- .insets(JBUI.insets(topBottom, leftInset, topBottom, innerInset))
- add(JLabel(emptyMenuRightArrowIcon), gbc)
- }
-
- override fun getListCellRendererComponent(list: JList?,
- value: AccountMenuItem.Action,
- index: Int,
- selected: Boolean,
- focused: Boolean): JComponent {
- actionTextLabel.text = value.text
- rightIconLabel.icon = value.rightIcon
- actionTextLabel.foreground = UIUtil.getListForeground(selected, true)
- return this
- }
- }
-
- private inner class GroupItemRenderer : JPanel(GridBagLayout()), ListCellRenderer {
- val actionTextLabel = JLabel()
- val rightIconLabel = JLabel()
-
- init {
- val topBottom = 3
- val insets = JBUI.insets(topBottom, leftInset, topBottom, 0)
-
- var gbc = GridBag().setDefaultAnchor(GridBag.WEST)
- gbc = gbc.nextLine().next().insets(insets)
- add(actionTextLabel, gbc)
- gbc = gbc.next().weightx(1.0)
- add(rightIconLabel, gbc)
- gbc = gbc.next().fillCellHorizontally().weightx(0.0).anchor(GridBag.EAST)
- .insets(JBUI.insets(topBottom, leftInset, topBottom, innerInset))
- add(JLabel(AllIcons.General.ArrowRight), gbc)
- }
-
- override fun getListCellRendererComponent(list: JList?,
- value: AccountMenuItem.Group,
- index: Int,
- selected: Boolean,
- focused: Boolean): JComponent {
- actionTextLabel.text = value.text
- actionTextLabel.foreground = UIUtil.getListForeground(selected, true)
- return this
- }
- }
-}
-
-fun browseAction(@Nls text: String, @NonNls link: String, showSeparatorAbove: Boolean = false): AccountMenuItem.Action {
- return AccountMenuItem.Action(text, { BrowserUtil.browse(link) }, AllIcons.Ide.External_link_arrow, showSeparatorAbove)
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceAutoUpdatableComponentService.kt b/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceAutoUpdatableComponentService.kt
deleted file mode 100644
index 7085deb3bdd1..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceAutoUpdatableComponentService.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-// 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.
-package com.intellij.space.ui
-
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.service
-import com.intellij.space.utils.LifetimedDisposable
-import com.intellij.space.utils.LifetimedDisposableImpl
-import com.intellij.ui.components.panels.Wrapper
-import com.intellij.util.concurrency.annotations.RequiresEdt
-import com.intellij.util.ui.components.BorderLayoutPanel
-import libraries.coroutines.extra.delay
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import runtime.reactive.SequentialLifetimes
-import javax.swing.JComponent
-
-@Service
-internal class SpaceAutoUpdatableComponentService : LifetimedDisposable by LifetimedDisposableImpl() {
- companion object {
- private const val DELAY = 60_000
-
- fun createAutoUpdatableComponent(componentFactory: () -> JComponent) =
- service().createAutoUpdatableComponentImpl(componentFactory)
- }
-
- private val autoUpdateLifetime = SequentialLifetimes(lifetime)
-
- private val componentsToUpdate = mutableListOf()
-
- @RequiresEdt
- private fun createAutoUpdatableComponentImpl(componentFactory: () -> JComponent): JComponent {
- val container = BorderLayoutPanel().apply {
- isOpaque = false
- add(componentFactory())
- }
- val componentToUpdate = ComponentToUpdate(container, componentFactory)
- return object : Wrapper(container) {
- override fun addNotify() {
- super.addNotify()
-
- if (componentsToUpdate.isEmpty()) {
- startUpdating()
- }
- if (componentToUpdate !in componentsToUpdate) {
- componentsToUpdate.add(componentToUpdate)
- }
- }
-
- override fun removeNotify() {
- super.removeNotify()
-
- componentsToUpdate.remove(componentToUpdate)
- if (componentsToUpdate.isEmpty()) {
- stopUpdating()
- }
- }
- }
- }
-
- private fun startUpdating() {
- launch(autoUpdateLifetime.next(), Ui) {
- while (true) {
- delay(DELAY)
- updateComponents()
- }
- }
- }
-
- private fun stopUpdating() {
- autoUpdateLifetime.clear()
- }
-
- private fun updateComponents() {
- componentsToUpdate.forEach { (container, factory) ->
- container.removeAll()
- container.addToCenter(factory())
- container.revalidate()
- container.repaint()
- }
- }
-
- private data class ComponentToUpdate(val container: BorderLayoutPanel, val componentFactory: () -> JComponent)
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceAvatars.kt b/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceAvatars.kt
deleted file mode 100644
index 88f6933fe3c9..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceAvatars.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.
-@file:Suppress("UndesirableClassUsage")
-
-package com.intellij.space.ui
-
-import com.intellij.ui.scale.ScaleContext
-import com.intellij.util.ui.AvatarUtils
-import com.intellij.util.ui.ImageUtil
-import com.intellij.util.ui.ImageUtil.applyQualityRenderingHints
-import com.intellij.util.ui.ImageUtil.createImageByMask
-import com.intellij.util.ui.JBImageIcon
-import com.intellij.util.ui.JBUI
-import icons.SpaceIcons
-import java.awt.Color
-import java.awt.geom.Area
-import java.awt.geom.Ellipse2D
-import java.awt.image.BufferedImage
-import javax.swing.Icon
-import kotlin.math.min
-
-object SpaceAvatarUtils {
- internal fun buildImageWithStatus(image: BufferedImage, statusColor: Color): BufferedImage {
- val size: Int = min(image.width, image.height)
-
- val outerD = size / 2.5
- val innerD = size / 3.5
- val greenSize = (size - (innerD + outerD) / 2).toInt()
-
- val avatarOvalArea = Area(Ellipse2D.Double(0.0, 0.0, size.toDouble(), size.toDouble()))
- val onlineOvalArea = Area(Ellipse2D.Double(greenSize.toDouble(), greenSize.toDouble(), outerD, outerD))
- avatarOvalArea.subtract(onlineOvalArea)
-
- val circleAvatar = createImageByMask(image, avatarOvalArea)
- val g2 = circleAvatar.createGraphics()
- applyQualityRenderingHints(g2)
- g2.paint = statusColor
- g2.fillOval(size - innerD.toInt(), size - innerD.toInt(), innerD.toInt(), innerD.toInt())
- g2.dispose()
- return circleAvatar
- }
-
- fun createAvatars(image: BufferedImage): SpaceAvatars {
- return SpaceAvatars.Image(image)
- }
-
- fun generateAvatars(gradientSeed: String, name: String): SpaceAvatars {
- val generatedImage = AvatarUtils.generateColoredAvatar(gradientSeed, name)
- return createAvatars(generatedImage)
- }
-}
-
-sealed class SpaceAvatars {
- abstract val circle: Icon
- abstract val offline: Icon
- abstract val online: Icon
-
- object MainIcon : SpaceAvatars() {
- override val circle: Icon = SpaceIcons.Main
- override val offline: Icon = SpaceIcons.Main
- override val online: Icon = SpaceIcons.Main
- }
-
- class Image(private val image: BufferedImage) : SpaceAvatars() {
- private val cache: MutableMap, JBImageIcon> = mutableMapOf()
-
- override val circle: Icon by lazy { JBImageIcon(ImageUtil.createCircleImage(image)) }
- override val offline: Icon
- get() = createStatusIcon(Color(224, 85, 85))
- override val online: Icon
- get() = createStatusIcon(Color(98, 181, 67))
-
- private fun createStatusIcon(color: Color): JBImageIcon {
- val size = JBUI.scale(16)
- return cache.getOrPut(color to size) {
- val hiDpi = ImageUtil.ensureHiDPI(SpaceAvatarUtils.buildImageWithStatus(image, color), ScaleContext.create())
- JBImageIcon(ImageUtil.scaleImage(hiDpi, size, size))
- }
- }
- }
-}
-
-
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceImageLoader.kt b/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceImageLoader.kt
deleted file mode 100644
index 99e51404c3ec..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/ui/SpaceImageLoader.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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.
-package com.intellij.space.ui
-
-import circlet.platform.api.TID
-import circlet.platform.api.oauth.TokenSource
-import com.google.common.cache.Cache
-import com.google.common.cache.CacheBuilder
-import com.intellij.execution.process.ProcessIOExecutorService
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.service
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.utils.LifetimedDisposable
-import com.intellij.space.utils.LifetimedDisposableImpl
-import io.ktor.client.HttpClient
-import io.ktor.client.request.get
-import io.ktor.client.request.header
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.ExecutorCoroutineDispatcher
-import kotlinx.coroutines.asCoroutineDispatcher
-import libraries.coroutines.extra.async
-import runtime.async.backoff
-import java.awt.image.BufferedImage
-import java.io.ByteArrayInputStream
-import java.util.concurrent.TimeUnit
-import javax.imageio.ImageIO
-
-@Service
-class SpaceImageLoader: LifetimedDisposable by LifetimedDisposableImpl() {
- private val coroutineDispatcher: ExecutorCoroutineDispatcher = ProcessIOExecutorService.INSTANCE.asCoroutineDispatcher()
-
- private val imageCache: Cache> = CacheBuilder.newBuilder()
- .expireAfterAccess(5, TimeUnit.MINUTES)
- .build()
-
-
- init {
- lifetime.add {
- imageCache.cleanUp()
- }
- SpaceWorkspaceComponent.getInstance().workspace.forEach(lifetime) {
- imageCache.cleanUp()
- }
- }
-
- suspend fun loadImageAsync(imageTID: TID): Deferred? {
- val kCircletClient = SpaceWorkspaceComponent.getInstance().workspace.value?.client ?: return null
-
- val server: String = kCircletClient.server.removeSuffix("/")
- val imagesEndpoint = "${server}/d"
- val tokenSource: TokenSource = kCircletClient.tokenSource
-
- return imageCache.get(imageTID) {
- async(kCircletClient.lifetime, coroutineDispatcher) {
- backoff {
- load(imageTID, tokenSource, imagesEndpoint)
- }
- }
- }
- }
-
- private suspend fun load(imageTID: TID,
- tokenSource: TokenSource,
- imagesEndpoint: String): BufferedImage? {
- val accessToken = tokenSource.token().accessToken
- return HttpClient().use { client ->
- val bytes = client.get("$imagesEndpoint/$imageTID") {
- header("Authorization", "Bearer $accessToken")
- }
- ImageIO.read(ByteArrayInputStream(bytes))
- }
- }
-
- companion object {
- fun getInstance(): SpaceImageLoader = service()
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/ui/Utilities.kt b/plugins/space/src/main/kotlin/com/intellij/space/ui/Utilities.kt
deleted file mode 100644
index 6afab86984df..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/ui/Utilities.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-package com.intellij.space.ui
-
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.openapi.wm.IdeFocusManager
-import com.intellij.util.IconUtil
-import com.intellij.util.ui.JBUI
-import java.awt.Component
-import javax.swing.Icon
-
-fun requestFocus(component: Component?) {
- if (component != null) {
- IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown {
- IdeFocusManager.getGlobalInstance().requestFocus(component, true)
- }
- }
-}
-
-fun resizeIcon(icon: Icon, size: Int): Icon {
- val scale = JBUI.scale(size).toFloat() / icon.iconWidth.toFloat()
- return IconUtil.scale(icon, null, scale)
-}
-
-@NlsSafe
-fun cleanupUrl(@NlsSafe url: String): String = url
- .removePrefix("https://")
- .removePrefix("http://")
- .removeSuffix("/")
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/utils/DateUtilities.kt b/plugins/space/src/main/kotlin/com/intellij/space/utils/DateUtilities.kt
deleted file mode 100644
index 83a57e15d37c..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/utils/DateUtilities.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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.
-package com.intellij.space.utils
-
-import circlet.platform.api.KDateTime
-import circlet.platform.api.millis
-import com.intellij.openapi.util.NlsSafe
-import com.intellij.util.text.JBDateFormat
-
-@NlsSafe
-internal fun Long.formatPrettyDateTime(): String = JBDateFormat.getFormatter().formatPrettyDateTime(this)
-
-@NlsSafe
-internal fun KDateTime.formatPrettyDateTime(): String = this.millis.formatPrettyDateTime()
-
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/utils/Persistence.kt b/plugins/space/src/main/kotlin/com/intellij/space/utils/Persistence.kt
deleted file mode 100644
index ae213c649eda..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/utils/Persistence.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-package com.intellij.space.utils
-
-import com.intellij.credentialStore.CredentialAttributes
-import com.intellij.ide.passwordSafe.PasswordSafe
-import libraries.coroutines.extra.Lifetime
-import runtime.json.JsonElement
-import runtime.json.jsonElement
-import runtime.json.text
-import runtime.persistence.Persistence
-
-object IdeaPasswordSafePersistence : Persistence {
-
- override suspend fun putJson(key: String, value: JsonElement) {
- put(key, value.text())
- }
-
- override suspend fun getJson(key: String): JsonElement? {
- return get(key)?.let { jsonElement(it) }
- }
-
- override suspend fun put(key: String, value: String) {
- PasswordSafe.instance.setPassword(createCredentialAttributes(key), value)
- }
-
- override suspend fun get(key: String): String? =
- PasswordSafe.instance.getPassword(createCredentialAttributes(key))
-
- override suspend fun delete(key: String) {
- PasswordSafe.instance.setPassword(createCredentialAttributes(key), null)
- }
-
- override fun forEach(lifetime: Lifetime, key: String, callback: (String?) -> Unit) {
- TODO("not implemented")
- }
-
- override suspend fun getAllKeys(): List {
- TODO("not implemented")
- }
-
- override suspend fun clear() {
- }
-
- private fun createCredentialAttributes(key: String) =
- CredentialAttributes("${javaClass.name}-$key")
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/utils/SpaceUrls.kt b/plugins/space/src/main/kotlin/com/intellij/space/utils/SpaceUrls.kt
deleted file mode 100644
index f74490b97523..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/utils/SpaceUrls.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.
-package com.intellij.space.utils
-
-import circlet.client.api.*
-import circlet.client.api.apps.ES_App
-import com.intellij.space.settings.SpaceSettings
-import runtime.routing.Location
-
-object SpaceUrls {
- // project
- fun project(key: ProjectKey): String = p(key).toUrl()
- fun projects(): String = Navigator.p.toUrl()
-
- fun repo(key: ProjectKey, repo: String): String = p(key).repo(repo).toUrl()
-
- fun commits(key: ProjectKey, repo: String, hash: String) = p(key).commits(repo, "", hash).toUrl()
-
- fun revision(key: ProjectKey, repo: String, revision: String): String = p(key).revision(repo, revision).toUrl()
-
- fun reviews(key: ProjectKey): String = p(key).reviews().toUrl()
-
- fun review(key: ProjectKey, reviewNumber: Int): String = p(key).review(reviewNumber).toUrl()
-
- fun reviewFiles(key: ProjectKey, reviewNumber: Int, revisions: List): String =
- p(key).reviewFiles(reviewNumber, revisions = revisions).toUrl()
-
- fun checklists(key: ProjectKey): String = p(key).checklists().toUrl()
-
- fun issues(key: ProjectKey): String = p(key).issues().toUrl()
-
- fun fileAnnotate(key: ProjectKey, repo: String, hash: String, relativePath: String, selectedLine: Int? = null): String =
- p(key).fileAnnotate(repo, hash, relativePath, selectedLine).toUrl()
-
- // member
- fun member(profile: TD_MemberProfile): String = member(profile.username)
- fun member(username: String): String = m().member(username).toUrl()
-
- fun git(username: String): String = m().member(username).git.toUrl()
-
- // chats
- fun p2pChat(profile: TD_MemberProfile): String = p2pChat(profile.username)
- fun p2pChat(username: String): String = im().p2pChat(username).toUrl()
-
- fun message(oldContactKey: String, message: ChannelItemRecord): String = im().message(oldContactKey, message).toUrl()
-
- private fun p(projectKey: ProjectKey): ProjectLocation = Navigator.p.project(projectKey)
- private fun m(): MembersLocation = Navigator.m
- private fun im(): ChatsLocation = Navigator.im
-
- // manage
- fun app(app: ES_App): String = Navigator.manage.apps.app(app).href
-
- private fun Location.toUrl(): String = absoluteHref(server())
-
- private fun server(): String = SpaceSettings.getInstance().serverSettings.server
-}
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/utils/Utilities.kt b/plugins/space/src/main/kotlin/com/intellij/space/utils/Utilities.kt
deleted file mode 100644
index 6a4b494e94f5..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/utils/Utilities.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-package com.intellij.space.utils
-
-import com.intellij.notification.Notification
-import com.intellij.notification.NotificationType
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.actionSystem.AnAction
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.components.ComponentManager
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.Computable
-import com.intellij.openapi.util.NlsContexts
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.xml.util.XmlStringUtil
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.LifetimeSource
-import libraries.coroutines.extra.Lifetimed
-import platform.common.ProductName
-
-interface LifetimedDisposable : Disposable, Lifetimed
-
-class LifetimedDisposableImpl : Lifetimed, LifetimedDisposable {
- private val lifetimeSource = LifetimeSource()
-
- override val lifetime: Lifetime get() = lifetimeSource
-
- override fun dispose() {
- lifetimeSource.terminate()
- }
-}
-
-inline fun ComponentManager.getComponent(): T =
- getComponent(T::class.java) ?: throw Error("Component ${T::class.java} not found in container $this")
-
-inline fun Project.getService(): T = service().checkService(this)
-
-inline fun T?.checkService(container: Any): T =
- this ?: throw Error("Service ${T::class.java} not found in container $container")
-
-inline fun C.computeSafe(crossinline compute: C.() -> T?): T? =
- ApplicationManager.getApplication().runReadAction(Computable {
- if (isDisposed) null else compute()
- })
-
-fun notify(@NlsContexts.NotificationContent text: String, actions: List = listOf()) {
- val notification = Notification(
- ProductName,
- SpaceBundle.message("product.name"),
- XmlStringUtil.wrapInHtml(text),
- NotificationType.INFORMATION
- )
- if (actions.isNotEmpty()) {
- notification.addActions(actions)
- }
- notification.notify(null)
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/vcs/PostStartupActivity.kt b/plugins/space/src/main/kotlin/com/intellij/space/vcs/PostStartupActivity.kt
deleted file mode 100644
index 4b814c32bd4b..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/vcs/PostStartupActivity.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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.
-package com.intellij.space.vcs
-
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.startup.StartupActivity
-
-open class PostStartupActivity : StartupActivity {
- override fun runActivity(project: Project) {
- SpaceProjectContext.getInstance(project) // init service
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceHttpPasswordState.kt b/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceHttpPasswordState.kt
deleted file mode 100644
index c0677865f4f7..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceHttpPasswordState.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-package com.intellij.space.vcs
-
-import circlet.client.api.SshKeyData
-import circlet.client.api.td.VcsHostingPassword
-
-sealed class SpaceHttpPasswordState {
- object NotChecked : SpaceHttpPasswordState()
-
- object NotSet : SpaceHttpPasswordState()
-
- class Set(val vcsHostingPassword: VcsHostingPassword) : SpaceHttpPasswordState()
-}
-
-sealed class SpaceKeysState {
- object NotChecked : SpaceKeysState()
-
- object NotSet : SpaceKeysState()
-
- class Set(val sshKeys: List) : SpaceKeysState()
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceOpenInBrowserAction.kt b/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceOpenInBrowserAction.kt
deleted file mode 100644
index 2af011efbc16..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceOpenInBrowserAction.kt
+++ /dev/null
@@ -1,266 +0,0 @@
-// 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.
-package com.intellij.space.vcs
-
-import circlet.client.api.ProjectKey
-import com.intellij.dvcs.repo.VcsRepositoryManager
-import com.intellij.ide.BrowserUtil
-import com.intellij.openapi.actionSystem.*
-import com.intellij.openapi.ide.CopyPasteManager
-import com.intellij.openapi.progress.ProgressIndicator
-import com.intellij.openapi.progress.Task
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.project.DumbAwareAction
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.NlsActions
-import com.intellij.openapi.vcs.VcsDataKeys
-import com.intellij.openapi.vcs.changes.Change
-import com.intellij.openapi.vcs.changes.ChangeListManager
-import com.intellij.openapi.vcs.history.VcsFileRevisionEx
-import com.intellij.openapi.vfs.VfsUtilCore
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.space.actions.SpaceActionUtils
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.utils.SpaceUrls
-import com.intellij.vcs.log.CommitId
-import com.intellij.vcs.log.VcsLogDataKeys
-import com.intellij.vcsUtil.VcsUtil
-import git4idea.GitRevisionNumber
-import git4idea.GitUtil
-import git4idea.history.GitHistoryUtils
-import git4idea.repo.GitRepository
-import icons.SpaceIcons
-import java.awt.datatransfer.StringSelection
-import com.intellij.openapi.util.Ref as Ref1
-
-abstract class SpaceOpenInBrowserActionGroup(@NlsActions.ActionText groupName: String,
- @NlsActions.ActionDescription val description: String) :
- ActionGroup(groupName, description, SpaceIcons.Main),
- DumbAware {
-
- abstract fun getData(dataContext: DataContext): List?
-
- abstract fun buildAction(it: T): AnAction
-
- override fun isPopup(): Boolean = true
-
- override fun canBePerformed(context: DataContext): Boolean = getData(context)?.size == 1
-
- override fun disableIfNoVisibleChildren(): Boolean = false
-
- override fun getChildren(e: AnActionEvent?): Array {
- e ?: return emptyArray()
- val data = getData(e.dataContext) ?: return emptyArray()
- if (data.size <= 1) return emptyArray()
-
- return data.mapNotNull { buildAction(it) }.toTypedArray()
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- getData(e.dataContext)?.let { buildAction(it.first()).actionPerformed(e) }
- }
-}
-
-abstract class SpaceOpenInBrowserAction(@NlsActions.ActionText groupName: String) :
- SpaceOpenInBrowserActionGroup>(groupName, SpaceBundle.message("open.in.browser.group.description")) {
-
- override fun update(e: AnActionEvent) {
- SpaceActionUtils.showIconInActionSearch(e)
- val project = e.project
- if (project != null) {
- val projectContext = SpaceProjectContext.getInstance(project)
- if (projectContext.currentContext.isAssociatedWithSpaceRepository) {
- e.presentation.isEnabledAndVisible = true
-
- return
- }
- }
- e.presentation.isEnabledAndVisible = false
- }
-
- override fun buildAction(it: Pair): AnAction =
- object : AnAction(SpaceBundle.message("open.in.browser.open.for.project.action", it.first.key.key)) {
- override fun actionPerformed(e: AnActionEvent) = BrowserUtil.browse(it.second)
- }
-
- companion object {
- internal fun getProjectAwareUrls(
- context: DataContext,
- urlsBuilder: (ProjectKey) -> String
- ): List>? {
- val project = context.getData(CommonDataKeys.PROJECT) ?: return null
- val description = SpaceProjectContext.getInstance(project).currentContext
-
- return description.reposInProject.keys.map {
- it to urlsBuilder(it.key)
- }.toList()
- }
- }
-}
-
-class OpenChecklists : SpaceOpenInBrowserAction(SpaceBundle.message("open.in.browser.group.checklists")) {
- override fun getData(dataContext: DataContext): List>? {
- return getProjectAwareUrls(dataContext, SpaceUrls::checklists)
- }
-}
-
-class OpenIssues : SpaceOpenInBrowserAction(SpaceBundle.message("open.in.browser.group.issues")) {
- override fun getData(dataContext: DataContext): List>? {
- return getProjectAwareUrls(dataContext, SpaceUrls::issues)
- }
-}
-
-internal abstract class SpaceUrlBasedActionGroup(@NlsActions.ActionText groupName: String,
- @NlsActions.ActionDescription description: String) :
- SpaceOpenInBrowserActionGroup(groupName, description) {
-
- override fun update(e: AnActionEvent) {
- val data = getData(e.dataContext)
- e.presentation.isEnabledAndVisible = (data != null)
- }
-
- override fun getData(dataContext: DataContext): List? {
- val project = dataContext.getData(CommonDataKeys.PROJECT) ?: return null
-
- return getDataFromHistory(dataContext, project)
- ?: getDataFromLog(dataContext, project)
- ?: getDataFromVirtualFile(dataContext, project)
- }
-
- private fun getDataFromVirtualFile(dataContext: DataContext, project: Project): List? {
- val virtualFile = dataContext.getData(CommonDataKeys.VIRTUAL_FILE) ?: return null
- val gitRepository = VcsRepositoryManager.getInstance(project).getRepositoryForFileQuick(virtualFile) ?: return null
- if (gitRepository !is GitRepository) return null
-
- val changeListManager = ChangeListManager.getInstance(project)
- if (changeListManager.isUnversioned(virtualFile)) return null
- if (changeListManager.isIgnoredFile(virtualFile)) return null
-
- val change = changeListManager.getChange(virtualFile)
- if (change != null && change.type == Change.Type.NEW) return null
-
- val repoDescription = findProjectInfo(gitRepository, project) ?: return null
-
- val editor = dataContext.getData(CommonDataKeys.EDITOR)
- val line = if (editor != null && editor.document.lineCount >= 1) {
- editor.caretModel.currentCaret.logicalPosition.line
- }
- else null
-
- return repoDescription.projectInfos.map { UrlData.File(project, it, repoDescription.name, virtualFile, line, gitRepository) }
- }
-
- private fun getDataFromHistory(dataContext: DataContext, project: Project): List? {
- val filePath = dataContext.getData(VcsDataKeys.FILE_PATH) ?: return null
- val fileRevision = dataContext.getData(VcsDataKeys.VCS_FILE_REVISION) ?: return null
- if (fileRevision !is VcsFileRevisionEx) return null
- val gitRepository = GitUtil.getRepositoryManager(project).getRepositoryForFileQuick(filePath) ?: return null
- val repoDescription = findProjectInfo(gitRepository, project) ?: return null
-
- return repoDescription.projectInfos.map { UrlData.FileRevision(project, it, repoDescription.name, fileRevision) }
- }
-
- private fun getDataFromLog(dataContext: DataContext, project: Project): List? {
- val vcsLog = dataContext.getData(VcsLogDataKeys.VCS_LOG) ?: return null
- val selectedCommit = vcsLog.selectedCommits.firstOrNull() ?: return null
- val gitRepository = GitUtil.getRepositoryManager(project).getRepositoryForFileQuick(selectedCommit.root) ?: return null
- val repoDescription = findProjectInfo(gitRepository, project) ?: return null
-
- return repoDescription.projectInfos.map { UrlData.Commit(project, it, repoDescription.name, selectedCommit) }
- }
-
- private fun findProjectInfo(gitRepository: GitRepository, project: Project): SpaceRepoInfo? {
- val spaceContext = SpaceProjectContext.getInstance(project)
-
- return getRemoteUrls(gitRepository)
- .mapNotNull { spaceContext.getRepoDescriptionByUrl(it) }
- .firstOrNull()
- }
-
- private fun getRemoteUrls(gitRepository: GitRepository): List {
- return gitRepository.remotes.flatMap { it.urls }.toList()
- }
-}
-
-internal class SpaceVcsOpenInBrowserActionGroup : SpaceUrlBasedActionGroup(SpaceBundle.message("open.in.browser.group.open.on.space"),
- SpaceBundle.message("open.in.browser.group.description")) {
- override fun buildAction(it: UrlData): AnAction = OpenAction(it)
-}
-
-internal class SpaceCopyLinkActionGroup : SpaceUrlBasedActionGroup(SpaceBundle.message("copy.link.to.space.action"),
- SpaceBundle.message("copy.link.to.space.action.description")) {
- override fun buildAction(it: UrlData): AnAction = CopyLinkAction(it)
-}
-
-internal class OpenAction(private val data: UrlData) : DumbAwareAction(
- SpaceBundle.message("open.in.browser.open.for.project.action", data.info.project.name)
-) {
- override fun actionPerformed(e: AnActionEvent) {
- data.url?.let { BrowserUtil.browse(it) }
- }
-}
-
-internal class CopyLinkAction(private val data: UrlData) : DumbAwareAction(
- SpaceBundle.messagePointer("copy.link.in.project.action", data.info.project.name)
-) {
- override fun actionPerformed(e: AnActionEvent) {
- data.url?.let {
- CopyPasteManager.getInstance().setContents(StringSelection(it))
- }
- }
-}
-
-
-internal sealed class UrlData(val project: Project,
- val info: SpaceProjectInfo,
- val repo: String
-) {
- abstract val url: String?
-
- internal class Commit(project: Project,
- projectKey: SpaceProjectInfo,
- repo: String,
- private val commit: CommitId) : UrlData(project, projectKey, repo) {
- override val url: String
- get() {
- return SpaceUrls.commits(info.key, repo, commit.hash.asString())
- }
- }
-
- internal class FileRevision(project: Project,
- projectKey: SpaceProjectInfo,
- repo: String,
- private val vcsFileRevisionEx: VcsFileRevisionEx) : UrlData(project, projectKey, repo) {
- override val url: String
- get() {
- return SpaceUrls.revision(info.key, repo, vcsFileRevisionEx.revisionNumber.asString())
- }
- }
-
- internal class File(project: Project,
- projectKey: SpaceProjectInfo,
- repo: String,
- private val virtualFile: VirtualFile,
- private val selectedLine: Int? = null,
- private val gitRepository: GitRepository) : UrlData(project, projectKey, repo) {
- override val url: String?
- get() {
- val relativePath = VfsUtilCore.getRelativePath(virtualFile, gitRepository.root) ?: return null
- val hash = getCurrentFileRevisionHash(project, virtualFile) ?: return null
-
- return SpaceUrls.fileAnnotate(info.key, repo, hash, relativePath, selectedLine)
- }
-
- private fun getCurrentFileRevisionHash(project: Project, file: VirtualFile): String? {
- val ref = Ref1()
- object : Task.Modal(project, SpaceBundle.message("open.file.on.space.getting.last.revision.indicator.text"), true) {
- override fun run(indicator: ProgressIndicator) {
- ref.set(GitHistoryUtils.getCurrentRevision(project, VcsUtil.getFilePath(file), GitUtil.HEAD) as GitRevisionNumber?)
- }
-
- override fun onThrowable(error: Throwable) {
- }
- }.queue()
- return if (ref.isNull) null else ref.get().rev
- }
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceProjectContext.kt b/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceProjectContext.kt
deleted file mode 100644
index 685ed427eb34..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceProjectContext.kt
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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.
-package com.intellij.space.vcs
-
-import circlet.client.api.*
-import circlet.client.pr
-import circlet.client.repoService
-import circlet.platform.client.ConnectionStatus
-import circlet.platform.client.resolve
-import circlet.workspaces.Workspace
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.Project
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.utils.LifetimedDisposable
-import com.intellij.space.utils.LifetimedDisposableImpl
-import com.intellij.space.vcs.hosting.SpaceGitHostingChecker
-import git4idea.GitUtil
-import git4idea.repo.GitRemote
-import git4idea.repo.GitRepository
-import git4idea.repo.GitRepositoryChangeListener
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import runtime.async.backoff
-import runtime.reactive.*
-import runtime.reactive.property.mapInit
-
-@Service
-class SpaceProjectContext(project: Project) : LifetimedDisposable by LifetimedDisposableImpl() {
-
- private val remoteUrls: MutableProperty> = Property.createMutable(emptySet())
-
- private val hostingChecker = SpaceGitHostingChecker()
-
- val context: LoadingProperty = lifetime.load(SpaceWorkspaceComponent.getInstance().workspace, remoteUrls) { ws, urls ->
- ws ?: return@load EMPTY
- ws.client.connectionStatus.filter { it is ConnectionStatus.Connected }.awaitFirst(ws.lifetime)
- reloadProjectKeys(ws, urls)
- }
-
- // true if project is associated with Space repository
- val probablyContainsSpaceRepo = lifetime.mapInit(remoteUrls, context, false) { urls, context ->
- val loadedContext = (context as? LoadingValue.Loaded)?.value
- (loadedContext != null && loadedContext.isAssociatedWithSpaceRepository) || hostingChecker.check(urls.map { it.remote }.toSet())
- }
-
- // use it as rare as possible
- // prefer to subscribe on [context]
- val currentContext: Context
- get() = (context.value as? LoadingValue.Loaded)?.value ?: EMPTY
-
- init {
- project.messageBus
- .connect(this)
- .subscribe(GitRepository.GIT_REPO_CHANGE, GitRepositoryChangeListener {
- launch(lifetime, Ui) {
- val newUrls = findRemoteUrls(project)
- remoteUrls.value = newUrls
- }
- })
- remoteUrls.value = findRemoteUrls(project)
- }
-
- fun getRepoDescriptionByUrl(remoteUrl: String): SpaceRepoInfo? {
- val coordinates = currentContext.repoByUrl.keys.find {
- it.url == remoteUrl
- }
-
- return currentContext.repoByUrl[coordinates]
- }
- private fun findRemoteUrls(project: Project): Set {
- return GitUtil.getRepositoryManager(project).repositories.flatMap { gitRepo ->
- gitRepo.remotes.flatMap { remote ->
- remote.urls.map { url ->
- GitRemoteUrlCoordinates(url, remote, gitRepo)
- }
- }
- }.toSet()
- }
-
- private suspend fun reloadProjectKeys(ws: Workspace, urls: Set): Context {
- val reposByUrl: Map = urls.map { url ->
- backoff {
- url to loadProjectKeysForUrl(ws, url)
- }
- }.toMap()
- val reposInProject = HashMap>()
-
- for (repoDescription in reposByUrl.values.filterNotNull()) {
- for (projectDescription in repoDescription.projectInfos) {
- reposInProject.getOrPut(projectDescription, { HashSet() })
- .add(repoDescription)
-
- }
- }
-
- return Context(reposByUrl, reposInProject)
- }
-
- private suspend fun loadProjectKeysForUrl(ws: Workspace, coordinates: GitRemoteUrlCoordinates): SpaceRepoInfo? {
- val repoService: RepositoryService = ws.client.repoService
- val (repoName, projectKeys) = repoService.findByRepositoryUrl(coordinates.url) ?: return null
- val projectService: Projects = ws.client.pr
- val projectInfos = projectKeys
- .map { SpaceProjectInfo(it, projectService.getProject(it.identifier).resolve()) }
- .toSet()
- return SpaceRepoInfo(coordinates.url,
- coordinates.remote,
- coordinates.repository,
- repoName,
- projectInfos)
- }
-
- companion object {
- fun getInstance(project: Project): SpaceProjectContext = project.service()
- }
-}
-
-data class Context(
- val repoByUrl: Map,
-
- val reposInProject: Map>
-) {
- val isAssociatedWithSpaceRepository: Boolean
- get() {
- return repoByUrl.values.filterNotNull().any()
- }
-}
-
-private val EMPTY: Context = Context(emptyMap(), emptyMap())
-
-data class SpaceRepoInfo(
- val url: String,
- val remote: GitRemote,
- val repository: GitRepository,
- val name: String,
- val projectInfos: Set
-)
-
-data class SpaceProjectInfo(
- val key: ProjectKey,
- val project: PR_Project
-)
-
-data class GitRemoteUrlCoordinates(val url: String,
- val remote: GitRemote,
- val repository: GitRepository)
\ No newline at end of file
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceSetGitHttpPasswordDialog.kt b/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceSetGitHttpPasswordDialog.kt
deleted file mode 100644
index 807d69b183d2..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/vcs/SpaceSetGitHttpPasswordDialog.kt
+++ /dev/null
@@ -1,159 +0,0 @@
-// 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.
-package com.intellij.space.vcs
-
-import circlet.client.api.TD_MemberProfile
-import circlet.client.api.identifier
-import circlet.client.api.impl.vcsPasswords
-import circlet.client.repoService
-import circlet.platform.client.KCircletClient
-import com.intellij.credentialStore.CredentialAttributes
-import com.intellij.credentialStore.Credentials
-import com.intellij.credentialStore.generateServiceName
-import com.intellij.ide.passwordSafe.PasswordSafe
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.ui.DialogWrapper
-import com.intellij.openapi.ui.ValidationInfo
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.util.text.StringUtil
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.ui.UIBundle
-import com.intellij.ui.components.JBPasswordField
-import com.intellij.ui.components.JBTextField
-import com.intellij.ui.components.panels.HorizontalLayout
-import com.intellij.ui.layout.*
-import com.intellij.util.UriUtil
-import com.intellij.util.io.URLUtil
-import com.intellij.util.ui.AsyncProcessIcon
-import com.intellij.util.ui.JBUI
-import git4idea.commands.GitHttpAuthenticator
-import libraries.coroutines.extra.LifetimeSource
-import libraries.coroutines.extra.launch
-import libraries.coroutines.extra.usingSource
-import libraries.klogging.logger
-import runtime.RpcException
-import runtime.Ui
-import runtime.message
-import java.util.concurrent.CancellationException
-import javax.swing.JCheckBox
-import javax.swing.JComponent
-import javax.swing.JPanel
-import javax.swing.SwingConstants
-
-internal class SpaceSetGitHttpPasswordDialog(
- private val me: TD_MemberProfile,
- private val client: KCircletClient
-) : DialogWrapper(null, false) {
- private val log = logger()
-
- private val lifetime: LifetimeSource = LifetimeSource()
-
- internal var result: SpaceHttpPasswordState = SpaceHttpPasswordState.NotSet
-
- private val passwordSafe: PasswordSafe = PasswordSafe.instance
-
- private val passwordField: JBPasswordField = JBPasswordField()
- private val rememberPassword: JCheckBox = JCheckBox(UIBundle.message("auth.remember.cb"), passwordSafe.isRememberPasswordByDefault)
-
- private val asyncProcessIcon = AsyncProcessIcon("Set password").apply {
- isVisible = false
- }
-
- init {
- title = SpaceBundle.message("set.http.password.dialog.title")
- setOKButtonText(SpaceBundle.message("set.http.password.dialog.ok.button"))
- init()
- Disposer.register(disposable, Disposable { lifetime.terminate() })
- }
-
- override fun doOKAction() {
- launch(lifetime, Ui) {
- okAction.isEnabled = false
- asyncProcessIcon.isVisible = true
-
- lifetime.usingSource {
- try {
- val password = passwordField.password
- log.info("Trying to set HTTP Git password")
- client.api.vcsPasswords().setVcsPassword(me.identifier, String(password))
- val httpPassword = client.api.vcsPasswords().getVcsPassword(me.identifier)
- log.info("Password set")
-
- result = if (httpPassword == null) SpaceHttpPasswordState.NotSet else SpaceHttpPasswordState.Set(httpPassword)
-
- if (rememberPassword.isSelected) {
- val username = me.username
- val repoService = client.repoService
- val httpUrl = repoService.getRepoUrlPatterns().httpUrl
-
- if (httpUrl != null) {
- val key = makeKey(getGitUrlHost(httpUrl), username)
- val credentialAttributes = CredentialAttributes(generateServiceName("Git HTTP", key), key, GitHttpAuthenticator::class.java)
- val credentials = Credentials(username, password)
- passwordSafe.set(credentialAttributes, credentials)
- }
- }
-
- close(OK_EXIT_CODE)
- }
- catch (e: CancellationException) {
- throw e
- }
- catch (e: RpcException) {
- log.error(e, e.failure.message())
- setErrorText(e.failure.message()) // NON-NLS
- }
- catch (e: Exception) {
- log.error(e, "Unable to set password")
- setErrorText(SpaceBundle.message("set.http.password.dialog.error.text.unable.to.set.password"))
- }
- }
-
- asyncProcessIcon.isVisible = false
- okAction.isEnabled = true
- }
- }
-
- override fun createCenterPanel(): JComponent = panel {
- row(SpaceBundle.message("set.http.password.dialog.username.label")) {
- JBTextField(me.username)().component.apply { // NON-NLS
- isEditable = false
- }
- }
- row(UIBundle.message("auth.password.label")) {
- passwordField().focused()
- }
- row {
- rememberPassword()
- }
- }
-
- override fun doValidate(): ValidationInfo? {
- if (passwordField.password.isEmpty()) {
- return ValidationInfo(SpaceBundle.message("set.http.password.dialog.validation.message.empty.password"), passwordField)
- }
- return null
- }
-
- override fun createSouthPanel(): JComponent {
- val buttons = super.createSouthPanel()
- return JPanel(HorizontalLayout(8, SwingConstants.BOTTOM)).apply {
- asyncProcessIcon.border = buttons.border
- add(asyncProcessIcon, HorizontalLayout.RIGHT)
- add(buttons, HorizontalLayout.RIGHT)
- }
- }
-}
-
-fun makeKey(url: String, login: String): String {
- val pair = UriUtil.splitScheme(url)
- val scheme: String = pair.getFirst()
- return if (!StringUtil.isEmpty(scheme)) {
- scheme + URLUtil.SCHEME_SEPARATOR + login + "@" + pair.getSecond()
- }
- else "$login@$url"
-}
-
-fun getGitUrlHost(url: String): String {
- val host = url.substringAfter("://").substringBefore("/")
- return "http://$host"
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/vcs/clone/SpaceCloneAction.kt b/plugins/space/src/main/kotlin/com/intellij/space/vcs/clone/SpaceCloneAction.kt
deleted file mode 100644
index ebf1d580b11e..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/vcs/clone/SpaceCloneAction.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.
-package com.intellij.space.vcs.clone
-
-import com.intellij.space.actions.SpaceActionUtils
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.CommonDataKeys
-import com.intellij.openapi.project.DumbAwareAction
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vcs.ProjectLevelVcsManager
-import com.intellij.util.ui.cloneDialog.VcsCloneDialog
-
-class SpaceCloneAction : DumbAwareAction() {
- override fun update(e: AnActionEvent) {
- val projectExists = e.project != null
- e.presentation.isEnabledAndVisible = projectExists
- SpaceActionUtils.showIconInActionSearch(e)
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- val project = e.getRequiredData(CommonDataKeys.PROJECT)
- runClone(project)
- }
-
- companion object {
- fun runClone(project: Project) {
- val checkoutListener = ProjectLevelVcsManager.getInstance(project).compositeCheckoutListener
- val dialog = VcsCloneDialog.Builder(project).forExtension(SpaceCloneExtension::class.java)
- if (dialog.showAndGet()) {
- dialog.doClone(checkoutListener)
- }
- }
- }
-}
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/vcs/clone/SpaceCloneComponent.kt b/plugins/space/src/main/kotlin/com/intellij/space/vcs/clone/SpaceCloneComponent.kt
deleted file mode 100644
index cd09c4293aea..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/vcs/clone/SpaceCloneComponent.kt
+++ /dev/null
@@ -1,482 +0,0 @@
-// 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.
-package com.intellij.space.vcs.clone
-
-import circlet.client.api.englishFullName
-import circlet.platform.client.BatchResult
-import circlet.platform.client.KCircletClient
-import com.intellij.dvcs.DvcsRememberedInputs
-import com.intellij.dvcs.repo.ClonePathProvider
-import com.intellij.dvcs.ui.CloneDvcsValidationUtils
-import com.intellij.dvcs.ui.DvcsBundle
-import com.intellij.dvcs.ui.SelectChildTextFieldWithBrowseButton
-import com.intellij.execution.process.ProcessIOExecutorService
-import com.intellij.icons.AllIcons
-import com.intellij.ide.BrowserUtil
-import com.intellij.ide.ui.fullRow
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
-import com.intellij.openapi.progress.ProgressIndicator
-import com.intellij.openapi.progress.Task
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.DialogPanel
-import com.intellij.openapi.ui.ValidationInfo
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.util.text.StringUtil
-import com.intellij.openapi.vcs.CheckoutProvider
-import com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogComponentStateListener
-import com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogExtensionComponent
-import com.intellij.openapi.vfs.LocalFileSystem
-import com.intellij.space.components.SpaceUserAvatarProvider
-import com.intellij.space.components.SpaceWorkspaceComponent
-import com.intellij.space.messages.SpaceBundle
-import com.intellij.space.promo.bigPromoBanner
-import com.intellij.space.promo.promoPanel
-import com.intellij.space.settings.CloneType
-import com.intellij.space.settings.SpaceLoginState
-import com.intellij.space.settings.SpaceSettings
-import com.intellij.space.settings.SpaceSettingsPanel
-import com.intellij.space.stats.SpaceStatsCounterCollector
-import com.intellij.space.ui.*
-import com.intellij.space.ui.LoginComponents.buildConnectingPanel
-import com.intellij.space.ui.LoginComponents.loginPanel
-import com.intellij.space.utils.SpaceUrls
-import com.intellij.space.vcs.SpaceHttpPasswordState
-import com.intellij.space.vcs.SpaceKeysState
-import com.intellij.space.vcs.SpaceSetGitHttpPasswordDialog
-import com.intellij.ui.*
-import com.intellij.ui.components.ActionLink
-import com.intellij.ui.components.JBList
-import com.intellij.ui.components.labels.LinkLabel
-import com.intellij.ui.components.panels.Wrapper
-import com.intellij.ui.layout.*
-import com.intellij.util.containers.ContainerUtil
-import com.intellij.util.ui.UIUtil
-import com.intellij.util.ui.cloneDialog.ListWithSearchComponent
-import com.intellij.util.ui.cloneDialog.VcsCloneDialogUiSpec
-import git4idea.GitUtil
-import git4idea.checkout.GitCheckoutProvider
-import git4idea.commands.Git
-import kotlinx.coroutines.asCoroutineDispatcher
-import libraries.coroutines.extra.*
-import runtime.Ui
-import runtime.reactive.SequentialLifetimes
-import java.awt.event.AdjustmentEvent
-import java.awt.event.MouseAdapter
-import java.awt.event.MouseEvent
-import java.nio.file.Paths
-import javax.swing.*
-import javax.swing.event.ListDataEvent
-import javax.swing.event.ListDataListener
-
-internal class SpaceCloneComponent(val project: Project) : VcsCloneDialogExtensionComponent() {
- // state
- private val uiLifetime = LifetimeSource()
-
- private val wrapper: Wrapper = Wrapper()
- private lateinit var cloneView: CloneView
-
- init {
- Disposer.register(this, Disposable { uiLifetime.terminate() })
-
- val workspace = SpaceWorkspaceComponent.getInstance()
- SpaceStatsCounterCollector.OPEN_SPACE_CLONE_TAB.log(SpaceStatsCounterCollector.LoginState.convert(workspace.loginState.value))
-
- workspace.loginState.forEach(uiLifetime) { st ->
- val view = createView(uiLifetime, st)
- wrapper.setContent(view)
- wrapper.repaint()
- }
- }
-
-
- private fun createView(lifetime: Lifetime, st: SpaceLoginState): JComponent {
- dialogStateListener.onOkActionEnabled(false)
- return when (st) {
- is SpaceLoginState.Connected -> {
- dialogStateListener.onListItemChanged()
- cloneView = CloneView(lifetime, project, dialogStateListener, st)
- cloneView.getView()
- }
-
- is SpaceLoginState.Connecting -> buildConnectingPanel(st, SpaceStatsCounterCollector.LoginPlace.CLONE) {
- st.cancel()
- }
-
- is SpaceLoginState.Disconnected -> buildCloneLoginPanel(st) { serverName ->
- SpaceWorkspaceComponent.getInstance().signInManually(serverName, lifetime, getView())
- }
- }.let { view ->
- UIUtil.addInsets(view, UIUtil.PANEL_REGULAR_INSETS)
- if (st is SpaceLoginState.Disconnected) ScrollPaneFactory.createScrollPane(view, true) else view
- }
- }
-
- private fun buildCloneLoginPanel(st: SpaceLoginState.Disconnected, loginAction: (String) -> Unit): JComponent {
- return panel {
- loginPanel(st, SpaceStatsCounterCollector.LoginPlace.CLONE, isLoginActionDefault = true) {
- loginAction(it)
- }
-
- promoPanel(SpaceStatsCounterCollector.ExplorePlace.CLONE)
-
- bigPromoBanner(SpaceStatsCounterCollector.OverviewPlace.CLONE)?.let {
- fullRow { it() }
- }
- }
- }
-
- override fun doClone(checkoutListener: CheckoutProvider.Listener) {
- SpaceStatsCounterCollector.CLONE_REPO.log()
- cloneView.doClone(checkoutListener)
- }
-
- override fun onComponentSelected() {
- val isConnected = SpaceWorkspaceComponent.getInstance().loginState.value is SpaceLoginState.Connected
- dialogStateListener.onOkActionNameChanged(DvcsBundle.message("clone.button"))
- dialogStateListener.onOkActionEnabled(isConnected && cloneView.getSelectedListItem() != null)
- }
-
- override fun doValidateAll(): List {
- return cloneView.doValidateAll()
- }
-
- override fun getView(): Wrapper = wrapper
-
- override fun getPreferredFocusedComponent(): JComponent = wrapper
-}
-
-private class CloneView(
- private val lifetime: Lifetime,
- private val project: Project,
- dialogStateListener: VcsCloneDialogComponentStateListener,
- private val st: SpaceLoginState.Connected
-) {
- val settings = SpaceSettings.getInstance()
-
- val listModel: CollectionListModel = object : CollectionListModel() {
- init {
- addListDataListener(object : ListDataListener {
- override fun contentsChanged(e: ListDataEvent?) = Unit
- override fun intervalRemoved(e: ListDataEvent?) = Unit
-
- override fun intervalAdded(e: ListDataEvent?) {
- e?.let { event ->
- (event.index0..event.index1).forEach { item ->
- getElementAt(item).repoDetails.forEach(lifetime) { details ->
- if (details != null) {
- val selection = circletProjectListWithSearch.list.selectedIndex
- fireContentsChanged(this, item, item)
- circletProjectListWithSearch.list.selectedIndex = selection
- }
- }
- }
- }
- }
- })
- }
- }
-
- private val directoryField: SelectChildTextFieldWithBrowseButton = SelectChildTextFieldWithBrowseButton(
- ClonePathProvider.defaultParentDirectoryPath(project, DvcsRememberedInputs())).apply {
- val fcd = FileChooserDescriptorFactory.createSingleFolderDescriptor()
- fcd.isShowFileSystemRoots = true
- fcd.isHideIgnored = false
- addBrowseFolderListener(DvcsBundle.message("clone.destination.directory.browser.title"),
- DvcsBundle.message("clone.destination.directory.browser.description"),
- project,
- fcd)
- }
-
- val client: KCircletClient = st.workspace.client
-
- private val circletProjectListWithSearch = ListWithSearchComponent(listModel, SpaceCloneListItemRenderer())
-
- private val searchTextField: SearchTextField = circletProjectListWithSearch.searchField
-
- private val list: JBList = circletProjectListWithSearch.list.apply {
- addListSelectionListener {
- if (it.valueIsAdjusting)
- return@addListSelectionListener
- // selection change is triggered when repo details update, so we can use value here.
- updateSelectedUrl()
- }
- setExpandableItemsEnabled(false)
- }
-
- val accountLabel = JLabel()
-
- private val passwordStatus: SimpleColoredComponent = SimpleColoredComponent().apply {
- isVisible = false
- }
-
- val cloneViewModel = SpaceCloneComponentViewModel(lifetime, st.workspace)
-
- private val linkLabel: LinkLabel<*> = LinkLabel.create(SpaceBundle.message("clone.dialog.link.set.password.text"), null).apply {
- horizontalTextPosition = SwingConstants.LEFT
- iconTextGap = 0
- }
-
- private val useSshLinkLabel = ActionLink(SpaceBundle.message("clone.dialog.link.label.use.ssh")) {
- SpaceSettings.getInstance().cloneType = CloneType.SSH
- cloneViewModel.cloneType.value = SpaceSettings.getInstance().cloneType
- }.apply {
- isVisible = false
- }
-
- private val useHttpLinkLabel = ActionLink(SpaceBundle.message("clone.dialog.link.label.use.http")) {
- SpaceSettings.getInstance().cloneType = CloneType.HTTPS
- cloneViewModel.cloneType.value = SpaceSettings.getInstance().cloneType
- }.apply {
- isVisible = false
- }
-
- var createDirectoryError: ValidationInfo? = null
-
- init {
- cloneViewModel.readyToClone.forEach(lifetime, dialogStateListener::onOkActionEnabled)
-
- cloneViewModel.selectedCloneListItem.forEach(lifetime) { cloneListItem ->
- cloneListItem ?: return@forEach
- val details = cloneListItem.repoDetails.value
- val httpUrl = details?.urls?.httpUrl ?: cloneListItem.repoInfo.name
-
- val path = StringUtil.trimEnd(ClonePathProvider.relativeDirectoryPathForVcsUrl(project, httpUrl), GitUtil.DOT_GIT)
- directoryField.trySetChildPath(path)
- }
-
- cloneViewModel.me.forEach(lifetime) { profile ->
- accountLabel.toolTipText = profile.englishFullName() // NON-NLS
- }
-
- cloneViewModel.repos.batches.forEach(lifetime) { batchResult ->
- when (batchResult) {
- is BatchResult.More -> {
- val selection = circletProjectListWithSearch.list.selectedIndex
- listModel.add(batchResult.items.flatten())
- circletProjectListWithSearch.list.selectedIndex = selection
- }
- is BatchResult.Reset -> listModel.removeAll()
- }
- }
-
- SpaceUserAvatarProvider.getInstance().avatars.forEach(lifetime) { avatars ->
- accountLabel.icon = resizeIcon(avatars.circle, VcsCloneDialogUiSpec.Components.avatarSize)
- }
-
- cloneViewModel.isLoading.forEach(lifetime, list::setPaintBusy)
-
- cloneViewModel.spaceHttpPasswordState.forEach(lifetime) {
- if (cloneViewModel.cloneType.value == CloneType.HTTPS) {
- passwordStatus.clear()
- passwordStatus.append(SpaceBundle.message("clone.dialog.error.http.password.not.set.text"), SimpleTextAttributes.ERROR_ATTRIBUTES)
- linkLabel.setListener({ _, _ -> setGitHttpPassword() }, null)
- linkLabel.text = SpaceBundle.message("clone.dialog.link.set.http.password.text")
- linkLabel.icon = null
-
- passwordStatus.isVisible = it is SpaceHttpPasswordState.NotSet
- linkLabel.isVisible = it is SpaceHttpPasswordState.NotSet
- useSshLinkLabel.isVisible = it is SpaceHttpPasswordState.NotSet
- useHttpLinkLabel.isVisible = false
- }
- }
-
- cloneViewModel.circletKeysState.forEach(lifetime) {
- if (cloneViewModel.cloneType.value == CloneType.SSH) {
- passwordStatus.clear()
- passwordStatus.append(SpaceBundle.message("clone.dialog.error.ssh.is.not.configured.text"), SimpleTextAttributes.ERROR_ATTRIBUTES)
- linkLabel.setListener({ _, _ -> openSshKeysPage() }, null)
- linkLabel.text = SpaceBundle.message("clone.dialog.link.configure.ssh.text")
- linkLabel.icon = AllIcons.Ide.External_link_arrow
-
- passwordStatus.isVisible = it is SpaceKeysState.NotSet
- linkLabel.isVisible = it is SpaceKeysState.NotSet
- useSshLinkLabel.isVisible = false
- useHttpLinkLabel.isVisible = it is SpaceKeysState.NotSet
- }
- }
-
- accountLabel.addMouseListener(object : MouseAdapter() {
- override fun mouseClicked(e: MouseEvent?) {
- showPopupMenu()
- }
-
- private fun showPopupMenu() {
- val host = st.server
- val serverUrl = cleanupUrl(st.server)
- val menuItems: MutableList = mutableListOf()
- menuItems += AccountMenuItem.Account(st.workspace.me.value.englishFullName(), // NON-NLS
- serverUrl,
- resizeIcon(SpaceUserAvatarProvider.getInstance().avatars.value.circle,
- VcsCloneDialogUiSpec.Components.popupMenuAvatarSize),
- listOf(
- browseAction(SpaceBundle.message("clone.dialog.browse.server.action", serverUrl), host)))
- menuItems += browseAction(SpaceBundle.message("clone.dialog.open.projects.action"), SpaceUrls.projects(), true)
- menuItems += AccountMenuItem.Action(SpaceBundle.message("clone.dialog.open.settings.action"),
- {
- SpaceSettingsPanel.openSettings(project)
- updateSelectedUrl()
- },
- showSeparatorAbove = true)
- menuItems += AccountMenuItem.Action(SpaceBundle.message("clone.dialog.logout.action"),
- { SpaceWorkspaceComponent.getInstance().signOut(SpaceStatsCounterCollector.LogoutPlace.CLONE) })
-
- AccountsMenuListPopup(null, AccountMenuPopupStep(menuItems))
- .showUnderneathOf(accountLabel)
- }
- })
- }
-
- private fun setGitHttpPassword() {
- val dialog = SpaceSetGitHttpPasswordDialog(st.workspace.me.value, client)
- if (dialog.showAndGet()) {
- cloneViewModel.spaceHttpPasswordState.value = dialog.result
- }
- }
-
- private fun openSshKeysPage() {
- val profile = st.workspace.me.value
- val gitConfigPage = SpaceUrls.git(profile.username)
- BrowserUtil.browse(gitConfigPage)
- }
-
- fun getView(): DialogPanel {
- return panel {
- row {
- cell(isFullWidth = true) {
- searchTextField.textEditor(pushX, growX)
- JSeparator(JSeparator.VERTICAL)(growY)
- accountLabel()
- }
- }
- row {
- val scrollableList = ScrollPaneFactory.createScrollPane(
- list,
- ScrollPaneFactory.VERTICAL_SCROLLBAR_AS_NEEDED,
- ScrollPaneFactory.HORIZONTAL_SCROLLBAR_NEVER)
-
- bindScroll(scrollableList)
-
- scrollableList(push, grow)
- }
- row(SpaceBundle.message("clone.dialog.directory.to.clone.label.text")) {
- directoryField(growX, pushX)
- }
- row {
- cell(isFullWidth = true) {
- passwordStatus()
- linkLabel()
- useHttpLinkLabel()
- useSshLinkLabel()
- }
- }
- }
- }
-
- private fun bindScroll(scrollableList: JScrollPane) {
- val slVisibility = SequentialLifetimes(lifetime)
-
- lateinit var scrollUpdater: (force: Boolean) -> Unit
-
- scrollUpdater = { force ->
- if (!lifetime.isTerminated) {
- // run element visibility updater, tracks elements in a view port and set visible to true.
- launch(slVisibility.next(), Ui) {
- delay(300)
- while (cloneViewModel.isLoading.value) {
- delay(300)
- }
- val first = list.firstVisibleIndex
- val last = list.lastVisibleIndex
- if (first >= 0 && last >= 0) {
- (first..last).forEach {
- val el = list.model.getElementAt(it)
- el.visible.value = true
- }
- }
- }
- val last = list.lastVisibleIndex
- if (force || !cloneViewModel.isLoading.value) {
- if ((last == -1 || list.model.size < last + 10) && cloneViewModel.repos.hasMore.value) {
- cloneViewModel.isLoading.value = true
- launch(lifetime, Ui) {
- cloneViewModel.repos.more()
- scrollUpdater(true)
- }
- }
- else {
- cloneViewModel.isLoading.value = false
- }
- }
- }
- }
- val listener: (e: AdjustmentEvent) -> Unit = {
- scrollUpdater(false)
- }
-
- scrollableList.verticalScrollBar.addAdjustmentListener(listener)
- lifetime.add {
- scrollableList.verticalScrollBar.removeAdjustmentListener(listener)
- }
- }
-
- fun updateSelectedUrl() {
- cloneViewModel.selectedCloneListItem.value = list.selectedValue
- }
-
- fun getSelectedListItem(): SpaceCloneListItem? {
- return cloneViewModel.selectedCloneListItem.value
- }
-
- fun getDirectory(): String = directoryField.text
-
- fun doValidateAll(): List {
- val list = ArrayList()
- ContainerUtil.addIfNotNull(list, CloneDvcsValidationUtils.checkDirectory(directoryField.text, directoryField.textField))
- return list
- }
-
- fun doClone(checkoutListener: CheckoutProvider.Listener) {
- val cloneListItem = getSelectedListItem() ?: return
-
- object : Task.Backgroundable(project, SpaceBundle.message("clone.dialog.progress.title.loading.repository.details"), false) {
- var details = cloneListItem.repoDetails.value
-
- override fun run(indicator: ProgressIndicator) {
- if (details != null) return
- details = st.workspace.lifetime.usingSource { lt ->
- runBlocking(lt, ProcessIOExecutorService.INSTANCE.asCoroutineDispatcher()) {
- cloneViewModel.loadDetails(cloneListItem)
- }
- }
- }
-
- override fun onSuccess() {
- val url = when (settings.cloneType) {
- CloneType.SSH -> details!!.urls.sshUrl
- CloneType.HTTPS -> details!!.urls.httpUrl
- } ?: return
-
- val directory = getDirectory()
-
- createDirectoryError = CloneDvcsValidationUtils.createDestination(directory)
- if (createDirectoryError != null) {
- return
- }
- val parent = Paths.get(directory).toAbsolutePath().parent
- val lfs = LocalFileSystem.getInstance()
- val destinationParent = lfs.findFileByIoFile(parent.toFile()) ?: lfs.refreshAndFindFileByIoFile(parent.toFile()) ?: return
-
- val directoryName = Paths.get(directory).fileName.toString()
- val parentDirectory = parent.toAbsolutePath().toString()
- GitCheckoutProvider.clone(project,
- Git.getInstance(),
- checkoutListener,
- destinationParent,
- url,
- directoryName,
- parentDirectory)
- }
- }.queue()
- }
-}
-
diff --git a/plugins/space/src/main/kotlin/com/intellij/space/vcs/clone/SpaceCloneComponentViewModel.kt b/plugins/space/src/main/kotlin/com/intellij/space/vcs/clone/SpaceCloneComponentViewModel.kt
deleted file mode 100644
index 3cac242486af..000000000000
--- a/plugins/space/src/main/kotlin/com/intellij/space/vcs/clone/SpaceCloneComponentViewModel.kt
+++ /dev/null
@@ -1,139 +0,0 @@
-// 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.
-package com.intellij.space.vcs.clone
-
-import circlet.client.api.*
-import circlet.client.api.impl.vcsPasswords
-import circlet.client.pr
-import circlet.client.repoService
-import circlet.client.ssh
-import circlet.client.star
-import circlet.platform.api.Ref
-import circlet.platform.client.XPagedListOnFlux
-import circlet.platform.client.resolve
-import circlet.platform.client.resolveRefsOrFetch
-import circlet.platform.client.xTransformedPagedListOnFlux
-import circlet.workspaces.Workspace
-import com.intellij.space.settings.CloneType
-import com.intellij.space.settings.CloneType.HTTPS
-import com.intellij.space.settings.SpaceSettings
-import com.intellij.space.vcs.SpaceHttpPasswordState
-import com.intellij.space.vcs.SpaceKeysState
-import com.intellij.util.ui.cloneDialog.SearchableListItem
-import libraries.coroutines.extra.Lifetime
-import libraries.coroutines.extra.Lifetimed
-import libraries.coroutines.extra.launch
-import runtime.Ui
-import runtime.UiDispatch
-import runtime.dispatchInterval
-import runtime.reactive.MutableProperty
-import runtime.reactive.Property
-import runtime.reactive.mutableProperty
-import runtime.reactive.property.mapInit
-import runtime.utils.mapToSet
-
-internal class SpaceCloneComponentViewModel(
- override val lifetime: Lifetime,
- workspace: Workspace
-) : Lifetimed {
- private val projectService: Projects = workspace.client.pr
- private val repositoryService: RepositoryService = workspace.client.repoService
- private val starService: Star = workspace.client.star
- private val ssh: SshKeys = workspace.client.ssh
-
- val isLoading: MutableProperty = mutableProperty(false)
-
- val me: MutableProperty = workspace.me
-
- val repos: XPagedListOnFlux> = xTransformedPagedListOnFlux(
- client = workspace.client,
- batchSize = 10,
- keyFn = { it.id },
- result = { allProjectRefs ->
- val allProjectsWithRepos = workspace.client.arena.resolveRefsOrFetch {
- allProjectRefs.map { it to it.extensionRef(ProjectReposRecord::class) }
- }
- val starredProjectIds = starService.starredProjects().mapToSet(Ref::id)
-
- allProjectsWithRepos.map { (projectRef, reposRef) ->
- val project = projectRef.resolve()
- val repos = reposRef.resolve().repos
- val isStarred = projectRef.id in starredProjectIds
- repos.map { repo ->
- val detailsProperty = mutableProperty(null)
- val item = SpaceCloneListItem(project, isStarred, repo, detailsProperty)
- item.visible.forEach(lifetime) { visible ->
- launch(lifetime, Ui) {
- if (visible) {
- detailsProperty.value = repositoryService.repositoryDetails(project.key, repo.name)
- }
- }
- }
- item
- }
- }
- }
- ) { batch ->
- projectService.projectsBatch(batch, "", "")
- }
-
- val cloneType: MutableProperty = mutableProperty(SpaceSettings.getInstance().cloneType)
-
- val selectedCloneListItem: MutableProperty = mutableProperty(null)
-
- val spaceHttpPasswordState: MutableProperty = lifetime.mapInit(cloneType, SpaceHttpPasswordState.NotChecked) { cloneType ->
- if (cloneType == CloneType.SSH) return@mapInit SpaceHttpPasswordState.NotChecked
-
- workspace.client.api.vcsPasswords().getVcsPassword(me.value.identifier).let {
- if (it == null) SpaceHttpPasswordState.NotSet else SpaceHttpPasswordState.Set(it)
- }
- } as MutableProperty
-
- val circletKeysState: MutableProperty = run {
- val property: MutableProperty