From 2ecf21fcd19382ba4755a06ded0abdb7dc1b15c4 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Wed, 29 Nov 2023 12:25:53 +0100 Subject: [PATCH 01/39] Changes to support 232 --- .github/workflows/publish-release.yml | 27 ------------------ .github/workflows/publish-snapshot.yml | 28 ------------------- build.gradle.kts | 9 +----- .../gradle/ConfigureGradleIntellijPlugin.kt | 2 +- plugin/build.gradle.kts | 25 ++--------------- .../PackageSearchGradleModelBuilder.java | 21 +++++--------- .../PackageSearchApplicationCachesService.kt | 20 +++++++------ .../services/PackageSearchProjectService.kt | 13 +++++---- .../plugin/ui/model/NoModulesFoundViewMode.kt | 20 ++++++++----- .../plugin/ui/model/ToolWindowViewModel.kt | 11 +++++++- .../ui/model/infopanel/InfoPanelViewModel.kt | 13 ++++++--- .../packageslist/PackageListViewModel.kt | 14 +++++++--- .../plugin/ui/model/tree/TreeViewModel.kt | 14 +++++++--- .../packagesearch/plugin/utils/Utils.kt | 2 +- 14 files changed, 83 insertions(+), 136 deletions(-) delete mode 100644 .github/workflows/publish-release.yml delete mode 100644 .github/workflows/publish-snapshot.yml diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml deleted file mode 100644 index dbede255..00000000 --- a/.github/workflows/publish-release.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Publish to Marketplace - -on: - release: - types: [published] - -jobs: - publish: - name: Publish Package Search to Marketplace - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'zulu' - - uses: gradle/gradle-build-action@v2 - - name: Run :publishShadowPlugin task - run: ./gradlew :plugin:publishShadowPluginToMarketplace publishAllPublicationsToSpaceRepository - env: - MARKETPLACE_TOKEN: ${{ secrets.MARKETPLACE_TOKEN }} - GRADLE_ENTERPRISE_KEY: ${{ secrets.GRADLE_ENTERPRISE_KEY }} - MAVEN_SPACE_PASSWORD: ${{ secrets.MAVEN_SPACE_PASSWORD }} - MAVEN_SPACE_USERNAME: ${{ secrets.MAVEN_SPACE_USERNAME }} diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml deleted file mode 100644 index 11fd1d99..00000000 --- a/.github/workflows/publish-snapshot.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Publish snapshot to TBE - -on: - push: - branches: [ master ] - -jobs: - publish: - name: Publish Package Search Snapshot to TBE - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'zulu' - cache: gradle - - uses: gradle/gradle-build-action@v2 - - name: Run :publishShadowPlugin task - run: ./gradlew :plugin:publishShadowPlugin publishAllPublicationsToSpaceRepository - env: - TOOLBOX_ENTERPRISE_TOKEN: ${{ secrets.TOOLBOX_ENTERPRISE_TOKEN }} - GRADLE_ENTERPRISE_KEY: ${{ secrets.GRADLE_ENTERPRISE_KEY }} - MAVEN_SPACE_PASSWORD: ${{ secrets.MAVEN_SPACE_PASSWORD }} - MAVEN_SPACE_USERNAME: ${{ secrets.MAVEN_SPACE_USERNAME }} diff --git a/build.gradle.kts b/build.gradle.kts index 7d99dc55..7fd9d698 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,14 +14,7 @@ plugins { allprojects { group = "org.jetbrains.packagesearch" - val baseVersion = "2.0.0-SNAPSHOT" - version = when (val ref = getenv("GITHUB_REF")) { - null -> baseVersion - else -> when { - ref.startsWith("refs/tags/") -> ref.removePrefix("refs/tags/") - else -> baseVersion - } - } + version = "1.1.0" repositories { mavenCentral() diff --git a/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt b/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt index 81d2a96c..a7c05ee1 100644 --- a/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt +++ b/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt @@ -15,7 +15,7 @@ fun Project.configureGradleIntellijPlugin(packageSearchExtension: PackageSearchE plugins.withId("org.jetbrains.intellij") { extensions.withType { - version = "233-EAP-SNAPSHOT" + version = "2023.2.5" instrumentCode = false downloadSources = !isCI } diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index afabc733..8699b3ed 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -53,7 +53,7 @@ dependencies { implementation(compose.desktop.macos_x64) implementation(compose.desktop.windows_x64) implementation(packageSearchCatalog.kotlinx.serialization.core) - implementation(packageSearchCatalog.jewel.bridge.ij233) + implementation(packageSearchCatalog.jewel.bridge.ij232) implementation(packageSearchCatalog.ktor.client.logging) implementation(packageSearchCatalog.packagesearch.api.models) implementation(projects.plugin.gradle.base) @@ -95,33 +95,12 @@ tasks { prepareSandbox { runtimeClasspathFiles = tooling } - val snapshotDateSuffix = buildString { - val now = Clock.System.now().toLocalDateTime(TimeZone.UTC) - append(now.year) - append(now.monthNumber) - append(now.dayOfMonth) - append(now.hour.toString().padStart(2, '0')) - append(now.minute.toString().padStart(2, '0')) - append(now.second.toString().padStart(2, '0')) - } patchPluginXml { pluginId = pkgsPluginId - version = when { - project.version.toString().endsWith("-SNAPSHOT") -> "${project.version}-$snapshotDateSuffix" - else -> project.version.toString() - } } val buildShadowPlugin by registering(Zip::class) { group = "intellij" - from(shadowJar) { - rename { - "package-search-plugin" + when { - it.endsWith("-SNAPSHOT.jar") -> it.replace(".jar", "-$snapshotDateSuffix.jar") - .also { logger.lifecycle("Snapshot version -> $it") } - else -> it - } - } - } + from(shadowJar) from(tooling) { rename { "gradle-tooling.jar" } } diff --git a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java index b6ba7fb2..5edae905 100644 --- a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java +++ b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.tooling.AbstractModelBuilderService; import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder; -import org.jetbrains.plugins.gradle.tooling.Message; import org.jetbrains.plugins.gradle.tooling.ModelBuilderContext; import java.util.ArrayList; @@ -100,20 +99,14 @@ public boolean canBuild(String modelName) { return modelName.equals(PackageSearchGradleJavaModel.class.getName()); } + @NotNull @Override - public void reportErrorMessage( - @NotNull String modelName, - @NotNull Project project, - @NotNull ModelBuilderContext context, - @NotNull Exception exception - ) { - context.getMessageReporter() - .createMessage() - .withException(exception) - .withKind(Message.Kind.ERROR) - .withGroup("gradle.packageSearch") - .withText("Error while building Package Search Gradle model") - .reportMessage(project); + public ErrorMessageBuilder getErrorMessageBuilder(@NotNull Project project, @NotNull Exception e) { + return ErrorMessageBuilder + .create(project, e, "Gradle import errors") + .withDescription("Unable to import resolved versions " + + "from configurations in project ''${project.name}'' for" + + " the Dependencies toolwindow."); } } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt index ac383374..6d998bec 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt @@ -10,8 +10,8 @@ import com.intellij.openapi.application.appSystemDir import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level import com.intellij.openapi.components.service -import com.jetbrains.packagesearch.plugin.PackageSearchBundle import com.jetbrains.packagesearch.plugin.core.PackageSearch +import com.jetbrains.packagesearch.plugin.PackageSearchBundle import com.jetbrains.packagesearch.plugin.core.nitrite.buildDefaultNitrate import com.jetbrains.packagesearch.plugin.core.nitrite.div import com.jetbrains.packagesearch.plugin.core.utils.PKGSInternalAPI @@ -23,19 +23,15 @@ import com.jetbrains.packagesearch.plugin.utils.ApiSearchEntry import com.jetbrains.packagesearch.plugin.utils.KtorDebugLogger import com.jetbrains.packagesearch.plugin.utils.PackageSearchApiPackageCache import com.jetbrains.packagesearch.plugin.utils.PackageSearchProjectService -import com.jetbrains.packagesearch.plugin.utils.timer import io.ktor.client.plugins.logging.LogLevel import io.ktor.client.plugins.logging.Logging import java.util.concurrent.CompletableFuture import kotlin.io.path.absolutePathString import kotlin.io.path.div -import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.future.future import kotlinx.coroutines.launch import org.dizitart.no2.IndexOptions @@ -45,23 +41,29 @@ import org.jetbrains.packagesearch.api.v3.http.PackageSearchApiClient import org.jetbrains.packagesearch.api.v3.http.PackageSearchEndpoints @Service(Level.APP) -class PackageSearchApplicationCachesService(private val coroutineScope: CoroutineScope) : Disposable, RecoveryAction { +class PackageSearchApplicationCachesService : RecoveryAction, Disposable { + + + private val coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob()) companion object { private val cacheFilePath - get() = appSystemDir / "caches" / "packagesearch" / "db-${PackageSearch.pluginVersion}.db" + get() = cacheDirectory / "db-${PackageSearch.pluginVersion}.db" + + private val cacheDirectory + get() = appSystemDir / "caches" / "packagesearch" } @PKGSInternalAPI val cache = buildDefaultNitrate( - path = appSystemDir - .resolve(cacheFilePath) + path = cacheFilePath .apply { parent.toFile().mkdirs() } .absolutePathString() ) override fun dispose() { cache.close() + coroutineScope.cancel() } private inline fun getRepository(key: String) = diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt index 6ebf2c54..7f210e1d 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt @@ -48,10 +48,10 @@ import kotlinx.coroutines.flow.stateIn import org.jetbrains.packagesearch.api.v3.ApiRepository @Service(Level.PROJECT) -class PackageSearchProjectService( - override val project: Project, - override val coroutineScope: CoroutineScope, -) : PackageSearchKnownRepositoriesContext { +class PackageSearchProjectService(override val project: Project) : PackageSearchKnownRepositoriesContext, Disposable { + + override val coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob()) + private val restartChannel = Channel() @@ -97,7 +97,7 @@ class PackageSearchProjectService( ) { nativeModules, transformerExtensions, context -> transformerExtensions.flatMap { transformer -> nativeModules.map { module -> - with (context) { + with(context) { transformer.provideModule(module).startWithNull() } } @@ -151,6 +151,9 @@ class PackageSearchProjectService( .launchIn(coroutineScope) } + override fun dispose() { + coroutineScope.cancel() + } } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/NoModulesFoundViewMode.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/NoModulesFoundViewMode.kt index 2e6caa08..2a1f16f5 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/NoModulesFoundViewMode.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/NoModulesFoundViewMode.kt @@ -1,5 +1,6 @@ package com.jetbrains.packagesearch.plugin.ui.model +import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service import com.intellij.openapi.externalSystem.ExternalSystemManager import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder @@ -8,20 +9,21 @@ import com.intellij.openapi.project.Project import com.jetbrains.packagesearch.plugin.core.utils.availableExtensionsFlow import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @Service(Service.Level.PROJECT) -class NoModulesFoundViewMode( - private val project: Project, - private val viewModelScope: CoroutineScope, -) { +class NoModulesFoundViewMode(private val project: Project) : Disposable { + + private val viewModelScope: CoroutineScope = CoroutineScope(SupervisorJob()) val isRefreshing = project.isProjectSyncing .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false) - + val hasExternalProjects = ExternalSystemManager.EP_NAME .availableExtensionsFlow .map { it.isNotEmpty() } @@ -30,7 +32,7 @@ class NoModulesFoundViewMode( started = SharingStarted.WhileSubscribed(), initialValue = ExternalSystemManager.EP_NAME.extensions.isNotEmpty() ) - + fun refreshExternalProjects() { viewModelScope.launch(Dispatchers.Main) { ExternalSystemManager.EP_NAME.extensions @@ -38,5 +40,9 @@ class NoModulesFoundViewMode( .forEach { ExternalSystemUtil.refreshProjects(it) } } } - + + override fun dispose() { + viewModelScope.cancel() + } + } \ No newline at end of file diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt index c257deb4..686c3660 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt @@ -1,5 +1,6 @@ package com.jetbrains.packagesearch.plugin.ui.model +import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level import com.intellij.openapi.components.service @@ -12,6 +13,8 @@ import com.jetbrains.packagesearch.plugin.utils.PackageSearchProjectService import kotlin.random.Random import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine @@ -20,7 +23,9 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @Service(Level.PROJECT) -class ToolWindowViewModel(project: Project, private val viewModelScope: CoroutineScope) { +class ToolWindowViewModel(project: Project) : Disposable { + + private val viewModelScope: CoroutineScope = CoroutineScope(SupervisorJob()) fun openLinkInBrowser(url: String) { viewModelScope.openLinkInBrowser(url) @@ -64,5 +69,9 @@ class ToolWindowViewModel(project: Project, private val viewModelScope: Coroutin started = SharingStarted.Lazily, initialValue = PackageSearchToolWindowState.Loading(message = easterEggMessage) ) + + override fun dispose() { + viewModelScope.cancel() + } } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt index 0fb50cff..996e41d2 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt @@ -1,6 +1,7 @@ package com.jetbrains.packagesearch.plugin.ui.model.infopanel import androidx.compose.foundation.ScrollState +import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level import com.intellij.openapi.components.service @@ -11,6 +12,8 @@ import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItem import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListViewModel import com.jetbrains.packagesearch.plugin.utils.PackageSearchProjectService import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -26,10 +29,9 @@ import kotlinx.coroutines.flow.stateIn import org.jetbrains.packagesearch.api.v3.ApiPackage @Service(Level.PROJECT) -class InfoPanelViewModel( - private val project: Project, - viewModelScope: CoroutineScope, -) { +class InfoPanelViewModel(private val project: Project) : Disposable { + + private val viewModelScope: CoroutineScope = CoroutineScope(SupervisorJob()) private val setDataEventChannel = Channel() @@ -135,6 +137,9 @@ class InfoPanelViewModel( ) } + override fun dispose() { + viewModelScope.cancel() + } } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt index 5f234573..ebe570e4 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt @@ -1,6 +1,7 @@ package com.jetbrains.packagesearch.plugin.ui.model.packageslist import androidx.compose.foundation.lazy.LazyListState +import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level import com.intellij.openapi.components.service @@ -26,6 +27,8 @@ import com.jetbrains.packagesearch.plugin.utils.searchPackages import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow @@ -49,10 +52,10 @@ import org.jetbrains.packagesearch.api.v3.ApiPackage import org.jetbrains.packagesearch.api.v3.search.buildSearchParameters @Service(Level.PROJECT) -class PackageListViewModel( - private val project: Project, - private val viewModelScope: CoroutineScope, -) { +class PackageListViewModel(private val project: Project) : Disposable { + + private val viewModelScope: CoroutineScope = CoroutineScope(SupervisorJob()) + private val isOnline get() = IntelliJApplication.PackageSearchApplicationCachesService @@ -614,4 +617,7 @@ class PackageListViewModel( } } + override fun dispose() { + viewModelScope.cancel() + } } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt index b1815893..32c0b078 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt @@ -1,6 +1,7 @@ package com.jetbrains.packagesearch.plugin.ui.model.tree import androidx.compose.foundation.lazy.LazyListState +import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level import com.intellij.openapi.project.Project @@ -8,6 +9,8 @@ import com.jetbrains.packagesearch.plugin.core.utils.IntelliJApplication import com.jetbrains.packagesearch.plugin.utils.PackageSearchApplicationCachesService import com.jetbrains.packagesearch.plugin.utils.PackageSearchProjectService import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine @@ -18,10 +21,9 @@ import org.jetbrains.jewel.foundation.lazy.tree.TreeState import org.jetbrains.jewel.foundation.lazy.tree.emptyTree @Service(Level.PROJECT) -internal class TreeViewModel( - project: Project, - viewModelScope: CoroutineScope, -) { +internal class TreeViewModel(project: Project) : Disposable { + + private val viewModelScope: CoroutineScope = CoroutineScope(SupervisorJob()) val tree: StateFlow> = combine( project.PackageSearchProjectService.modulesStateFlow, @@ -46,5 +48,9 @@ internal class TreeViewModel( treeState.openNodes = emptySet() } + override fun dispose() { + viewModelScope.cancel() + } + } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt index 5395f555..801bc323 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt @@ -29,7 +29,7 @@ internal val Project.nativeModules: List get() = ModuleManager.getInstance(this).modules.toList() internal val Project.nativeModulesFlow: FlowWithInitialValue> - get() = messageBus.flow(ModuleListener.TOPIC) { + get() = messageBus.flow(ProjectTopics.MODULES) { object : ModuleListener { override fun modulesAdded(project: Project, modules: NativeModules) { trySend(nativeModules) From 2ee98fe814caef1df8400582c465545912323d03 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Thu, 30 Nov 2023 13:35:20 +0100 Subject: [PATCH 02/39] Adapted publication logic for 232 --- .github/workflows/publish-release.yml | 27 ++++++++++++++++++ .github/workflows/publish-snapshot.yml | 28 +++++++++++++++++++ build.gradle.kts | 9 +++++- .../gradle/ConfigureGradleIntellijPlugin.kt | 2 +- plugin/build.gradle.kts | 23 ++++++++++++++- 5 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/publish-release.yml create mode 100644 .github/workflows/publish-snapshot.yml diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 00000000..dbede255 --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,27 @@ +name: Publish to Marketplace + +on: + release: + types: [published] + +jobs: + publish: + name: Publish Package Search to Marketplace + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'zulu' + - uses: gradle/gradle-build-action@v2 + - name: Run :publishShadowPlugin task + run: ./gradlew :plugin:publishShadowPluginToMarketplace publishAllPublicationsToSpaceRepository + env: + MARKETPLACE_TOKEN: ${{ secrets.MARKETPLACE_TOKEN }} + GRADLE_ENTERPRISE_KEY: ${{ secrets.GRADLE_ENTERPRISE_KEY }} + MAVEN_SPACE_PASSWORD: ${{ secrets.MAVEN_SPACE_PASSWORD }} + MAVEN_SPACE_USERNAME: ${{ secrets.MAVEN_SPACE_USERNAME }} diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml new file mode 100644 index 00000000..11fd1d99 --- /dev/null +++ b/.github/workflows/publish-snapshot.yml @@ -0,0 +1,28 @@ +name: Publish snapshot to TBE + +on: + push: + branches: [ master ] + +jobs: + publish: + name: Publish Package Search Snapshot to TBE + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'zulu' + cache: gradle + - uses: gradle/gradle-build-action@v2 + - name: Run :publishShadowPlugin task + run: ./gradlew :plugin:publishShadowPlugin publishAllPublicationsToSpaceRepository + env: + TOOLBOX_ENTERPRISE_TOKEN: ${{ secrets.TOOLBOX_ENTERPRISE_TOKEN }} + GRADLE_ENTERPRISE_KEY: ${{ secrets.GRADLE_ENTERPRISE_KEY }} + MAVEN_SPACE_PASSWORD: ${{ secrets.MAVEN_SPACE_PASSWORD }} + MAVEN_SPACE_USERNAME: ${{ secrets.MAVEN_SPACE_USERNAME }} diff --git a/build.gradle.kts b/build.gradle.kts index 7fd9d698..254f041e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,7 +14,14 @@ plugins { allprojects { group = "org.jetbrains.packagesearch" - version = "1.1.0" + val baseVersion = "232.10227-SNAPSHOT" + version = when (val ref = getenv("GITHUB_REF")) { + null -> baseVersion + else -> when { + ref.startsWith("refs/tags/") -> ref.removePrefix("refs/tags/") + else -> baseVersion + } + } repositories { mavenCentral() diff --git a/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt b/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt index a7c05ee1..4a36a13d 100644 --- a/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt +++ b/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt @@ -15,7 +15,7 @@ fun Project.configureGradleIntellijPlugin(packageSearchExtension: PackageSearchE plugins.withId("org.jetbrains.intellij") { extensions.withType { - version = "2023.2.5" + version = "232.10227.8" instrumentCode = false downloadSources = !isCI } diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 8699b3ed..8f2de792 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -95,12 +95,33 @@ tasks { prepareSandbox { runtimeClasspathFiles = tooling } + val snapshotDateSuffix = buildString { + val now = Clock.System.now().toLocalDateTime(TimeZone.UTC) + append(now.year) + append(now.monthNumber) + append(now.dayOfMonth) + append(now.hour.toString().padStart(2, '0')) + append(now.minute.toString().padStart(2, '0')) + append(now.second.toString().padStart(2, '0')) + } patchPluginXml { pluginId = pkgsPluginId + version = when { + project.version.toString().endsWith("-SNAPSHOT") -> "${project.version}-$snapshotDateSuffix" + else -> project.version.toString() + } } val buildShadowPlugin by registering(Zip::class) { group = "intellij" - from(shadowJar) + from(shadowJar) { + rename { + "package-search-plugin" + when { + it.endsWith("-SNAPSHOT.jar") -> it.replace(".jar", "-$snapshotDateSuffix.jar") + .also { logger.lifecycle("Snapshot version -> $it") } + else -> it + } + } + } from(tooling) { rename { "gradle-tooling.jar" } } From ab90ce92fdd5806fb4a30862ea00ce8979e22498 Mon Sep 17 00:00:00 2001 From: Fabrizio Scarponi <36624359+fscarponi@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:40:44 +0000 Subject: [PATCH 03/39] Adding scrollbars to tree and packages list, added minimum details panel width (#3) Fixing [PKGS-1300](https://youtrack.jetbrains.com/issue/PKGS-1301/Compose-UI-Modules-tree-missing-scrollbars), [PKGS-1301](https://youtrack.jetbrains.com/issue/PKGS-1299/Compose-UI-Details-pane-is-missing-the-scrollbar), [PKGS-1284](https://youtrack.jetbrains.com/issue/PKGS-1284/Compose-UI-Details-panel-should-have-a-minimum-width) (cherry picked from commit ee4ce08d3fe1dc8f1d50682ab8cb5aaf3e511ccd) --- .../plugin/PackageSearchToolWindowFactory.kt | 11 +++-- .../plugin/ui/PackageSearchMetrics.kt | 22 ++++++++-- .../plugin/ui/PackageSearchPackagePanel.kt | 14 +++---- .../plugin/ui/model/tree/TreeViewModel.kt | 3 +- .../packages/PackageSearchCentralPanel.kt | 8 ++++ .../packages/PackageSearchPackageList.kt | 18 +++++--- .../panels/packages/PackageSearchSearchBar.kt | 35 +++++++++++++++- .../packages/items/PackageGroupHeader.kt | 26 +++++++----- .../ui/panels/side/PackageSearchInfoPanel.kt | 8 +++- .../panels/tree/PackageSearchModulesTree.kt | 41 ++++++++++++------- 10 files changed, 135 insertions(+), 51 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt index 4013e26a..d24467c2 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt @@ -7,12 +7,14 @@ import com.intellij.openapi.wm.ToolWindow import com.intellij.openapi.wm.ToolWindowFactory import com.jetbrains.packagesearch.plugin.ui.LocalComponentManager import com.jetbrains.packagesearch.plugin.ui.PackageSearchToolwindow -import com.jetbrains.packagesearch.plugin.ui.panels.packages.packageSearchGlobalColors -import com.jetbrains.packagesearch.plugin.ui.panels.packages.packageSearchTabStyle +import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchTabStyle +import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchTreeStyle +import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchGlobalColors import com.jetbrains.packagesearch.plugin.utils.installActions import org.jetbrains.jewel.bridge.addComposeTab import org.jetbrains.jewel.foundation.LocalGlobalColors import org.jetbrains.jewel.ui.component.styling.LocalDefaultTabStyle +import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle class PackageSearchToolWindowFactory : ToolWindowFactory, DumbAware { override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { @@ -20,8 +22,9 @@ class PackageSearchToolWindowFactory : ToolWindowFactory, DumbAware { toolWindow.addComposeTab(PackageSearchBundle.message("packagesearch.title.tab")) { CompositionLocalProvider( LocalComponentManager provides project, - LocalGlobalColors provides packageSearchGlobalColors(), - LocalDefaultTabStyle provides packageSearchTabStyle() + LocalGlobalColors provides PackageSearchGlobalColors(), + LocalDefaultTabStyle provides PackageSearchTabStyle(), + LocalLazyTreeStyle provides PackageSearchTreeStyle() ) { PackageSearchToolwindow() } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt index 3ae971c9..66d65787 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt @@ -1,10 +1,24 @@ package com.jetbrains.packagesearch.plugin.ui import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import org.jetbrains.jewel.foundation.theme.JewelTheme +import org.jetbrains.jewel.ui.theme.scrollbarStyle object PackageSearchMetrics { + + val scrollbarWidth: Dp + @Composable + get() { + val metrics = JewelTheme.scrollbarStyle.metrics + return metrics.thumbThickness + + metrics.trackPadding.calculateEndPadding(LocalLayoutDirection.current) + } + object Popups { val minWidth: Dp = 50.dp @@ -14,9 +28,9 @@ object PackageSearchMetrics { val maxHeight: Dp = 250.dp } - object PackageList{ - object Item{ - val height= 24.dp + object PackageList { + object Item { + val height = 24.dp val padding = 8.dp } } @@ -24,7 +38,7 @@ object PackageSearchMetrics { val searchBarHeight = 36.dp val treeActionsHeight = searchBarHeight - object Dropdown{ + object Dropdown { val maxHeight = 100.dp } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt index 7b7165c2..871f01f2 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt @@ -1,15 +1,12 @@ package com.jetbrains.packagesearch.plugin.ui import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule -import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItem import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchCentralPanel import com.jetbrains.packagesearch.plugin.ui.panels.side.PackageSearchInfoPanel import com.jetbrains.packagesearch.plugin.ui.panels.tree.PackageSearchModulesTree -import org.jetbrains.jewel.foundation.lazy.SelectableLazyListState import org.jetbrains.jewel.ui.component.HorizontalSplitLayout @Composable @@ -17,7 +14,7 @@ fun PackageSearchPackagePanel( onSelectionModulesSelectionChanged: (Set) -> Unit, isInfoPanelOpen: Boolean, onLinkClick: (String) -> Unit, - onPackageEvent:(PackageListItemEvent) -> Unit, + onPackageEvent: (PackageListItemEvent) -> Unit, ) { HorizontalSplitLayout( first = { PackageSearchModulesTree(it, onSelectionModulesSelectionChanged) }, @@ -25,12 +22,13 @@ fun PackageSearchPackagePanel( if (isInfoPanelOpen) { HorizontalSplitLayout( modifier = it, - initialDividerPosition = 700.dp, + initialDividerPosition = 900.dp, first = { PackageSearchCentralPanel(it, onLinkClick) }, - second = { PackageSearchInfoPanel(it, onLinkClick, onPackageEvent) } + second = { PackageSearchInfoPanel(it, onLinkClick, onPackageEvent) }, + maxRatio = 0.8f ) } else PackageSearchCentralPanel(it, onLinkClick) - } + }, + minRatio = 0.1f, ) } - diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt index 32c0b078..99427a71 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt @@ -33,7 +33,8 @@ internal class TreeViewModel(project: Project) : Disposable { } .stateIn(viewModelScope, SharingStarted.Lazily, emptyTree()) - val treeState = TreeState(SelectableLazyListState(LazyListState())) + internal val lazyListState = LazyListState() + internal val treeState = TreeState(SelectableLazyListState(lazyListState)) val isOnline get() = IntelliJApplication.PackageSearchApplicationCachesService diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt index fbd9ee59..2493715e 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt @@ -2,16 +2,20 @@ package com.jetbrains.packagesearch.plugin.ui.panels.packages import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListViewModel import com.jetbrains.packagesearch.plugin.ui.viewModel import org.jetbrains.jewel.ui.Orientation import org.jetbrains.jewel.ui.component.Divider import org.jetbrains.jewel.ui.component.IndeterminateHorizontalProgressBar +import org.jetbrains.jewel.ui.component.VerticalScrollbar @Composable fun PackageSearchCentralPanel( @@ -39,6 +43,10 @@ fun PackageSearchCentralPanel( selectableLazyListState = viewModel.selectableLazyListState, onPackageEvent = viewModel::onPackageListItemEvent, ) + VerticalScrollbar( + adapter = rememberScrollbarAdapter(scrollState = viewModel.selectableLazyListState.lazyListState), + modifier = Modifier.fillMaxHeight().align(Alignment.CenterEnd), + ) } } val isLoading by viewModel.isLoadingFlow.collectAsState() diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt index 7660a4d3..c1cd2916 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt @@ -46,7 +46,7 @@ import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemE import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent.OnPackageAction.GoToSource import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent.OnPackageAction.Install import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent.OnPackageAction.Remove -import com.jetbrains.packagesearch.plugin.ui.panels.packages.items.PackageListItem +import com.jetbrains.packagesearch.plugin.ui.panels.packages.items.PackageListHeader import org.jetbrains.jewel.foundation.lazy.SelectableLazyColumn import org.jetbrains.jewel.foundation.lazy.SelectableLazyItemScope import org.jetbrains.jewel.foundation.lazy.SelectableLazyListState @@ -60,6 +60,7 @@ import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle @Composable fun PackageSearchPackageList( + modifier: Modifier = Modifier, packagesList: List, isCompact: Boolean, selectableLazyListState: SelectableLazyListState, @@ -67,6 +68,7 @@ fun PackageSearchPackageList( ) { var openPopupId by remember { mutableStateOf(null) } SelectableLazyColumn( + modifier = modifier, selectionMode = SelectionMode.Single, state = selectableLazyListState, onSelectedIndexesChanged = { @@ -80,12 +82,17 @@ fun PackageSearchPackageList( ) { packagesList.forEachIndexed { index, item -> when (item) { - is PackageListItem.Header -> stickyHeader(item.id, "header") { - PackageListItem(item, onPackageEvent) + is PackageListItem.Header -> stickyHeader(key = item.id, contentType = "header") { + PackageListHeader( + additionalContentModifier = Modifier.padding(end = PackageSearchMetrics.scrollbarWidth), + content = item, + onEvent = onPackageEvent + ) } - is PackageListItem.Package -> item(item.id, contentType = item.contentType()) { + is PackageListItem.Package -> item(key = item.id, contentType = item.contentType()) { PackageListItem( + modifier = Modifier.padding(end = PackageSearchMetrics.scrollbarWidth), content = item, packagesList = packagesList, index = index, @@ -103,6 +110,7 @@ fun PackageSearchPackageList( @Composable private fun SelectableLazyItemScope.PackageListItem( + modifier: Modifier = Modifier, content: PackageListItem.Package, packagesList: List, index: Int, @@ -117,7 +125,7 @@ private fun SelectableLazyItemScope.PackageListItem( isLastItem = packagesList.getOrNull(index + 1) !is PackageListItem.Package ) Box( - modifier = Modifier + modifier = modifier .padding(itemPaddings) .onClick( interactionSource = remember { MutableInteractionSource() }, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt index 5dd1f894..3379b748 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt @@ -1,7 +1,9 @@ package com.jetbrains.packagesearch.plugin.ui.panels.packages import androidx.compose.animation.Crossfade +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -10,6 +12,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.dp import com.intellij.icons.AllIcons import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message @@ -21,7 +24,10 @@ import org.jetbrains.jewel.ui.component.Icon import org.jetbrains.jewel.ui.component.IconButton import org.jetbrains.jewel.ui.component.Text import org.jetbrains.jewel.ui.component.TextField +import org.jetbrains.jewel.ui.component.styling.LazyTreeMetrics +import org.jetbrains.jewel.ui.component.styling.LazyTreeStyle import org.jetbrains.jewel.ui.component.styling.LocalDefaultTabStyle +import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle import org.jetbrains.jewel.ui.component.styling.LocalTextFieldStyle import org.jetbrains.jewel.ui.component.styling.TabMetrics import org.jetbrains.jewel.ui.component.styling.TabStyle @@ -82,7 +88,7 @@ fun PackageSearchSearchBar( } @Composable -internal fun packageSearchTabStyle(): TabStyle { +internal fun PackageSearchTabStyle(): TabStyle { val current = LocalDefaultTabStyle.current return TabStyle( colors = current.colors, @@ -99,7 +105,7 @@ internal fun packageSearchTabStyle(): TabStyle { @Composable -fun packageSearchGlobalColors(): GlobalColors { +fun PackageSearchGlobalColors(): GlobalColors { val colors = LocalGlobalColors.current return remember(colors) { @@ -118,3 +124,28 @@ fun packageSearchGlobalColors(): GlobalColors { } } + +@Composable +internal fun PackageSearchTreeStyle(): LazyTreeStyle { + val currentStyle = LocalLazyTreeStyle.current + val paddings = currentStyle.metrics.elementPadding + return LazyTreeStyle( + currentStyle.colors, + metrics = LazyTreeMetrics( + indentSize = currentStyle.metrics.indentSize, + elementPadding = PaddingValues( + top = paddings.calculateTopPadding(), + bottom = paddings.calculateBottomPadding(), + start = paddings.calculateStartPadding(LocalLayoutDirection.current), + end = 0.dp + ), + elementContentPadding = currentStyle.metrics.elementContentPadding, + elementMinHeight = currentStyle.metrics.elementMinHeight, + chevronContentGap = currentStyle.metrics.chevronContentGap, + elementBackgroundCornerSize = currentStyle.metrics.elementBackgroundCornerSize, + ), + currentStyle.icons, + ) +} + + diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt index 86175c3b..01bb324b 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt @@ -32,7 +32,8 @@ import org.jetbrains.jewel.ui.component.Link import org.jetbrains.jewel.ui.component.Text @Composable -fun PackageListItem( +fun PackageListHeader( + additionalContentModifier: Modifier = Modifier, content: PackageListItem.Header, onEvent: (PackageListItemEvent) -> Unit, ) { @@ -107,17 +108,22 @@ fun PackageListItem( } } if (content.additionalContent != null) { - when (content.additionalContent) { - is PackageListItem.Header.AdditionalContent.VariantsText -> - LabelInfo( - text = content.additionalContent.text, - maxLines = 1 - ) + Box( + modifier = additionalContentModifier, + ) { + + when (content.additionalContent) { + is PackageListItem.Header.AdditionalContent.VariantsText -> + LabelInfo( + text = content.additionalContent.text, + maxLines = 1 + ) - is PackageListItem.Header.AdditionalContent.UpdatesAvailableCount -> - UpdateAllLink(content.additionalContent, content, onEvent) + is PackageListItem.Header.AdditionalContent.UpdatesAvailableCount -> + UpdateAllLink(content.additionalContent, content, onEvent) - PackageListItem.Header.AdditionalContent.Loading -> CircularProgressIndicator() + PackageListItem.Header.AdditionalContent.Loading -> CircularProgressIndicator() + } } } } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt index dedaf526..8436175e 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.jetbrains.packagesearch.plugin.PackageSearchBundle +import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics import com.jetbrains.packagesearch.plugin.ui.bridge.LabelInfo import com.jetbrains.packagesearch.plugin.ui.model.infopanel.InfoPanelContent import com.jetbrains.packagesearch.plugin.ui.model.infopanel.InfoPanelViewModel @@ -56,7 +57,7 @@ fun PackageSearchInfoPanel( Box(modifier = Modifier.fillMaxWidth()) { Column( modifier = Modifier - .padding(start = 4.dp, top = 4.dp, end = 16.dp, bottom = 12.dp) + .padding(start = 4.dp, end = PackageSearchMetrics.scrollbarWidth) .verticalScroll(viewModel.scrollState) ) { val tab = activeTab @@ -83,7 +84,10 @@ private fun NoTabsAvailable() { Modifier.fillMaxSize(), contentAlignment = Alignment.Center, ) { - LabelInfo(PackageSearchBundle.message("packagesearch.ui.toolwindow.packages.details.noItemSelected"), textAlign = TextAlign.Center) + LabelInfo( + PackageSearchBundle.message("packagesearch.ui.toolwindow.packages.details.noItemSelected"), + textAlign = TextAlign.Center + ) } } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt index 93fcf62c..3e2aadfb 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt @@ -3,14 +3,17 @@ package com.jetbrains.packagesearch.plugin.ui.panels.tree import androidx.compose.animation.Crossfade import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -38,6 +41,7 @@ import org.jetbrains.jewel.ui.component.IconButton import org.jetbrains.jewel.ui.component.LazyTree import org.jetbrains.jewel.ui.component.Text import org.jetbrains.jewel.ui.component.Tooltip +import org.jetbrains.jewel.ui.component.VerticalScrollbar @Composable fun PackageSearchModulesTree( @@ -76,21 +80,28 @@ fun PackageSearchModulesTree( .toSet() } } - - LazyTree( - modifier = Modifier.padding(top = 4.dp), - tree = tree, - treeState = viewModel.treeState, - onSelectionChange = { - onSelectionChanged( - it.map { it.id } - .filterIsInstance() - .toSet() - ) - }, - ) { item -> - TreeItem(item) + Box { + LazyTree( + modifier = Modifier.padding(top = 4.dp, end = PackageSearchMetrics.scrollbarWidth), + tree = tree, + treeState = viewModel.treeState, + onSelectionChange = { + onSelectionChanged( + it.map { it.id } + .filterIsInstance() + .toSet() + ) + }, + ) { item -> + TreeItem(item) + } + VerticalScrollbar( + adapter = rememberScrollbarAdapter(scrollState = viewModel.lazyListState), + modifier = Modifier.fillMaxHeight().align(Alignment.CenterEnd), + ) } + + } @Composable @@ -181,7 +192,7 @@ private fun TreeItem(element: Tree.Element) { } if (element.data.hasUpdates) { Icon( - modifier = Modifier.padding(end = 20.dp), + modifier = Modifier.padding(end = 12.dp), resource = "icons/intui/upgradableMark.svg", iconClass = IconProvider::class.java, contentDescription = "" From 0e8ada8ef285643f217650a17d01538ba2aea940 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Mon, 4 Dec 2023 19:08:48 +0100 Subject: [PATCH 04/39] Adapted publication logic for snapshots --- .github/workflows/publish-snapshot.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index 11fd1d99..f95430ef 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -1,8 +1,6 @@ name: Publish snapshot to TBE -on: - push: - branches: [ master ] +on: [ push ] jobs: publish: From 6a4d26193b0719166733eeb1daf0417b8c66d3c5 Mon Sep 17 00:00:00 2001 From: Fabrizio Scarponi <36624359+fscarponi@users.noreply.github.com> Date: Mon, 4 Dec 2023 18:59:36 +0000 Subject: [PATCH 05/39] Details panel has spurious padding at the top and bottom (cherry picked from commit 3de49fe313d84196770a9be24777a46cd881704a) --- .../packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt | 2 +- .../plugin/ui/panels/side/PackageSearchInfoPanel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt index 25785349..f4cdc9d7 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt @@ -48,7 +48,7 @@ internal fun PackageOverviewTab( ) { Column( verticalArrangement = Arrangement.spacedBy(4.dp), - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize().padding(start = 4.dp) ) { Row( horizontalArrangement = Arrangement.spacedBy(4.dp), diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt index 8436175e..2b5f1e6a 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt @@ -57,7 +57,7 @@ fun PackageSearchInfoPanel( Box(modifier = Modifier.fillMaxWidth()) { Column( modifier = Modifier - .padding(start = 4.dp, end = PackageSearchMetrics.scrollbarWidth) + .padding(end = PackageSearchMetrics.scrollbarWidth) .verticalScroll(viewModel.scrollState) ) { val tab = activeTab From f0658671848d55fffbd8131e0192b5160ca1ac49 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Tue, 5 Dec 2023 16:04:54 +0100 Subject: [PATCH 06/39] Improve search result retrieval and clean unused import Refactored how the search results are retrieved in PackageListViewModel for better code simplicity and readability. Also, an unused import from Utils.kt has been removed improving code cleanliness. (cherry picked from commit 34c012dde6b22c6bef26d35151825fec1d61be3f) --- .../plugin/ui/model/packageslist/PackageListViewModel.kt | 2 +- .../kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt index ebe570e4..1428793a 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt @@ -291,7 +291,7 @@ class PackageListViewModel(private val project: Project) : Disposable { when (event.eventId) { is PackageListItem.Package.Remote.Base.Id -> { val headerId = PackageListItem.Header.Id.Remote.Base(event.eventId.moduleIdentity) - val search = searchResultMapFlow.value.getValue(headerId) as? Search.Results.Base + val search = searchResultMapFlow.value[headerId] as? Search.Results.Base ?: return infoPanelViewModel.setPackage( module = event.eventId.getModule() as? PackageSearchModule.Base ?: return, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt index 801bc323..dcaef115 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt @@ -4,7 +4,6 @@ package com.jetbrains.packagesearch.plugin.utils import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState -import com.intellij.ProjectTopics import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.ModuleListener From 0d04536d1b9630a13ea67bf46df59f0a38025b2a Mon Sep 17 00:00:00 2001 From: Fabrizio Scarponi <36624359+fscarponi@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:55:23 +0100 Subject: [PATCH 07/39] Migrate Dropdown API to DropdownLink, fixes various cosmetics issues like spacing and color - IJ232 (#5) Created PackageSearchDropdownLink with a specific Style, injected top level (cherry picked from commit 3adb17ede10a5fd141d4759fac4b35f50f4c42dd) --------- Co-authored-by: Lamberto Basti --- .../plugin/PackageSearchToolWindowFactory.kt | 11 +- .../plugin/ui/bridge/Components.kt | 56 +-------- .../plugin/ui/bridge/CustomStyles.kt | 112 ++++++++++++++++++ .../packages/PackageSearchPackageList.kt | 10 +- .../panels/packages/PackageSearchSearchBar.kt | 78 ------------ .../ui/panels/side/PackageOverviewInfo.kt | 18 ++- .../packagesearch/plugin/utils/Utils.kt | 1 + 7 files changed, 137 insertions(+), 149 deletions(-) create mode 100644 plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/CustomStyles.kt diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt index d24467c2..3f5138e3 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt @@ -7,9 +7,11 @@ import com.intellij.openapi.wm.ToolWindow import com.intellij.openapi.wm.ToolWindowFactory import com.jetbrains.packagesearch.plugin.ui.LocalComponentManager import com.jetbrains.packagesearch.plugin.ui.PackageSearchToolwindow -import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchTabStyle -import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchTreeStyle -import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchGlobalColors +import com.jetbrains.packagesearch.plugin.ui.bridge.LocalPackageSearchDropdownLinkStyle +import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchDropdownLinkStyle +import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchGlobalColors +import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchTabStyle +import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchTreeStyle import com.jetbrains.packagesearch.plugin.utils.installActions import org.jetbrains.jewel.bridge.addComposeTab import org.jetbrains.jewel.foundation.LocalGlobalColors @@ -24,7 +26,8 @@ class PackageSearchToolWindowFactory : ToolWindowFactory, DumbAware { LocalComponentManager provides project, LocalGlobalColors provides PackageSearchGlobalColors(), LocalDefaultTabStyle provides PackageSearchTabStyle(), - LocalLazyTreeStyle provides PackageSearchTreeStyle() + LocalLazyTreeStyle provides PackageSearchTreeStyle(), + LocalPackageSearchDropdownLinkStyle provides PackageSearchDropdownLinkStyle(), ) { PackageSearchToolwindow() } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt index 59d18cd4..d583a81e 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt @@ -6,7 +6,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily @@ -20,15 +19,12 @@ import com.intellij.icons.AllIcons import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics import org.jetbrains.jewel.foundation.theme.JewelTheme import org.jetbrains.jewel.foundation.theme.LocalTextStyle -import org.jetbrains.jewel.ui.component.Dropdown +import org.jetbrains.jewel.ui.component.DropdownLink import org.jetbrains.jewel.ui.component.Icon import org.jetbrains.jewel.ui.component.IconButton import org.jetbrains.jewel.ui.component.MenuScope import org.jetbrains.jewel.ui.component.PopupMenu import org.jetbrains.jewel.ui.component.Text -import org.jetbrains.jewel.ui.component.styling.DropdownColors -import org.jetbrains.jewel.ui.component.styling.DropdownStyle -import org.jetbrains.jewel.ui.theme.dropdownStyle @Composable fun LabelInfo( @@ -71,7 +67,7 @@ fun LabelInfo( @Composable -fun TextSelectionDropdown( +fun PackageSearchDropdownLink( modifier: Modifier, menuModifier: Modifier, items: List, @@ -79,11 +75,11 @@ fun TextSelectionDropdown( enabled: Boolean, onSelection: (String) -> Unit, ) { - Dropdown( + DropdownLink( modifier = modifier, menuModifier = menuModifier.heightIn(max = PackageSearchMetrics.Dropdown.maxHeight), enabled = enabled && items.isNotEmpty(), - style = packageSearchDropdownStyle(), + style = LocalPackageSearchDropdownLinkStyle.current, menuContent = { items.forEach { selectableItem( @@ -94,18 +90,11 @@ fun TextSelectionDropdown( } } }, - content = { - Text( - modifier = Modifier.align(Alignment.CenterEnd), - text = content, - maxLines = 1, - overflow = TextOverflow.Clip, - textAlign = TextAlign.End - ) - } + text = content ) } + @Composable internal fun PackageActionPopup( isOpen: Boolean, @@ -141,36 +130,3 @@ internal fun PackageActionPopup( } } } - -@Composable -private fun packageSearchDropdownStyle(): DropdownStyle { - val currentStyle = JewelTheme.dropdownStyle - return DropdownStyle( - colors = DropdownColors( - background = Color.Transparent, - backgroundDisabled = Color.Transparent, - backgroundFocused = Color.Transparent, - backgroundPressed = Color.Transparent, - backgroundHovered = Color.Transparent, - content = currentStyle.colors.content, - contentDisabled = currentStyle.colors.contentDisabled, - contentFocused = currentStyle.colors.contentFocused, - contentPressed = currentStyle.colors.contentPressed, - contentHovered = currentStyle.colors.contentHovered, - border = Color.Transparent, - borderDisabled = Color.Transparent, - borderFocused = Color.Transparent, - borderPressed = Color.Transparent, - borderHovered = Color.Transparent, - iconTintDisabled = Color.Transparent, - iconTint = currentStyle.colors.iconTint, - iconTintFocused = currentStyle.colors.iconTintFocused, - iconTintPressed = currentStyle.colors.iconTintPressed, - iconTintHovered = currentStyle.colors.iconTintHovered, - ), - metrics = currentStyle.metrics, - icons = currentStyle.icons, - textStyle = currentStyle.textStyle, - menuStyle = currentStyle.menuStyle, - ) -} \ No newline at end of file diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/CustomStyles.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/CustomStyles.kt new file mode 100644 index 00000000..755aa56f --- /dev/null +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/CustomStyles.kt @@ -0,0 +1,112 @@ +package com.jetbrains.packagesearch.plugin.ui.bridge + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.calculateStartPadding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.ProvidableCompositionLocal +import androidx.compose.runtime.remember +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.dp +import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics +import org.jetbrains.jewel.foundation.GlobalColors +import org.jetbrains.jewel.foundation.LocalGlobalColors +import org.jetbrains.jewel.foundation.OutlineColors +import org.jetbrains.jewel.foundation.theme.JewelTheme +import org.jetbrains.jewel.foundation.theme.LocalContentColor +import org.jetbrains.jewel.ui.component.styling.LazyTreeMetrics +import org.jetbrains.jewel.ui.component.styling.LazyTreeStyle +import org.jetbrains.jewel.ui.component.styling.LinkColors +import org.jetbrains.jewel.ui.component.styling.LinkStyle +import org.jetbrains.jewel.ui.component.styling.LocalDefaultTabStyle +import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle +import org.jetbrains.jewel.ui.component.styling.TabMetrics +import org.jetbrains.jewel.ui.component.styling.TabStyle +import org.jetbrains.jewel.ui.theme.linkStyle + + +@Composable +internal fun PackageSearchDropdownLinkStyle(): LinkStyle { + val currentStyle = JewelTheme.linkStyle + val contentColor = LocalContentColor.current + return LinkStyle( + colors = LinkColors( + content = contentColor, + contentDisabled = currentStyle.colors.contentDisabled, + contentHovered = contentColor, + contentPressed = contentColor, + contentFocused = contentColor, + contentVisited = contentColor, + ), + metrics = currentStyle.metrics, + icons = currentStyle.icons, + textStyles = currentStyle.textStyles, + ) +} + + +@Composable +internal fun PackageSearchTabStyle(): TabStyle { + val current = LocalDefaultTabStyle.current + return TabStyle( + colors = current.colors, + metrics = TabMetrics( + underlineThickness = current.metrics.underlineThickness, + tabPadding = current.metrics.tabPadding, + tabHeight = PackageSearchMetrics.searchBarHeight, + closeContentGap = current.metrics.closeContentGap, + ), + icons = current.icons, + contentAlpha = current.contentAlpha + ) +} + +@Composable +fun PackageSearchGlobalColors(): GlobalColors { + val colors = LocalGlobalColors.current + + return remember(colors) { + GlobalColors( + borders = colors.borders, + outlines = OutlineColors( + focused = Color.Transparent, + focusedWarning = colors.outlines.focusedWarning, + focusedError = colors.outlines.focusedError, + warning = colors.outlines.warning, + error = colors.outlines.error, + ), + infoContent = colors.infoContent, + paneBackground = colors.paneBackground, + ) + } +} + +@Composable +internal fun PackageSearchTreeStyle(): LazyTreeStyle { + val currentStyle = LocalLazyTreeStyle.current + val paddings = currentStyle.metrics.elementPadding + return LazyTreeStyle( + currentStyle.colors, + metrics = LazyTreeMetrics( + indentSize = currentStyle.metrics.indentSize, + elementPadding = PaddingValues( + top = paddings.calculateTopPadding(), + bottom = paddings.calculateBottomPadding(), + start = paddings.calculateStartPadding(LocalLayoutDirection.current), + end = 0.dp + ), + elementContentPadding = currentStyle.metrics.elementContentPadding, + elementMinHeight = currentStyle.metrics.elementMinHeight, + chevronContentGap = currentStyle.metrics.chevronContentGap, + elementBackgroundCornerSize = currentStyle.metrics.elementBackgroundCornerSize, + ), + currentStyle.icons, + ) +} + + +internal val LocalPackageSearchDropdownLinkStyle: ProvidableCompositionLocal = + staticCompositionLocalOf { + error("No PackageSearchDropdownLinkStyle provided. Have you forgotten the theme?") + } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt index c1cd2916..2f15a369 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt @@ -36,7 +36,7 @@ import com.jetbrains.packagesearch.plugin.ui.LearnMoreLink import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics import com.jetbrains.packagesearch.plugin.ui.bridge.LabelInfo import com.jetbrains.packagesearch.plugin.ui.bridge.PackageActionPopup -import com.jetbrains.packagesearch.plugin.ui.bridge.TextSelectionDropdown +import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchDropdownLink import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItem import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent.EditPackageEvent.SetPackageScope @@ -173,7 +173,6 @@ private fun ScopeAndVersionDropdowns( Row() { Box(modifier = Modifier.widthIn(max = 180.dp)) { ScopeSelectionDropdown( - modifier = Modifier.align(Alignment.CenterEnd), declaredScope = item.selectedScope, allowMissingScope = item.allowMissingScope, availableScopes = item.availableScopes, @@ -182,9 +181,8 @@ private fun ScopeAndVersionDropdowns( ) } - Box(modifier = Modifier.width(180.dp)) { + Box(modifier = Modifier.width(180.dp), contentAlignment = Alignment.CenterEnd) { VersionSelectionDropdown( - modifier = Modifier.align(Alignment.CenterEnd), declaredVersion = item.declaredVersion, availableVersions = item.availableVersions, latestVersion = item.latestVersion, @@ -439,7 +437,7 @@ fun VersionSelectionDropdown( } } } - TextSelectionDropdown( + PackageSearchDropdownLink( modifier = modifier, menuModifier = menuModifier, items = availableVersions, @@ -459,7 +457,7 @@ fun ScopeSelectionDropdown( enabled: Boolean, onScopeChanged: (String?) -> Unit, ) { - TextSelectionDropdown( + PackageSearchDropdownLink( modifier = modifier, menuModifier = menuModifier, items = buildList { diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt index 3379b748..81cad39e 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt @@ -1,36 +1,22 @@ package com.jetbrains.packagesearch.plugin.ui.panels.packages import androidx.compose.animation.Crossfade -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.dp import com.intellij.icons.AllIcons import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics -import org.jetbrains.jewel.foundation.GlobalColors -import org.jetbrains.jewel.foundation.LocalGlobalColors -import org.jetbrains.jewel.foundation.OutlineColors import org.jetbrains.jewel.ui.component.Icon import org.jetbrains.jewel.ui.component.IconButton import org.jetbrains.jewel.ui.component.Text import org.jetbrains.jewel.ui.component.TextField -import org.jetbrains.jewel.ui.component.styling.LazyTreeMetrics -import org.jetbrains.jewel.ui.component.styling.LazyTreeStyle -import org.jetbrains.jewel.ui.component.styling.LocalDefaultTabStyle -import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle import org.jetbrains.jewel.ui.component.styling.LocalTextFieldStyle -import org.jetbrains.jewel.ui.component.styling.TabMetrics -import org.jetbrains.jewel.ui.component.styling.TabStyle @Composable fun PackageSearchSearchBar( @@ -84,68 +70,4 @@ fun PackageSearchSearchBar( ) } - } - -@Composable -internal fun PackageSearchTabStyle(): TabStyle { - val current = LocalDefaultTabStyle.current - return TabStyle( - colors = current.colors, - metrics = TabMetrics( - underlineThickness = current.metrics.underlineThickness, - tabPadding = current.metrics.tabPadding, - tabHeight = PackageSearchMetrics.searchBarHeight, - closeContentGap = current.metrics.closeContentGap, - ), - icons = current.icons, - contentAlpha = current.contentAlpha - ) -} - - -@Composable -fun PackageSearchGlobalColors(): GlobalColors { - val colors = LocalGlobalColors.current - - return remember(colors) { - GlobalColors( - borders = colors.borders, - outlines = OutlineColors( - focused = Color.Transparent, - focusedWarning = colors.outlines.focusedWarning, - focusedError = colors.outlines.focusedError, - warning = colors.outlines.warning, - error = colors.outlines.error, - ), - infoContent = colors.infoContent, - paneBackground = colors.paneBackground, - ) - } -} - - -@Composable -internal fun PackageSearchTreeStyle(): LazyTreeStyle { - val currentStyle = LocalLazyTreeStyle.current - val paddings = currentStyle.metrics.elementPadding - return LazyTreeStyle( - currentStyle.colors, - metrics = LazyTreeMetrics( - indentSize = currentStyle.metrics.indentSize, - elementPadding = PaddingValues( - top = paddings.calculateTopPadding(), - bottom = paddings.calculateBottomPadding(), - start = paddings.calculateStartPadding(LocalLayoutDirection.current), - end = 0.dp - ), - elementContentPadding = currentStyle.metrics.elementContentPadding, - elementMinHeight = currentStyle.metrics.elementMinHeight, - chevronContentGap = currentStyle.metrics.chevronContentGap, - elementBackgroundCornerSize = currentStyle.metrics.elementBackgroundCornerSize, - ), - currentStyle.icons, - ) -} - - diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt index f4cdc9d7..fcaff406 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import com.jetbrains.packagesearch.plugin.PackageSearchBundle import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message import com.jetbrains.packagesearch.plugin.core.data.IconProvider import com.jetbrains.packagesearch.plugin.ui.bridge.LabelInfo @@ -50,10 +49,7 @@ internal fun PackageOverviewTab( verticalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.fillMaxSize().padding(start = 4.dp) ) { - Row( - horizontalArrangement = Arrangement.spacedBy(4.dp), - verticalAlignment = Alignment.Top - ) { + Row(verticalAlignment = Alignment.Top) { InfoPanelPackageTitle(modifier = Modifier.weight(1f), content.title, content.subtitle) InfoPanelPackageActions(content, onPackageEvent) } @@ -63,7 +59,7 @@ internal fun PackageOverviewTab( ) { if (content is InfoPanelContent.PackageInfo.Declared) { Row( - horizontalArrangement = Arrangement.spacedBy(4.dp), + horizontalArrangement = Arrangement.spacedBy(2.dp), verticalAlignment = Alignment.Top ) { LabelInfo( @@ -80,7 +76,7 @@ internal fun PackageOverviewTab( } } Row( - horizontalArrangement = Arrangement.spacedBy(4.dp), + horizontalArrangement = Arrangement.spacedBy(2.dp), verticalAlignment = Alignment.Top ) { LabelInfo( @@ -222,7 +218,7 @@ private fun InfoPanelPackageActions( @Composable private fun PackageType(name: String, icon: IconProvider.Icon) { - Row(horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.CenterVertically) { + Row(horizontalArrangement = Arrangement.spacedBy(2.dp), verticalAlignment = Alignment.CenterVertically) { LabelInfo( modifier = Modifier.defaultMinSize(90.dp), text = message("packagesearch.ui.toolwindow.packages.columns.type") @@ -244,7 +240,7 @@ private fun InfoPanelPackageDetailLine(name: String, value: String) { verticalAlignment = Alignment.Top, ) { LabelInfo( - modifier = Modifier.defaultMinSize(90.dp), + modifier = Modifier.defaultMinSize(90.dp,16.dp), text = name ) Text(value) @@ -283,7 +279,7 @@ private fun InfoPanelPackageTitle( horizontalArrangement = Arrangement.spacedBy(4.dp) ) { Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { - org.jetbrains.jewel.ui.component.Text(name ?: id, fontWeight = FontWeight.Bold) + Text(name ?: id, fontWeight = FontWeight.Bold) if (name != null) LabelInfo(id) } } @@ -300,7 +296,7 @@ private fun InfoPanelPackageLinks( ) { LabelInfo( modifier = Modifier.defaultMinSize(90.dp), - text = PackageSearchBundle.message("packagesearch.ui.toolwindow.packages.details.info.licenses") + text = message("packagesearch.ui.toolwindow.packages.details.info.licenses") ) licenses.forEachIndexed { index, license -> when (license.url) { diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt index dcaef115..801bc323 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/Utils.kt @@ -4,6 +4,7 @@ package com.jetbrains.packagesearch.plugin.utils import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState +import com.intellij.ProjectTopics import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.ModuleListener From 4eec4f207e716ce58495d3ef35cf77cdecb8ef80 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Wed, 6 Dec 2023 12:41:23 +0100 Subject: [PATCH 08/39] Fixed logic for compatible package types for Maven, Gradle and KMP. (cherry picked from commit 53b33be923d42662fb42135d68f412dfd19619a8) --- package-search-api-models | 2 +- .../plugin/gradle/GradleModuleProvider.kt | 34 +++---------------- .../KotlinMultiplatformModuleProvider.kt | 20 +++++------ .../plugin/gradle/PackageSearchGradleModel.kt | 2 +- .../PackageSearchProjectResolverExtension.kt | 2 +- .../tooling/PackageSearchGradleJavaModel.java | 2 +- .../PackageSearchGradleJavaModelImpl.java | 2 +- .../PackageSearchGradleModelBuilder.java | 2 +- .../packagesearch/plugin/maven/MavenUtils.kt | 17 ++-------- .../packages/PackageSearchPackageList.kt | 2 +- tests.http | 30 ++++++++++++++-- 11 files changed, 52 insertions(+), 63 deletions(-) diff --git a/package-search-api-models b/package-search-api-models index 908fd5ce..1f02f0e7 160000 --- a/package-search-api-models +++ b/package-search-api-models @@ -1 +1 @@ -Subproject commit 908fd5ce55cdea67c28e3e24074aa99a33d339a7 +Subproject commit 1f02f0e7c19416e79979042f9d6fd68e6eb06b2d diff --git a/plugin/gradle/base/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/GradleModuleProvider.kt b/plugin/gradle/base/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/GradleModuleProvider.kt index 0a5629c0..eebf5f17 100644 --- a/plugin/gradle/base/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/GradleModuleProvider.kt +++ b/plugin/gradle/base/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/GradleModuleProvider.kt @@ -9,9 +9,11 @@ import com.jetbrains.packagesearch.plugin.gradle.utils.getDeclaredDependencies import com.jetbrains.packagesearch.plugin.gradle.utils.getDeclaredKnownRepositories import kotlinx.coroutines.flow.FlowCollector import org.jetbrains.packagesearch.api.v3.ApiMavenRepository +import org.jetbrains.packagesearch.api.v3.search.androidPackages import org.jetbrains.packagesearch.api.v3.search.buildPackageTypes import org.jetbrains.packagesearch.api.v3.search.javaApi import org.jetbrains.packagesearch.api.v3.search.javaRuntime +import org.jetbrains.packagesearch.api.v3.search.jvmGradlePackages import org.jetbrains.packagesearch.api.v3.search.libraryElements class GradleModuleProvider : AbstractGradleModuleProvider() { @@ -49,36 +51,10 @@ class GradleModuleProvider : AbstractGradleModuleProvider() { compatiblePackageTypes = buildPackageTypes { mavenPackages() when { - model.isKotlinJvmApplied -> gradlePackages { - mustBeRootPublication = true - variant { - javaApi() - javaRuntime() - libraryElements("jar") - } - } - - model.isKotlinAndroidApplied -> { - gradlePackages { - mustBeRootPublication = true - variant { - javaApi() - javaRuntime() - libraryElements("aar") - } - } - gradlePackages { - mustBeRootPublication = true - variant { - javaApi() - javaRuntime() - libraryElements("jar") - } - } - } - + model.isKotlinAndroidApplied -> androidPackages() + model.isJavaApplied -> jvmGradlePackages("jar") else -> gradlePackages { - mustBeRootPublication = true + isRootPublication = true } } }, diff --git a/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt b/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt index 23f51ff2..2f28b220 100644 --- a/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt +++ b/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt @@ -23,7 +23,9 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.FlowCollector import org.jetbrains.packagesearch.api.v3.ApiMavenPackage import org.jetbrains.packagesearch.api.v3.ApiPackage +import org.jetbrains.packagesearch.api.v3.search.androidPackages import org.jetbrains.packagesearch.api.v3.search.buildPackageTypes +import org.jetbrains.packagesearch.api.v3.search.jvmGradlePackages import org.jetbrains.packagesearch.api.v3.search.kotlinMultiplatform import org.jetbrains.packagesearch.packageversionutils.normalization.NormalizedVersion @@ -77,7 +79,7 @@ class KotlinMultiplatformModuleProvider : AbstractGradleModuleProvider() { compatiblePackageTypes = buildPackageTypes { mavenPackages() gradlePackages { - mustBeRootPublication = true + isRootPublication = true } }, availableScopes = availableScopes, @@ -105,7 +107,7 @@ class KotlinMultiplatformModuleProvider : AbstractGradleModuleProvider() { .distinct() .map { it.packageId } - val dependencyInfo = getPackageInfoByIdHashes(packageIds.map { ApiPackage.hashPackageId(it) }.toSet()) + val dependencyInfo = getPackageInfoByIdHashes(packageIds.map { ApiPackage.hashPackageId(it) }.toSet()) val declaredSourceSetDependencies = rawDeclaredSourceSetDependencies @@ -133,19 +135,16 @@ class KotlinMultiplatformModuleProvider : AbstractGradleModuleProvider() { declaredDependencies = declaredSourceSetDependencies[sourceSetName] ?: emptyList(), attributes = compilationTargets.buildAttributes(), compatiblePackageTypes = buildPackageTypes { - if (compilationTargets.singleOrNull() == Jvm) { - mavenPackages() - } else gradlePackages { + gradlePackages { kotlinMultiplatform { compilationTargets.forEach { compilationTarget -> - when (compilationTarget) { - is Js -> when (compilationTarget.compiler) { + when { + compilationTarget is Js -> when (compilationTarget.compiler) { Js.Compiler.IR -> jsIr() Js.Compiler.LEGACY -> jsLegacy() } - - is Native -> native(compilationTarget.target) - else -> {} + compilationTarget is Native -> native(compilationTarget.target) + compilationTarget == MppCompilationInfoModel.Wasm -> wasm() } } when { @@ -161,5 +160,6 @@ class KotlinMultiplatformModuleProvider : AbstractGradleModuleProvider() { sourceSetVariants + dependenciesBlockVariant.await() } + } diff --git a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchGradleModel.kt b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchGradleModel.kt index 5d6b7393..d730c604 100644 --- a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchGradleModel.kt +++ b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchGradleModel.kt @@ -9,7 +9,7 @@ data class PackageSearchGradleModel( @Serializable(with = NioPathSerializer::class) val projectDir: Path, val configurations: List, val repositories: List, - val isKotlinJvmApplied: Boolean, + val isJavaApplied: Boolean, val isKotlinAndroidApplied: Boolean, val isKotlinMultiplatformApplied: Boolean, val projectIdentityPath: String, diff --git a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchProjectResolverExtension.kt b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchProjectResolverExtension.kt index 3cd2870d..d0ae5b41 100644 --- a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchProjectResolverExtension.kt +++ b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchProjectResolverExtension.kt @@ -43,7 +43,7 @@ internal fun PackageSearchGradleJavaModel.toPackageSearchModel() = ) }, repositories = repositoryUrls, - isKotlinJvmApplied = isKotlinJvmApplied, + isJavaApplied = isJavaApplied, isKotlinAndroidApplied = isKotlinAndroidApplied, isKotlinMultiplatformApplied = isKotlinMultiplatformApplied, rootProjectName = rootProjectName, diff --git a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModel.java b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModel.java index cc08a2b6..07257384 100644 --- a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModel.java +++ b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModel.java @@ -11,7 +11,7 @@ public interface PackageSearchGradleJavaModel extends Serializable { List getConfigurations(); List getRepositoryUrls(); String getRootProjectName(); - boolean isKotlinJvmApplied(); + boolean isJavaApplied(); boolean isKotlinAndroidApplied(); boolean isKotlinMultiplatformApplied(); String getBuildFilePath(); diff --git a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModelImpl.java b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModelImpl.java index 7b567ac9..0bac4a24 100644 --- a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModelImpl.java +++ b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModelImpl.java @@ -73,7 +73,7 @@ public boolean isKotlinAndroidApplied() { return isKotlinAndroidApplied; } - public boolean isKotlinJvmApplied() { + public boolean isJavaApplied() { return isKotlinJvmApplied; } diff --git a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java index 5edae905..0355e181 100644 --- a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java +++ b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java @@ -86,7 +86,7 @@ public PackageSearchGradleJavaModel buildAll( projectIdentityPath, configurations, repositories, - project.getPluginManager().hasPlugin("org.jetbrains.kotlin.jvm"), + project.getPluginManager().hasPlugin("org.gradle.java"), project.getPluginManager().hasPlugin("org.jetbrains.kotlin.multiplatform"), project.getPluginManager().hasPlugin("org.jetbrains.kotlin.android"), buildFilePath, diff --git a/plugin/maven/src/main/kotlin/com/jetbrains/packagesearch/plugin/maven/MavenUtils.kt b/plugin/maven/src/main/kotlin/com/jetbrains/packagesearch/plugin/maven/MavenUtils.kt index 18459430..b384abdd 100644 --- a/plugin/maven/src/main/kotlin/com/jetbrains/packagesearch/plugin/maven/MavenUtils.kt +++ b/plugin/maven/src/main/kotlin/com/jetbrains/packagesearch/plugin/maven/MavenUtils.kt @@ -42,6 +42,7 @@ import org.jetbrains.packagesearch.api.v3.ApiRepository import org.jetbrains.packagesearch.api.v3.search.buildPackageTypes import org.jetbrains.packagesearch.api.v3.search.javaApi import org.jetbrains.packagesearch.api.v3.search.javaRuntime +import org.jetbrains.packagesearch.api.v3.search.jvmMavenPackages import org.jetbrains.packagesearch.maven.POM_XML_NAMESPACE import org.jetbrains.packagesearch.maven.ProjectObjectModel import org.jetbrains.packagesearch.maven.decodeFromString @@ -110,21 +111,7 @@ suspend fun Module.toPackageSearch( declaredDependencies = declaredDependencies, availableScopes = commonScopes.plus(declaredDependencies.mapNotNull { it.declaredScope }).distinct(), compatiblePackageTypes = buildPackageTypes { - mavenPackages() - gradlePackages { - mustBeRootPublication = false - variant { - mustHaveFilesAttribute = true - javaApi() - } - } - gradlePackages { - mustBeRootPublication = false - variant { - mustHaveFilesAttribute = true - javaRuntime() - } - } + jvmMavenPackages() }, nativeModule = this ) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt index 2f15a369..f445cbca 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt @@ -109,7 +109,7 @@ fun PackageSearchPackageList( } @Composable -private fun SelectableLazyItemScope.PackageListItem( +internal fun SelectableLazyItemScope.PackageListItem( modifier: Modifier = Modifier, content: PackageListItem.Package, packagesList: List, diff --git a/tests.http b/tests.http index 93ae9f3d..cc569e9c 100644 --- a/tests.http +++ b/tests.http @@ -1,4 +1,30 @@ -GET https://api.dev.package-search.services.jetbrains.com/package-info-by-hashes +GET https://api.dev.package-search.services.jetbrains.com/search-packages Content-Type: application/json -["6d2eceeb52da1da9817f4fb83d0c8a98173960f3690eb65206b606ad14b2f1d1"] \ No newline at end of file +{ + "packagesType": [ + { + "type": "maven" + }, + { + "type": "gradle", + "variants": [ + { + "attributes": { + "org.gradle.usage": { + "type": "exactMatch", + "value": "java-runtime" + }, + "org.gradle.libraryelements": { + "type": "exactMatch", + "value": "jar" + } + }, + "mustBeWithFiles": false + } + ], + "mustBeRootPublication": true + } + ], + "searchQuery": "kotlinx-datetime" +} \ No newline at end of file From 1b646fb0c72c1e5fa5233d8bf80fb0eb4c2f86f8 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Thu, 7 Dec 2023 20:11:14 +0100 Subject: [PATCH 09/39] Fix TBE issues with semver tags --- plugin/build.gradle.kts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 8f2de792..03be5ccf 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -106,9 +106,12 @@ tasks { } patchPluginXml { pluginId = pkgsPluginId + val versionString = project.version.toString() version = when { - project.version.toString().endsWith("-SNAPSHOT") -> "${project.version}-$snapshotDateSuffix" - else -> project.version.toString() + versionString.endsWith("-SNAPSHOT") -> + "${versionString.removePrefix("-SNAPSHOT")}.$snapshotDateSuffix" + + else -> versionString } } val buildShadowPlugin by registering(Zip::class) { @@ -116,8 +119,10 @@ tasks { from(shadowJar) { rename { "package-search-plugin" + when { - it.endsWith("-SNAPSHOT.jar") -> it.replace(".jar", "-$snapshotDateSuffix.jar") - .also { logger.lifecycle("Snapshot version -> $it") } + it.endsWith("-SNAPSHOT.jar") -> + it.replace("-SNAPSHOT.jar", ".$snapshotDateSuffix.jar") + .also { logger.lifecycle("Snapshot version -> $it") } + else -> it } } From 3722a40880d9af2b75e87e1e0ed6e276f53f773b Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Thu, 7 Dec 2023 20:16:47 +0100 Subject: [PATCH 10/39] Update publish-snapshot.yml to restrict pushes to master releases/232 --- .github/workflows/publish-snapshot.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index f95430ef..41496558 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -1,6 +1,8 @@ name: Publish snapshot to TBE -on: [ push ] +on: + push: + branches: [ releases/232 ] jobs: publish: From b5803218902f2a93d56e6aaa83c37f8173bc4799 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 13:42:53 +0100 Subject: [PATCH 11/39] Refactor snapshot versioning and deployment process Removed time-based version suffix for snapshots in build.gradle.kts and replaced it with an approach dependent on the environment variables "RUN_NUMBER" and "RUN_ATTEMPT". Included these variables into the action workflow publish-snapshot.yml (cherry picked from commit 046267d0c83b242757013848e88659a91f7363a2) --- .github/workflows/publish-snapshot.yml | 2 ++ plugin/build.gradle.kts | 35 +++++++++++--------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index 41496558..60f63924 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -26,3 +26,5 @@ jobs: GRADLE_ENTERPRISE_KEY: ${{ secrets.GRADLE_ENTERPRISE_KEY }} MAVEN_SPACE_PASSWORD: ${{ secrets.MAVEN_SPACE_PASSWORD }} MAVEN_SPACE_USERNAME: ${{ secrets.MAVEN_SPACE_USERNAME }} + RUN_NUMBER: ${{ github.run_number }} + RUN_ATTEMPT: ${{ github.run_attempt }} diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 03be5ccf..baf9d433 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -1,8 +1,5 @@ @file:Suppress("UnstableApiUsage") -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime import org.jetbrains.intellij.tasks.PublishPluginTask import org.jetbrains.packagesearch.gradle.lafFile import org.jetbrains.packagesearch.gradle.logCategoriesFile @@ -12,6 +9,7 @@ import org.jetbrains.packagesearch.gradle.patchSettingsFile import org.jetbrains.packagesearch.gradle.patchTextRegistryFile import org.jetbrains.packagesearch.gradle.registryTextFile import org.jetbrains.packagesearch.gradle.settingsFile +import kotlin.math.max plugins { @@ -95,21 +93,17 @@ tasks { prepareSandbox { runtimeClasspathFiles = tooling } - val snapshotDateSuffix = buildString { - val now = Clock.System.now().toLocalDateTime(TimeZone.UTC) - append(now.year) - append(now.monthNumber) - append(now.dayOfMonth) - append(now.hour.toString().padStart(2, '0')) - append(now.minute.toString().padStart(2, '0')) - append(now.second.toString().padStart(2, '0')) - } + + val runNumber = System.getenv("RUN_NUMBER")?.toInt() ?: 0 + val runAttempt = System.getenv("RUN_ATTEMPT")?.toInt() ?: 0 + val snapshotMinorVersion = max(0, runNumber + runAttempt - 1) + val versionString = project.version.toString() + patchPluginXml { pluginId = pkgsPluginId - val versionString = project.version.toString() version = when { versionString.endsWith("-SNAPSHOT") -> - "${versionString.removePrefix("-SNAPSHOT")}.$snapshotDateSuffix" + "${versionString.removePrefix("-SNAPSHOT")}.$snapshotMinorVersion" else -> versionString } @@ -118,20 +112,19 @@ tasks { group = "intellij" from(shadowJar) { rename { - "package-search-plugin" + when { - it.endsWith("-SNAPSHOT.jar") -> - it.replace("-SNAPSHOT.jar", ".$snapshotDateSuffix.jar") - .also { logger.lifecycle("Snapshot version -> $it") } + "package-search-plugin-" + when { + versionString.endsWith("-SNAPSHOT") -> + versionString.replace("-SNAPSHOT", ".$snapshotMinorVersion") - else -> it - } + else -> versionString + } + ".jar" } } from(tooling) { rename { "gradle-tooling.jar" } } into("$pkgsPluginId/lib") - archiveFileName.set("packagesearch-plugin.zip") + archiveFileName = "packagesearch-plugin.zip" destinationDirectory = layout.buildDirectory.dir("distributions") } From a19e0bb99432c61972cf2dbdb3ce4f6b503c2cc2 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 14:09:17 +0100 Subject: [PATCH 12/39] Refactor snapshot versioning and deployment process v2 (cherry picked from commit 6ffafc5161e1d4dfab9e3dfa90c8f65ecbe4cbfb) --- plugin/build.gradle.kts | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index baf9d433..38838086 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -101,30 +101,19 @@ tasks { patchPluginXml { pluginId = pkgsPluginId - version = when { - versionString.endsWith("-SNAPSHOT") -> - "${versionString.removePrefix("-SNAPSHOT")}.$snapshotMinorVersion" - - else -> versionString - } + version = versionString.replace("-SNAPSHOT", ".$snapshotMinorVersion") } val buildShadowPlugin by registering(Zip::class) { group = "intellij" from(shadowJar) { - rename { - "package-search-plugin-" + when { - versionString.endsWith("-SNAPSHOT") -> - versionString.replace("-SNAPSHOT", ".$snapshotMinorVersion") - - else -> versionString - } + ".jar" - } + rename { "packageSearch.jar" } } from(tooling) { rename { "gradle-tooling.jar" } } into("$pkgsPluginId/lib") - archiveFileName = "packagesearch-plugin.zip" + archiveFileName = "packageSearch-${project.version}.zip" + .replace("-SNAPSHOT", ".$snapshotMinorVersion") destinationDirectory = layout.buildDirectory.dir("distributions") } From a8ff6d59a79f68af5821c0107caaf61e16ee36de Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 14:49:07 +0100 Subject: [PATCH 13/39] Use map lookup operations instead of `getValue` in PackageListViewModel Changed the `getValue` calls to direct map lookup operations in the PackageListViewModel. This approach ensures the code is more readable and allows us to handle null values with the Elvis operator, improving the overall robustness of the module variant and search result handling. (cherry picked from commit 17baa2bb7cda7fe9ffbb0b1f41e1c7aa0256988f) --- .../packageslist/PackageListViewModel.kt | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt index 1428793a..c12452f6 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt @@ -305,7 +305,7 @@ class PackageListViewModel(private val project: Project) : Disposable { event.eventId.moduleIdentity, event.eventId.headerId.compatibleVariantNames ) - val search = searchResultMapFlow.value.getValue(headerId) as? Search.Results.WithVariants + val search = searchResultMapFlow.value[headerId] as? Search.Results.WithVariants ?: return infoPanelViewModel.setPackage( module = event.eventId.getModule() as? PackageSearchModule.WithVariants ?: return, @@ -328,7 +328,8 @@ class PackageListViewModel(private val project: Project) : Disposable { val module = event.eventId .getModule() as? PackageSearchModule.WithVariants ?: return - val variant = module.variants.getValue(event.eventId.variantName) + val variant = module.variants[event.eventId.variantName] + ?: return val declaredPackage = variant.declaredDependencies .firstOrNull { it.id == event.eventId.packageId } ?: return @@ -369,8 +370,8 @@ class PackageListViewModel(private val project: Project) : Disposable { val eventId = actionType .eventId as? PackageListItem.Package.Declared.Id.WithVariant ?: return@editModule - val variant = module.variants - .getValue(eventId.variantName) + val variant = module.variants[eventId.variantName] + ?: return@editModule val declaredPackage = variant.declaredDependencies .firstOrNull { it.id == eventId.packageId } ?: return@editModule @@ -385,7 +386,8 @@ class PackageListViewModel(private val project: Project) : Disposable { val module = actionType.eventId .getModule() as? PackageSearchModule.WithVariants ?: return - val variant = module.variants.getValue(actionType.selectedVariantName) + val variant = module.variants[actionType.selectedVariantName] + ?: return val search = searchResultMapFlow .value[actionType.headerId] as? Search.Results.WithVariants ?: return @@ -446,7 +448,8 @@ class PackageListViewModel(private val project: Project) : Disposable { val eventId = actionType .eventId as? PackageListItem.Package.Declared.Id.WithVariant ?: return - val variant = module.variants.getValue(eventId.variantName) + val variant = module.variants[eventId.variantName] + ?: return variant.declaredDependencies.firstOrNull { it.id == eventId.packageId } } @@ -505,11 +508,13 @@ class PackageListViewModel(private val project: Project) : Disposable { val module = event.eventId .getModule() as? PackageSearchModule.WithVariants ?: return - val variant = module.variants.getValue(event.eventId.variantName) + val variant = module.variants[event.eventId.variantName] + ?: return val declaredPackage = variant.declaredDependencies .firstOrNull { it.id == event.eventId.packageId } ?: return - val newVariant = module.variants.getValue(event.selectedVariantName) + val newVariant = module.variants[event.selectedVariantName] + ?: return module.editModule { variant.removeDependency(declaredPackage) // newVariant.addDependency( @@ -605,7 +610,8 @@ class PackageListViewModel(private val project: Project) : Disposable { val withVariants = modulesById[moduleIdentity] as? PackageSearchModule.WithVariants ?: return null - val variant = withVariants.variants.getValue(variantName) + val variant = withVariants.variants[variantName] + ?: return null PackageSearchDependencyHandlers( modifier = withVariants, manager = variant, From df41fa2abc9d5d770996e6e4dd4eabfb9bde45ce Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 14:49:20 +0100 Subject: [PATCH 14/39] Remove kotlinx-datetime dependency from build files (cherry picked from commit 45f9cc714b6da166c3cb1978f4490cae99daaaad) --- build.gradle.kts | 3 --- buildSrc/build.gradle.kts | 1 - 2 files changed, 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 254f041e..32e5c558 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,6 @@ @file:Suppress("UnstableApiUsage") import java.lang.System.getenv -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime import org.jetbrains.packagesearch.gradle.pkgsSpace plugins { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 27a63437..17199620 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -30,5 +30,4 @@ dependencies { implementation(packageSearchCatalog.kotlinx.serialization.json) implementation("com.squareup:kotlinpoet:1.14.2") implementation("io.github.pdvrieze.xmlutil:serialization:0.86.2") - implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.1") } From 6cb4db84e74c5fb3370748f1789fcc4e25c24f6e Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 15:11:27 +0100 Subject: [PATCH 15/39] fix PKGS-1324 Ignore duplicate package declarations (cherry picked from commit 8f8a2e0bd3c0d9ae9283eecc16b62c2ec1dddb88) --- .../KotlinMultiplatformModuleProvider.kt | 2 +- .../plugin/gradle/GradleDependencyModel.kt | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt b/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt index 2f28b220..426a0162 100644 --- a/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt +++ b/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt @@ -97,7 +97,7 @@ class KotlinMultiplatformModuleProvider : AbstractGradleModuleProvider() { val rawDeclaredSourceSetDependencies = MppDependencyModifier .dependenciesBySourceSet(this@getKMPVariants) ?.filterNotNullValues() - ?.mapValues { readAction { it.value.artifacts().map { it.toGradleDependencyModel() } } } + ?.mapValues { readAction { it.value.artifacts().map { it.toGradleDependencyModel() } }.distinct() } ?: emptyMap() val packageIds = rawDeclaredSourceSetDependencies diff --git a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/GradleDependencyModel.kt b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/GradleDependencyModel.kt index c1a9b117..e9ab513e 100644 --- a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/GradleDependencyModel.kt +++ b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/GradleDependencyModel.kt @@ -12,4 +12,28 @@ data class GradleDependencyModel( val packageId get() = "maven:$groupId:$artifactId" + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as GradleDependencyModel + + if (groupId != other.groupId) return false + if (artifactId != other.artifactId) return false + if (version != other.version) return false + if (configuration != other.configuration) return false + + return true + } + + override fun hashCode(): Int { + var result = groupId.hashCode() + result = 31 * result + artifactId.hashCode() + result = 31 * result + (version?.hashCode() ?: 0) + result = 31 * result + configuration.hashCode() + return result + } + + } \ No newline at end of file From 78deedfc917d1dffe105fed534bc54d341c80b4c Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 15:31:32 +0100 Subject: [PATCH 16/39] fix PKGS-1325 Filter installed packages based on search (cherry picked from commit fdd1ef63dc5ebbab79a21d4de6d84eb7bee0f59c) --- .../ui/model/packageslist/PackageListBuilder.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt index eb92c291..f3d34010 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt @@ -92,7 +92,9 @@ class PackageListBuilder( } ) if (state == PackageListItem.Header.State.OPEN) { - dependenciesToShow.forEach { dependency -> + dependenciesToShow + .filter { it.matchesSearchQuery() } + .forEach { dependency -> addDeclaredPackage( title = dependency.displayName, subtitle = dependency.coordinates, @@ -193,7 +195,9 @@ class PackageListBuilder( } ) if (state == PackageListItem.Header.State.OPEN) { - variant.declaredDependencies.forEach { dependency -> + variant.declaredDependencies + .filter { it.matchesSearchQuery() } + .forEach { dependency -> addDeclaredPackage( title = dependency.displayName, subtitle = dependency.coordinates, @@ -234,7 +238,9 @@ class PackageListBuilder( } ) if (state == PackageListItem.Header.State.OPEN) { - dependenciesToShow.forEach { (variant, dependency) -> + dependenciesToShow + .filter { it.second.matchesSearchQuery() } + .forEach { (variant, dependency) -> addDeclaredPackage( title = dependency.displayName, subtitle = variant.name, From d653a0546073244265f8ddd32fd353bfa7db6162 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 15:32:25 +0100 Subject: [PATCH 17/39] Remove PackageSearch ApiClient coroutine scope. (cherry picked from commit bff01443f6cae389d55ec8961c0768188bb73e24) --- package-search-api-models | 2 +- .../services/PackageSearchApplicationCachesService.kt | 10 +++++++--- .../plugin/services/PackageSearchProjectService.kt | 2 +- .../ui/model/packageslist/PackageListViewModel.kt | 1 - .../plugin/ui/model/tree/TreeViewModel.kt | 4 +--- .../plugin/utils/PackageSearchApiPackageCache.kt | 5 +++-- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/package-search-api-models b/package-search-api-models index 1f02f0e7..7a6a50d0 160000 --- a/package-search-api-models +++ b/package-search-api-models @@ -1 +1 @@ -Subproject commit 1f02f0e7c19416e79979042f9d6fd68e6eb06b2d +Subproject commit 7a6a50d037e86b0ba858b7fc273ab2db76b641e7 diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt index 6d998bec..a749ae39 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt @@ -10,8 +10,8 @@ import com.intellij.openapi.application.appSystemDir import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level import com.intellij.openapi.components.service -import com.jetbrains.packagesearch.plugin.core.PackageSearch import com.jetbrains.packagesearch.plugin.PackageSearchBundle +import com.jetbrains.packagesearch.plugin.core.PackageSearch import com.jetbrains.packagesearch.plugin.core.nitrite.buildDefaultNitrate import com.jetbrains.packagesearch.plugin.core.nitrite.div import com.jetbrains.packagesearch.plugin.core.utils.PKGSInternalAPI @@ -32,6 +32,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.future.future import kotlinx.coroutines.launch import org.dizitart.no2.IndexOptions @@ -89,10 +91,12 @@ class PackageSearchApplicationCachesService : RecoveryAction, Disposable { logger = KtorDebugLogger() filter { it.attributes.getOrNull(PackageSearchApiClient.Attributes.Cache) == true } } - }, - scope = coroutineScope + } ) + val isOnlineFlow = devApiClient.isOnlineFlow() + .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), true) + val apiPackageCache = PackageSearchApiPackageCache( apiPackageCache = packagesRepository, searchCache = searchesRepository, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt index 7f210e1d..e678777c 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt @@ -126,7 +126,7 @@ class PackageSearchProjectService(override val project: Project) : PackageSearch IntelliJApplication.PackageSearchApplicationCachesService .apiPackageCache - .isOnlineFlow + .isOnlineFlow() .filter { it } .onEach { restart() } .launchIn(coroutineScope) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt index c12452f6..9ae4c33a 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt @@ -59,7 +59,6 @@ class PackageListViewModel(private val project: Project) : Disposable { private val isOnline get() = IntelliJApplication.PackageSearchApplicationCachesService - .apiPackageCache .isOnlineFlow val isCompactFlow diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt index 99427a71..f162a8d3 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/tree/TreeViewModel.kt @@ -37,9 +37,7 @@ internal class TreeViewModel(project: Project) : Disposable { internal val treeState = TreeState(SelectableLazyListState(lazyListState)) val isOnline - get() = IntelliJApplication.PackageSearchApplicationCachesService - .apiPackageCache - .isOnlineFlow + get() = IntelliJApplication.PackageSearchApplicationCachesService.isOnlineFlow fun expandAll() { treeState.openNodes = tree.value.walkBreadthFirst().map { it.id }.toSet() diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/PackageSearchApiPackageCache.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/PackageSearchApiPackageCache.kt index cd5a7e68..365e045a 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/PackageSearchApiPackageCache.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/PackageSearchApiPackageCache.kt @@ -74,8 +74,9 @@ class PackageSearchApiPackageCache( .toList() .associateBy { it.id } val missingIds = ids - localDatabaseResults.keys - if (missingIds.isNotEmpty() && isOnlineFlow.value) { - val networkResults = apiCall(missingIds) + if (missingIds.isNotEmpty()) { + val networkResults = runCatching { apiCall(missingIds) } + .getOrDefault(emptyMap()) // TODO cache also miss in network to avoid pointless empty query if (networkResults.isNotEmpty()) { val packageEntries = networkResults.values.map { it.asCacheEntry() } From 04f6bd8b499109adf895501328df5ec0c8692a70 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 17:02:48 +0100 Subject: [PATCH 18/39] Refactor API call handling and error flow control This commit removes the use of runCatching for API calls in PackageSearchApiPackageCache and instead handles potential failures further upstream. Additionally, introduced in the PackageSearchProjectService is a restart mechanism with a retry limit that prevents continuous restarts and avoids potential infinite loops. The PackageSearchGradleModelBuilder class also had an unused import that was removed. (cherry picked from commit 173215375e084a25098d2b52f6abbbca9f938246) --- .../services/PackageSearchProjectService.kt | 23 +++++++++++++++++-- .../utils/PackageSearchApiPackageCache.kt | 3 +-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt index e678777c..8802473d 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt @@ -20,6 +20,7 @@ import com.jetbrains.packagesearch.plugin.core.utils.withInitialValue import com.jetbrains.packagesearch.plugin.utils.PackageSearchApplicationCachesService import com.jetbrains.packagesearch.plugin.utils.WindowedModuleBuilderContext import com.jetbrains.packagesearch.plugin.utils.filterNotNullKeys +import com.jetbrains.packagesearch.plugin.utils.logWarn import com.jetbrains.packagesearch.plugin.utils.nativeModulesFlow import com.jetbrains.packagesearch.plugin.utils.startWithNull import com.jetbrains.packagesearch.plugin.utils.timer @@ -33,6 +34,7 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.flow.debounce @@ -45,6 +47,8 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.jetbrains.packagesearch.api.v3.ApiRepository @Service(Level.PROJECT) @@ -109,9 +113,25 @@ class PackageSearchProjectService(override val project: Project) : PackageSearch private val restartFlow = restartChannel.consumeAsFlow() .shareIn(coroutineScope, SharingStarted.Eagerly, replay = 1) + private var counter = 0 + private val counterMutex = Mutex() + + private suspend fun restartWithCounter() = counterMutex.withLock { + if (counter++ < 3) { + restart() + } + } + + private suspend fun resetCounter() = counterMutex.withLock { counter = 0 } + val modulesStateFlow = restartFlow .withInitialValue(Unit) .flatMapLatest { moduleProvidersList } + .catch { + logWarn("${this::class.simpleName}#modulesStateFlow", throwable = it) + restartWithCounter() + } + .onEach { resetCounter() } .stateIn(coroutineScope, SharingStarted.Eagerly, emptyList()) val modulesByBuildFile = modulesStateFlow @@ -125,8 +145,7 @@ class PackageSearchProjectService(override val project: Project) : PackageSearch init { IntelliJApplication.PackageSearchApplicationCachesService - .apiPackageCache - .isOnlineFlow() + .isOnlineFlow .filter { it } .onEach { restart() } .launchIn(coroutineScope) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/PackageSearchApiPackageCache.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/PackageSearchApiPackageCache.kt index 365e045a..c4758283 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/PackageSearchApiPackageCache.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/utils/PackageSearchApiPackageCache.kt @@ -75,8 +75,7 @@ class PackageSearchApiPackageCache( .associateBy { it.id } val missingIds = ids - localDatabaseResults.keys if (missingIds.isNotEmpty()) { - val networkResults = runCatching { apiCall(missingIds) } - .getOrDefault(emptyMap()) + val networkResults = apiCall(missingIds) // TODO cache also miss in network to avoid pointless empty query if (networkResults.isNotEmpty()) { val packageEntries = networkResults.values.map { it.asCacheEntry() } From ce4a355dedfac02b193e15537079a5c141df555d Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 18:10:07 +0100 Subject: [PATCH 19/39] Fix PKGS-1285 Some Maven dependencies get "unknown" type (cherry picked from commit 318a3d7e545d4edae6f10e8ed58fe7d4c2659ee0) --- .../ui/model/infopanel/InfoPanelContent.kt | 11 +- .../ui/model/infopanel/asPanelContent.kt | 218 ++++++++++-------- ...eOverviewInfo.kt => PackageOverviewTab.kt} | 36 +-- .../messages/packageSearchBundle.properties | 2 + 4 files changed, 143 insertions(+), 124 deletions(-) rename plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/{PackageOverviewInfo.kt => PackageOverviewTab.kt} (92%) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContent.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContent.kt index 66d2afd9..b95b719b 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContent.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContent.kt @@ -23,13 +23,14 @@ sealed interface InfoPanelContent { ) : Scm } data class Repository(val name: String, val url: String) + data class Type(val name: String, val icon: IconProvider.Icon) val packageListId: PackageListItem.Package.Id val moduleId: PackageSearchModule.Identity val title: String val subtitle: String val icon: IconProvider.Icon - val type: String? + val type: Type? val licenses: List val authors: List val description: String? @@ -55,7 +56,7 @@ sealed interface InfoPanelContent { override val title: String, override val subtitle: String, override val icon: IconProvider.Icon, - override val type: String, + override val type: Type?, override val licenses: List, override val authors: List, override val description: String?, @@ -78,7 +79,7 @@ sealed interface InfoPanelContent { override val title: String, override val subtitle: String, override val icon: IconProvider.Icon, - override val type: String, + override val type: Type?, override val licenses: List, override val authors: List, override val description: String?, @@ -107,7 +108,7 @@ sealed interface InfoPanelContent { override val title: String, override val subtitle: String, override val icon: IconProvider.Icon, - override val type: String, + override val type: Type, override val licenses: List, override val authors: List, override val description: String?, @@ -124,7 +125,7 @@ sealed interface InfoPanelContent { override val title: String, override val subtitle: String, override val icon: IconProvider.Icon, - override val type: String, + override val type: Type, override val licenses: List, override val authors: List, override val description: String?, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/asPanelContent.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/asPanelContent.kt index 4042a86e..f2dc380a 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/asPanelContent.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/asPanelContent.kt @@ -1,6 +1,8 @@ package com.jetbrains.packagesearch.plugin.ui.model.infopanel import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message +import com.jetbrains.packagesearch.plugin.core.data.IconProvider +import com.jetbrains.packagesearch.plugin.core.data.PackageSearchDeclaredPackage import com.jetbrains.packagesearch.plugin.core.extensions.PackageSearchKnownRepositoriesContext import com.jetbrains.packagesearch.plugin.core.utils.icon import com.jetbrains.packagesearch.plugin.ui.model.getLatestVersion @@ -18,45 +20,66 @@ context(PackageSearchKnownRepositoriesContext) internal fun InfoPanelContentEvent.Package.Declared.Base.asPanelContent( onlyStable: Boolean, isLoading: Boolean, -) = - listOf( - InfoPanelContent.PackageInfo.Declared.Base( - moduleId = module.identity, - packageListId = packageListId, - tabTitle = message("packagesearch.ui.toolwindow.packages.details.info.overview"), - title = declaredPackage.displayName, - subtitle = declaredPackage.coordinates, - icon = declaredPackage.icon, - type = when (declaredPackage.remoteInfo) { +) = listOf( + InfoPanelContent.PackageInfo.Declared.Base( + moduleId = module.identity, + packageListId = packageListId, + tabTitle = message("packagesearch.ui.toolwindow.packages.details.info.overview"), + title = declaredPackage.displayName, + subtitle = declaredPackage.coordinates, + icon = declaredPackage.icon, + type = declaredPackage.typeInfo, + licenses = declaredPackage.remoteInfo?.licenses?.asInfoPanelLicenseList() ?: emptyList(), + authors = declaredPackage.remoteInfo?.authors?.mapNotNull { it.name } ?: emptyList(), + description = declaredPackage.remoteInfo + ?.description + ?.sanitizeDescription(), + scm = declaredPackage.remoteInfo?.scm?.asInfoPanelScm(), + readmeUrl = declaredPackage.remoteInfo?.scm?.readme?.htmlUrl ?: declaredPackage.remoteInfo?.scm?.readmeUrl, + repositories = declaredPackage.remoteInfo?.repositories() ?: emptyList(), + latestVersion = declaredPackage.getLatestVersion(onlyStable)?.versionName, + declaredVersion = declaredPackage.declaredVersion + ?.versionName + ?: message("packagesearch.ui.missingVersion"), + declaredScope = declaredPackage.declaredScope + ?: message("packagesearch.ui.missingScope"), + availableVersions = declaredPackage.remoteInfo + ?.versions + ?.all + ?.filter { if (onlyStable) it.normalizedVersion.isStable else true } + ?.map { it.normalizedVersion.versionName } + ?: emptyList(), + availableScopes = module.availableScopes, + isLoading = isLoading, + allowMissingScope = !module.dependencyMustHaveAScope + ) +) + +internal val PackageSearchDeclaredPackage.typeInfo: InfoPanelContent.PackageInfo.Type? + get() { + return InfoPanelContent.PackageInfo.Type( + name = when (remoteInfo) { is ApiMavenPackage -> message("packagesearch.configuration.maven.title") - null -> message("packagesearch.ui.toolwindow.packages.details.info.unknown") + null -> when (icon) { + IconProvider.Icons.MAVEN -> message("packagesearch.configuration.maven.title") + IconProvider.Icons.NPM -> message("packagesearch.configuration.npm.title") + IconProvider.Icons.COCOAPODS -> message("packagesearch.configuration.cocoapods.title") + else -> return null + } }, - licenses = declaredPackage.remoteInfo?.licenses?.asInfoPanelLicenseList() ?: emptyList(), - authors = declaredPackage.remoteInfo?.authors?.mapNotNull { it.name } ?: emptyList(), - description = declaredPackage.remoteInfo - ?.description - ?.sanitizeDescription(), - scm = declaredPackage.remoteInfo?.scm?.asInfoPanelScm(), - readmeUrl = declaredPackage.remoteInfo?.scm?.readmeUrl, - repositories = declaredPackage.remoteInfo?.repositories() ?: emptyList(), - latestVersion = declaredPackage.getLatestVersion(onlyStable)?.versionName, - declaredVersion = declaredPackage.declaredVersion - ?.versionName - ?: message("packagesearch.ui.missingVersion"), - declaredScope = declaredPackage.declaredScope - ?: message("packagesearch.ui.missingScope"), - availableVersions = declaredPackage.remoteInfo - ?.versions - ?.all - ?.filter { if (onlyStable) it.normalizedVersion.isStable else true } - ?.map { it.normalizedVersion.versionName } - ?: emptyList(), - availableScopes = module.availableScopes, - isLoading = isLoading, - allowMissingScope = !module.dependencyMustHaveAScope + icon = icon ) + } + +internal val ApiPackage.typeInfo: InfoPanelContent.PackageInfo.Type + get() = InfoPanelContent.PackageInfo.Type( + name = when (this) { + is ApiMavenPackage -> message("packagesearch.configuration.maven.title") + }, + icon = icon ) + private fun String.sanitizeDescription() = replace("\r\n", "\n") .replace("\r", "\n") @@ -68,76 +91,69 @@ context(PackageSearchKnownRepositoriesContext) internal fun InfoPanelContentEvent.Package.Declared.WithVariant.asPanelContent( onlyStable: Boolean, isLoading: Boolean, -) = - listOf( - InfoPanelContent.PackageInfo.Declared.WithVariant( - moduleId = module.identity, - packageListId = packageListId, - tabTitle = message("packagesearch.ui.toolwindow.packages.details.info.overview"), - title = declaredPackage.displayName, - subtitle = declaredPackage.coordinates, - icon = declaredPackage.icon, - type = when (declaredPackage.remoteInfo) { - is ApiMavenPackage -> message("packagesearch.configuration.maven.title") - null -> message("packagesearch.ui.toolwindow.packages.details.info.unknown") - }, - licenses = declaredPackage.remoteInfo?.licenses?.asInfoPanelLicenseList() ?: emptyList(), - authors = declaredPackage.remoteInfo?.authors?.mapNotNull { it.name } ?: emptyList(), - description = declaredPackage.remoteInfo - ?.description - ?.sanitizeDescription(), - scm = declaredPackage.remoteInfo?.scm?.asInfoPanelScm(), - readmeUrl = declaredPackage.remoteInfo?.scm?.readmeUrl, - repositories = declaredPackage.remoteInfo?.repositories() ?: emptyList(), - latestVersion = declaredPackage.getLatestVersion(onlyStable)?.versionName, - declaredVersion = declaredPackage.declaredVersion - ?.versionName - ?: message("packagesearch.ui.missingVersion"), - declaredScope = declaredPackage.declaredScope - ?: message("packagesearch.ui.missingScope"), - availableVersions = declaredPackage.remoteInfo - ?.versions - ?.all - ?.filter { if (onlyStable) it.normalizedVersion.isStable else true } - ?.map { it.normalizedVersion.versionName } - ?: emptyList(), - availableScopes = module.variants.getValue(variantName).availableScopes, - isLoading = isLoading, - compatibleVariants = module.variants.keys.sorted() - variantName, - declaredVariant = variantName, - allowMissingScope = !module.dependencyMustHaveAScope, - variantTerminology = module.variantTerminology - ) +) = listOf( + InfoPanelContent.PackageInfo.Declared.WithVariant( + moduleId = module.identity, + packageListId = packageListId, + tabTitle = message("packagesearch.ui.toolwindow.packages.details.info.overview"), + title = declaredPackage.displayName, + subtitle = declaredPackage.coordinates, + icon = declaredPackage.icon, + type = declaredPackage.typeInfo, + licenses = declaredPackage.remoteInfo?.licenses?.asInfoPanelLicenseList() ?: emptyList(), + authors = declaredPackage.remoteInfo?.authors?.mapNotNull { it.name } ?: emptyList(), + description = declaredPackage.remoteInfo + ?.description + ?.sanitizeDescription(), + scm = declaredPackage.remoteInfo?.scm?.asInfoPanelScm(), + readmeUrl = declaredPackage.remoteInfo?.scm?.readme?.htmlUrl ?: declaredPackage.remoteInfo?.scm?.readmeUrl, + repositories = declaredPackage.remoteInfo?.repositories() ?: emptyList(), + latestVersion = declaredPackage.getLatestVersion(onlyStable)?.versionName, + declaredVersion = declaredPackage.declaredVersion + ?.versionName + ?: message("packagesearch.ui.missingVersion"), + declaredScope = declaredPackage.declaredScope + ?: message("packagesearch.ui.missingScope"), + availableVersions = declaredPackage.remoteInfo + ?.versions + ?.all + ?.filter { if (onlyStable) it.normalizedVersion.isStable else true } + ?.map { it.normalizedVersion.versionName } + ?: emptyList(), + availableScopes = module.variants.getValue(variantName).availableScopes, + isLoading = isLoading, + compatibleVariants = module.variants.keys.sorted() - variantName, + declaredVariant = variantName, + allowMissingScope = !module.dependencyMustHaveAScope, + variantTerminology = module.variantTerminology ) +) context(PackageSearchKnownRepositoriesContext) internal fun InfoPanelContentEvent.Package.Remote.WithVariants.asPanelContent( isLoading: Boolean, -) = - listOf( - InfoPanelContent.PackageInfo.Remote.WithVariant( - tabTitle = message("packagesearch.ui.toolwindow.packages.details.info.overview"), - moduleId = module.identity, - packageListId = packageListId, - title = apiPackage.name, - subtitle = apiPackage.coordinates, - icon = apiPackage.icon, - type = when (apiPackage) { - is ApiMavenPackage -> message("packagesearch.configuration.maven.title") - }, - licenses = apiPackage.licenses?.asInfoPanelLicenseList() ?: emptyList(), - authors = apiPackage.authors.mapNotNull { it.name }, - description = apiPackage.description?.sanitizeDescription(), - scm = apiPackage.scm?.asInfoPanelScm(), - readmeUrl = apiPackage.scm?.readmeUrl, - primaryVariant = primaryVariantName, - additionalVariants = compatibleVariantNames.sorted() - primaryVariantName, - repositories = apiPackage.repositories(), - isLoading = isLoading, - isInstalledInPrimaryVariant = module.variants.getValue(primaryVariantName).declaredDependencies - .any { it.id == apiPackage.id } - ) +) = listOf( + InfoPanelContent.PackageInfo.Remote.WithVariant( + tabTitle = message("packagesearch.ui.toolwindow.packages.details.info.overview"), + moduleId = module.identity, + packageListId = packageListId, + title = apiPackage.name, + subtitle = apiPackage.coordinates, + icon = apiPackage.icon, + type = apiPackage.typeInfo, + licenses = apiPackage.licenses?.asInfoPanelLicenseList() ?: emptyList(), + authors = apiPackage.authors.mapNotNull { it.name }, + description = apiPackage.description?.sanitizeDescription(), + scm = apiPackage.scm?.asInfoPanelScm(), + readmeUrl = apiPackage.scm?.readme?.htmlUrl ?: apiPackage.scm?.readmeUrl, + primaryVariant = primaryVariantName, + additionalVariants = compatibleVariantNames.sorted() - primaryVariantName, + repositories = apiPackage.repositories(), + isLoading = isLoading, + isInstalledInPrimaryVariant = module.variants.getValue(primaryVariantName).declaredDependencies + .any { it.id == apiPackage.id } ) +) context(PackageSearchKnownRepositoriesContext) internal fun InfoPanelContentEvent.Package.Remote.Base.asPanelContent( @@ -150,14 +166,12 @@ internal fun InfoPanelContentEvent.Package.Remote.Base.asPanelContent( title = apiPackage.name, subtitle = apiPackage.coordinates, icon = apiPackage.icon, - type = when (apiPackage) { - is ApiMavenPackage -> message("packagesearch.configuration.maven.title") - }, + type = apiPackage.typeInfo, licenses = apiPackage.licenses?.asInfoPanelLicenseList() ?: emptyList(), authors = apiPackage.authors.mapNotNull { it.name }, description = apiPackage.description?.sanitizeDescription(), scm = apiPackage.scm?.asInfoPanelScm(), - readmeUrl = apiPackage.scm?.readmeUrl, + readmeUrl = apiPackage.scm?.readme?.htmlUrl ?: apiPackage.scm?.readmeUrl, repositories = apiPackage.repositories(), isLoading = isLoading ) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewTab.kt similarity index 92% rename from plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt rename to plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewTab.kt index fcaff406..94d2109c 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewInfo.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewTab.kt @@ -50,8 +50,8 @@ internal fun PackageOverviewTab( modifier = Modifier.fillMaxSize().padding(start = 4.dp) ) { Row(verticalAlignment = Alignment.Top) { - InfoPanelPackageTitle(modifier = Modifier.weight(1f), content.title, content.subtitle) - InfoPanelPackageActions(content, onPackageEvent) + PackageTitle(modifier = Modifier.weight(1f), content.title, content.subtitle) + Actions(content, onPackageEvent) } Column( modifier = Modifier.fillMaxWidth().padding(12.dp), @@ -94,18 +94,18 @@ internal fun PackageOverviewTab( } } - content.type?.let { PackageType(it, content.icon) } + content.type?.let { PackageType(it) } if (content.repositories.isNotEmpty()) { - InfoPanelPackageDetailLine( + DetailLabel( name = message("packagesearch.ui.toolwindow.packages.details.info.repositories"), value = content.repositories.map { it.name }.joinToString(", ") ) } if (content.licenses.isNotEmpty()) { - InfoPanelPackageLinks(content.licenses, onLinkClick) + PackageLinks(content.licenses, onLinkClick) } if (content.authors.isNotEmpty()) { - InfoPanelPackageDetailLine( + DetailLabel( name = message("packagesearch.ui.toolwindow.packages.details.info.authors"), value = content.authors.joinToString(", ") ) @@ -120,7 +120,7 @@ internal fun PackageOverviewTab( } content.scm?.let { - InfoPanelPackageScmLinks(it, onLinkClick) + ScmLinks(it, onLinkClick) } content.readmeUrl?.let { readmeUrl -> ExternalLink( @@ -132,7 +132,7 @@ internal fun PackageOverviewTab( } @Composable -private fun InfoPanelPackageActions( +private fun Actions( tabContent: InfoPanelContent.PackageInfo, onPackageEvent: (PackageListItemEvent) -> Unit, ) { @@ -217,24 +217,27 @@ private fun InfoPanelPackageActions( } @Composable -private fun PackageType(name: String, icon: IconProvider.Icon) { - Row(horizontalArrangement = Arrangement.spacedBy(2.dp), verticalAlignment = Alignment.CenterVertically) { +private fun PackageType(type: InfoPanelContent.PackageInfo.Type) { + Row( + horizontalArrangement = Arrangement.spacedBy(2.dp), + verticalAlignment = Alignment.CenterVertically + ) { LabelInfo( modifier = Modifier.defaultMinSize(90.dp), text = message("packagesearch.ui.toolwindow.packages.columns.type") ) - val iconPath = if (JewelTheme.isDark) icon.darkIconPath else icon.lightIconPath + val iconPath = if (JewelTheme.isDark) type.icon.darkIconPath else type.icon.lightIconPath Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { Icon(iconPath, null, IconProvider::class.java) - Text(name) + Text(type.name) } } } @Composable -private fun InfoPanelPackageDetailLine(name: String, value: String) { +private fun DetailLabel(name: String, value: String) { Row( horizontalArrangement = Arrangement.spacedBy(2.dp), verticalAlignment = Alignment.Top, @@ -247,9 +250,8 @@ private fun InfoPanelPackageDetailLine(name: String, value: String) { } } - @Composable -private fun InfoPanelPackageScmLinks( +private fun ScmLinks( scm: InfoPanelContent.PackageInfo.Scm, onLinkClick: (String) -> Unit, ) { @@ -269,7 +271,7 @@ private fun InfoPanelPackageScmLinks( } @Composable -private fun InfoPanelPackageTitle( +private fun PackageTitle( modifier: Modifier = Modifier, name: String?, id: String, @@ -286,7 +288,7 @@ private fun InfoPanelPackageTitle( } @Composable -private fun InfoPanelPackageLinks( +private fun PackageLinks( licenses: List, onLinkClick: (String) -> Unit, ) { diff --git a/plugin/src/main/resources/messages/packageSearchBundle.properties b/plugin/src/main/resources/messages/packageSearchBundle.properties index a0154d02..96e92e95 100644 --- a/plugin/src/main/resources/messages/packageSearchBundle.properties +++ b/plugin/src/main/resources/messages/packageSearchBundle.properties @@ -19,6 +19,8 @@ packagesearch.configuration.gradle.title=Gradle packagesearch.configuration.maven.scopes.default=Default Maven scope: packagesearch.configuration.maven.scopes=Maven scopes: packagesearch.configuration.maven.title=Maven +packagesearch.configuration.npm.title=NPM +packagesearch.configuration.cocoapods.title=Cocoapods packagesearch.configuration.restore.defaults=Restore defaults packagesearch.configuration.recovery.caches=Delete Package Search project caches packagesearch.configuration.recovery.caches.global=Delete Package Search global caches From c519711df3f7b935dd4257d5e2ce705c87ab0f48 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 18:47:24 +0100 Subject: [PATCH 20/39] Reduce initial divider position in PackageSearchPackagePanel (cherry picked from commit d9a4fac081a2b2bc6413454c167f8011057d40f8) --- .../packagesearch/plugin/ui/PackageSearchPackagePanel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt index 871f01f2..62c26228 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt @@ -22,7 +22,7 @@ fun PackageSearchPackagePanel( if (isInfoPanelOpen) { HorizontalSplitLayout( modifier = it, - initialDividerPosition = 900.dp, + initialDividerPosition = 700.dp, first = { PackageSearchCentralPanel(it, onLinkClick) }, second = { PackageSearchInfoPanel(it, onLinkClick, onPackageEvent) }, maxRatio = 0.8f From c0bc1f68ce4668644bacb0fa281123e380f1ab11 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 19:19:56 +0100 Subject: [PATCH 21/39] Refactor PackageListBuilder removing count This commit removes unused properties 'count' and 'attributes' from PackageList Builder. Additionally, a misnamed variable 'attriutes' has been renamed to 'attributes' across different methods enhancing code readability and maintenance. (cherry picked from commit 8b3796c69b561073f37e620c7ba2ff1155591971) --- .../model/packageslist/PackageListBuilder.kt | 37 ++++++++----------- .../ui/model/packageslist/PackageListItem.kt | 3 +- .../packages/items/PackageGroupHeader.kt | 6 +-- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt index f3d34010..14c4ac8a 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt @@ -81,16 +81,17 @@ class PackageListBuilder( val dependenciesToShow = base.declaredDependencies .filter { it.matchesSearchQuery() } val state = getStateForOrOpen(id) - addHeader( - title = base.name, - id = id, - count = base.declaredDependencies.size, - state = state, - additionalContent = when (id) { - in headerLoadingStates -> PackageListItem.Header.AdditionalContent.Loading - else -> dependenciesToShow.getUpdatesAvailableAdditionalContent() - } - ) + if (dependenciesToShow.isNotEmpty() || isCompact) { + addHeader( + title = base.name, + id = id, + state = state, + additionalContent = when (id) { + in headerLoadingStates -> PackageListItem.Header.AdditionalContent.Loading + else -> dependenciesToShow.getUpdatesAvailableAdditionalContent() + } + ) + } if (state == PackageListItem.Header.State.OPEN) { dependenciesToShow .filter { it.matchesSearchQuery() } @@ -144,7 +145,6 @@ class PackageListBuilder( title: String, id: PackageListItem.Header.Id, state: PackageListItem.Header.State, - count: Int?, attributes: List = emptyList(), additionalContent: PackageListItem.Header.AdditionalContent? = null, ) { @@ -153,8 +153,7 @@ class PackageListBuilder( title = title, id = id, state = state, - count = count, - attriutes = attributes, + attributes = attributes, additionalContent = additionalContent, ) ) @@ -186,9 +185,8 @@ class PackageListBuilder( moduleIdentity = module.identity, variantName = variant.name ), - count = variant.declaredDependencies.size, - attributes = variant.attributes.map { it.value }, state = state, + attributes = variant.attributes.map { it.value }, additionalContent = when (id) { in headerLoadingStates -> PackageListItem.Header.AdditionalContent.Loading else -> variant.getUpdatesAvailableAdditionalContent() @@ -229,7 +227,6 @@ class PackageListBuilder( addHeader( title = module.name, id = id, - count = dependenciesToShow.size, state = state, additionalContent = when (id) { in headerLoadingStates -> PackageListItem.Header.AdditionalContent.Loading @@ -270,8 +267,7 @@ class PackageListBuilder( state = when (headerCollapsedStates[headerId]) { TargetState.OPEN -> PackageListItem.Header.State.LOADING else -> PackageListItem.Header.State.CLOSED - }, - count = null + } ) is Search.Query.WithVariants -> addHeader( @@ -282,8 +278,7 @@ class PackageListBuilder( else -> PackageListItem.Header.State.CLOSED }, attributes = search.attributes, - additionalContent = search.buildVariantsText(), - count = null + additionalContent = search.buildVariantsText() ) is Search.Results.Base -> addFromSearchQueryBase( @@ -313,7 +308,6 @@ class PackageListBuilder( addHeader( title = PackageSearchBundle.message("packagesearch.ui.toolwindow.tab.packages.searchResults"), id = headerId, - count = search.packages.size, state = state, attributes = search.attributes, additionalContent = search.buildVariantsText(), @@ -366,7 +360,6 @@ class PackageListBuilder( addHeader( title = PackageSearchBundle.message("packagesearch.ui.toolwindow.tab.packages.searchResults"), id = headerId, - count = search.packages.size, state = state ) if (state == PackageListItem.Header.State.OPEN) { diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListItem.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListItem.kt index 72d631d9..177d8aab 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListItem.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListItem.kt @@ -18,8 +18,7 @@ sealed interface PackageListItem { override val title: String, override val id: Id, val state: State, - val count: Int? = null, - val attriutes: List = emptyList(), + val attributes: List = emptyList(), val additionalContent: AdditionalContent? = null, ) : PackageListItem { diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt index 01bb324b..05f7538d 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt @@ -37,7 +37,6 @@ fun PackageListHeader( content: PackageListItem.Header, onEvent: (PackageListItemEvent) -> Unit, ) { - // TODO check if needed val backgroundColor = if (JewelTheme.isDark) { pickComposeColorFromLaf("ToolWindow.HeaderTab.selectedInactiveBackground") @@ -90,8 +89,7 @@ fun PackageListHeader( text = content.title, maxLines = 1 ) - content.count?.let { LabelInfo(text = it.toString()) } - if (content.attriutes.isNotEmpty()) { + if (content.attributes.isNotEmpty()) { Box( modifier = Modifier .onClick { @@ -101,7 +99,7 @@ fun PackageListHeader( contentAlignment = Alignment.Center, ) { LabelInfo( - text = content.attriutes.joinToString(" "), + text = content.attributes.joinToString(" "), maxLines = 1 ) } From 69469b0770a1e6240818a9612ebf070d14270d99 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Fri, 8 Dec 2023 19:40:40 +0100 Subject: [PATCH 22/39] Made header title clickable as well, made updates count in header be filtered by search query (cherry picked from commit 7c1ece2f5d82f13f37799770e0d522be48e25638) --- .../ui/model/packageslist/PackageListBuilder.kt | 10 +++------- .../panels/packages/items/PackageGroupHeader.kt | 16 ++++++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt index 14c4ac8a..a432dab5 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListBuilder.kt @@ -35,12 +35,8 @@ class PackageListBuilder( } private fun List.getUpdatesAvailableAdditionalContent() = - count { it.hasUpdates(onlyStable) } - .takeIf { it > 0 } - ?.let { PackageListItem.Header.AdditionalContent.UpdatesAvailableCount(it) } - - private fun PackageSearchModuleVariant.getUpdatesAvailableAdditionalContent() = - declaredDependencies.count { it.hasUpdates(onlyStable) } + filter { it.matchesSearchQuery() } + .count { it.hasUpdates(onlyStable) } .takeIf { it > 0 } ?.let { PackageListItem.Header.AdditionalContent.UpdatesAvailableCount(it) } @@ -189,7 +185,7 @@ class PackageListBuilder( attributes = variant.attributes.map { it.value }, additionalContent = when (id) { in headerLoadingStates -> PackageListItem.Header.AdditionalContent.Loading - else -> variant.getUpdatesAvailableAdditionalContent() + else -> variant.declaredDependencies.getUpdatesAvailableAdditionalContent() } ) if (state == PackageListItem.Header.State.OPEN) { diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt index 05f7538d..e13e1981 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt @@ -1,6 +1,7 @@ package com.jetbrains.packagesearch.plugin.ui.panels.packages.items import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement.SpaceBetween import androidx.compose.foundation.layout.Box @@ -54,7 +55,7 @@ fun PackageListHeader( verticalAlignment = Alignment.CenterVertically, ) { Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { - Box( + Row( modifier = Modifier.onClick(enabled = content.state != State.LOADING) { onEvent( PackageListItemEvent.SetHeaderState( @@ -65,6 +66,8 @@ fun PackageListHeader( ) ) } + .pointerHoverIcon(PointerIcon(Cursor(Cursor.HAND_CURSOR))), + horizontalArrangement = Arrangement.spacedBy(8.dp) ) { when (content.state) { State.OPEN -> Icon( @@ -83,12 +86,13 @@ fun PackageListHeader( State.LOADING -> CircularProgressIndicator() } + + Text( + fontWeight = FontWeight(600), + text = content.title, + maxLines = 1 + ) } - Text( - fontWeight = FontWeight(600), - text = content.title, - maxLines = 1 - ) if (content.attributes.isNotEmpty()) { Box( modifier = Modifier From 5b14f6fcbf01a7c161217a8a855364fc13e6d034 Mon Sep 17 00:00:00 2001 From: Fabrizio Scarponi <36624359+fscarponi@users.noreply.github.com> Date: Fri, 8 Dec 2023 19:53:01 +0100 Subject: [PATCH 23/39] Fix PKGS-1319 - Search glitch on module selection change (#7) (cherry picked from commit d888fb89b02f5bbfd891f9d7237fea5c34e0584a) --- .../plugin/ui/model/packageslist/PackageListViewModel.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt index 9ae4c33a..a1d2d41d 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt @@ -139,6 +139,13 @@ class PackageListViewModel(private val project: Project) : Disposable { else -> value } } + }.modifiedBy(selectedModulesFlow) { current: Map, change -> + val changeIdentities = change.map { it.identity } + if (current.keys.any { it.moduleIdentity !in changeIdentities }) { + emptyMap() + } else { + current + } } .stateIn(viewModelScope, SharingStarted.Eagerly, emptyMap()) From 0de896312e6e48f9478fca8f9173948e121460ea Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Mon, 11 Dec 2023 16:54:14 +0100 Subject: [PATCH 24/39] Add logging facilities for analytics Integrated analytics event loggers to track events such as package installations, removed or upgrades, search requests, toggles, and GUI actions. This will aid in better understanding user behavior and improving features. The commit also includes changes for issues with module selection and aligning panels but focuses mainly on the introduction of analytics. (cherry picked from commit f07465351af3c8037372ef10d63c1b60f759e5b8) --- plugin/build.gradle.kts | 6 +- .../packagesearch/plugin/fus/FUSGroupIds.kt | 120 ++++++++ .../plugin/fus/PackageSearchEventsLogger.kt | 266 ++++++++++++++++++ .../services/PackageSearchProjectService.kt | 8 +- .../ui/model/infopanel/InfoPanelViewModel.kt | 5 +- .../packageslist/PackageListViewModel.kt | 127 +++++++-- .../plugin/ui/model/packageslist/Utils.kt | 9 +- .../packages/PackageSearchCentralPanel.kt | 1 + .../panels/packages/PackageSearchSearchBar.kt | 3 +- .../ui/panels/side/PackageOverviewTab.kt | 23 +- .../ui/panels/side/PackageSearchInfoPanel.kt | 22 +- plugin/src/main/resources/META-INF/plugin.xml | 3 + 12 files changed, 549 insertions(+), 44 deletions(-) create mode 100644 plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/FUSGroupIds.kt create mode 100644 plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 38838086..e7765cd6 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -1,5 +1,6 @@ @file:Suppress("UnstableApiUsage") +import kotlin.math.max import org.jetbrains.intellij.tasks.PublishPluginTask import org.jetbrains.packagesearch.gradle.lafFile import org.jetbrains.packagesearch.gradle.logCategoriesFile @@ -9,7 +10,6 @@ import org.jetbrains.packagesearch.gradle.patchSettingsFile import org.jetbrains.packagesearch.gradle.patchTextRegistryFile import org.jetbrains.packagesearch.gradle.registryTextFile import org.jetbrains.packagesearch.gradle.settingsFile -import kotlin.math.max plugins { @@ -40,6 +40,10 @@ packagesearch { isRunIdeEnabled = true } +intellij { + plugins.add("org.jetbrains.idea.reposearch") +} + val tooling: Configuration by configurations.creating { isCanBeResolved = true } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/FUSGroupIds.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/FUSGroupIds.kt new file mode 100644 index 00000000..5f6bd195 --- /dev/null +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/FUSGroupIds.kt @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright 2000-2022 JetBrains s.r.o. and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ + +package com.jetbrains.packagesearch.plugin.fus + +object FUSGroupIds { + + const val GROUP_ID = "packagesearch" + + // FIELDS + const val IS_SEARCH_HEADER = "is_search_header" + const val PANEL_OPENED = "info_panel_opened" + const val GO_TO_SOURCE = "got_to_source" + const val HEADER_ATTRIBUTES_CLICK = "header_attributes_click" + const val HEADER_VARIANTS_CLICK = "header_variants_click" + const val MODULE_OPERATION_PROVIDER_CLASS = "module_operation_provider_class" + const val PACKAGE_ID = "package_id" + const val PACKAGE_VERSION = "package_version" + const val PACKAGE_FROM_VERSION = "package_from_version" + const val REPOSITORY_ID = "repository_id" + const val REPOSITORY_URL = "repository_url" + const val REPOSITORY_USES_CUSTOM_URL = "repository_uses_custom_url" + const val PACKAGE_IS_INSTALLED = "package_is_installed" + const val TARGET_MODULES = "target_modules" + const val TARGET_MODULES_MIXED_BUILD_SYSTEMS = "target_modules_mixed_build_systems" + + const val PREFERENCES_GRADLE_SCOPES_COUNT = "preferences_gradle_scopes_count" + const val PREFERENCES_UPDATE_SCOPES_ON_USAGE = "preferences_update_scopes_on_usage" + const val PREFERENCES_DEFAULT_GRADLE_SCOPE_CHANGED = "preferences_default_gradle_scope_changed" + const val PREFERENCES_DEFAULT_MAVEN_SCOPE_CHANGED = "preferences_default_maven_scope_changed" + const val PREFERENCES_AUTO_ADD_REPOSITORIES = "preferences_auto_add_repositories" + const val DETAILS_LINK_LABEL = "details_link_label" + const val CHECKBOX_NAME = "checkbox_name" + const val CHECKBOX_STATE = "checkbox_state" + const val SEARCH_QUERY_LENGTH = "search_query_length" + const val SORT_METRIC = "sort_metric" + + enum class DetailsLinkTypes { Scm, Documentation, License, ProjectWebsite, Readme } + + enum class IndexedRepositories(val ids: Set, val urls: Set) { + OTHER(ids = emptySet(), urls = emptySet()), + NONE(ids = emptySet(), urls = emptySet()), + MAVEN_CENTRAL( + ids = setOf("maven_central"), + urls = setOf( + "https://repo.maven.apache.org/maven2/", + "https://maven-central.storage-download.googleapis.com/maven2", + "https://repo1.maven.org/maven2/" + ) + ), + GOOGLE_MAVEN( + ids = setOf("gmaven"), + urls = setOf("https://maven.google.com/") + ), + JETBRAINS_REPOS( + ids = setOf("dokka_dev", "compose_dev", "ktor_eap", "space_sdk"), + urls = setOf( + "https://maven.pkg.jetbrains.space/kotlin/p/dokka/dev/", + "https://maven.pkg.jetbrains.space/public/p/compose/dev/", + "https://maven.pkg.jetbrains.space/public/p/ktor/eap/", + "https://maven.pkg.jetbrains.space/public/p/space/maven/" + ) + ), + CLOJARS( + ids = setOf("clojars"), + urls = setOf("https://repo.clojars.org/") + ); + + companion object { + + fun forId(repositoryId: String?): IndexedRepositories { + if (repositoryId.isNullOrBlank()) return NONE + return entries.find { repositoryId in it.ids } ?: OTHER + } + + fun validateUrl(repositoryUrl: String?): String? { + if (repositoryUrl.isNullOrBlank()) return null + return if (repositoryUrl in indexedRepositoryUrls) repositoryUrl else null + } + } + } + + val indexedRepositoryUrls = IndexedRepositories.entries + .flatMap { it.urls } + + // EVENTS + const val PACKAGE_INSTALLED = "package_installed" + const val PACKAGE_REMOVED = "package_removed" + const val PACKAGE_VERSION_UPDATED = "package_version_updated" + const val PACKAGE_SCOPE_UPDATED = "package_scope_updated" + const val PACKAGE_VARIANT_UPDATED = "package_variant_updated" + const val REPOSITORY_ADDED = "repository_added" + const val REPOSITORY_REMOVED = "repository_removed" + const val PREFERENCES_CHANGED = "preferences_changed" + const val PREFERENCES_RESTORE_DEFAULTS = "preferences_restore_defaults" + const val PACKAGE_SELECTED = "package_selected" + const val MODULES_SELECTED = "modules_selected" + const val DETAILS_LINK_CLICK = "details_link_click" + const val TOGGLE = "toggle" + const val SORT_METRIC_CHANGED = "sort_metric_changed" + const val SEARCH_REQUEST = "search_request" + const val SEARCH_QUERY_CLEAR = "search_query_clear" + const val UPGRADE_ALL = "upgrade_all_event" + + // VALIDATORS + const val RULE_TOP_PACKAGE_ID = "top_package_id" +} diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt new file mode 100644 index 00000000..4675f481 --- /dev/null +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt @@ -0,0 +1,266 @@ +/******************************************************************************* + * Copyright 2000-2022 JetBrains s.r.o. and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ + +@file:Suppress("UnstableApiUsage") + +package com.jetbrains.packagesearch.plugin.fus + +import com.intellij.internal.statistic.eventLog.EventLogGroup +import com.intellij.internal.statistic.eventLog.events.BaseEventId +import com.intellij.internal.statistic.eventLog.events.EventFields +import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector +import com.intellij.openapi.diagnostic.RuntimeExceptionWithAttachments +import com.jetbrains.packagesearch.plugin.PackageSearchBundle +import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule +import com.jetbrains.packagesearch.plugin.utils.logError +import org.jetbrains.idea.reposearch.statistics.TopPackageIdValidationRule +import org.jetbrains.packagesearch.api.v3.ApiRepository + +private const val FUS_ENABLED = true + +class PackageSearchEventsLogger : CounterUsagesCollector() { + override fun getGroup() = GROUP +} + +private const val VERSION = 13 + +private val GROUP = EventLogGroup(FUSGroupIds.GROUP_ID, VERSION) + +// FIELDS +private val buildSystemField = EventFields.Class(FUSGroupIds.MODULE_OPERATION_PROVIDER_CLASS) +private val packageIdField = + EventFields.StringValidatedByCustomRule(FUSGroupIds.PACKAGE_ID, TopPackageIdValidationRule::class.java) +private val packageVersionField = + EventFields.StringValidatedByRegexpReference(FUSGroupIds.PACKAGE_VERSION, regexpRef = "version") +private val packageFromVersionField = + EventFields.StringValidatedByRegexpReference(FUSGroupIds.PACKAGE_FROM_VERSION, regexpRef = "version") +private val repositoryIdField = EventFields.Enum(FUSGroupIds.REPOSITORY_ID) +private val repositoryUrlField = + EventFields.String(FUSGroupIds.REPOSITORY_URL, allowedValues = FUSGroupIds.indexedRepositoryUrls) +private val repositoryUsesCustomUrlField = EventFields.Boolean(FUSGroupIds.REPOSITORY_USES_CUSTOM_URL) +private val packageIsInstalledField = EventFields.Boolean(FUSGroupIds.PACKAGE_IS_INSTALLED) +private val targetModulesCountField = EventFields.Int(FUSGroupIds.TARGET_MODULES) +private val targetModulesMixedBuildSystemsField = + EventFields.Boolean(FUSGroupIds.TARGET_MODULES_MIXED_BUILD_SYSTEMS) +val preferencesGradleScopeCountField = EventFields.Int(FUSGroupIds.PREFERENCES_GRADLE_SCOPES_COUNT) +val preferencesUpdateScopesOnUsageField = EventFields.Boolean(FUSGroupIds.PREFERENCES_UPDATE_SCOPES_ON_USAGE) +val preferencesDefaultGradleScopeChangedField = + EventFields.Boolean(FUSGroupIds.PREFERENCES_DEFAULT_GRADLE_SCOPE_CHANGED) +val preferencesDefaultMavenScopeChangedField = + EventFields.Boolean(FUSGroupIds.PREFERENCES_DEFAULT_MAVEN_SCOPE_CHANGED) +internal val preferencesAutoAddRepositoriesField = + EventFields.Boolean(FUSGroupIds.PREFERENCES_AUTO_ADD_REPOSITORIES) +private val detailsLinkLabelField = + EventFields.Enum(FUSGroupIds.DETAILS_LINK_LABEL) +private val toggleValueField = EventFields.Boolean(FUSGroupIds.CHECKBOX_STATE) +private val searchQueryLengthField = EventFields.Int(FUSGroupIds.SEARCH_QUERY_LENGTH) +private val isSearchHeader = EventFields.Boolean(FUSGroupIds.IS_SEARCH_HEADER) + +// EVENTS +private val packageInstalledEvent = GROUP.registerEvent( + eventId = FUSGroupIds.PACKAGE_INSTALLED, + eventField1 = packageIdField, + eventField2 = buildSystemField +) +private val packageRemovedEvent = GROUP.registerEvent( + eventId = FUSGroupIds.PACKAGE_REMOVED, + eventField1 = packageIdField, + eventField2 = packageVersionField, + eventField3 = buildSystemField +) +private val packageVersionChangedEvent = GROUP.registerVarargEvent( + eventId = FUSGroupIds.PACKAGE_VERSION_UPDATED, + packageIdField, packageFromVersionField, packageVersionField, buildSystemField +) +private val packageScopeChangedEvent = GROUP.registerEvent( + eventId = FUSGroupIds.PACKAGE_SCOPE_UPDATED, + eventField1 = packageIdField, + eventField2 = buildSystemField +) +private val packageVariantChangedEvent = GROUP.registerEvent( + eventId = FUSGroupIds.PACKAGE_VARIANT_UPDATED, + eventField1 = packageIdField, + eventField2 = buildSystemField +) +private val repositoryAddedEvent = GROUP.registerEvent( + eventId = FUSGroupIds.REPOSITORY_ADDED, + eventField1 = repositoryIdField, + eventField2 = repositoryUrlField +) +private val repositoryRemovedEvent = GROUP.registerEvent( + eventId = FUSGroupIds.REPOSITORY_REMOVED, + eventField1 = repositoryIdField, + eventField2 = repositoryUrlField, + eventField3 = repositoryUsesCustomUrlField +) +private val preferencesRestoreDefaultsEvent = GROUP.registerEvent(FUSGroupIds.PREFERENCES_RESTORE_DEFAULTS) +private val packageSelectedEvent = + GROUP.registerEvent(eventId = FUSGroupIds.PACKAGE_SELECTED, packageIsInstalledField) +private val targetModulesSelectedEvent = GROUP.registerEvent( + eventId = FUSGroupIds.MODULES_SELECTED, + eventField1 = targetModulesCountField, + eventField2 = targetModulesMixedBuildSystemsField +) +private val detailsLinkClickEvent = GROUP.registerEvent( + eventId = FUSGroupIds.DETAILS_LINK_CLICK, + eventField1 = detailsLinkLabelField +) +private val onlyStableToggleEvent = GROUP.registerEvent( + eventId = FUSGroupIds.TOGGLE, + eventField1 = toggleValueField, +) +private val searchRequestEvent = GROUP.registerEvent( + eventId = FUSGroupIds.SEARCH_REQUEST, + eventField1 = searchQueryLengthField +) +private val searchQueryClearEvent = GROUP.registerEvent(FUSGroupIds.SEARCH_QUERY_CLEAR) +private val upgradeAllEvent = GROUP.registerEvent(FUSGroupIds.UPGRADE_ALL) +private val infoPanelOpenedEvent = GROUP.registerEvent(FUSGroupIds.PANEL_OPENED) +private val goToSourceEvent = GROUP.registerEvent( + eventId = FUSGroupIds.GO_TO_SOURCE, + eventField1 = buildSystemField, + eventField2 = packageIdField +) +private val headerAttributesClick = GROUP.registerEvent( + FUSGroupIds.HEADER_ATTRIBUTES_CLICK, + eventField1 = isSearchHeader +) +private val headerVariantClick = GROUP.registerEvent(FUSGroupIds.HEADER_VARIANTS_CLICK) +fun logPackageInstalled( + packageIdentifier: String, + targetModule: PackageSearchModule, +) = runSafelyIfEnabled(packageInstalledEvent) { + log(packageIdentifier, targetModule::class.java) +} + +fun logPackageRemoved( + packageIdentifier: String, + packageVersion: String?, + targetModule: PackageSearchModule, +) = runSafelyIfEnabled(packageRemovedEvent) { + log(packageIdentifier, packageVersion, targetModule::class.java) +} + +fun logPackageVersionChanged( + packageIdentifier: String, + packageFromVersion: String?, + packageTargetVersion: String, + targetModule: PackageSearchModule, +) = runSafelyIfEnabled(packageVersionChangedEvent) { + log( + packageIdField.with(packageIdentifier), + packageFromVersionField.with(packageFromVersion), + packageVersionField.with(packageTargetVersion), + buildSystemField.with(targetModule::class.java) + ) +} + +fun logPackageVariantChanged( + packageIdentifier: String, + targetModule: PackageSearchModule, +) = runSafelyIfEnabled(packageVariantChangedEvent) { + log(packageIdentifier, targetModule::class.java) +} + +fun logPackageScopeChanged( + packageIdentifier: String, + targetModule: PackageSearchModule, +) = runSafelyIfEnabled(packageScopeChangedEvent) { + log(packageIdentifier, targetModule::class.java) +} + +fun logRepositoryAdded(model: ApiRepository) = runSafelyIfEnabled(repositoryAddedEvent) { + log(FUSGroupIds.IndexedRepositories.forId(model.id), FUSGroupIds.IndexedRepositories.validateUrl(model.url)) +} + +fun logRepositoryRemoved(model: ApiRepository) = runSafelyIfEnabled(repositoryRemovedEvent) { + val repository = FUSGroupIds.IndexedRepositories.forId(model.id) + val validatedUrl = FUSGroupIds.IndexedRepositories.validateUrl(model.url) + val usesCustomUrl = repository != FUSGroupIds.IndexedRepositories.NONE && + repository != FUSGroupIds.IndexedRepositories.OTHER && + validatedUrl == null + log(repository, validatedUrl, usesCustomUrl) +} + +fun logPreferencesRestoreDefaults() = runSafelyIfEnabled(preferencesRestoreDefaultsEvent) { + log() +} + +fun logTargetModuleSelected(targetModules: List) = + runSafelyIfEnabled(targetModulesSelectedEvent) { + if (targetModules.isNotEmpty()) { + log(targetModules.size, targetModules.groupBy { it.identity.group }.keys.size != 1) + } + } + +fun logPackageSelected(isInstalled: Boolean) = runSafelyIfEnabled(packageSelectedEvent) { + log(isInstalled) +} + +fun logDetailsLinkClick(type: FUSGroupIds.DetailsLinkTypes) = runSafelyIfEnabled(detailsLinkClickEvent) { + log(type) +} + +fun logOnlyStableToggle(state: Boolean) = runSafelyIfEnabled(onlyStableToggleEvent) { + log(state) +} + +fun logSearchRequest(query: String) = runSafelyIfEnabled(searchRequestEvent) { + log(query.length) +} + +fun logSearchQueryClear() = runSafelyIfEnabled(searchQueryClearEvent) { + log() +} + +fun logUpgradeAll() = runSafelyIfEnabled(upgradeAllEvent) { + log() +} + +fun logInfoPanelOpened() = runSafelyIfEnabled(infoPanelOpenedEvent) { + log() +} + +fun logGoToSource( + module: PackageSearchModule, + packageId: String, +) = runSafelyIfEnabled(goToSourceEvent) { + log(module::class.java, packageId) +} + +fun logHeaderAttributesClick(isSearchHeader: Boolean) = runSafelyIfEnabled(headerAttributesClick) { + log(isSearchHeader) +} + +fun logHeaderVariantsClick() = runSafelyIfEnabled(headerVariantClick) { + log() +} + +private fun runSafelyIfEnabled(event: T, action: T.() -> Unit) { + if (FUS_ENABLED) { + try { + event.action() + } catch (e: RuntimeException) { + logError( + message = PackageSearchBundle.message("packagesearch.logging.error", event.eventId), + throwable = RuntimeExceptionWithAttachments( + "Non-critical error while logging analytics event. This doesn't impact plugin functionality.", + e + ) + ) + } + } +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt index 8802473d..e2f44ffb 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt @@ -3,7 +3,6 @@ package com.jetbrains.packagesearch.plugin.services import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer -import com.intellij.openapi.Disposable import com.intellij.openapi.application.readAction import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level @@ -17,6 +16,7 @@ import com.jetbrains.packagesearch.plugin.core.utils.PackageSearchProjectCachesS import com.jetbrains.packagesearch.plugin.core.utils.fileOpenedFlow import com.jetbrains.packagesearch.plugin.core.utils.replayOn import com.jetbrains.packagesearch.plugin.core.utils.withInitialValue +import com.jetbrains.packagesearch.plugin.fus.logOnlyStableToggle import com.jetbrains.packagesearch.plugin.utils.PackageSearchApplicationCachesService import com.jetbrains.packagesearch.plugin.utils.WindowedModuleBuilderContext import com.jetbrains.packagesearch.plugin.utils.filterNotNullKeys @@ -27,8 +27,6 @@ import com.jetbrains.packagesearch.plugin.utils.timer import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.BufferOverflow.DROP_OLDEST import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow @@ -144,6 +142,10 @@ class PackageSearchProjectService(override val project: Project) : PackageSearch init { + stableOnlyStateFlow + .onEach { logOnlyStableToggle(it) } + .launchIn(coroutineScope) + IntelliJApplication.PackageSearchApplicationCachesService .isOnlineFlow .filter { it } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt index 996e41d2..d3015e90 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt @@ -65,7 +65,8 @@ class InfoPanelViewModel(private val project: Project) : Disposable { } } } - }.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) + } + .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) private val activeTabTitleMutableStateFlow: MutableStateFlow = MutableStateFlow(null) val activeTabTitleFlow = activeTabTitleMutableStateFlow.asStateFlow() @@ -74,7 +75,6 @@ class InfoPanelViewModel(private val project: Project) : Disposable { activeTabTitleMutableStateFlow.value = title } - init { combine( tabs.map { it.map { it.tabTitle } }, @@ -87,7 +87,6 @@ class InfoPanelViewModel(private val project: Project) : Disposable { .launchIn(viewModelScope) } - fun setPackage( module: PackageSearchModule.Base, declaredPackage: PackageSearchDeclaredPackage, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt index a1d2d41d..f7a215d4 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt @@ -13,6 +13,20 @@ import com.jetbrains.packagesearch.plugin.core.data.PackageSearchDependencyManag import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModuleEditor import com.jetbrains.packagesearch.plugin.core.utils.IntelliJApplication +import com.jetbrains.packagesearch.plugin.fus.logGoToSource +import com.jetbrains.packagesearch.plugin.fus.logHeaderAttributesClick +import com.jetbrains.packagesearch.plugin.fus.logHeaderVariantsClick +import com.jetbrains.packagesearch.plugin.fus.logInfoPanelOpened +import com.jetbrains.packagesearch.plugin.fus.logPackageInstalled +import com.jetbrains.packagesearch.plugin.fus.logPackageRemoved +import com.jetbrains.packagesearch.plugin.fus.logPackageScopeChanged +import com.jetbrains.packagesearch.plugin.fus.logPackageSelected +import com.jetbrains.packagesearch.plugin.fus.logPackageVariantChanged +import com.jetbrains.packagesearch.plugin.fus.logPackageVersionChanged +import com.jetbrains.packagesearch.plugin.fus.logSearchQueryClear +import com.jetbrains.packagesearch.plugin.fus.logSearchRequest +import com.jetbrains.packagesearch.plugin.fus.logTargetModuleSelected +import com.jetbrains.packagesearch.plugin.fus.logUpgradeAll import com.jetbrains.packagesearch.plugin.ui.model.ToolWindowViewModel import com.jetbrains.packagesearch.plugin.ui.model.getLatestVersion import com.jetbrains.packagesearch.plugin.ui.model.hasUpdates @@ -38,9 +52,12 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -74,19 +91,31 @@ class PackageListViewModel(private val project: Project) : Disposable { val isOnlineSearchEnabledFlow = combine(listOf(selectedModuleIdsSharedFlow.map { it.size == 1 }, isOnline)) { it.all { it } - }.stateIn(viewModelScope, SharingStarted.Eagerly, true) - - private val selectedModulesFlow - get() = combine( - selectedModuleIdsSharedFlow, - project.PackageSearchProjectService.modulesByIdentity - ) { selectedModules, modulesByIdentity -> - modulesByIdentity.filterKeys { it in selectedModules }.values.toList() } + .stateIn(viewModelScope, SharingStarted.Eagerly, true) + + private val selectedModulesFlow = combine( + selectedModuleIdsSharedFlow, + project.PackageSearchProjectService.modulesByIdentity + ) { selectedModules, modulesByIdentity -> + modulesByIdentity.filterKeys { it in selectedModules }.values.toList() + } + .shareIn(viewModelScope, SharingStarted.Lazily) private val searchQueryMutableStateFlow = MutableStateFlow("") val searchQueryStateFlow = searchQueryMutableStateFlow.asStateFlow() + init { + searchQueryStateFlow + .filter { it.isNotEmpty() } + .onEach { logSearchRequest(it) } + .launchIn(viewModelScope) + + selectedModulesFlow + .onEach { logTargetModuleSelected(it) } + .launchIn(viewModelScope) + } + private val headerCollapsedStatesFlow: MutableStateFlow> = MutableStateFlow(emptyMap()) @@ -253,6 +282,13 @@ class PackageListViewModel(private val project: Project) : Disposable { headerId to search } + fun clearSearchQuery() { + viewModelScope.launch { + searchQueryMutableStateFlow.emit("") + logSearchQueryClear() + } + } + fun setSearchQuery(searchQuery: String) { viewModelScope.launch { searchQueryMutableStateFlow.emit(searchQuery) } } @@ -273,8 +309,8 @@ class PackageListViewModel(private val project: Project) : Disposable { viewModelScope.launch { when (event) { is PackageListItemEvent.EditPackageEvent -> handle(event) - is PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick -> logTODO() - is PackageListItemEvent.InfoPanelEvent.OnHeaderVariantsClick -> logTODO() + is PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick -> handle(event) + is PackageListItemEvent.InfoPanelEvent.OnHeaderVariantsClick -> handle(event) is PackageListItemEvent.InfoPanelEvent.OnPackageSelected -> handle(event) is PackageListItemEvent.InfoPanelEvent.OnPackageDoubleClick -> handle(event) is PackageListItemEvent.OnPackageAction.GoToSource -> handle(event) @@ -288,12 +324,19 @@ class PackageListViewModel(private val project: Project) : Disposable { } } + private fun handle(event: PackageListItemEvent.InfoPanelEvent.OnHeaderVariantsClick) { + logTODO() + logHeaderVariantsClick() + } + private suspend fun handle(event: PackageListItemEvent.InfoPanelEvent.OnPackageDoubleClick) { project.service().isInfoPanelOpen.emit(true) + logInfoPanelOpened() } private fun handle(event: PackageListItemEvent.InfoPanelEvent.OnPackageSelected) { val infoPanelViewModel = project.service() + logPackageSelected(event.eventId is PackageListItem.Package.Declared.Id) when (event.eventId) { is PackageListItem.Package.Remote.Base.Id -> { val headerId = PackageListItem.Header.Id.Remote.Base(event.eventId.moduleIdentity) @@ -346,7 +389,7 @@ class PackageListViewModel(private val project: Project) : Disposable { private suspend fun handle(actionType: PackageListItemEvent.OnPackageAction.Update) { packagesLoadingMutableStateFlow.update { it + actionType.eventId } - val (editor, manager, dependency) = + val (module, editor, manager, dependency) = actionType.eventId.getDependencyManagers() ?: return val newVersion = when { project.PackageSearchProjectService.stableOnlyStateFlow.value -> @@ -355,6 +398,12 @@ class PackageListViewModel(private val project: Project) : Disposable { else -> dependency.remoteInfo?.versions?.latest?.normalized?.versionName } ?: return + logPackageVersionChanged( + packageIdentifier = dependency.id, + packageFromVersion = dependency.declaredVersion?.versionName, + packageTargetVersion = newVersion, + targetModule = module + ) editor.editModule { manager.updateDependency(dependency, newVersion, dependency.declaredScope) } @@ -369,6 +418,11 @@ class PackageListViewModel(private val project: Project) : Disposable { val declaredPackage = module.declaredDependencies .firstOrNull { it.id == actionType.eventId.packageId } ?: return@editModule + logPackageRemoved( + packageIdentifier = actionType.eventId.packageId, + packageVersion = declaredPackage.declaredVersion?.versionName, + targetModule = module + ) module.removeDependency(declaredPackage) } @@ -381,6 +435,11 @@ class PackageListViewModel(private val project: Project) : Disposable { val declaredPackage = variant.declaredDependencies .firstOrNull { it.id == eventId.packageId } ?: return@editModule + logPackageRemoved( + packageIdentifier = actionType.eventId.packageId, + packageVersion = declaredPackage.declaredVersion?.versionName, + targetModule = module + ) variant.removeDependency(declaredPackage) } } @@ -400,6 +459,7 @@ class PackageListViewModel(private val project: Project) : Disposable { val apiPackage = search.packages .firstOrNull { it.id == actionType.eventId.packageId } ?: return + logPackageInstalled(apiPackage.id, module) installDependency( manager = variant, updater = module, @@ -417,6 +477,7 @@ class PackageListViewModel(private val project: Project) : Disposable { val apiPackage = search.packages .firstOrNull { it.id == actionType.eventId.packageId } ?: return + logPackageInstalled(apiPackage.id, module) installDependency( manager = module, updater = module, @@ -461,6 +522,7 @@ class PackageListViewModel(private val project: Project) : Disposable { null -> return } ?: return + logGoToSource(module, dependency.id) val buildFile = module.buildFilePath ?.let { LocalFileSystem.getInstance().findFileByNioFile(it) } ?: return @@ -486,22 +548,44 @@ class PackageListViewModel(private val project: Project) : Disposable { private suspend fun handle(event: PackageListItemEvent.EditPackageEvent) { packagesLoadingMutableStateFlow.update { it + event.eventId } + val (module, editor, manager, dependency) = + event.eventId.getDependencyManagers() ?: return runCatching { - val (editor, manager, dependency) = - event.eventId.getDependencyManagers() ?: return editor.editModule { when (event) { - is PackageListItemEvent.EditPackageEvent.SetPackageScope -> + is PackageListItemEvent.EditPackageEvent.SetPackageScope -> { + viewModelScope.launch { + logPackageScopeChanged(dependency.id, module) + } manager.updateDependency( declaredPackage = dependency, newVersion = dependency.declaredVersion?.versionName, newScope = event.scope ) + } - is PackageListItemEvent.EditPackageEvent.SetPackageVersion -> - manager.updateDependency(dependency, event.version, dependency.declaredScope) + is PackageListItemEvent.EditPackageEvent.SetPackageVersion -> { + viewModelScope.launch { + logPackageVersionChanged( + packageIdentifier = dependency.id, + packageFromVersion = dependency.declaredVersion?.versionName, + packageTargetVersion = event.version, + targetModule = module + ) + } + manager.updateDependency( + declaredPackage = dependency, + newVersion = event.version, + newScope = dependency.declaredScope + ) + } - is PackageListItemEvent.EditPackageEvent.SetVariant -> logTODO() + is PackageListItemEvent.EditPackageEvent.SetVariant -> { + viewModelScope.launch { + logPackageVariantChanged(dependency.id, module) + } + logTODO() + } } } } @@ -510,6 +594,13 @@ class PackageListViewModel(private val project: Project) : Disposable { } } + private fun handle(event: PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick) { + logTODO() + logHeaderAttributesClick( + isSearchHeader = event.eventId is PackageListItem.Header.Id.Remote + ) + } + private suspend fun handle(event: PackageListItemEvent.EditPackageEvent.SetVariant) { val module = event.eventId .getModule() as? PackageSearchModule.WithVariants @@ -533,6 +624,7 @@ class PackageListViewModel(private val project: Project) : Disposable { private suspend fun handle(event: PackageListItemEvent.UpdateAllPackages) { headerLoadingStatesFlow.update { it + event.eventId } + logUpgradeAll() val onlyStable = project.PackageSearchProjectService.stableOnlyStateFlow.value when (val module = event.eventId.getModule()) { is PackageSearchModule.Base -> { @@ -619,6 +711,7 @@ class PackageListViewModel(private val project: Project) : Disposable { val variant = withVariants.variants[variantName] ?: return null PackageSearchDependencyHandlers( + module = withVariants, modifier = withVariants, manager = variant, declaredPackage = variant.declaredDependencies diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/Utils.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/Utils.kt index 15378b24..a381ec39 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/Utils.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/Utils.kt @@ -57,6 +57,7 @@ internal fun buildPackageList( ).apply(block).build() internal data class PackageSearchDependencyHandlers( + val module: PackageSearchModule, val modifier: PackageSearchModuleEditor, val manager: PackageSearchDependencyManager, val declaredPackage: PackageSearchDeclaredPackage, @@ -65,8 +66,12 @@ internal data class PackageSearchDependencyHandlers( internal fun PackageSearchDependencyHandlers( module: PackageSearchModule.Base, declaredPackage: PackageSearchDeclaredPackage, -) = - PackageSearchDependencyHandlers(module, module, declaredPackage) +) = PackageSearchDependencyHandlers( + module = module, + modifier = module, + manager = module, + declaredPackage = declaredPackage +) internal fun combineListChanges( modulesFlow: Flow>, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt index 2493715e..bdf64fe1 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt @@ -29,6 +29,7 @@ fun PackageSearchCentralPanel( onlineSearchEnabled = isOnlineSearchEnabled, searchQuery = searchQuery, onSearchQueryChange = { viewModel.setSearchQuery(it) }, + onSearchQueryClear = { viewModel.clearSearchQuery() } ) Divider(Orientation.Horizontal) val packagesList by viewModel.packageListItemsFlow.collectAsState() diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt index 81cad39e..8de444f4 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchSearchBar.kt @@ -23,6 +23,7 @@ fun PackageSearchSearchBar( onlineSearchEnabled: Boolean, searchQuery: String, onSearchQueryChange: (String) -> Unit, + onSearchQueryClear: () -> Unit, ) { Row( modifier = Modifier @@ -58,7 +59,7 @@ fun PackageSearchSearchBar( trailingIcon = { Crossfade(searchQuery.isEmpty()) { if (it) return@Crossfade - IconButton(onClick = { onSearchQueryChange("") }) { + IconButton(onClick = { onSearchQueryClear() }) { Icon( resource = "actions/close.svg", contentDescription = null, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewTab.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewTab.kt index 94d2109c..0627a8eb 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewTab.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageOverviewTab.kt @@ -20,6 +20,8 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message import com.jetbrains.packagesearch.plugin.core.data.IconProvider +import com.jetbrains.packagesearch.plugin.fus.FUSGroupIds +import com.jetbrains.packagesearch.plugin.fus.logDetailsLinkClick import com.jetbrains.packagesearch.plugin.ui.bridge.LabelInfo import com.jetbrains.packagesearch.plugin.ui.model.infopanel.InfoPanelContent import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent @@ -114,7 +116,7 @@ internal fun PackageOverviewTab( Text( modifier = Modifier.fillMaxWidth(), text = description.trimStart(), - textAlign = TextAlign.Justify, + textAlign = TextAlign.Start, overflow = TextOverflow.Ellipsis, ) } @@ -122,10 +124,15 @@ internal fun PackageOverviewTab( content.scm?.let { ScmLinks(it, onLinkClick) } + content.readmeUrl?.let { readmeUrl -> ExternalLink( text = message("packagesearch.ui.toolwindow.link.readme.capitalized"), - onClick = { onLinkClick(readmeUrl) }) + onClick = { + onLinkClick(readmeUrl) + logDetailsLinkClick(FUSGroupIds.DetailsLinkTypes.Readme) + } + ) } } } @@ -243,7 +250,7 @@ private fun DetailLabel(name: String, value: String) { verticalAlignment = Alignment.Top, ) { LabelInfo( - modifier = Modifier.defaultMinSize(90.dp,16.dp), + modifier = Modifier.defaultMinSize(90.dp, 16.dp), text = name ) Text(value) @@ -261,7 +268,10 @@ private fun ScmLinks( ) { ExternalLink( text = message("packagesearch.ui.toolwindow.link.github"), - onClick = { onLinkClick(scm.url) }, + onClick = { + logDetailsLinkClick(FUSGroupIds.DetailsLinkTypes.Scm) + onLinkClick(scm.url) + }, ) if (scm is InfoPanelContent.PackageInfo.Scm.GitHub) { Icon(resource = "icons/Rating.svg", contentDescription = null, IconProvider::class.java) @@ -305,7 +315,10 @@ private fun PackageLinks( null -> Text(license.name) else -> ExternalLink( text = license.name, - onClick = { onLinkClick(license.url) }, + onClick = { + onLinkClick(license.url) + logDetailsLinkClick(FUSGroupIds.DetailsLinkTypes.License) + }, ) } if (index != licenses.lastIndex) { diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt index 2b5f1e6a..77d69cdf 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt @@ -15,7 +15,6 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp import com.jetbrains.packagesearch.plugin.PackageSearchBundle import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics import com.jetbrains.packagesearch.plugin.ui.bridge.LabelInfo @@ -36,12 +35,10 @@ fun PackageSearchInfoPanel( val viewModel = viewModel() val tabs by viewModel.tabs.collectAsState() val activeTabTitle by viewModel.activeTabTitleFlow.collectAsState() - val activeTab by derivedStateOf { - tabs.firstOrNull { it.tabTitle == activeTabTitle } - } + // if you use `by derivedStateOf`, the then will fail + val activeTab = derivedStateOf { tabs.firstOrNull { it.tabTitle == activeTabTitle } }.value when { tabs.isEmpty() || activeTab == null -> NoTabsAvailable() - else -> Column(modifier = Modifier.fillMaxSize()) { TabStrip( modifier = Modifier.fillMaxWidth(), @@ -60,13 +57,14 @@ fun PackageSearchInfoPanel( .padding(end = PackageSearchMetrics.scrollbarWidth) .verticalScroll(viewModel.scrollState) ) { - val tab = activeTab - if (tab is InfoPanelContent.PackageInfo) { - PackageOverviewTab( - onLinkClick = onLinkClick, - onPackageEvent = onPackageEvent, - content = tab - ) + when (activeTab) { + is InfoPanelContent.PackageInfo -> { + PackageOverviewTab( + onLinkClick = onLinkClick, + onPackageEvent = onPackageEvent, + content = activeTab + ) + } } } VerticalScrollbar( diff --git a/plugin/src/main/resources/META-INF/plugin.xml b/plugin/src/main/resources/META-INF/plugin.xml index 6c93cece..5f142722 100644 --- a/plugin/src/main/resources/META-INF/plugin.xml +++ b/plugin/src/main/resources/META-INF/plugin.xml @@ -13,6 +13,7 @@ Supports Maven and Gradle projects. org.jetbrains.idea.maven com.intellij.gradle + org.jetbrains.idea.reposearch + Date: Mon, 11 Dec 2023 16:55:21 +0100 Subject: [PATCH 25/39] Disabling KMP Gradle support when Amper Gradle plugin is enabled. (cherry picked from commit 1650b58dc69fc6e950d24661213442ba6a614b40) --- .../gradle/KotlinMultiplatformModuleProvider.kt | 4 +--- .../plugin/gradle/PackageSearchGradleModel.kt | 3 ++- .../PackageSearchProjectResolverExtension.kt | 1 + .../packagesearch/plugin/gradle/utils/Utils.kt | 3 ++- .../tooling/PackageSearchGradleJavaModel.java | 2 ++ .../PackageSearchGradleJavaModelImpl.java | 16 ++++++++++++---- .../tooling/PackageSearchGradleModelBuilder.java | 1 + 7 files changed, 21 insertions(+), 9 deletions(-) diff --git a/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt b/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt index 426a0162..2e6a454d 100644 --- a/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt +++ b/plugin/gradle/kmp/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/KotlinMultiplatformModuleProvider.kt @@ -23,9 +23,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.FlowCollector import org.jetbrains.packagesearch.api.v3.ApiMavenPackage import org.jetbrains.packagesearch.api.v3.ApiPackage -import org.jetbrains.packagesearch.api.v3.search.androidPackages import org.jetbrains.packagesearch.api.v3.search.buildPackageTypes -import org.jetbrains.packagesearch.api.v3.search.jvmGradlePackages import org.jetbrains.packagesearch.api.v3.search.kotlinMultiplatform import org.jetbrains.packagesearch.packageversionutils.normalization.NormalizedVersion @@ -36,7 +34,7 @@ class KotlinMultiplatformModuleProvider : AbstractGradleModuleProvider() { module: Module, model: PackageSearchGradleModel, ) { - if (model.isKotlinMultiplatformApplied) + if (model.isKotlinMultiplatformApplied && !model.isAmperApplied) MppCompilationInfoProvider.sourceSetsMap(project, model.projectDir) .collect { compilationModel -> val variants = module.getKMPVariants( diff --git a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchGradleModel.kt b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchGradleModel.kt index d730c604..d740b34d 100644 --- a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchGradleModel.kt +++ b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchGradleModel.kt @@ -10,13 +10,14 @@ data class PackageSearchGradleModel( val configurations: List, val repositories: List, val isJavaApplied: Boolean, + val isAmperApplied: Boolean, val isKotlinAndroidApplied: Boolean, val isKotlinMultiplatformApplied: Boolean, val projectIdentityPath: String, val projectName: String, val rootProjectName: String, @Serializable(with = NioPathSerializer::class) val buildFilePath: Path?, - @Serializable(with = NioPathSerializer::class) val rootProjectPath: Path + @Serializable(with = NioPathSerializer::class) val rootProjectPath: Path, ) { @Serializable diff --git a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchProjectResolverExtension.kt b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchProjectResolverExtension.kt index d0ae5b41..89748e62 100644 --- a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchProjectResolverExtension.kt +++ b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/PackageSearchProjectResolverExtension.kt @@ -44,6 +44,7 @@ internal fun PackageSearchGradleJavaModel.toPackageSearchModel() = }, repositories = repositoryUrls, isJavaApplied = isJavaApplied, + isAmperApplied = isAmperApplied, isKotlinAndroidApplied = isKotlinAndroidApplied, isKotlinMultiplatformApplied = isKotlinMultiplatformApplied, rootProjectName = rootProjectName, diff --git a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/utils/Utils.kt b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/utils/Utils.kt index 89005384..494db97a 100644 --- a/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/utils/Utils.kt +++ b/plugin/gradle/src/main/kotlin/com/jetbrains/packagesearch/plugin/gradle/utils/Utils.kt @@ -34,7 +34,8 @@ val Module.gradleIdentityPathOrNull: String? ?.data ?.gradleIdentityPathOrNull -fun PackageSearchModuleBuilderContext.getGradleModelRepository(): CoroutineObjectRepository = +context(PackageSearchModuleBuilderContext) +fun getGradleModelRepository(): CoroutineObjectRepository = projectCaches.getRepository("gradle") val Project.gradleSyncNotifierFlow: Flow diff --git a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModel.java b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModel.java index 07257384..edf0daa8 100644 --- a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModel.java +++ b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModel.java @@ -12,6 +12,8 @@ public interface PackageSearchGradleJavaModel extends Serializable { List getRepositoryUrls(); String getRootProjectName(); boolean isJavaApplied(); + + boolean isAmperApplied(); boolean isKotlinAndroidApplied(); boolean isKotlinMultiplatformApplied(); String getBuildFilePath(); diff --git a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModelImpl.java b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModelImpl.java index 0bac4a24..5e97d027 100644 --- a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModelImpl.java +++ b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleJavaModelImpl.java @@ -9,7 +9,8 @@ public class PackageSearchGradleJavaModelImpl implements PackageSearchGradleJava private final List repositories; private final String projectIdentityPath; - boolean isKotlinJvmApplied; + boolean isJavaApplied; + private boolean isAmperApplied; boolean isKotlinMultiplatformApplied; boolean isKotlinAndroidApplied; private final String projectName; @@ -24,7 +25,8 @@ public PackageSearchGradleJavaModelImpl( String projectIdentityPath, List configurations, List repositories, - boolean isKotlinJvmApplied, + boolean isJavaApplied, + boolean isAmperApplied, boolean isKotlinMultiplatformApplied, boolean isKotlinAndroidApplied, String buildFilePath, @@ -34,13 +36,14 @@ public PackageSearchGradleJavaModelImpl( this.configurations = configurations; this.repositories = repositories; this.projectIdentityPath = projectIdentityPath; - this.isKotlinJvmApplied = isKotlinJvmApplied; + this.isJavaApplied = isJavaApplied; this.isKotlinMultiplatformApplied = isKotlinMultiplatformApplied; this.isKotlinAndroidApplied = isKotlinAndroidApplied; this.projectName = projectName; this.rootProjectName = rootProjectName; this.buildFilePath = buildFilePath; this.rootProjectPath = rootProjectPath; + this.isAmperApplied = isAmperApplied; } @Override @@ -74,7 +77,12 @@ public boolean isKotlinAndroidApplied() { } public boolean isJavaApplied() { - return isKotlinJvmApplied; + return isJavaApplied; + } + + @Override + public boolean isAmperApplied() { + return isAmperApplied; } @Override diff --git a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java index 0355e181..798bddad 100644 --- a/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java +++ b/plugin/gradle/tooling/src/main/java/com/jetbrains/packagesearch/plugin/gradle/tooling/PackageSearchGradleModelBuilder.java @@ -87,6 +87,7 @@ public PackageSearchGradleJavaModel buildAll( configurations, repositories, project.getPluginManager().hasPlugin("org.gradle.java"), + project.getPluginManager().hasPlugin("org.jetbrains.amper.settings.plugin"), project.getPluginManager().hasPlugin("org.jetbrains.kotlin.multiplatform"), project.getPluginManager().hasPlugin("org.jetbrains.kotlin.android"), buildFilePath, From 2a406bb2a5d36ca8fe453d991799b96629e8cf86 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Mon, 11 Dec 2023 17:18:39 +0100 Subject: [PATCH 26/39] Refactor validation and preference fields to use different method and access modifier The `packageVersionField` and `packageFromVersionField` were both refactored to use `StringValidatedByRegexp` instead of `StringValidatedByRegexpReference`. In addition, several preference fields were changed from public to private, enhancing the encapsulation of these fields. (cherry picked from commit 4c6b8661f828d55d0aa2e7c2b74fed19f39d3753) --- .../plugin/fus/PackageSearchEventsLogger.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt index 4675f481..93c0404f 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt @@ -44,9 +44,9 @@ private val buildSystemField = EventFields.Class(FUSGroupIds.MODULE_OPERATION_PR private val packageIdField = EventFields.StringValidatedByCustomRule(FUSGroupIds.PACKAGE_ID, TopPackageIdValidationRule::class.java) private val packageVersionField = - EventFields.StringValidatedByRegexpReference(FUSGroupIds.PACKAGE_VERSION, regexpRef = "version") + EventFields.StringValidatedByRegexp(FUSGroupIds.PACKAGE_VERSION, regexpRef = "version") private val packageFromVersionField = - EventFields.StringValidatedByRegexpReference(FUSGroupIds.PACKAGE_FROM_VERSION, regexpRef = "version") + EventFields.StringValidatedByRegexp(FUSGroupIds.PACKAGE_FROM_VERSION, regexpRef = "version") private val repositoryIdField = EventFields.Enum(FUSGroupIds.REPOSITORY_ID) private val repositoryUrlField = EventFields.String(FUSGroupIds.REPOSITORY_URL, allowedValues = FUSGroupIds.indexedRepositoryUrls) @@ -55,13 +55,14 @@ private val packageIsInstalledField = EventFields.Boolean(FUSGroupIds.PACKAGE_IS private val targetModulesCountField = EventFields.Int(FUSGroupIds.TARGET_MODULES) private val targetModulesMixedBuildSystemsField = EventFields.Boolean(FUSGroupIds.TARGET_MODULES_MIXED_BUILD_SYSTEMS) -val preferencesGradleScopeCountField = EventFields.Int(FUSGroupIds.PREFERENCES_GRADLE_SCOPES_COUNT) -val preferencesUpdateScopesOnUsageField = EventFields.Boolean(FUSGroupIds.PREFERENCES_UPDATE_SCOPES_ON_USAGE) -val preferencesDefaultGradleScopeChangedField = + +private val preferencesGradleScopeCountField = EventFields.Int(FUSGroupIds.PREFERENCES_GRADLE_SCOPES_COUNT) +private val preferencesUpdateScopesOnUsageField = EventFields.Boolean(FUSGroupIds.PREFERENCES_UPDATE_SCOPES_ON_USAGE) +private val preferencesDefaultGradleScopeChangedField = EventFields.Boolean(FUSGroupIds.PREFERENCES_DEFAULT_GRADLE_SCOPE_CHANGED) -val preferencesDefaultMavenScopeChangedField = +private val preferencesDefaultMavenScopeChangedField = EventFields.Boolean(FUSGroupIds.PREFERENCES_DEFAULT_MAVEN_SCOPE_CHANGED) -internal val preferencesAutoAddRepositoriesField = +private val preferencesAutoAddRepositoriesField = EventFields.Boolean(FUSGroupIds.PREFERENCES_AUTO_ADD_REPOSITORIES) private val detailsLinkLabelField = EventFields.Enum(FUSGroupIds.DETAILS_LINK_LABEL) From 016a1f1ae28bef534706066727acb9748c900b0d Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Mon, 11 Dec 2023 17:21:00 +0100 Subject: [PATCH 27/39] Improve encapsulation and access control in PackageSearchEventsLogger Access level for PackageSearchEventsLogger has been changed to internal. Furthermore, several preference fields in PackageSearchEventsLogger have been changed to private - improving data encapsulation. Logging functions have also been shifted to internal to control the scope of their usage. --- .../plugin/fus/PackageSearchEventsLogger.kt | 41 ++++++++++--------- .../services/PackageSearchProjectService.kt | 3 ++ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt index 93c0404f..4b2062c7 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt @@ -31,7 +31,7 @@ import org.jetbrains.packagesearch.api.v3.ApiRepository private const val FUS_ENABLED = true -class PackageSearchEventsLogger : CounterUsagesCollector() { +internal class PackageSearchEventsLogger : CounterUsagesCollector() { override fun getGroup() = GROUP } @@ -140,14 +140,15 @@ private val headerAttributesClick = GROUP.registerEvent( eventField1 = isSearchHeader ) private val headerVariantClick = GROUP.registerEvent(FUSGroupIds.HEADER_VARIANTS_CLICK) -fun logPackageInstalled( + +internal fun logPackageInstalled( packageIdentifier: String, targetModule: PackageSearchModule, ) = runSafelyIfEnabled(packageInstalledEvent) { log(packageIdentifier, targetModule::class.java) } -fun logPackageRemoved( +internal fun logPackageRemoved( packageIdentifier: String, packageVersion: String?, targetModule: PackageSearchModule, @@ -155,7 +156,7 @@ fun logPackageRemoved( log(packageIdentifier, packageVersion, targetModule::class.java) } -fun logPackageVersionChanged( +internal fun logPackageVersionChanged( packageIdentifier: String, packageFromVersion: String?, packageTargetVersion: String, @@ -169,25 +170,25 @@ fun logPackageVersionChanged( ) } -fun logPackageVariantChanged( +internal fun logPackageVariantChanged( packageIdentifier: String, targetModule: PackageSearchModule, ) = runSafelyIfEnabled(packageVariantChangedEvent) { log(packageIdentifier, targetModule::class.java) } -fun logPackageScopeChanged( +internal fun logPackageScopeChanged( packageIdentifier: String, targetModule: PackageSearchModule, ) = runSafelyIfEnabled(packageScopeChangedEvent) { log(packageIdentifier, targetModule::class.java) } -fun logRepositoryAdded(model: ApiRepository) = runSafelyIfEnabled(repositoryAddedEvent) { +internal fun logRepositoryAdded(model: ApiRepository) = runSafelyIfEnabled(repositoryAddedEvent) { log(FUSGroupIds.IndexedRepositories.forId(model.id), FUSGroupIds.IndexedRepositories.validateUrl(model.url)) } -fun logRepositoryRemoved(model: ApiRepository) = runSafelyIfEnabled(repositoryRemovedEvent) { +internal fun logRepositoryRemoved(model: ApiRepository) = runSafelyIfEnabled(repositoryRemovedEvent) { val repository = FUSGroupIds.IndexedRepositories.forId(model.id) val validatedUrl = FUSGroupIds.IndexedRepositories.validateUrl(model.url) val usesCustomUrl = repository != FUSGroupIds.IndexedRepositories.NONE && @@ -196,57 +197,57 @@ fun logRepositoryRemoved(model: ApiRepository) = runSafelyIfEnabled(repositoryRe log(repository, validatedUrl, usesCustomUrl) } -fun logPreferencesRestoreDefaults() = runSafelyIfEnabled(preferencesRestoreDefaultsEvent) { +internal fun logPreferencesRestoreDefaults() = runSafelyIfEnabled(preferencesRestoreDefaultsEvent) { log() } -fun logTargetModuleSelected(targetModules: List) = +internal fun logTargetModuleSelected(targetModules: List) = runSafelyIfEnabled(targetModulesSelectedEvent) { if (targetModules.isNotEmpty()) { log(targetModules.size, targetModules.groupBy { it.identity.group }.keys.size != 1) } } -fun logPackageSelected(isInstalled: Boolean) = runSafelyIfEnabled(packageSelectedEvent) { +internal fun logPackageSelected(isInstalled: Boolean) = runSafelyIfEnabled(packageSelectedEvent) { log(isInstalled) } -fun logDetailsLinkClick(type: FUSGroupIds.DetailsLinkTypes) = runSafelyIfEnabled(detailsLinkClickEvent) { +internal fun logDetailsLinkClick(type: FUSGroupIds.DetailsLinkTypes) = runSafelyIfEnabled(detailsLinkClickEvent) { log(type) } -fun logOnlyStableToggle(state: Boolean) = runSafelyIfEnabled(onlyStableToggleEvent) { +internal fun logOnlyStableToggle(state: Boolean) = runSafelyIfEnabled(onlyStableToggleEvent) { log(state) } -fun logSearchRequest(query: String) = runSafelyIfEnabled(searchRequestEvent) { +internal fun logSearchRequest(query: String) = runSafelyIfEnabled(searchRequestEvent) { log(query.length) } -fun logSearchQueryClear() = runSafelyIfEnabled(searchQueryClearEvent) { +internal fun logSearchQueryClear() = runSafelyIfEnabled(searchQueryClearEvent) { log() } -fun logUpgradeAll() = runSafelyIfEnabled(upgradeAllEvent) { +internal fun logUpgradeAll() = runSafelyIfEnabled(upgradeAllEvent) { log() } -fun logInfoPanelOpened() = runSafelyIfEnabled(infoPanelOpenedEvent) { +internal fun logInfoPanelOpened() = runSafelyIfEnabled(infoPanelOpenedEvent) { log() } -fun logGoToSource( +internal fun logGoToSource( module: PackageSearchModule, packageId: String, ) = runSafelyIfEnabled(goToSourceEvent) { log(module::class.java, packageId) } -fun logHeaderAttributesClick(isSearchHeader: Boolean) = runSafelyIfEnabled(headerAttributesClick) { +internal fun logHeaderAttributesClick(isSearchHeader: Boolean) = runSafelyIfEnabled(headerAttributesClick) { log(isSearchHeader) } -fun logHeaderVariantsClick() = runSafelyIfEnabled(headerVariantClick) { +internal fun logHeaderVariantsClick() = runSafelyIfEnabled(headerVariantClick) { log() } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt index e2f44ffb..2c25624b 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchProjectService.kt @@ -3,6 +3,7 @@ package com.jetbrains.packagesearch.plugin.services import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer +import com.intellij.openapi.Disposable import com.intellij.openapi.application.readAction import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level @@ -27,6 +28,8 @@ import com.jetbrains.packagesearch.plugin.utils.timer import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.BufferOverflow.DROP_OLDEST import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow From ce6b8078b9c7da78f2f11c187fed79d9a563e863 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Tue, 12 Dec 2023 11:10:21 +0100 Subject: [PATCH 28/39] Improve logPackageScopeChanged function and add scope validation (cherry picked from commit a4d20a2e4f6b3af405367c983b0ac353be044060) (cherry picked from commit 33c408b016099b5ee7cb405763e8064072cbb76a) --- .../packagesearch/plugin/fus/FUSGroupIds.kt | 2 ++ .../plugin/fus/PackageSearchEventsLogger.kt | 31 +++++++++++++++---- .../packageslist/PackageListViewModel.kt | 2 +- plugin/src/main/resources/fus/scopes.txt | 24 ++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 plugin/src/main/resources/fus/scopes.txt diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/FUSGroupIds.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/FUSGroupIds.kt index 5f6bd195..c77eed8d 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/FUSGroupIds.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/FUSGroupIds.kt @@ -30,6 +30,8 @@ object FUSGroupIds { const val PACKAGE_ID = "package_id" const val PACKAGE_VERSION = "package_version" const val PACKAGE_FROM_VERSION = "package_from_version" + const val PACKAGE_FROM_SCOPE = "package_from_scope" + const val PACKAGE_TO_SCOPE = "package_to_scope" const val REPOSITORY_ID = "repository_id" const val REPOSITORY_URL = "repository_url" const val REPOSITORY_USES_CUSTOM_URL = "repository_uses_custom_url" diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt index 4b2062c7..49e347e2 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt @@ -21,6 +21,7 @@ package com.jetbrains.packagesearch.plugin.fus import com.intellij.internal.statistic.eventLog.EventLogGroup import com.intellij.internal.statistic.eventLog.events.BaseEventId import com.intellij.internal.statistic.eventLog.events.EventFields +import com.intellij.internal.statistic.eventLog.validator.rules.impl.LocalFileCustomValidationRule import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector import com.intellij.openapi.diagnostic.RuntimeExceptionWithAttachments import com.jetbrains.packagesearch.plugin.PackageSearchBundle @@ -39,14 +40,24 @@ private const val VERSION = 13 private val GROUP = EventLogGroup(FUSGroupIds.GROUP_ID, VERSION) +internal class TopScopesValidationRule : LocalFileCustomValidationRule( + /* ruleId = */ "top_scopes_id", + /* resource = */ TopScopesValidationRule::class.java, + /* path = */ "/fus/scopes.txt" +) + // FIELDS private val buildSystemField = EventFields.Class(FUSGroupIds.MODULE_OPERATION_PROVIDER_CLASS) private val packageIdField = EventFields.StringValidatedByCustomRule(FUSGroupIds.PACKAGE_ID, TopPackageIdValidationRule::class.java) private val packageVersionField = - EventFields.StringValidatedByRegexp(FUSGroupIds.PACKAGE_VERSION, regexpRef = "version") + EventFields.StringValidatedByRegexpReference(FUSGroupIds.PACKAGE_VERSION, regexpRef = "version") private val packageFromVersionField = - EventFields.StringValidatedByRegexp(FUSGroupIds.PACKAGE_FROM_VERSION, regexpRef = "version") + EventFields.StringValidatedByRegexpReference(FUSGroupIds.PACKAGE_FROM_VERSION, regexpRef = "version") +private val packageScopeFromField = + EventFields.StringValidatedByCustomRule(FUSGroupIds.PACKAGE_FROM_SCOPE) +private val packageScopeToField = + EventFields.StringValidatedByCustomRule(FUSGroupIds.PACKAGE_TO_SCOPE) private val repositoryIdField = EventFields.Enum(FUSGroupIds.REPOSITORY_ID) private val repositoryUrlField = EventFields.String(FUSGroupIds.REPOSITORY_URL, allowedValues = FUSGroupIds.indexedRepositoryUrls) @@ -86,11 +97,12 @@ private val packageVersionChangedEvent = GROUP.registerVarargEvent( eventId = FUSGroupIds.PACKAGE_VERSION_UPDATED, packageIdField, packageFromVersionField, packageVersionField, buildSystemField ) -private val packageScopeChangedEvent = GROUP.registerEvent( + +private val packageScopeChangedEvent = GROUP.registerVarargEvent( eventId = FUSGroupIds.PACKAGE_SCOPE_UPDATED, - eventField1 = packageIdField, - eventField2 = buildSystemField + packageIdField, packageScopeFromField, packageScopeToField, buildSystemField ) + private val packageVariantChangedEvent = GROUP.registerEvent( eventId = FUSGroupIds.PACKAGE_VARIANT_UPDATED, eventField1 = packageIdField, @@ -179,9 +191,16 @@ internal fun logPackageVariantChanged( internal fun logPackageScopeChanged( packageIdentifier: String, + scopeFrom: String?, + scopeTo: String?, targetModule: PackageSearchModule, ) = runSafelyIfEnabled(packageScopeChangedEvent) { - log(packageIdentifier, targetModule::class.java) + log( + packageIdField.with(packageIdentifier), + packageScopeFromField.with(scopeFrom ?: "[default]"), + packageScopeToField.with(scopeTo ?: "[default]"), + buildSystemField.with(targetModule::class.java) + ) } internal fun logRepositoryAdded(model: ApiRepository) = runSafelyIfEnabled(repositoryAddedEvent) { diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt index f7a215d4..971628fe 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt @@ -555,7 +555,7 @@ class PackageListViewModel(private val project: Project) : Disposable { when (event) { is PackageListItemEvent.EditPackageEvent.SetPackageScope -> { viewModelScope.launch { - logPackageScopeChanged(dependency.id, module) + logPackageScopeChanged(dependency.id, dependency.declaredScope, event.scope, module) } manager.updateDependency( declaredPackage = dependency, diff --git a/plugin/src/main/resources/fus/scopes.txt b/plugin/src/main/resources/fus/scopes.txt new file mode 100644 index 00000000..33c67315 --- /dev/null +++ b/plugin/src/main/resources/fus/scopes.txt @@ -0,0 +1,24 @@ +[default] +compile +runtime +provided +test +implementation +api +compileOnly +runtimeOnly +testImplementation +testCompileOnly +testRuntimeOnly +kapt +testKapt +androidTestImplementation +androidTestCompileOnly +androidTestRuntimeOnly +androidTestUtil +androidTestUtilDebug +androidTestUtilRelease +androidTestAnnotationProcessor +detekt +detektPlugins +detektTest From ca512401c633d8e9c2279feeabe96825b2e0c7e6 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Tue, 12 Dec 2023 11:53:27 +0100 Subject: [PATCH 29/39] Changed FUS field validators to use "StringValidatedByRegexp" instead of "StringValidatedByRegexpReference" --- .../packagesearch/plugin/fus/PackageSearchEventsLogger.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt index 49e347e2..7534a03d 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/fus/PackageSearchEventsLogger.kt @@ -51,9 +51,9 @@ private val buildSystemField = EventFields.Class(FUSGroupIds.MODULE_OPERATION_PR private val packageIdField = EventFields.StringValidatedByCustomRule(FUSGroupIds.PACKAGE_ID, TopPackageIdValidationRule::class.java) private val packageVersionField = - EventFields.StringValidatedByRegexpReference(FUSGroupIds.PACKAGE_VERSION, regexpRef = "version") + EventFields.StringValidatedByRegexp(FUSGroupIds.PACKAGE_VERSION, regexpRef = "version") private val packageFromVersionField = - EventFields.StringValidatedByRegexpReference(FUSGroupIds.PACKAGE_FROM_VERSION, regexpRef = "version") + EventFields.StringValidatedByRegexp(FUSGroupIds.PACKAGE_FROM_VERSION, regexpRef = "version") private val packageScopeFromField = EventFields.StringValidatedByCustomRule(FUSGroupIds.PACKAGE_FROM_SCOPE) private val packageScopeToField = From c5bddc4b132468c134bcf02c0aa754f0701734ca Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Thu, 14 Dec 2023 12:59:56 +0100 Subject: [PATCH 30/39] Update ideaGradlePlugin version The version of ideaGradlePlugin in the packagesearch.versions.toml file has been updated from 1.14.1 to 1.16.1. (cherry picked from commit 9efc9888b41f3a41c26052ed6b44f6ea7ac13058) --- packagesearch.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packagesearch.versions.toml b/packagesearch.versions.toml index 50d21b44..3d6d0ff1 100644 --- a/packagesearch.versions.toml +++ b/packagesearch.versions.toml @@ -9,7 +9,7 @@ dokka = "1.9.10" foojay = "0.5.0" gradlePublishPlugin = "1.1.0" idea = "2023.1.2" -ideaGradlePlugin = "1.14.1" +ideaGradlePlugin = "1.16.1" junit = "5.10.0" junit4 = "4.13.2" kotlin = "1.9.20" From d17c01e80eb3e80cd3c80f97f36e8d9a672a8bb9 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Thu, 14 Dec 2023 13:47:06 +0100 Subject: [PATCH 31/39] Generate correct plugin version sources in `core` module. (cherry picked from commit f9e1a87767ce605030e27075735d786425c21a8d) --- package-search-api-models | 2 +- plugin/core/build.gradle.kts | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/package-search-api-models b/package-search-api-models index 7a6a50d0..9e098b97 160000 --- a/package-search-api-models +++ b/package-search-api-models @@ -1 +1 @@ -Subproject commit 7a6a50d037e86b0ba858b7fc273ab2db76b641e7 +Subproject commit 9e098b97fe7437e64092ca49862cdc82966a7693 diff --git a/plugin/core/build.gradle.kts b/plugin/core/build.gradle.kts index 981fb2a0..d1e0014d 100644 --- a/plugin/core/build.gradle.kts +++ b/plugin/core/build.gradle.kts @@ -1,5 +1,6 @@ @file:Suppress("UnstableApiUsage") +import kotlin.math.max import org.jetbrains.packagesearch.gradle.GeneratePackageSearchObject @@ -42,6 +43,11 @@ kotlin.sourceSets.main { val pkgsPluginId: String by project +val runNumber = System.getenv("RUN_NUMBER")?.toInt() ?: 0 +val runAttempt = System.getenv("RUN_ATTEMPT")?.toInt() ?: 0 +val snapshotMinorVersion = max(0, runNumber + runAttempt - 1) +val versionString = project.version.toString() + tasks { withType { environment("DB_PATH", layout.buildDirectory.file("tests/cache.db").get().asFile.absolutePath) @@ -49,6 +55,7 @@ tasks { val generatePluginDataSources by registering(GeneratePackageSearchObject::class) { pluginId = pkgsPluginId outputDir = generatedDir + pluginVersion = versionString.replace("-SNAPSHOT", ".$snapshotMinorVersion") packageName = "com.jetbrains.packagesearch.plugin.core" } sourcesJar { From f3f45f2572f875e09364612560795f6b7c5b8e9d Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Wed, 20 Dec 2023 12:11:45 +0100 Subject: [PATCH 32/39] Refactor UI theme and refresh status handling in Package Search plugin Moved UI theme construction to a new file called `UiUtils.kt` for better organized code. Also improved how the Package Search plugin handles project refreshes and renames `isProjectSyncing` to `isProjectImportingFlow`, the latter better represents the process. These changes enhance clarity and maintainability. (cherry picked from commit 0b9b65da511b14c98d828edb31d20b75f53fb88f) --- package-search-api-models | 2 +- .../plugin/PackageSearchToolWindowFactory.kt | 20 +-------- .../packagesearch/plugin/ui/NoModulesFound.kt | 4 +- .../packagesearch/plugin/ui/UiUtils.kt | 26 +++++++++++ .../plugin/ui/model/NoModulesFoundViewMode.kt | 43 +++++++++++++++++-- .../plugin/ui/model/ToolWindowViewModel.kt | 2 +- .../packagesearch/plugin/ui/model/Utils.kt | 2 +- 7 files changed, 73 insertions(+), 26 deletions(-) create mode 100644 plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/UiUtils.kt diff --git a/package-search-api-models b/package-search-api-models index 9e098b97..d86dd9ff 160000 --- a/package-search-api-models +++ b/package-search-api-models @@ -1 +1 @@ -Subproject commit 9e098b97fe7437e64092ca49862cdc82966a7693 +Subproject commit d86dd9ffe15da557e7e74224dd348a74e057bc70 diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt index 3f5138e3..18343f4f 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/PackageSearchToolWindowFactory.kt @@ -1,37 +1,21 @@ package com.jetbrains.packagesearch.plugin -import androidx.compose.runtime.CompositionLocalProvider 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.jetbrains.packagesearch.plugin.ui.LocalComponentManager +import com.jetbrains.packagesearch.plugin.ui.PackageSearchTheme import com.jetbrains.packagesearch.plugin.ui.PackageSearchToolwindow -import com.jetbrains.packagesearch.plugin.ui.bridge.LocalPackageSearchDropdownLinkStyle -import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchDropdownLinkStyle -import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchGlobalColors -import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchTabStyle -import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchTreeStyle import com.jetbrains.packagesearch.plugin.utils.installActions import org.jetbrains.jewel.bridge.addComposeTab -import org.jetbrains.jewel.foundation.LocalGlobalColors -import org.jetbrains.jewel.ui.component.styling.LocalDefaultTabStyle -import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle class PackageSearchToolWindowFactory : ToolWindowFactory, DumbAware { override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { toolWindow.installActions(project) toolWindow.addComposeTab(PackageSearchBundle.message("packagesearch.title.tab")) { - CompositionLocalProvider( - LocalComponentManager provides project, - LocalGlobalColors provides PackageSearchGlobalColors(), - LocalDefaultTabStyle provides PackageSearchTabStyle(), - LocalLazyTreeStyle provides PackageSearchTreeStyle(), - LocalPackageSearchDropdownLinkStyle provides PackageSearchDropdownLinkStyle(), - ) { + PackageSearchTheme(project) { PackageSearchToolwindow() } } } } - diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/NoModulesFound.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/NoModulesFound.kt index 0b95cc80..e91db084 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/NoModulesFound.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/NoModulesFound.kt @@ -36,9 +36,9 @@ fun NoModulesFound( if (hasExternalProjects) { Row { LabelInfo("Try ") - val isEnabled by viewModel.isRefreshing.collectAsState() + val isRefreshing by viewModel.isRefreshing.collectAsState() Link( - enabled = isEnabled, + enabled = !isRefreshing, text = "refreshing", onClick = { viewModel.refreshExternalProjects() }, ) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/UiUtils.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/UiUtils.kt new file mode 100644 index 00000000..724cc5a3 --- /dev/null +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/UiUtils.kt @@ -0,0 +1,26 @@ +package com.jetbrains.packagesearch.plugin.ui + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import com.intellij.openapi.project.Project +import com.jetbrains.packagesearch.plugin.ui.bridge.LocalPackageSearchDropdownLinkStyle +import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchDropdownLinkStyle +import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchGlobalColors +import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchTabStyle +import com.jetbrains.packagesearch.plugin.ui.bridge.PackageSearchTreeStyle +import org.jetbrains.jewel.foundation.LocalGlobalColors +import org.jetbrains.jewel.ui.component.styling.LocalDefaultTabStyle +import org.jetbrains.jewel.ui.component.styling.LocalLazyTreeStyle + +@Composable +internal fun PackageSearchTheme(project: Project, content: @Composable () -> Unit) { + CompositionLocalProvider( + LocalComponentManager provides project, + LocalGlobalColors provides PackageSearchGlobalColors(), + LocalDefaultTabStyle provides PackageSearchTabStyle(), + LocalLazyTreeStyle provides PackageSearchTreeStyle(), + LocalPackageSearchDropdownLinkStyle provides PackageSearchDropdownLinkStyle(), + ) { + content() + } +} diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/NoModulesFoundViewMode.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/NoModulesFoundViewMode.kt index 2a1f16f5..b3ad63ec 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/NoModulesFoundViewMode.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/NoModulesFoundViewMode.kt @@ -4,6 +4,10 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service import com.intellij.openapi.externalSystem.ExternalSystemManager import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder +import com.intellij.openapi.externalSystem.model.DataNode +import com.intellij.openapi.externalSystem.model.project.ProjectData +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId +import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback import com.intellij.openapi.externalSystem.util.ExternalSystemUtil import com.intellij.openapi.project.Project import com.jetbrains.packagesearch.plugin.core.utils.availableExtensionsFlow @@ -11,7 +15,9 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @@ -21,8 +27,10 @@ class NoModulesFoundViewMode(private val project: Project) : Disposable { private val viewModelScope: CoroutineScope = CoroutineScope(SupervisorJob()) - val isRefreshing = project.isProjectSyncing - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false) + private val isRefreshingChannel = Channel() + + val isRefreshing = isRefreshingChannel.consumeAsFlow() + .stateIn(viewModelScope, SharingStarted.Eagerly, false) val hasExternalProjects = ExternalSystemManager.EP_NAME .availableExtensionsFlow @@ -34,13 +42,42 @@ class NoModulesFoundViewMode(private val project: Project) : Disposable { ) fun refreshExternalProjects() { + isRefreshingChannel.trySend(true) viewModelScope.launch(Dispatchers.Main) { ExternalSystemManager.EP_NAME.extensions - .map { ImportSpecBuilder(project, it.systemId) } + .map { + ImportSpecBuilder(project, it.systemId) + .callback(handleRefreshCallback()) + } .forEach { ExternalSystemUtil.refreshProjects(it) } } } + private fun handleRefreshCallback() = object : ExternalProjectRefreshCallback { + override fun onSuccess( + externalTaskId: ExternalSystemTaskId, + externalProject: DataNode?, + ) { + isRefreshingChannel.trySend(false) + } + + override fun onSuccess(externalProject: DataNode?) { + isRefreshingChannel.trySend(false) + } + + override fun onFailure( + externalTaskId: ExternalSystemTaskId, + errorMessage: String, + errorDetails: String?, + ) { + isRefreshingChannel.trySend(false) + } + + override fun onFailure(errorMessage: String, errorDetails: String?) { + isRefreshingChannel.trySend(false) + } + } + override fun dispose() { viewModelScope.cancel() } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt index 686c3660..fd7f5a42 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt @@ -39,7 +39,7 @@ class ToolWindowViewModel(project: Project) : Disposable { val toolWindowState = combine( project.PackageSearchProjectService.packagesBeingDownloadedFlow, - project.isProjectSyncing, + project.isProjectImportingFlow, project.service() .tree .map { !it.isEmpty() } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/Utils.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/Utils.kt index 17a8c450..a72338df 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/Utils.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/Utils.kt @@ -21,7 +21,7 @@ internal fun PackageSearchDeclaredPackage.getLatestVersion(onlyStable: Boolean): } } -internal val Project.isProjectSyncing +internal val Project.isProjectImportingFlow get() = messageBus.flow(ProjectDataImportListener.TOPIC) { object : ProjectDataImportListener { override fun onImportStarted(projectPath: String?) { From a47a98dc68f21f9a5316d46d09f9a6fb85133fb4 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Wed, 20 Dec 2023 12:11:45 +0100 Subject: [PATCH 33/39] Bump api-models commit hash --- package-search-api-models | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-search-api-models b/package-search-api-models index d86dd9ff..925dc481 160000 --- a/package-search-api-models +++ b/package-search-api-models @@ -1 +1 @@ -Subproject commit d86dd9ffe15da557e7e74224dd348a74e057bc70 +Subproject commit 925dc48111f647516e73e26a0288be5f99c89ff7 From 3a5e07581abdd9f1d2860aba4dbcba62b76ff949 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Tue, 9 Jan 2024 11:13:14 +0100 Subject: [PATCH 34/39] Change PackageSearchApiClient to use default endpoints The PackageSearchApiClient within the PackageSearchApplicationCachesService is updated to use the DEFAULT endpoints from PackageSearchEndpoints instead of the DEV endpoints. This change doesn't affect the behavior of the application but makes the code more consistent and easier to read. --- package-search-api-models | 2 +- .../services/PackageSearchApplicationCachesService.kt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-search-api-models b/package-search-api-models index 925dc481..dabcc4de 160000 --- a/package-search-api-models +++ b/package-search-api-models @@ -1 +1 @@ -Subproject commit 925dc48111f647516e73e26a0288be5f99c89ff7 +Subproject commit dabcc4dee952a94a35df58686ec6b31be24f9c65 diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt index a749ae39..44a81b6b 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/services/PackageSearchApplicationCachesService.kt @@ -83,8 +83,8 @@ class PackageSearchApplicationCachesService : RecoveryAction, Disposable { private val repositoryCache get() = getRepository("repositories") - private val devApiClient = PackageSearchApiClient( - endpoints = PackageSearchEndpoints.DEV, + private val apiClient = PackageSearchApiClient( + endpoints = PackageSearchEndpoints.DEFAULT, httpClient = PackageSearchApiClient.defaultHttpClient { install(Logging) { level = LogLevel.ALL @@ -94,13 +94,13 @@ class PackageSearchApplicationCachesService : RecoveryAction, Disposable { } ) - val isOnlineFlow = devApiClient.isOnlineFlow() + val isOnlineFlow = apiClient.isOnlineFlow() .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), true) val apiPackageCache = PackageSearchApiPackageCache( apiPackageCache = packagesRepository, searchCache = searchesRepository, - apiClient = devApiClient + apiClient = apiClient ) private suspend fun createIndexes() { From 5c4a3f86eb504c2eb45f6dbf1c0768dc11cb97c6 Mon Sep 17 00:00:00 2001 From: Lamberto Basti Date: Tue, 9 Jan 2024 11:34:17 +0100 Subject: [PATCH 35/39] Add Apache License, update README, create CODE_OF_CONDUCT.md Introduces Apache License 2.0 to the project. Modifies the README.md to include JetBrains official project badge. A new Code of Conduct file has been created, referring to the JetBrains Open Source and Community Code of Conduct. (cherry picked from commit 68a88bb122e470989e07307214d4bedce8b4907a) --- CODE_OF_CONDUCT.md | 5 ++ LICENSE | 202 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 34 ++++++++ tests.http | 2 +- 4 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 LICENSE create mode 100644 README.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..215272e3 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,5 @@ +## Code of Conduct + +This project and the corresponding community is governed by +the [JetBrains Open Source and Community Code of Conduct](https://confluence.jetbrains.com/display/ALL/JetBrains+Open+Source+and+Community+Code+of+Conduct). +Please make sure you read it. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..8541f77f --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2000-2021 JetBrains s.r.o. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..038a5bfe --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# Package Search [![official JetBrains project](https://jb.gg/badges/official-flat-square.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) + +Package Search is an IntelliJ plugin that allows you to search for packages from the editor. It supports searching for +packages from the following package managers by default: + +- [Maven](https://maven.apache.org/) +- [Gradle](https://gradle.org/) +- [Amper](https://blog.jetbrains.com/blog/2023/11/09/amper-improving-the-build-tooling-user-experience/) + +It also supports Kotlin Multiplatform projects for both for Gradle and Amper. + +![Package Search](https://plugins.jetbrains.com/files/12507/screenshot_2db7914e-4a6a-45a1-aa34-ed00b150cf62) +![Package Search](https://plugins.jetbrains.com/files/12507/screenshot_26124d52-4baf-4e5c-bff3-1ecb81efd83c) + +# Installation + +You can download the plugin from the [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/12507-package-search) +or directly in IntelliJ by going to `Preferences > Plugins > Marketplace` and searching for `Package Search`. + +The plugin is compatible with IntelliJ 2023.2 and newer. + +# Building + +To build the plugin, run the following command: + +```shell +./gradlew :plugin:buildShadowPlugin +``` + +To run the plugin, run the following command: + +```shell +./gradlew :plugin:runIde +``` diff --git a/tests.http b/tests.http index cc569e9c..66e907d9 100644 --- a/tests.http +++ b/tests.http @@ -1,4 +1,4 @@ -GET https://api.dev.package-search.services.jetbrains.com/search-packages +POST https://package-search.services.jetbrains.com/search-packages Content-Type: application/json { From 1adaea53d482ec4815d81cac3b3c33d8c917bae7 Mon Sep 17 00:00:00 2001 From: Fabrizio Scarponi <36624359+fscarponi@users.noreply.github.com> Date: Wed, 10 Jan 2024 12:51:19 +0100 Subject: [PATCH 36/39] Removed Jewel from dependencies and Compose/Jewel shadowing from fatjar (#12) (cherry picked from commit 85f94dc4293fb0f0cf1f0552d80ceca4adeb4c7f) --- .../gradle/ConfigureGradleIntellijPlugin.kt | 5 +- plugin/build.gradle.kts | 5 - .../packages/PackageSearchPackageList.kt | 9 +- .../panels/tree/PackageSearchModulesTree.kt | 104 +++++++++--------- 4 files changed, 58 insertions(+), 65 deletions(-) diff --git a/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt b/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt index 4a36a13d..fdc682f1 100644 --- a/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt +++ b/buildSrc/src/main/kotlin/org/jetbrains/packagesearch/gradle/ConfigureGradleIntellijPlugin.kt @@ -24,9 +24,6 @@ fun Project.configureGradleIntellijPlugin(packageSearchExtension: PackageSearchE relocate("io.ktor", "shadow.io.ktor") relocate("kotlinx.serialization", "shadow.kotlinx.serialization") relocate("kotlinx.datetime", "shadow.kotlinx.datetime") - relocate("androidx", "shadow.androidx") - relocate("org.jetbrains.jewel", "shadow.org.jetbrains.jewel") - relocate("org.jetbrains.compose", "shadow.org.jetbrains.compose") exclude { it.name.containsAny(packageSearchExtension.librariesToDelete.get()) && !it.name.containsAny(packageSearchExtension.librariesToKeep.get()) @@ -43,4 +40,4 @@ fun Project.configureGradleIntellijPlugin(packageSearchExtension: PackageSearchE } } } -} \ No newline at end of file +} diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index e7765cd6..f7f0261b 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -49,11 +49,6 @@ val tooling: Configuration by configurations.creating { } dependencies { - implementation(compose.desktop.linux_arm64) - implementation(compose.desktop.linux_x64) - implementation(compose.desktop.macos_arm64) - implementation(compose.desktop.macos_x64) - implementation(compose.desktop.windows_x64) implementation(packageSearchCatalog.kotlinx.serialization.core) implementation(packageSearchCatalog.jewel.bridge.ij232) implementation(packageSearchCatalog.ktor.client.logging) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt index f445cbca..85be9f20 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt @@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.onClick -import androidx.compose.material.Divider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -52,7 +51,9 @@ import org.jetbrains.jewel.foundation.lazy.SelectableLazyItemScope import org.jetbrains.jewel.foundation.lazy.SelectableLazyListState import org.jetbrains.jewel.foundation.lazy.SelectionMode import org.jetbrains.jewel.foundation.theme.JewelTheme +import org.jetbrains.jewel.ui.Orientation import org.jetbrains.jewel.ui.component.CircularProgressIndicator +import org.jetbrains.jewel.ui.component.Divider import org.jetbrains.jewel.ui.component.Icon import org.jetbrains.jewel.ui.component.Link import org.jetbrains.jewel.ui.component.Text @@ -319,7 +320,7 @@ internal fun RemotePackageWithVariantsActionPopup( } if (!isInstalledInPrimaryVariant) { passiveItem { - Divider(modifier = Modifier.padding(vertical = 4.dp)) + Divider(Orientation.Horizontal,modifier = Modifier.padding(vertical = 4.dp)) } selectableItem( selected = false, @@ -331,7 +332,7 @@ internal fun RemotePackageWithVariantsActionPopup( if (additionalVariants.isNotEmpty()) { passiveItem { - Divider(modifier = Modifier.padding(vertical = 4.dp)) + Divider(Orientation.Horizontal,modifier = Modifier.padding(vertical = 4.dp)) } additionalVariants.forEach { selectableItem( @@ -375,7 +376,7 @@ internal fun DeclaredPackageActionPopup( } } passiveItem { - Divider(modifier = Modifier.padding(vertical = 4.dp)) + Divider(Orientation.Horizontal,modifier = Modifier.padding(vertical = 4.dp)) } selectableItem( selected = false, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt index 3e2aadfb..71e3e739 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt @@ -1,7 +1,6 @@ package com.jetbrains.packagesearch.plugin.ui.panels.tree import androidx.compose.animation.Crossfade -import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -34,6 +33,7 @@ import org.jetbrains.jewel.foundation.lazy.tree.Tree import org.jetbrains.jewel.foundation.lazy.tree.buildTree import org.jetbrains.jewel.foundation.lazy.tree.rememberTreeState import org.jetbrains.jewel.foundation.theme.JewelTheme +import org.jetbrains.jewel.foundation.theme.ThemeDefinition import org.jetbrains.jewel.ui.Orientation import org.jetbrains.jewel.ui.component.Divider import org.jetbrains.jewel.ui.component.Icon @@ -58,7 +58,7 @@ fun PackageSearchModulesTree( onExpandAll = viewModel::expandAll, onCollapseAll = { val rootIds = tree.roots.map { it.id }.toSet() - viewModel.treeState.selectedKeys = viewModel.treeState.selectedKeys intersect rootIds + viewModel.treeState.selectedKeys = (viewModel.treeState.selectedKeys intersect rootIds).toList() viewModel.collapseAll() }, ) @@ -77,7 +77,7 @@ fun PackageSearchModulesTree( viewModel.treeState.selectedKeys = tree.walkBreadthFirst() .take(1) .map { it.data.id } - .toSet() + .toList() } } Box { @@ -200,52 +200,52 @@ private fun TreeItem(element: Tree.Element) { } } } - -@Preview -@Composable -private fun TreeItemPreview() { - val items = listOf( - TreeItemModel( - id = PackageSearchModule.Identity("a", ":"), - text = "JetBrains", - hasUpdates = true, - icon = IconProvider.Icon("icons/npm.svg"), - ), - TreeItemModel( - id = PackageSearchModule.Identity("a", ":b"), - text = "Kotlin", - hasUpdates = false, - icon = IconProvider.Icon("icons/maven.svg"), - ), - TreeItemModel( - id = PackageSearchModule.Identity("a", ":c"), - text = "Ktor", - hasUpdates = false, - icon = IconProvider.Icon("icons/cocoapods.svg.svg"), - ), - TreeItemModel( - id = PackageSearchModule.Identity("a", ":c:d"), - text = "Compose", - hasUpdates = true, - icon = IconProvider.Icon("icons/npm.svg"), - ), - ) - val tree = buildTree { - addLeaf(items[0], items[0].id) - addNode(items[1], items[1].id) { - addLeaf(items[2], items[2].id) - } - addLeaf(items[3], items[3].id) - } - LazyTree( - modifier = Modifier.padding(top = 4.dp), - tree = tree, - treeState = rememberTreeState(), - onSelectionChange = {}, - ) { item -> - TreeItem(item) - } -} - - - +// +//@Preview +//@Composable +//private fun TreeItemPreview() { +// val items = listOf( +// TreeItemModel( +// id = PackageSearchModule.Identity("a", ":"), +// text = "JetBrains", +// hasUpdates = true, +// icon = IconProvider.Icon("icons/npm.svg"), +// ), +// TreeItemModel( +// id = PackageSearchModule.Identity("a", ":b"), +// text = "Kotlin", +// hasUpdates = false, +// icon = IconProvider.Icon("icons/maven.svg"), +// ), +// TreeItemModel( +// id = PackageSearchModule.Identity("a", ":c"), +// text = "Ktor", +// hasUpdates = false, +// icon = IconProvider.Icon("icons/cocoapods.svg.svg"), +// ), +// TreeItemModel( +// id = PackageSearchModule.Identity("a", ":c:d"), +// text = "Compose", +// hasUpdates = true, +// icon = IconProvider.Icon("icons/npm.svg"), +// ), +// ) +// val tree = buildTree { +// addLeaf(items[0], items[0].id) +// addNode(items[1], items[1].id) { +// addLeaf(items[2], items[2].id) +// } +// addLeaf(items[3], items[3].id) +// } +// LazyTree( +// modifier = Modifier.padding(top = 4.dp), +// tree = tree, +// treeState = rememberTreeState(), +// onSelectionChange = {}, +// ) { item -> +// TreeItem(item) +// } +//} +// +// +// From a2eb53a10fa4b1e43c95ee44857d370caa7296ff Mon Sep 17 00:00:00 2001 From: Fabrizio Scarponi <36624359+fscarponi@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:37:21 +0100 Subject: [PATCH 37/39] Rollback to Compose Foundation SplitPane (#10) (cherry picked from commit 461e2d7b0e18e00bd4f08ae585e130bc355da3f4) --- packagesearch.versions.toml | 1 + plugin/build.gradle.kts | 4 ++ .../plugin/ui/PackageSearchMetrics.kt | 11 +++- .../plugin/ui/PackageSearchPackagePanel.kt | 52 +++++++++++++------ .../plugin/ui/bridge/Components.kt | 41 +++++++++++++++ .../plugin/ui/model/ToolWindowViewModel.kt | 17 ++++++ .../packages/PackageSearchCentralPanel.kt | 2 +- .../ui/panels/side/PackageSearchInfoPanel.kt | 2 +- 8 files changed, 111 insertions(+), 19 deletions(-) diff --git a/packagesearch.versions.toml b/packagesearch.versions.toml index 3d6d0ff1..5a21e761 100644 --- a/packagesearch.versions.toml +++ b/packagesearch.versions.toml @@ -39,6 +39,7 @@ jewel-ui = { module = "org.jetbrains.jewel:jewel-ui", version.ref = "jewel" } jewel-foundation = { module = "org.jetbrains.jewel:jewel-foundation", version.ref = "jewel" } jewel-bridge-ij232 = { module = "org.jetbrains.jewel:jewel-ide-laf-bridge", version.ref = "jewel-bridge-232" } jewel-bridge-ij233 = { module = "org.jetbrains.jewel:jewel-ide-laf-bridge", version.ref = "jewel-bridge-233" } +compose-desktop-components-splitpane = { module = "org.jetbrains.compose.components:components-splitpane", version.ref = "composeDesktop" } junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" } diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index f7f0261b..a271b9b9 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -50,6 +50,10 @@ val tooling: Configuration by configurations.creating { dependencies { implementation(packageSearchCatalog.kotlinx.serialization.core) + implementation(packageSearchCatalog.compose.desktop.components.splitpane){ + exclude(group = "org.jetbrains.compose.runtime") + exclude(group = "org.jetbrains.compose.foundation") + } implementation(packageSearchCatalog.jewel.bridge.ij232) implementation(packageSearchCatalog.ktor.client.logging) implementation(packageSearchCatalog.packagesearch.api.models) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt index 66d65787..d7b11bb0 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchMetrics.kt @@ -19,6 +19,14 @@ object PackageSearchMetrics { metrics.trackPadding.calculateEndPadding(LocalLayoutDirection.current) } + object Splitpane { + + val minWidth: Dp = 300.dp + const val firstSplitterPositionPercentage = .20f + + const val secondSplittePositionPercentage = .80f + } + object Popups { val minWidth: Dp = 50.dp @@ -54,5 +62,4 @@ object PackageSearchMetrics { } } } - -} \ No newline at end of file +} diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt index 62c26228..86143fb4 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt @@ -1,13 +1,23 @@ package com.jetbrains.packagesearch.plugin.ui +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.intellij.ui.JBColor import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule +import com.jetbrains.packagesearch.plugin.ui.bridge.packageSearchSplitter +import com.jetbrains.packagesearch.plugin.ui.model.ToolWindowViewModel import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent import com.jetbrains.packagesearch.plugin.ui.panels.packages.PackageSearchCentralPanel import com.jetbrains.packagesearch.plugin.ui.panels.side.PackageSearchInfoPanel import com.jetbrains.packagesearch.plugin.ui.panels.tree.PackageSearchModulesTree -import org.jetbrains.jewel.ui.component.HorizontalSplitLayout +import org.jetbrains.compose.splitpane.HorizontalSplitPane +import org.jetbrains.jewel.bridge.toComposeColor +import org.jetbrains.jewel.foundation.theme.JewelTheme @Composable fun PackageSearchPackagePanel( @@ -16,19 +26,31 @@ fun PackageSearchPackagePanel( onLinkClick: (String) -> Unit, onPackageEvent: (PackageListItemEvent) -> Unit, ) { - HorizontalSplitLayout( - first = { PackageSearchModulesTree(it, onSelectionModulesSelectionChanged) }, - second = { + val toolWindowsViewModel = viewModel() + + val splitPaneState by remember { toolWindowsViewModel.firstSplitPaneState } + val innerSplitPaneState by remember { toolWindowsViewModel.secondSplitPaneState } + val splitterColor by remember(JewelTheme.isDark) { mutableStateOf(JBColor.border().toComposeColor()) } + + HorizontalSplitPane(Modifier.fillMaxSize(), splitPaneState) { + first(PackageSearchMetrics.Splitpane.minWidth) { + PackageSearchModulesTree(Modifier, onSelectionModulesSelectionChanged) + } + packageSearchSplitter(splitterColor) + second { if (isInfoPanelOpen) { - HorizontalSplitLayout( - modifier = it, - initialDividerPosition = 700.dp, - first = { PackageSearchCentralPanel(it, onLinkClick) }, - second = { PackageSearchInfoPanel(it, onLinkClick, onPackageEvent) }, - maxRatio = 0.8f - ) - } else PackageSearchCentralPanel(it, onLinkClick) - }, - minRatio = 0.1f, - ) + HorizontalSplitPane(Modifier.fillMaxSize(), innerSplitPaneState) { + first(PackageSearchMetrics.Splitpane.minWidth) { + PackageSearchCentralPanel(onLinkClick = onLinkClick) + } + packageSearchSplitter(splitterColor) + second(PackageSearchMetrics.Splitpane.minWidth) { + PackageSearchInfoPanel(onLinkClick = onLinkClick, onPackageEvent = onPackageEvent) + } + } + + } else PackageSearchCentralPanel(onLinkClick = onLinkClick) + } + } } + diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt index d583a81e..92198ed7 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt @@ -1,11 +1,17 @@ package com.jetbrains.packagesearch.plugin.ui.bridge +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.PointerIcon +import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily @@ -15,8 +21,11 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp import com.intellij.icons.AllIcons import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics +import java.awt.Cursor +import org.jetbrains.compose.splitpane.SplitPaneScope import org.jetbrains.jewel.foundation.theme.JewelTheme import org.jetbrains.jewel.foundation.theme.LocalTextStyle import org.jetbrains.jewel.ui.component.DropdownLink @@ -130,3 +139,35 @@ internal fun PackageActionPopup( } } } + + + +internal fun SplitPaneScope.packageSearchSplitter( + splitterColor: Color, + cursor: PointerIcon = PointerIcon(Cursor(Cursor.E_RESIZE_CURSOR)), + hidden: Boolean = false, +) { + splitter { + visiblePart { + if (!hidden) { + Box( + modifier = Modifier + .fillMaxHeight() + .width(1.dp) + .background(splitterColor), + ) + } + } + handle { + if (!hidden) { + Box( + modifier = Modifier + .fillMaxHeight() + .width(8.dp) + .markAsHandle() + .pointerHoverIcon(cursor), + ) + } + } + } +} diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt index fd7f5a42..1d555b4c 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/ToolWindowViewModel.kt @@ -1,12 +1,14 @@ package com.jetbrains.packagesearch.plugin.ui.model import com.intellij.openapi.Disposable +import androidx.compose.runtime.mutableStateOf import com.intellij.openapi.components.Service import com.intellij.openapi.components.Service.Level import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message import com.jetbrains.packagesearch.plugin.core.utils.smartModeFlow +import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics import com.jetbrains.packagesearch.plugin.ui.bridge.openLinkInBrowser import com.jetbrains.packagesearch.plugin.ui.model.tree.TreeViewModel import com.jetbrains.packagesearch.plugin.utils.PackageSearchProjectService @@ -21,12 +23,27 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +import org.jetbrains.compose.splitpane.SplitPaneState @Service(Level.PROJECT) class ToolWindowViewModel(project: Project) : Disposable { private val viewModelScope: CoroutineScope = CoroutineScope(SupervisorJob()) + + val firstSplitPaneState = mutableStateOf( + SplitPaneState( + initialPositionPercentage = PackageSearchMetrics.Splitpane.firstSplitterPositionPercentage, + moveEnabled = true, + ) + ) + val secondSplitPaneState = mutableStateOf( + SplitPaneState( + initialPositionPercentage = PackageSearchMetrics.Splitpane.secondSplittePositionPercentage, + moveEnabled = true, + ) + ) + fun openLinkInBrowser(url: String) { viewModelScope.openLinkInBrowser(url) } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt index bdf64fe1..7d11c0b0 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchCentralPanel.kt @@ -19,7 +19,7 @@ import org.jetbrains.jewel.ui.component.VerticalScrollbar @Composable fun PackageSearchCentralPanel( - modifier: Modifier, + modifier: Modifier = Modifier, onLinkClick: (String) -> Unit, ) = Column(modifier) { val viewModel: PackageListViewModel = viewModel() diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt index 77d69cdf..0a9f4a30 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt @@ -28,7 +28,7 @@ import org.jetbrains.jewel.ui.component.VerticalScrollbar @Composable fun PackageSearchInfoPanel( - modifier: Modifier, + modifier: Modifier = Modifier, onLinkClick: (String) -> Unit, onPackageEvent: (PackageListItemEvent) -> Unit, ) = Box(modifier) { From 7f0a23d26b369a0e853c1458ca70a7c408fbd793 Mon Sep 17 00:00:00 2001 From: Fabrizio Scarponi <36624359+fscarponi@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:05:34 +0100 Subject: [PATCH 38/39] Introduce InfoPanelContent attributes and update UI in HeaderAttributesTab (#9) Refactor platformListMock to getter in HeaderAttributesTab scrollToAttribute has CoroutineScope as receiver rename InfoPanelContentEvent Attributes Declared into FromVariant and Search into FromSearch rename Attributes Declared into FromVariant and Search into FromSearch This commit adds InfoPanelContent Attributes for "Declared" type to the asPanelContent function, including the tab's title, variant's title, and attributes. A click event handler for the selected packages is also added to refresh the side panel content. A new event for package selection has been placed in 'PackageListItemEvent'. Furthermore, the attribute type name description and content title in the package search UI have been updated for clarity. The style of the 'Search' content in HeaderAttributesTab has also been modified to reduce redundancy and clarify display conditions. Now, by clicking on an attribute badge, it's possible to scroll to individual attributes with a smooth animation. (cherry picked from commit 259a0d297dbc7f11f61e42a23b625f7297461781) --- packagesearch.versions.toml | 1 + .../plugin/ui/PackageSearchColors.kt | 17 ++ .../plugin/ui/PackageSearchPackagePanel.kt | 1 - .../plugin/ui/bridge/Components.kt | 47 ++- .../packagesearch/plugin/ui/bridge/Utils.kt | 1 - .../packagesearch/plugin/ui/model/Utils.kt | 2 +- .../ui/model/infopanel/InfoPanelContent.kt | 18 ++ .../model/infopanel/InfoPanelContentEvent.kt | 19 +- .../ui/model/infopanel/InfoPanelViewModel.kt | 35 +++ .../plugin/ui/model/infopanel/Utils.kt | 4 +- .../ui/model/infopanel/asPanelContent.kt | 26 ++ .../packageslist/PackageListItemEvent.kt | 22 +- .../packageslist/PackageListViewModel.kt | 50 ++- .../packages/PackageSearchPackageList.kt | 7 +- .../packages/items/PackageGroupHeader.kt | 43 ++- .../ui/panels/side/HeaderAttributesTab.kt | 286 ++++++++++++++++++ .../ui/panels/side/PackageSearchInfoPanel.kt | 8 + .../panels/tree/PackageSearchModulesTree.kt | 5 +- .../messages/packageSearchBundle.properties | 7 +- 19 files changed, 565 insertions(+), 34 deletions(-) create mode 100644 plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchColors.kt create mode 100644 plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/HeaderAttributesTab.kt diff --git a/packagesearch.versions.toml b/packagesearch.versions.toml index 5a21e761..64c1e6cd 100644 --- a/packagesearch.versions.toml +++ b/packagesearch.versions.toml @@ -37,6 +37,7 @@ ij-platform-ide-core = { module = "com.jetbrains.intellij.platform:ide-core", ve ij-platform-ide-impl = { module = "com.jetbrains.intellij.platform:ide-impl", version.ref = "idea" } jewel-ui = { module = "org.jetbrains.jewel:jewel-ui", version.ref = "jewel" } jewel-foundation = { module = "org.jetbrains.jewel:jewel-foundation", version.ref = "jewel" } +jewel-standalone = { module= "org.jetbrains.jewel:jewel-int-ui-standalone", version.ref = "jewel" } jewel-bridge-ij232 = { module = "org.jetbrains.jewel:jewel-ide-laf-bridge", version.ref = "jewel-bridge-232" } jewel-bridge-ij233 = { module = "org.jetbrains.jewel:jewel-ide-laf-bridge", version.ref = "jewel-bridge-233" } compose-desktop-components-splitpane = { module = "org.jetbrains.compose.components:components-splitpane", version.ref = "composeDesktop" } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchColors.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchColors.kt new file mode 100644 index 00000000..01beec23 --- /dev/null +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchColors.kt @@ -0,0 +1,17 @@ +package com.jetbrains.packagesearch.plugin.ui + +import androidx.compose.ui.graphics.Color +import com.jetbrains.packagesearch.plugin.ui.bridge.pickComposeColorFromLaf + +object PackageSearchColors { + object Backgrounds { + fun packageItemHeader(): Color = + pickComposeColorFromLaf("ToolWindow.HeaderTab.selectedInactiveBackground") + + + fun attributeBadge() = packageItemHeader() + + } + + +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt index 86143fb4..ef36d5ec 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/PackageSearchPackagePanel.kt @@ -6,7 +6,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp import com.intellij.ui.JBColor import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule import com.jetbrains.packagesearch.plugin.ui.bridge.packageSearchSplitter diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt index 92198ed7..abe57e57 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Components.kt @@ -4,7 +4,10 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.onClick +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -23,9 +26,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import com.intellij.icons.AllIcons +import com.jetbrains.packagesearch.plugin.ui.PackageSearchColors import com.jetbrains.packagesearch.plugin.ui.PackageSearchMetrics import java.awt.Cursor -import org.jetbrains.compose.splitpane.SplitPaneScope import org.jetbrains.jewel.foundation.theme.JewelTheme import org.jetbrains.jewel.foundation.theme.LocalTextStyle import org.jetbrains.jewel.ui.component.DropdownLink @@ -34,6 +37,7 @@ import org.jetbrains.jewel.ui.component.IconButton import org.jetbrains.jewel.ui.component.MenuScope import org.jetbrains.jewel.ui.component.PopupMenu import org.jetbrains.jewel.ui.component.Text +import org.jetbrains.compose.splitpane.SplitPaneScope @Composable fun LabelInfo( @@ -141,7 +145,6 @@ internal fun PackageActionPopup( } - internal fun SplitPaneScope.packageSearchSplitter( splitterColor: Color, cursor: PointerIcon = PointerIcon(Cursor(Cursor.E_RESIZE_CURSOR)), @@ -171,3 +174,43 @@ internal fun SplitPaneScope.packageSearchSplitter( } } } + + +@Composable +internal fun AttributeBadge(text: String, onClick: () -> Unit) { + val isDark = JewelTheme.isDark + val background = remember(isDark) { + PackageSearchColors.Backgrounds.attributeBadge() + } + + Box( + modifier = Modifier + .background(color = background, shape = RoundedCornerShape(12.dp)) + .pointerHoverIcon(PointerIcon(Cursor(Cursor.HAND_CURSOR))) + .onClick { onClick() }, + ) { + Text( + modifier = Modifier.padding(horizontal = 8.dp, vertical = 2.dp), text = text, + ) + } + +} + +//@Preview +//@Composable +//internal fun AttributeBadgePreview() { +// Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { +// IntUiTheme { +// Box(Modifier.background(LocalGlobalColors.current.paneBackground).padding(16.dp)) { +// AttributeBadge(text = "Android") {} +// } +// } +// IntUiTheme(true) { +// Box(Modifier.background(LocalGlobalColors.current.paneBackground).padding(16.dp)) { +// AttributeBadge(text = "Android") {} +// } +// } +// } +// +// +//} \ No newline at end of file diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Utils.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Utils.kt index 772738c9..a81e88f3 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Utils.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/Utils.kt @@ -41,4 +41,3 @@ fun isLightTheme(): Boolean { private fun Color.getBrightness() = (red * 299 + green * 587 + blue * 114) / 1000 -fun Modifier.pointerChangeToHandModifier() = this.pointerHoverIcon(PointerIcon(Cursor(Cursor.HAND_CURSOR))) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/Utils.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/Utils.kt index a72338df..8fc1f628 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/Utils.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/Utils.kt @@ -32,4 +32,4 @@ internal val Project.isProjectImportingFlow trySend(false) } } - }.withInitialValue(false) \ No newline at end of file + }.withInitialValue(false) diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContent.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContent.kt index b95b719b..d4004664 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContent.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContent.kt @@ -2,6 +2,7 @@ package com.jetbrains.packagesearch.plugin.ui.model.infopanel import com.jetbrains.packagesearch.plugin.core.data.IconProvider import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule +import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModuleVariant import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItem sealed interface InfoPanelContent { @@ -140,4 +141,21 @@ sealed interface InfoPanelContent { } } + sealed interface Attributes : InfoPanelContent{ + val attributes: List + + data class FromVariant( + override val tabTitle: String, + val variantName: String, + override val attributes: List, + ) : Attributes + + data class FromSearch( + override val tabTitle: String, + override val attributes: List, + val defaultSourceSet: String, + val additionalSourceSets: List, + ) : Attributes + } + } \ No newline at end of file diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContentEvent.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContentEvent.kt index 79f5a506..28da25d2 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContentEvent.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelContentEvent.kt @@ -2,14 +2,14 @@ package com.jetbrains.packagesearch.plugin.ui.model.infopanel import com.jetbrains.packagesearch.plugin.core.data.PackageSearchDeclaredPackage import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule +import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModuleVariant import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItem import org.jetbrains.packagesearch.api.v3.ApiPackage sealed interface InfoPanelContentEvent { - val module: PackageSearchModule - sealed interface Package : InfoPanelContentEvent { + val module: PackageSearchModule val packageListId: PackageListItem.Package.Id @@ -51,5 +51,20 @@ sealed interface InfoPanelContentEvent { } } + sealed interface Attributes : InfoPanelContentEvent { + val attributes: List + + data class FromVariant( + val variantName: String, + override val attributes: List, + ) : Attributes + + data class FromSearch( + val defaultVariant: String, + val additionalVariants: List, + override val attributes: List, + ) : Attributes + + } } \ No newline at end of file diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt index d3015e90..fe660eed 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/InfoPanelViewModel.kt @@ -8,6 +8,7 @@ import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.jetbrains.packagesearch.plugin.core.data.PackageSearchDeclaredPackage import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModule +import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModuleVariant import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItem import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListViewModel import com.jetbrains.packagesearch.plugin.utils.PackageSearchProjectService @@ -64,6 +65,14 @@ class InfoPanelViewModel(private val project: Project) : Disposable { } } } + + is InfoPanelContentEvent.Attributes.FromVariant -> { + event.asPanelContent() + } + + is InfoPanelContentEvent.Attributes.FromSearch -> { + event.asPanelContent() + } } } .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) @@ -136,6 +145,32 @@ class InfoPanelViewModel(private val project: Project) : Disposable { ) } + fun setDeclaredHeaderAttributes( + variantName: String, + attributes: List, + ) { + setDataEventChannel.trySend( + InfoPanelContentEvent.Attributes.FromVariant( + variantName = variantName, + attributes = attributes + ) + ) + } + + fun setSearchHeaderAttributes( + defaultVariant: String, + additionalVariants: List, + attributes: List, + ) { + setDataEventChannel.trySend( + InfoPanelContentEvent.Attributes.FromSearch( + defaultVariant = defaultVariant, + additionalVariants = additionalVariants, + attributes = attributes + ) + ) + } + override fun dispose() { viewModelScope.cancel() } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/Utils.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/Utils.kt index 3d237a05..b62d6d07 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/Utils.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/Utils.kt @@ -1,6 +1,7 @@ package com.jetbrains.packagesearch.plugin.ui.model.infopanel import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message +import org.jetbrains.jewel.foundation.lazy.tree.buildTree import org.jetbrains.packagesearch.api.v3.ApiGitHub import org.jetbrains.packagesearch.api.v3.ApiScm import org.jetbrains.packagesearch.api.v3.LicenseFile @@ -24,4 +25,5 @@ internal fun Licenses<*>.asInfoPanelLicenseList() = buildList { internal fun LicenseFile.toInfoPanelLicense(): InfoPanelContent.PackageInfo.License? { val name = name ?: url ?: return null return InfoPanelContent.PackageInfo.License(name, url) -} \ No newline at end of file +} + diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/asPanelContent.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/asPanelContent.kt index f2dc380a..61b0f4e5 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/asPanelContent.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/infopanel/asPanelContent.kt @@ -126,6 +126,11 @@ internal fun InfoPanelContentEvent.Package.Declared.WithVariant.asPanelContent( declaredVariant = variantName, allowMissingScope = !module.dependencyMustHaveAScope, variantTerminology = module.variantTerminology + ), + InfoPanelContent.Attributes.FromVariant( + variantName = variantName, + tabTitle = message("packagesearch.ui.toolwindow.sidepanel.platforms"), + attributes = module.variants.getValue(variantName).attributes ) ) @@ -152,6 +157,11 @@ internal fun InfoPanelContentEvent.Package.Remote.WithVariants.asPanelContent( isLoading = isLoading, isInstalledInPrimaryVariant = module.variants.getValue(primaryVariantName).declaredDependencies .any { it.id == apiPackage.id } + ), + InfoPanelContent.Attributes.FromVariant( + tabTitle = message("packagesearch.ui.toolwindow.sidepanel.platforms"), + variantName = primaryVariantName, + attributes = module.variants.getValue(primaryVariantName).attributes ) ) @@ -175,4 +185,20 @@ internal fun InfoPanelContentEvent.Package.Remote.Base.asPanelContent( repositories = apiPackage.repositories(), isLoading = isLoading ) +) + +internal fun InfoPanelContentEvent.Attributes.FromVariant.asPanelContent() = listOf( + InfoPanelContent.Attributes.FromVariant( + variantName = variantName, + tabTitle = message("packagesearch.ui.toolwindow.sidepanel.platforms"), + attributes = attributes, + ) +) +internal fun InfoPanelContentEvent.Attributes.FromSearch.asPanelContent() = listOf( + InfoPanelContent.Attributes.FromSearch( + tabTitle = message("packagesearch.ui.toolwindow.packages.details.info.attributes"), + defaultSourceSet = defaultVariant, + additionalSourceSets = additionalVariants, + attributes = attributes, + ) ) \ No newline at end of file diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListItemEvent.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListItemEvent.kt index 1a0f27f7..62233de8 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListItemEvent.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListItemEvent.kt @@ -21,7 +21,19 @@ sealed interface PackageListItemEvent { sealed interface InfoPanelEvent : PackageListItemEvent { @Serializable - data class OnHeaderAttributesClick(override val eventId: PackageListItem.Header.Id) : InfoPanelEvent + sealed interface OnHeaderAttributesClick : InfoPanelEvent { + @Serializable + data class DeclaredHeaderAttributesClick( + override val eventId: PackageListItem.Header.Id.Declared, + val variantName: String, + ) : OnHeaderAttributesClick + @Serializable + data class SearchHeaderAttributesClick( + override val eventId: PackageListItem.Header.Id.Remote, + val attributesNames: List + ) : OnHeaderAttributesClick + + } @Serializable data class OnHeaderVariantsClick(override val eventId: PackageListItem.Header.Id) : InfoPanelEvent @@ -31,6 +43,11 @@ sealed interface PackageListItemEvent { @Serializable data class OnPackageDoubleClick(override val eventId: PackageListItem.Id) : InfoPanelEvent + + @Serializable + data class OnSelectedPackageClick(override val eventId: PackageListItem.Id) : InfoPanelEvent + + } @Serializable @@ -87,9 +104,6 @@ sealed interface PackageListItemEvent { } - - - @Serializable data class Update(override val eventId: PackageListItem.Package.Declared.Id) : OnPackageAction diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt index 971628fe..7e018f72 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/model/packageslist/PackageListViewModel.kt @@ -313,6 +313,7 @@ class PackageListViewModel(private val project: Project) : Disposable { is PackageListItemEvent.InfoPanelEvent.OnHeaderVariantsClick -> handle(event) is PackageListItemEvent.InfoPanelEvent.OnPackageSelected -> handle(event) is PackageListItemEvent.InfoPanelEvent.OnPackageDoubleClick -> handle(event) + is PackageListItemEvent.InfoPanelEvent.OnSelectedPackageClick -> handle(event) is PackageListItemEvent.OnPackageAction.GoToSource -> handle(event) is PackageListItemEvent.OnPackageAction.Install.Base -> handle(event) is PackageListItemEvent.OnPackageAction.Install.WithVariant -> handle(event) @@ -334,6 +335,12 @@ class PackageListViewModel(private val project: Project) : Disposable { logInfoPanelOpened() } + private fun handle(event: PackageListItemEvent.InfoPanelEvent.OnSelectedPackageClick) { + if (event.eventId is PackageListItem.Package.Id) handle( + PackageListItemEvent.InfoPanelEvent.OnPackageSelected(event.eventId) + ) + } + private fun handle(event: PackageListItemEvent.InfoPanelEvent.OnPackageSelected) { val infoPanelViewModel = project.service() logPackageSelected(event.eventId is PackageListItem.Package.Declared.Id) @@ -594,13 +601,46 @@ class PackageListViewModel(private val project: Project) : Disposable { } } - private fun handle(event: PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick) { - logTODO() - logHeaderAttributesClick( - isSearchHeader = event.eventId is PackageListItem.Header.Id.Remote - ) + private suspend fun handle(event: PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick) { + logHeaderAttributesClick(isSearchHeader = event.eventId is PackageListItem.Header.Id.Remote) + val infoPanelViewModel = project.service() + + val module = event.eventId.getModule() as? PackageSearchModule.WithVariants ?: return + + when (event) { + is PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick.DeclaredHeaderAttributesClick -> { + val attributes = module.variants[event.variantName]?.attributes ?: return + infoPanelViewModel.setDeclaredHeaderAttributes(event.variantName, attributes = attributes) + } + + is PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick.SearchHeaderAttributesClick -> { + val attributes = module + .variants + .map { it.value.attributes } + .flatten() + .filter { it.value in event.attributesNames } + .distinct() + + val variants = module.variants.values.map { it.name } - module.mainVariantName + + infoPanelViewModel.setSearchHeaderAttributes( + defaultVariant = module.mainVariantName, + additionalVariants = variants, + attributes = attributes + ) + } + } + + + project.service().isInfoPanelOpen.let { openStateFlow -> + if (!openStateFlow.value) { + openStateFlow.emit(true) + } + } + } + private suspend fun handle(event: PackageListItemEvent.EditPackageEvent.SetVariant) { val module = event.eventId .getModule() as? PackageSearchModule.WithVariants diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt index 85be9f20..2a745c06 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/PackageSearchPackageList.kt @@ -131,7 +131,12 @@ internal fun SelectableLazyItemScope.PackageListItem( .onClick( interactionSource = remember { MutableInteractionSource() }, onDoubleClick = { onPackageListItemEvent(OnPackageDoubleClick(content.id)) }, - onClick = { } + onClick = { + //this event should be handled when you click on a selected package to refresh side panel content + if (isSelected ) onPackageListItemEvent( + PackageListItemEvent.InfoPanelEvent.OnSelectedPackageClick(content.id) + ) + } ), ) { Row( diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt index e13e1981..3151cb0f 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/packages/items/PackageGroupHeader.kt @@ -1,7 +1,6 @@ package com.jetbrains.packagesearch.plugin.ui.panels.packages.items import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement.SpaceBetween import androidx.compose.foundation.layout.Box @@ -11,6 +10,10 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.onClick import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -20,17 +23,19 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.intellij.icons.AllIcons import com.jetbrains.packagesearch.plugin.PackageSearchBundle.message +import com.jetbrains.packagesearch.plugin.ui.PackageSearchColors import com.jetbrains.packagesearch.plugin.ui.bridge.LabelInfo -import com.jetbrains.packagesearch.plugin.ui.bridge.pickComposeColorFromLaf import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItem import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItem.Header.State import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent import java.awt.Cursor +import org.jetbrains.jewel.foundation.modifier.onHover import org.jetbrains.jewel.foundation.theme.JewelTheme import org.jetbrains.jewel.ui.component.CircularProgressIndicator import org.jetbrains.jewel.ui.component.Icon import org.jetbrains.jewel.ui.component.Link import org.jetbrains.jewel.ui.component.Text +import org.jetbrains.jewel.ui.theme.linkStyle @Composable fun PackageListHeader( @@ -38,12 +43,10 @@ fun PackageListHeader( content: PackageListItem.Header, onEvent: (PackageListItemEvent) -> Unit, ) { - val backgroundColor = - if (JewelTheme.isDark) { - pickComposeColorFromLaf("ToolWindow.HeaderTab.selectedInactiveBackground") - } else { - pickComposeColorFromLaf("Tree.selectionInactiveBackground") - } + val isDarkTheme = JewelTheme.isDark + val backgroundColor = remember(isDarkTheme) { + PackageSearchColors.Backgrounds.packageItemHeader() + } Row( modifier = Modifier @@ -88,22 +91,40 @@ fun PackageListHeader( } Text( - fontWeight = FontWeight(600), + fontWeight = FontWeight.ExtraBold, text = content.title, maxLines = 1 ) } if (content.attributes.isNotEmpty()) { + var attributeTextColor by remember { mutableStateOf(Color.Unspecified) } + val linkTextColor = JewelTheme.linkStyle.colors.content Box( modifier = Modifier .onClick { - onEvent(PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick(content.id)) + val event = + when (content.id) { + is PackageListItem.Header.Id.Declared.Base -> return@onClick + is PackageListItem.Header.Id.Remote -> PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick.SearchHeaderAttributesClick( + eventId = content.id, + attributesNames = content.attributes + ) + is PackageListItem.Header.Id.Declared.WithVariant -> PackageListItemEvent.InfoPanelEvent.OnHeaderAttributesClick.DeclaredHeaderAttributesClick( + eventId = content.id, + variantName = content.title, + ) + } + onEvent(event) + } + .onHover { + attributeTextColor = if (it) linkTextColor else Color.Unspecified } .pointerHoverIcon(PointerIcon(Cursor(Cursor.HAND_CURSOR))), contentAlignment = Alignment.Center, ) { - LabelInfo( + Text( text = content.attributes.joinToString(" "), + color = attributeTextColor, maxLines = 1 ) } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/HeaderAttributesTab.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/HeaderAttributesTab.kt new file mode 100644 index 00000000..2715203a --- /dev/null +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/HeaderAttributesTab.kt @@ -0,0 +1,286 @@ +package com.jetbrains.packagesearch.plugin.ui.panels.side + +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.positionInParent +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.jetbrains.packagesearch.plugin.PackageSearchBundle +import com.jetbrains.packagesearch.plugin.core.data.PackageSearchModuleVariant +import com.jetbrains.packagesearch.plugin.ui.bridge.AttributeBadge +import com.jetbrains.packagesearch.plugin.ui.bridge.LabelInfo +import com.jetbrains.packagesearch.plugin.ui.model.infopanel.InfoPanelContent +import kotlin.math.roundToInt +import kotlin.random.Random +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.jetbrains.jewel.ui.component.Text + +@Composable +fun HeaderAttributesTab( + content: InfoPanelContent.Attributes, + scrollState: ScrollState, +) { + HeaderAttributesTabImpl( + content = content, + scrollState = scrollState, + contentTitle = PackageSearchBundle.message("packagesearch.ui.toolwindow.sidepanel.searchResultSupport"), + attributeTypeName = PackageSearchBundle.message("packagesearch.ui.toolwindow.sidepanel.platformsList"), + sourceSetString = PackageSearchBundle.message("packagesearch.ui.toolwindow.sidepanel.searchResultSupport.sourceSets"), + ) +} + +@Composable +private fun HeaderAttributesTabImpl( + content: InfoPanelContent.Attributes, + contentTitle: String, + scrollState: ScrollState, + attributeTypeName: String, + sourceSetString: String, +) { + val scope = rememberCoroutineScope() + val attributes = content.attributes + // Global positions of attributes will be used to store the y offset used on scrollToItem + val attributeGlobalPositionMap = remember { mutableMapOf() } + + Column(verticalArrangement = Arrangement.spacedBy(12.dp), modifier = Modifier.padding(12.dp)) { + if (content is InfoPanelContent.Attributes.FromSearch) { + Text( + text = contentTitle, + fontSize = 14.sp, + fontWeight = FontWeight.ExtraBold, + modifier = Modifier.padding(top = 4.dp) + ) + } + + + Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { + attributes.forEachIndexed { index, attribute -> + AttributeBadge(text = attribute.value) { + scope.scrollToAttribute(scrollState, attributeGlobalPositionMap, index) + } + } + } + + if (content is InfoPanelContent.Attributes.FromSearch) { + SourceSetsList(content, sourceSetString) + } + + AttributeItems(attributeTypeName = attributeTypeName, attributes, attributeGlobalPositionMap) + } +} + + +@Composable +private fun ColumnScope.SourceSetsList( + content: InfoPanelContent.Attributes.FromSearch, + title: String, +) { + Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + Text( + text = title, + fontSize = 14.sp, + fontWeight = FontWeight.ExtraBold, + modifier = Modifier.padding(top = 4.dp) + ) + Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { + Text(text = content.defaultSourceSet) + LabelInfo(PackageSearchBundle.message("packagesearch.ui.toolwindow.variant.default.text")) + } + Text(text = content.additionalSourceSets.joinToString(", ")) + + } +} + +@Composable +private fun AttributeItems( + attributeTypeName: String, + attributesName: List, + attributeGlobalPosition: MutableMap, +) { + Text( + text = attributeTypeName, + fontSize = 14.sp, + fontWeight = FontWeight.ExtraBold, + modifier = Modifier.padding(top = 4.dp) + ) + + attributesName.forEachIndexed { index, attribute -> + AttributeItem( + modifier = Modifier.onGloballyPositioned { + attributeGlobalPosition[index] = it.positionInParent().y.roundToInt() + }, + attributeName = attribute.value, + nestedAttributesName = attribute.flatten() + ) + } +} + +private fun PackageSearchModuleVariant.Attribute.flatten(): List = + when (this) { + is PackageSearchModuleVariant.Attribute.NestedAttribute -> children.flatMap { it.flatten() } + is PackageSearchModuleVariant.Attribute.StringAttribute -> listOf(value) + } + + +private fun CoroutineScope.scrollToAttribute( + scrollState: ScrollState, + attributeGlobalPosition: MutableMap, + index: Int, +) { + launch { + scrollState.animateScrollTo( + value = attributeGlobalPosition[index] ?: 0, + animationSpec = spring( + dampingRatio = Spring.DampingRatioMediumBouncy, + stiffness = Spring.StiffnessVeryLow + ) + ) + } +} + +@Composable +fun AttributeItem(modifier: Modifier = Modifier, attributeName: String, nestedAttributesName: List) { + + Row(modifier = modifier, verticalAlignment = Alignment.Top, horizontalArrangement = Arrangement.spacedBy(8.dp)) { + Row( + modifier = Modifier.width(160.dp), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text(text = attributeName) + LabelInfo(nestedAttributesName.size.toString()) + } + + Text(text = nestedAttributesName.joinToString("\n")) + } +} + + +//@Preview +//@Composable +//private fun HeaderAttributesPreviewTab() { +// val activeTabMock = InfoPanelContent.Attributes.FromVariant( +// tabTitle = "FromVariant", +// variantName = "jvm", +// attributes = generateAttributesMock() +// ) +// val scrollStateMock = ScrollState(0) +// Column(Modifier.padding(8.dp)) { +// IntUiTheme(true) { +// Column(Modifier.background(LocalGlobalColors.current.paneBackground).padding(16.dp)) { +// HeaderAttributesTabImpl( +// content = activeTabMock, +// scrollState = scrollStateMock, +// contentTitle = "FromSearch results that support:", +// attributeTypeName = "Platforms:", +// sourceSetString = "Source Sets:" +// ) +// +// } +// +// Divider(orientation = Orientation.Horizontal, modifier = Modifier.padding(vertical = 16.dp)) +// +// } +// +// +// IntUiTheme(false) { +// Column(Modifier.background(LocalGlobalColors.current.paneBackground).padding(16.dp)) { +// HeaderAttributesTabImpl( +// content = activeTabMock, +// scrollState = scrollStateMock, +// contentTitle = "FromSearch results that support:", +// attributeTypeName = "Platforms:", +// sourceSetString = "Source Sets:" +// ) +// +// } +// } +// } +//} + +private fun generateAttributesMock(): List { + val attributes = mutableListOf() + + platformListMock.take(Random.nextInt(2, 10)).forEach { + attributes.add( + if (Random.nextBoolean()) { + PackageSearchModuleVariant.Attribute.NestedAttribute( + it, + platformListMock.take(Random.nextInt(2, 10)).map { + PackageSearchModuleVariant.Attribute.StringAttribute(it) + } + ) + + + } else { + + PackageSearchModuleVariant.Attribute.StringAttribute(it) + } + ) + } + + return attributes + +} + +internal val platformListMock get() = buildList { + add("Android") + add("android") + add("Apple") + add("iOS") + add("iosX64") + add("iosArm64") + add("iosSimulatorArm64") + add("macOS") + add("macosArm64") + add("macosX64") + + add("watchOS") + add("watchosArm32") + add("watchosArm64") + add("watchosX64") + add("watchosSimulatorArm64") + + add("tvOS") + add("tvosX64") + add("tvosArm64") + add("tvosSimulatorArm64") + + + add("Java") + add("jvm") + + add("JavaScript") + add("jsLegacy") + add("jslr") + + add("Linux") + add("LinuxMipsel32") + add("LinuxArm64") + add("LinuxArm32Hfp") + add("LinuxX64") + + add("Windows") + add("WindowsX64") + add("WindowsX86") + + add("WebAssembly") + add("wasm") + add("wasm32") + +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt index 0a9f4a30..4cc06021 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt @@ -65,6 +65,14 @@ fun PackageSearchInfoPanel( content = activeTab ) } + + is InfoPanelContent.Attributes.FromVariant -> { + HeaderAttributesTab(content = activeTab, scrollState = viewModel.scrollState) + + } + is InfoPanelContent.Attributes.FromSearch -> { + HeaderAttributesTab(content = activeTab, scrollState = viewModel.scrollState) + } } } VerticalScrollbar( diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt index 71e3e739..4f98fd43 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt @@ -30,10 +30,7 @@ import com.jetbrains.packagesearch.plugin.ui.model.tree.TreeItemModel import com.jetbrains.packagesearch.plugin.ui.model.tree.TreeViewModel import com.jetbrains.packagesearch.plugin.ui.viewModel import org.jetbrains.jewel.foundation.lazy.tree.Tree -import org.jetbrains.jewel.foundation.lazy.tree.buildTree -import org.jetbrains.jewel.foundation.lazy.tree.rememberTreeState import org.jetbrains.jewel.foundation.theme.JewelTheme -import org.jetbrains.jewel.foundation.theme.ThemeDefinition import org.jetbrains.jewel.ui.Orientation import org.jetbrains.jewel.ui.component.Divider import org.jetbrains.jewel.ui.component.Icon @@ -157,7 +154,7 @@ private fun TreeActionToolbar( modifier = Modifier.padding(5.dp), resource = "icons/intui/toggleOfflineMode.svg", iconClass = IconProvider::class.java, - contentDescription = "Package Search is offline." + contentDescription = "Package FromSearch is offline." ) }, ) diff --git a/plugin/src/main/resources/messages/packageSearchBundle.properties b/plugin/src/main/resources/messages/packageSearchBundle.properties index 96e92e95..56b0bdf9 100644 --- a/plugin/src/main/resources/messages/packageSearchBundle.properties +++ b/plugin/src/main/resources/messages/packageSearchBundle.properties @@ -215,6 +215,7 @@ packagesearch.toolwindow.loading.easterEgg.2=Asking the Mages in Dalaran to Tele packagesearch.toolwindow.loading.easterEgg.3=Hiring Goblin Engineers for High-Speed Package Data Transfer... packagesearch.toolwindow.loading.easterEgg.4=Deciphering Runes in Ulduar for Encrypted Package Data... packagesearch.ui.toolwindow.packages.details.info.overview=Overview +packagesearch.ui.toolwindow.packages.details.info.attributes=Attributes packagesearch.ui.toolwindow.packages.details.info.unknown=Unknown packagesearch.ui.tree.tooltips.offline=Package Search is offline packagesearch.ui.toolwindow.packages.details.info.scm.github=GitHub @@ -222,4 +223,8 @@ packagesearch.ui.toolwindow.packages.actions.remove=Remove packagesearch.ui.toolwindow.packages.details.info.scope=Scope: packagesearch.toolwindow.loading.dumbMode=Project is initializing... packagesearch.ui.tree.tooltips.expand=Expand all -packagesearch.ui.tree.tooltips.collapse=Collapse all \ No newline at end of file +packagesearch.ui.tree.tooltips.collapse=Collapse all +packagesearch.ui.toolwindow.sidepanel.platformsList=Platforms: +packagesearch.ui.toolwindow.sidepanel.platforms=Platforms +packagesearch.ui.toolwindow.sidepanel.searchResultSupport=Search results that support: +packagesearch.ui.toolwindow.sidepanel.searchResultSupport.sourceSets=Source Sets: From 3d477a2d96dede580c62fec536b9e8b26493c9d5 Mon Sep 17 00:00:00 2001 From: fscarponi Date: Wed, 10 Jan 2024 17:11:34 +0100 Subject: [PATCH 39/39] Fix Jewel and Compose dependencies, align code to jewel 0.12 --- plugin/build.gradle.kts | 6 ++++++ .../packagesearch/plugin/ui/bridge/CustomStyles.kt | 1 + .../plugin/ui/panels/side/PackageSearchInfoPanel.kt | 10 ++++++---- .../plugin/ui/panels/tree/PackageSearchModulesTree.kt | 4 ++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index a271b9b9..b9b1f0d6 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -49,6 +49,12 @@ val tooling: Configuration by configurations.creating { } dependencies { + implementation(compose.desktop.linux_arm64) + implementation(compose.desktop.linux_x64) + implementation(compose.desktop.macos_arm64) + implementation(compose.desktop.macos_x64) + implementation(compose.desktop.windows_x64) + implementation(packageSearchCatalog.jewel.bridge.ij233) implementation(packageSearchCatalog.kotlinx.serialization.core) implementation(packageSearchCatalog.compose.desktop.components.splitpane){ exclude(group = "org.jetbrains.compose.runtime") diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/CustomStyles.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/CustomStyles.kt index 755aa56f..26f20d1d 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/CustomStyles.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/bridge/CustomStyles.kt @@ -55,6 +55,7 @@ internal fun PackageSearchTabStyle(): TabStyle { underlineThickness = current.metrics.underlineThickness, tabPadding = current.metrics.tabPadding, tabHeight = PackageSearchMetrics.searchBarHeight, + tabContentSpacing = 0.dp, closeContentGap = current.metrics.closeContentGap, ), icons = current.icons, diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt index 4cc06021..8e5296e4 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/side/PackageSearchInfoPanel.kt @@ -22,6 +22,7 @@ import com.jetbrains.packagesearch.plugin.ui.model.infopanel.InfoPanelContent import com.jetbrains.packagesearch.plugin.ui.model.infopanel.InfoPanelViewModel import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent import com.jetbrains.packagesearch.plugin.ui.viewModel +import org.jetbrains.jewel.ui.component.SimpleTabContent import org.jetbrains.jewel.ui.component.TabData import org.jetbrains.jewel.ui.component.TabStrip import org.jetbrains.jewel.ui.component.VerticalScrollbar @@ -42,12 +43,12 @@ fun PackageSearchInfoPanel( else -> Column(modifier = Modifier.fillMaxSize()) { TabStrip( modifier = Modifier.fillMaxWidth(), - tabs = tabs.map { + tabs = tabs.map { infoPanelContent -> TabData.Default( - selected = activeTabTitle == it.tabTitle, - label = it.tabTitle, + selected = activeTabTitle == infoPanelContent.tabTitle, + content = { SimpleTabContent(label = infoPanelContent.tabTitle, state = it) }, closable = false, - onClick = { viewModel.setActiveTabTitle(it.tabTitle) }, + onClick = { viewModel.setActiveTabTitle(infoPanelContent.tabTitle) }, ) } ) @@ -70,6 +71,7 @@ fun PackageSearchInfoPanel( HeaderAttributesTab(content = activeTab, scrollState = viewModel.scrollState) } + is InfoPanelContent.Attributes.FromSearch -> { HeaderAttributesTab(content = activeTab, scrollState = viewModel.scrollState) } diff --git a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt index 4f98fd43..15565fde 100644 --- a/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt +++ b/plugin/src/main/kotlin/com/jetbrains/packagesearch/plugin/ui/panels/tree/PackageSearchModulesTree.kt @@ -55,7 +55,7 @@ fun PackageSearchModulesTree( onExpandAll = viewModel::expandAll, onCollapseAll = { val rootIds = tree.roots.map { it.id }.toSet() - viewModel.treeState.selectedKeys = (viewModel.treeState.selectedKeys intersect rootIds).toList() + viewModel.treeState.selectedKeys = viewModel.treeState.selectedKeys intersect rootIds viewModel.collapseAll() }, ) @@ -74,7 +74,7 @@ fun PackageSearchModulesTree( viewModel.treeState.selectedKeys = tree.walkBreadthFirst() .take(1) .map { it.data.id } - .toList() + .toSet() } } Box {