Skip to content

Commit 0a74809

Browse files
authored
Merge pull request #55 from square/amorde/code-references-filter-by-extras
Add support for filtering code references by values in 'extras'
2 parents 35d9943 + c2bc85c commit 0a74809

File tree

1 file changed

+122
-30
lines changed

1 file changed

+122
-30
lines changed

invert-report/src/jsMain/kotlin/com/squareup/invert/common/pages/CodeReferencesReportPage.kt

Lines changed: 122 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.squareup.invert.models.StatMetadata
2525
import org.jetbrains.compose.web.dom.H1
2626
import org.jetbrains.compose.web.dom.H3
2727
import org.jetbrains.compose.web.dom.H4
28+
import org.jetbrains.compose.web.dom.H5
2829
import org.jetbrains.compose.web.dom.Li
2930
import org.jetbrains.compose.web.dom.P
3031
import org.jetbrains.compose.web.dom.Text
@@ -46,6 +47,7 @@ data class CodeReferencesNavRoute(
4647
val module: String? = null,
4748
val treemap: Boolean? = null,
4849
val chart: Boolean? = null,
50+
val extras: Map<String, String>? = null
4951
) : BaseNavRoute(CodeReferencesReportPage.navPage) {
5052

5153
override fun toSearchParams(): Map<String, String> = toParamsWithOnlyPageId(this)
@@ -65,6 +67,11 @@ data class CodeReferencesNavRoute(
6567
chart?.let {
6668
params[CHART_PARAM] = chart.toString()
6769
}
70+
extras?.let {
71+
it.forEach { (key, value) ->
72+
params["extra_$key"] = value
73+
}
74+
}
6875
}
6976

7077
companion object {
@@ -74,37 +81,51 @@ data class CodeReferencesNavRoute(
7481
private const val OWNER_PARAM = "owner"
7582
private const val MODULE_PARAM = "module"
7683
private const val TREEMAP_PARAM = "treemap"
84+
private const val EXTRAS_PARAM_PREFIX = "extra_"
85+
7786

7887
fun parser(params: Map<String, String?>): NavRoute {
79-
val statKey = params[STATKEY_PARAM]
80-
val owner = params[OWNER_PARAM]?.trim()?.let {
81-
if (it.isNotBlank()) {
82-
it
83-
} else {
84-
null
85-
}
86-
}
87-
val module = params[MODULE_PARAM]?.trim()?.let {
88-
if (it.isNotBlank()) {
89-
it
90-
} else {
91-
null
92-
}
93-
}
94-
val treemap = params[TREEMAP_PARAM]?.trim()?.let {
95-
if (it.isNotBlank()) {
96-
it.toBoolean()
97-
} else {
98-
null
88+
var statKey: String? = null
89+
var owner: String? = null
90+
var module: String? = null
91+
var treemap: Boolean? = null
92+
var chart: Boolean? = null
93+
var extras: MutableMap<String, String> = mutableMapOf()
94+
params.forEach { (key, value) ->
95+
val trimmedValue = value?.trim()?.let {
96+
if (it.isNotBlank()) {
97+
it
98+
} else {
99+
null
100+
}
99101
}
100-
}
101-
val chart = params[CHART_PARAM]?.trim()?.let {
102-
if (it.isNotBlank()) {
103-
it.toBoolean()
104-
} else {
105-
null
102+
if (trimmedValue != null) {
103+
when (key) {
104+
STATKEY_PARAM -> {
105+
statKey = trimmedValue
106+
}
107+
OWNER_PARAM -> {
108+
owner = trimmedValue
109+
}
110+
MODULE_PARAM -> {
111+
module = trimmedValue
112+
}
113+
TREEMAP_PARAM -> {
114+
treemap = trimmedValue.toBoolean()
115+
}
116+
CHART_PARAM -> {
117+
chart = trimmedValue.toBoolean()
118+
}
119+
else -> {
120+
if (key.startsWith(EXTRAS_PARAM_PREFIX)) {
121+
val extraKey = key.substring(EXTRAS_PARAM_PREFIX.length)
122+
extras[extraKey] = trimmedValue
123+
}
124+
}
125+
}
106126
}
107127
}
128+
108129
return if (statKey == null) {
109130
AllStatsNavRoute()
110131
} else {
@@ -114,6 +135,7 @@ data class CodeReferencesNavRoute(
114135
module = module,
115136
treemap = treemap,
116137
chart = chart,
138+
extras = extras.let { if (it.isEmpty()) null else it }
117139
)
118140
}
119141
}
@@ -293,6 +315,18 @@ fun CodeReferencesComposable(
293315
true
294316
}
295317
}
318+
// Filter by extras
319+
.filter { ownerAndCodeReference: ModuleOwnerAndCodeReference ->
320+
val codeReference = ownerAndCodeReference.codeReference
321+
val extras = codeReferencesNavRoute.extras ?: mapOf()
322+
if (extras.isEmpty()) {
323+
true
324+
} else {
325+
extras.all { (key, value) ->
326+
codeReference.extras[key] == value
327+
}
328+
}
329+
}
296330

297331
if (codeReferencesNavRoute.treemap == true) {
298332
BootstrapRow {
@@ -337,12 +371,18 @@ fun CodeReferencesComposable(
337371
}
338372
}
339373

374+
BootstrapRow {
375+
H3 {
376+
Text("Filters")
377+
}
378+
}
379+
340380
val codeReferencesByOwner = allCodeReferencesForStat.groupBy { it.owner }
341381
val totalCodeReferenceCount = allCodeReferencesForStat.size
342382
BootstrapRow {
343383
BootstrapColumn(6) {
344-
H3 {
345-
Text("Filter by Owner")
384+
H5 {
385+
Text("Owner")
346386
BootstrapSelectDropdown(
347387
placeholderText = "-- All Owners ($totalCodeReferenceCount Total) --",
348388
currentValue = codeReferencesNavRoute.owner,
@@ -364,8 +404,8 @@ fun CodeReferencesComposable(
364404
val codeReferencesByModule =
365405
allCodeReferencesForStat.groupBy { it.module }
366406
BootstrapColumn(6) {
367-
H3 {
368-
Text("Filter by Module")
407+
H5 {
408+
Text("Module")
369409
BootstrapSelectDropdown(
370410
placeholderText = "-- All Modules --",// (${codeReferencesByModule.size} Total) --",
371411
currentValue = codeReferencesNavRoute.module,
@@ -385,6 +425,58 @@ fun CodeReferencesComposable(
385425
}
386426
}
387427
}
428+
// Limit filterable extras to ones where the amount of possible values is within a reasonable limit
429+
val filterableExtraCountLimit = 5000
430+
val allExtraValuesByKey = allCodeReferencesForStat.flatMap {
431+
it.codeReference.extras.entries.toList()
432+
}.groupBy { it.key }.mapValues { it.value.map { entry -> entry.value }.toSet().sorted() }
433+
val filterableExtras = currentStatMetadata.extras.filter {
434+
val extraValues = allExtraValuesByKey[it.key] ?: emptyList()
435+
(it.type == ExtraDataType.STRING || it.type == ExtraDataType.BOOLEAN) &&
436+
extraValues.size < filterableExtraCountLimit
437+
}.sortedBy { it.description }
438+
if (filterableExtras.isNotEmpty()) {
439+
filterableExtras.chunked(size = 2).map { extraGroup ->
440+
BootstrapRow {
441+
extraGroup.forEach { extra ->
442+
BootstrapColumn(6) {
443+
H5 {
444+
Text(extra.description)
445+
BootstrapSelectDropdown(
446+
placeholderText = "-- All Values --",
447+
currentValue = codeReferencesNavRoute.extras?.get(extra.key),
448+
options = allCodeReferencesForStat.mapNotNull {
449+
it.codeReference.extras[extra.key]
450+
}.toSet().map {
451+
BootstrapSelectOption(
452+
value = it,
453+
displayText = it,
454+
)
455+
}.sortedBy { it.displayText }
456+
) {
457+
val value = it?.value
458+
var newExtras: Map<String, String>? = null
459+
val currentExtras = codeReferencesNavRoute.extras ?: mapOf()
460+
if (value != null) {
461+
newExtras = currentExtras + mapOf(extra.key to value)
462+
} else {
463+
newExtras = currentExtras.minus(extra.key)
464+
if (newExtras.isEmpty()) {
465+
newExtras = null
466+
}
467+
}
468+
navRouteRepo.pushNavRoute(
469+
codeReferencesNavRoute.copy(
470+
extras = newExtras
471+
)
472+
)
473+
}
474+
}
475+
}
476+
}
477+
}
478+
}
479+
}
388480

389481
BootstrapTable(
390482
headers = listOf(

0 commit comments

Comments
 (0)