From 8f76b286c45fd3f993d85b46d8bf31c983498e26 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Mon, 30 Sep 2024 16:35:07 -0400 Subject: [PATCH] Better Description for Stats and added "Used Directly By" --- .../squareup/invert/common/ReportDataRepo.kt | 15 +- .../common/pages/ModuleDetailReportPage.kt | 424 +++++++++--------- .../common/pages/StatDetailReportPage.kt | 2 +- 3 files changed, 236 insertions(+), 205 deletions(-) diff --git a/invert-report/src/jsMain/kotlin/com/squareup/invert/common/ReportDataRepo.kt b/invert-report/src/jsMain/kotlin/com/squareup/invert/common/ReportDataRepo.kt index 639ccc9..e219b43 100644 --- a/invert-report/src/jsMain/kotlin/com/squareup/invert/common/ReportDataRepo.kt +++ b/invert-report/src/jsMain/kotlin/com/squareup/invert/common/ReportDataRepo.kt @@ -203,6 +203,17 @@ class ReportDataRepo( } } + + fun moduleDirectlyUsedBy(path: ModulePath): Flow>?> = + collectedDataRepo.directDependenciesData.mapLatest { directDependenciesData -> + val directDependencies = directDependenciesData?.directDependencies + directDependencies?.entries?.filter { (modulePath, configurationToDependencyIds) -> + configurationToDependencyIds.any { it.value.contains(path) } + }?.associate { (modulePath, configurationToDependencyIds) -> + modulePath to configurationToDependencyIds.keys.toList() + } + } + fun moduleTransitivelyUsedBy(path: ModulePath): Flow>?> = allInvertedDependencies.mapLatest { allInvertedDependenciesMap: Map>>? -> if (allInvertedDependenciesMap != null) { @@ -214,8 +225,8 @@ class ReportDataRepo( fun directDependenciesOf(modulePath: ModulePath?): Flow>?> = - collectedDataRepo.directDependenciesData.mapLatest { directDependenciesData -> - directDependenciesData?.directDependencies?.get(modulePath) + allDirectDependencies.mapLatest { directDependenciesData -> + directDependenciesData?.get(modulePath) } fun statsForKey(statKey: StatKey): Flow> = diff --git a/invert-report/src/jsMain/kotlin/com/squareup/invert/common/pages/ModuleDetailReportPage.kt b/invert-report/src/jsMain/kotlin/com/squareup/invert/common/pages/ModuleDetailReportPage.kt index 9965a20..5379a4c 100644 --- a/invert-report/src/jsMain/kotlin/com/squareup/invert/common/pages/ModuleDetailReportPage.kt +++ b/invert-report/src/jsMain/kotlin/com/squareup/invert/common/pages/ModuleDetailReportPage.kt @@ -35,247 +35,267 @@ import ui.BootstrapTable import kotlin.reflect.KClass data class ModuleDetailNavRoute( - val path: ModulePath, - val configurationName: ConfigurationName? = null, + val path: ModulePath, + val configurationName: ConfigurationName? = null, ) : BaseNavRoute(ModuleDetailReportPage.navPage) { - override fun toSearchParams() = toParamsWithOnlyPageId(this) - .also { map -> - map[PATH_PARAM] = path - configurationName?.let { - map[CONFIGURATION_PARAM] = it - } - } + override fun toSearchParams() = toParamsWithOnlyPageId(this) + .also { map -> + map[PATH_PARAM] = path + configurationName?.let { + map[CONFIGURATION_PARAM] = it + } + } - companion object { + companion object { - private const val PATH_PARAM = "path" - private const val CONFIGURATION_PARAM = "configuration" - fun parser(params: Map): NavRoute { - val path = params[PATH_PARAM] - val configurationName = params[CONFIGURATION_PARAM] - return if (!path.isNullOrEmpty()) { - ModuleDetailNavRoute( - path = path, - configurationName = configurationName - ) - } else { - AllModulesNavRoute() - } - } + private const val PATH_PARAM = "path" + private const val CONFIGURATION_PARAM = "configuration" + fun parser(params: Map): NavRoute { + val path = params[PATH_PARAM] + val configurationName = params[CONFIGURATION_PARAM] + return if (!path.isNullOrEmpty()) { + ModuleDetailNavRoute( + path = path, + configurationName = configurationName + ) + } else { + AllModulesNavRoute() + } } + } } object ModuleDetailReportPage : InvertReportPage { - override val navPage: NavPage = NavPage( - pageId = "module_detail", - navRouteParser = { parser(it) } - ) - override val navRouteKClass: KClass = ModuleDetailNavRoute::class + override val navPage: NavPage = NavPage( + pageId = "module_detail", + navRouteParser = { parser(it) } + ) + override val navRouteKClass: KClass = ModuleDetailNavRoute::class - override val composableContent: @Composable (ModuleDetailNavRoute) -> Unit = { navRoute -> - ModuleDetailComposable(navRoute) - } + override val composableContent: @Composable (ModuleDetailNavRoute) -> Unit = { navRoute -> + ModuleDetailComposable(navRoute) + } } private data class DependencyIdAndConfiguration( - val dependencyId: DependencyId, - val configurationName: ConfigurationName, + val dependencyId: DependencyId, + val configurationName: ConfigurationName, ) @OptIn(ExperimentalCoroutinesApi::class) @Composable fun ModuleDetailComposable( - navRoute: ModuleDetailNavRoute, - reportDataRepo: ReportDataRepo = DependencyGraph.reportDataRepo, - navRouteRepo: NavRouteRepo = DependencyGraph.navRouteRepo, + navRoute: ModuleDetailNavRoute, + reportDataRepo: ReportDataRepo = DependencyGraph.reportDataRepo, + navRouteRepo: NavRouteRepo = DependencyGraph.navRouteRepo, ) { - val modulePath = navRoute.path + val modulePath = navRoute.path - val pluginsForModule by reportDataRepo.allPlugins.mapLatest { it?.get(navRoute.path) }.collectAsState(null) + val pluginsForModule by reportDataRepo.allPlugins.mapLatest { it?.get(navRoute.path) }.collectAsState(null) - val directDependenciesMapOrig by reportDataRepo.directDependenciesOf(modulePath).collectAsState(null) - val moduleToOwnerMapCollected by reportDataRepo.moduleToOwnerMap.collectAsState(null) - val statInfos by reportDataRepo.statInfos.collectAsState(null) + val directDependenciesMapOrig by reportDataRepo.directDependenciesOf(modulePath).collectAsState(null) + val moduleToOwnerMapCollected by reportDataRepo.moduleToOwnerMap.collectAsState(null) + val statInfos by reportDataRepo.statInfos.collectAsState(null) - if (moduleToOwnerMapCollected == null || pluginsForModule == null || statInfos == null) { - H2 { - BootstrapLoadingMessageWithSpinner() - } - return + if (moduleToOwnerMapCollected == null || statInfos == null) { + H2 { + BootstrapLoadingMessageWithSpinner() } - val moduleToOwnerMap = moduleToOwnerMapCollected!! - val ownerName: OwnerName? = moduleToOwnerMap[modulePath] - ownerName?.let { - H2 { - Text("Module $modulePath is owned by ") - AppLink({ - onClick { - navRouteRepo.updateNavRoute(OwnerDetailNavRoute(ownerName)) - } - }) { - Text(ownerName) - } - Br { } - Br { } + return + } + val moduleToOwnerMap = moduleToOwnerMapCollected!! + val ownerName: OwnerName? = moduleToOwnerMap[modulePath] + ownerName?.let { + H2 { + Text("Module $modulePath is owned by ") + AppLink({ + onClick { + navRouteRepo.updateNavRoute(OwnerDetailNavRoute(ownerName)) } + }) { + Text(ownerName) + } + Br { } + Br { } } + } - if (directDependenciesMapOrig == null) { - BootstrapLoadingMessageWithSpinner("Loading Direct Dependencies...") - return - } + if (directDependenciesMapOrig == null) { + BootstrapLoadingMessageWithSpinner("Loading Direct Dependencies...") + return + } - val directDependenciesMap = directDependenciesMapOrig!! + val directDependenciesMap = directDependenciesMapOrig!! - val pageTabs = mutableListOf() - pageTabs.add( - BootstrapTabData(tabName = "Stats") { - val statsForModule: Map? by reportDataRepo.statsData.map { it?.statsByModule?.get(navRoute.path) } - .collectAsState(null) + val pageTabs = mutableListOf() + pageTabs.add( + BootstrapTabData(tabName = "Stats") { + val statsForModule: Map? by reportDataRepo.statsData.map { it?.statsByModule?.get(navRoute.path) } + .collectAsState(null) - if (statsForModule != null && statInfos != null) { - val statsForModuleMap: Map = statsForModule!!.mapKeys { - statInfos!!.first { statInfo -> statInfo.key == it.key } - } - BootstrapTable( - headers = listOf("Stat", "Value"), - rows = statsForModuleMap.filter { it.key != null && it.value is Stat.NumericStat } - .map { (key, value) -> - listOf(key!!.description, (value as Stat.NumericStat).value.toString()) - }, - types = listOf(String::class, Int::class), - maxResultsLimitConstant = MAX_RESULTS, - onItemClickCallback = { - navRouteRepo.updateNavRoute( - StatDetailNavRoute( - statKeys = listOf(statInfos!!.first { statInfo -> statInfo.description == it[0] }).map { it.key } - ) - ) - }, - sortAscending = false, - sortByColumn = 0 - ) - } + if (statsForModule != null && statInfos != null) { + val statsForModuleMap: Map = statsForModule!!.mapKeys { + statInfos!!.first { statInfo -> statInfo.key == it.key } + } + BootstrapTable( + headers = listOf("Stat", "Value"), + rows = statsForModuleMap.filter { it.key != null && it.value is Stat.NumericStat } + .map { (key, value) -> + listOf(key!!.description, (value as Stat.NumericStat).value.toString()) + }, + types = listOf(String::class, Int::class), + maxResultsLimitConstant = MAX_RESULTS, + onItemClickCallback = { + navRouteRepo.updateNavRoute( + StatDetailNavRoute( + statKeys = listOf(statInfos!!.first { statInfo -> statInfo.description == it[0] }).map { it.key } + ) + ) + }, + sortAscending = false, + sortByColumn = 0 + ) + } + + }) + pageTabs.add( + BootstrapTabData(tabName = "Direct Dependencies") { - }) - pageTabs.add( - BootstrapTabData(tabName = "Direct Dependencies") { + val allDirectDependencyToConfigurationEntries = mutableSetOf() + directDependenciesMap.entries.forEach { + it.value + .filter { it.startsWith(":") } + .forEach { depId: DependencyId -> + allDirectDependencyToConfigurationEntries.add( + DependencyIdAndConfiguration( + dependencyId = depId, + configurationName = it.key + ) + ) + } + } + val directDepsDependencyIdToConfigurations: Map> = + allDirectDependencyToConfigurationEntries + .groupBy { it.dependencyId } + .mapValues { entry -> + entry.value + .map { it.configurationName } + .distinct() + .sorted() + } - val allDirectDependencyToConfigurationEntries = mutableSetOf() - directDependenciesMap.entries.forEach { - it.value - .filter { it.startsWith(":") } - .forEach { depId: DependencyId -> - allDirectDependencyToConfigurationEntries.add( - DependencyIdAndConfiguration( - dependencyId = depId, - configurationName = it.key - ) - ) - } - } - val directDepsDependencyIdToConfigurations: Map> = - allDirectDependencyToConfigurationEntries - .groupBy { it.dependencyId } - .mapValues { entry -> - entry.value - .map { it.configurationName } - .distinct() - .sorted() - } + BootstrapTable( + headers = listOf("Module", "Configurations"), + rows = directDepsDependencyIdToConfigurations.entries.map { + listOf( + it.key, + it.value.joinToString("\n") + ) + }, + types = listOf(String::class, String::class), + maxResultsLimitConstant = MAX_RESULTS, + onItemClickCallback = { + navRouteRepo.updateNavRoute(ModuleDetailNavRoute(it[0])) + } + ) + } + ) - BootstrapTable( - headers = listOf("Module", "Configurations"), - rows = directDepsDependencyIdToConfigurations.entries.map { - listOf( - it.key, - it.value.joinToString("\n") - ) - }, - types = listOf(String::class, String::class), - maxResultsLimitConstant = MAX_RESULTS, - onItemClickCallback = { - navRouteRepo.updateNavRoute(ModuleDetailNavRoute(it[0])) - } + val moduleDirectUsageCollected by reportDataRepo.moduleDirectlyUsedBy(modulePath).collectAsState(null) + moduleDirectUsageCollected?.let {moduleUsage -> + pageTabs.add(BootstrapTabData(tabName = "Used Directly By") { + BootstrapTable( + headers = listOf("Module", "Used in Configurations"), + rows = moduleUsage.keys.map { key -> listOf(key, moduleUsage[key]?.joinToString() ?: "") }, + types = moduleUsage.keys.map { String::class }, + maxResultsLimitConstant = MAX_RESULTS, + onItemClickCallback = { + navRouteRepo.updateNavRoute( + ModuleDetailNavRoute( + it[0] ) + ) } - ) + ) + }) + } - val configurationToDependencyMapCollected by reportDataRepo.dependenciesOf(navRoute.path).collectAsState(null) - if (configurationToDependencyMapCollected != null) { - pageTabs.add(BootstrapTabData(tabName = "Transitive Dependencies") { - val configurationToDependencyMap = configurationToDependencyMapCollected!! - val allTransitiveDependencyToConfigurationEntries = mutableSetOf() - configurationToDependencyMap.entries.forEach { - it.value - .filter { it.startsWith(":") } - .forEach { depId: DependencyId -> - allTransitiveDependencyToConfigurationEntries.add( - DependencyIdAndConfiguration( - dependencyId = depId, - configurationName = it.key - ) - ) - } - } + val configurationToDependencyMapCollected by reportDataRepo.dependenciesOf(navRoute.path).collectAsState(null) + if (configurationToDependencyMapCollected != null) { + pageTabs.add(BootstrapTabData(tabName = "Transitive Dependencies") { + val configurationToDependencyMap = configurationToDependencyMapCollected!! + val allTransitiveDependencyToConfigurationEntries = mutableSetOf() + configurationToDependencyMap.entries.forEach { + it.value + .filter { it.startsWith(":") } + .forEach { depId: DependencyId -> + allTransitiveDependencyToConfigurationEntries.add( + DependencyIdAndConfiguration( + dependencyId = depId, + configurationName = it.key + ) + ) + } + } - val transitiveDepsDependencyIdToConfigurations: Map> = - allTransitiveDependencyToConfigurationEntries - .groupBy { it.dependencyId } - .mapValues { entry -> - entry.value - .map { it.configurationName } - .distinct() - .sorted() - } + val transitiveDepsDependencyIdToConfigurations: Map> = + allTransitiveDependencyToConfigurationEntries + .groupBy { it.dependencyId } + .mapValues { entry -> + entry.value + .map { it.configurationName } + .distinct() + .sorted() + } - BootstrapTable( - headers = listOf("Module", "Configurations"), - rows = transitiveDepsDependencyIdToConfigurations.entries.map { - listOf( - it.key, - it.value.joinToString("\n") - ) - }, - types = listOf(String::class, String::class), - maxResultsLimitConstant = MAX_RESULTS, - onItemClickCallback = { - navRouteRepo.updateNavRoute(ModuleDetailNavRoute(it[0])) - } - ) - }) - } + BootstrapTable( + headers = listOf("Module", "Configurations"), + rows = transitiveDepsDependencyIdToConfigurations.entries.map { + listOf( + it.key, + it.value.joinToString("\n") + ) + }, + types = listOf(String::class, String::class), + maxResultsLimitConstant = MAX_RESULTS, + onItemClickCallback = { + navRouteRepo.updateNavRoute(ModuleDetailNavRoute(it[0])) + } + ) + }) + } - val moduleUsageCollected by reportDataRepo.moduleTransitivelyUsedBy(modulePath).collectAsState(null) - moduleUsageCollected?.let { - pageTabs.add(BootstrapTabData(tabName = "Used Transitively By") { - val moduleUsage = moduleUsageCollected!! - BootstrapTable( - headers = listOf("Module", "Used in Configurations"), - rows = moduleUsage.keys.map { key -> listOf(key, moduleUsage[key]?.joinToString() ?: "") }, - types = moduleUsage.keys.map { String::class }, - maxResultsLimitConstant = MAX_RESULTS, - onItemClickCallback = { - navRouteRepo.updateNavRoute( - ModuleDetailNavRoute( - it[0] - ) - ) - } + val moduleUsageCollected by reportDataRepo.moduleTransitivelyUsedBy(modulePath).collectAsState(null) + moduleUsageCollected?.let { + pageTabs.add(BootstrapTabData(tabName = "Used Transitively By") { + val moduleUsage = moduleUsageCollected!! + BootstrapTable( + headers = listOf("Module", "Used in Configurations"), + rows = moduleUsage.keys.map { key -> listOf(key, moduleUsage[key]?.joinToString() ?: "") }, + types = moduleUsage.keys.map { String::class }, + maxResultsLimitConstant = MAX_RESULTS, + onItemClickCallback = { + navRouteRepo.updateNavRoute( + ModuleDetailNavRoute( + it[0] ) - }) - } + ) + } + ) + }) + } + pluginsForModule?.let {pluginsForModuleNonNull -> pageTabs.add(BootstrapTabData(tabName = "Gradle Plugins") { - val pluginsForModuleNonNull = pluginsForModule!! - BootstrapClickableList("Gradle Plugins", pluginsForModuleNonNull, MAX_RESULTS) { - navRouteRepo.updateNavRoute( - PluginDetailNavRoute( - pluginId = it - ) - ) - } + BootstrapClickableList("Gradle Plugins", pluginsForModuleNonNull, MAX_RESULTS) { + navRouteRepo.updateNavRoute( + PluginDetailNavRoute( + pluginId = it + ) + ) + } }) + } - BootstrapTabPane(pageTabs) + BootstrapTabPane(pageTabs) } \ No newline at end of file diff --git a/invert-report/src/jsMain/kotlin/com/squareup/invert/common/pages/StatDetailReportPage.kt b/invert-report/src/jsMain/kotlin/com/squareup/invert/common/pages/StatDetailReportPage.kt index 47039d2..6ce24bb 100644 --- a/invert-report/src/jsMain/kotlin/com/squareup/invert/common/pages/StatDetailReportPage.kt +++ b/invert-report/src/jsMain/kotlin/com/squareup/invert/common/pages/StatDetailReportPage.kt @@ -158,7 +158,7 @@ fun StatDetailComposable( BootstrapSearchBox( query = query ?: "", - placeholderText = "Module Query...", + placeholderText = "Module Filter...", ) { navRouteRepo.updateNavRoute(statsNavRoute.copy(moduleQuery = it)) }