Skip to content

Commit

Permalink
Migrate React to FC and upgrade Kotlin to 1.8.20
Browse files Browse the repository at this point in the history
  • Loading branch information
nathan3d committed May 8, 2023
1 parent 249468a commit 5023c3c
Show file tree
Hide file tree
Showing 14 changed files with 645 additions and 340 deletions.
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ buildscript {
classpath(Dependencies.KOTLIN_GRADLE_PLUGIN)
classpath(Dependencies.PROGUARD_GRADLE_PLUGIN)
classpath(Dependencies.KOTLINX_SERIALIZATION_GRADLE_PLUGIN)
classpath(Dependencies.KOTLIN_REACT_FUNCTION_GRADLE_PLUGIN)
classpath(Dependencies.DETEKT_GRADLE_PLUGIN)
classpath(Dependencies.NEXUS_PUBLISH_GRADLE_PLUGIN)
classpath(Dependencies.SHADOW_GRADLE_PLUGIN)
Expand Down
13 changes: 5 additions & 8 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ object Dependencies {
const val KOTLIN_GRADLE_PLUGIN = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.KOTLIN}"
const val PROGUARD_GRADLE_PLUGIN = "com.guardsquare:proguard-gradle:${Versions.PROGUARD_GRADLE_PLUGIN}"
const val KOTLINX_SERIALIZATION_GRADLE_PLUGIN = "org.jetbrains.kotlin:kotlin-serialization:${Versions.KOTLIN}"
const val KOTLIN_REACT_FUNCTION_GRADLE_PLUGIN = "gradle.plugin.com.bnorm.react:kotlin-react-function-gradle:${Versions.KOTLIN_REACT_FUNCTION}"
const val DETEKT_GRADLE_PLUGIN = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:${Versions.DETEKT_GRADLE_PLUGIN}"
const val NEXUS_PUBLISH_GRADLE_PLUGIN = "io.github.gradle-nexus.publish-plugin:io.github.gradle-nexus.publish-plugin.gradle.plugin:${Versions.NEXUS_PUBLISH_GRADLE_PLUGIN}"
const val SHADOW_GRADLE_PLUGIN = "gradle.plugin.com.github.johnrengelman:shadow:${Versions.SHADOW_GRADLE_PLUGIN}"
Expand All @@ -45,10 +44,9 @@ object Dependencies {
const val GOOGLE_GUAVA = "com.google.guava:guava:${Versions.GOOGLE_GUAVA}"

const val KOTLIN_REACT = "org.jetbrains.kotlin-wrappers:kotlin-react:${Versions.KOTLIN_REACT}"
const val KOTLIN_REACT_DOM = "org.jetbrains.kotlin-wrappers:kotlin-react-dom-legacy:${Versions.KOTLIN_REACT}"
const val KOTLIN_REACT_DOM = "org.jetbrains.kotlin-wrappers:kotlin-react-dom:${Versions.KOTLIN_REACT}"
const val KOTLIN_REACT_ROUTER = "org.jetbrains.kotlin-wrappers:kotlin-react-router-dom:${Versions.KOTLIN_REACT_ROUTER}"
const val KOTLIN_JS_EXTENSIONS = "org.jetbrains.kotlin-wrappers:kotlin-extensions:${Versions.KOTLIN_JS_EXTENSIONS}"
const val KOTLIN_REACT_FUNCTION = "com.bnorm.react:kotlin-react-function:${Versions.KOTLIN_REACT_FUNCTION}"

const val SELENIUM_WEBDRIVER = "org.seleniumhq.selenium:selenium-java:${Versions.SELENIUM_WEBDRIVER}"
const val SELENIUM_WEBDRIVER_MANAGER = "io.github.bonigarcia:webdrivermanager:${Versions.SELENIUM_WEBDRIVER_MANAGER}"
Expand All @@ -60,9 +58,8 @@ object Dependencies {

object Versions {
const val ANDROID_GRADLE_PLUGIN = "7.4.2" // https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google
const val KOTLIN = "1.6.21" // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib
const val KOTLIN = "1.8.20" // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib
const val PROGUARD_GRADLE_PLUGIN = "7.2.1" // https://mvnrepository.com/artifact/com.guardsquare/proguard-gradle
const val KOTLIN_REACT_FUNCTION = "0.7.0" // https://mvnrepository.com/artifact/com.bnorm.react.kotlin-react-function/com.bnorm.react.kotlin-react-function.gradle.plugin
const val DETEKT_GRADLE_PLUGIN = "1.21.0" // https://mvnrepository.com/artifact/io.gitlab.arturbosch.detekt/detekt-gradle-plugin
const val NEXUS_PUBLISH_GRADLE_PLUGIN = "1.1.0" // https://mvnrepository.com/artifact/io.github.gradle-nexus.publish-plugin/io.github.gradle-nexus.publish-plugin.gradle.plugin
const val SHADOW_GRADLE_PLUGIN = "7.1.2" // https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow
Expand All @@ -80,9 +77,9 @@ object Dependencies {
const val GOOGLE_TRUTH = "1.1.3" // https://mvnrepository.com/artifact/com.google.truth/truth
const val GOOGLE_GUAVA = "31.1-jre" // https://mvnrepository.com/artifact/com.google.guava/guava

const val KOTLIN_REACT = "18.1.0-pre.343" // https://mvnrepository.com/artifact/org.jetbrains.kotlin-wrappers/kotlin-react
const val KOTLIN_REACT_ROUTER = "6.3.0-pre.343" // https://mvnrepository.com/artifact/org.jetbrains.kotlin-wrappers/kotlin-react-router-dom
const val KOTLIN_JS_EXTENSIONS = "1.0.1-pre.343" // https://mvnrepository.com/artifact/org.jetbrains.kotlin-wrappers/kotlin-extensions
const val KOTLIN_REACT = "18.2.0-pre.545" // https://mvnrepository.com/artifact/org.jetbrains.kotlin-wrappers/kotlin-react
const val KOTLIN_REACT_ROUTER = "6.11.0-pre.545" // https://mvnrepository.com/artifact/org.jetbrains.kotlin-wrappers/kotlin-react-router-dom
const val KOTLIN_JS_EXTENSIONS = "1.0.1-pre.545" // https://mvnrepository.com/artifact/org.jetbrains.kotlin-wrappers/kotlin-extensions

const val SELENIUM_WEBDRIVER = "4.8.1" // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java
const val SELENIUM_WEBDRIVER_MANAGER = "5.3.2" // https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager
Expand Down
6 changes: 3 additions & 3 deletions ruler-frontend/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@

plugins {
id("org.jetbrains.kotlin.js")
id("com.bnorm.react.kotlin-react-function")
id("io.gitlab.arturbosch.detekt")
}

kotlin {
js(IR) {
browser {
commonWebpackConfig {
cssSupport.enabled = true
cssSupport {
enabled.set(true)
}
}
}
binaries.executable()
Expand All @@ -38,7 +39,6 @@ dependencies {
implementation(Dependencies.KOTLIN_REACT_DOM)
implementation(Dependencies.KOTLIN_REACT_ROUTER)
implementation(Dependencies.KOTLIN_JS_EXTENSIONS)
implementation(Dependencies.KOTLIN_REACT_FUNCTION)
implementation(Dependencies.KOTLINX_SERIALIZATION_JSON)

implementation(npm(Dependencies.REACT, Dependencies.Versions.REACT))
Expand Down
27 changes: 16 additions & 11 deletions ruler-frontend/src/main/kotlin/com/spotify/ruler/frontend/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,14 @@

package com.spotify.ruler.frontend

import com.spotify.ruler.frontend.components.report
import com.spotify.ruler.frontend.components.Report
import com.spotify.ruler.models.AppReport
import kotlinext.js.require
import kotlinx.browser.document
import kotlinx.html.dom.append
import kotlinx.html.js.link
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import react.Props
import react.createElement
import react.Fragment
import react.create
import react.dom.client.createRoot

fun main() {
Expand All @@ -35,16 +33,23 @@ fun main() {
require("bootstrap/dist/js/bootstrap.bundle.js")

// Load and show the favicon
val favicon = require("./favicon.svg").toString()
document.head?.append?.link(href = favicon, rel = "icon")
val favicon = kotlinext.js.require("./favicon.svg").toString()
val link = document.createElement("link").apply {
setAttribute("rel", "icon")
setAttribute("href", favicon)
}
document.head?.append(link)

// Load and deserialize the report data
val rawReport = require("report.json").toString()
val report = Json.decodeFromString<AppReport>(rawReport)
val reportData = Json.decodeFromString<AppReport>(rawReport)

// Visualize and display the report data
val root = createRoot(requireNotNull(document.getElementById("root")))
root.render(createElement<Props> {
report(report)
val container =
web.dom.document.getElementById("root") ?: error("Couldn't find root container!")
createRoot(container).render(Fragment.create {
Report {
report = reportData
}
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package com.spotify.ruler.frontend.chart

import com.spotify.ruler.frontend.binding.ApexChartOptions
import kotlinx.js.jso
import js.core.jso

/** Base config for displaying charts. Check https://apexcharts.com/docs/options/ for all chart types and options. */
abstract class ChartConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package com.spotify.ruler.frontend.chart

import com.spotify.ruler.frontend.binding.Series
import kotlinx.js.jso
import js.core.jso

fun seriesOf(name: String, data: LongArray): Series = jso {
this.name = name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,97 +16,161 @@

package com.spotify.ruler.frontend.components

import com.bnorm.react.RFunction
import com.bnorm.react.RKey
import com.spotify.ruler.frontend.formatSize
import com.spotify.ruler.models.AppComponent
import com.spotify.ruler.models.AppFile
import com.spotify.ruler.models.FileContainer
import com.spotify.ruler.models.Measurable
import kotlinx.html.id
import react.RBuilder
import react.dom.button
import react.dom.div
import react.dom.h2
import react.dom.h4
import react.dom.span

@RFunction
fun RBuilder.breakdown(components: List<AppComponent>, sizeType: Measurable.SizeType) {
h4(classes = "mb-3") { +"Breakdown (${components.size} components)" }
div(classes = "row") {
containerList(components, sizeType)
import react.FC
import react.Props
import react.dom.html.ReactHTML.button
import react.dom.html.ReactHTML.div
import react.dom.html.ReactHTML.h2
import react.dom.html.ReactHTML.h4
import react.dom.html.ReactHTML.span
import web.cssom.ClassName

external interface BreakdownProps : Props {
var components: List<AppComponent>
var sizeType: Measurable.SizeType
}

val Breakdown = FC<BreakdownProps> { props ->
h4 {
className = ClassName("mb-3")
+"Breakdown (${props.components.size} components)"
}
Row {
ContainerList {
containers = props.components
sizeType = props.sizeType
}
}
}

external interface ContainerListProps : Props {
var containers: List<FileContainer>
var sizeType: Measurable.SizeType
}

@RFunction
fun RBuilder.containerList(containers: List<FileContainer>, sizeType: Measurable.SizeType) {
div(classes = "accordion") {
containers.forEachIndexed { index, container ->
containerListItem(index, container, sizeType, container.name)
val ContainerList = FC<ContainerListProps> { props ->
div {
className = ClassName("accordion")
props.containers.forEachIndexed { index, container ->
ContainerListItem {
id = index
ContainerListItem@this.container = container
sizeType = props.sizeType
key = container.name
}
}
}
}

@RFunction
@Suppress("UNUSED_PARAMETER")
fun RBuilder.containerListItem(id: Int, container: FileContainer, sizeType: Measurable.SizeType, @RKey key: String) {
div(classes = "accordion-item") {
containerListItemHeader(id, container, sizeType)
containerListItemBody(id, container, sizeType)
external interface ContainerListItemProps: Props {
var id: Int
var container: FileContainer
var sizeType: Measurable.SizeType
}

val ContainerListItem = FC<ContainerListItemProps> { props ->
div {
className = ClassName("accordion-item")
ContainerListItemHeader {
id = props.id
container = props.container
sizeType = props.sizeType
}
ContainerListItemBody {
id = props.id
container = props.container
sizeType = props.sizeType
}
}
}

@RFunction
fun RBuilder.containerListItemHeader(id: Int, container: FileContainer, sizeType: Measurable.SizeType) {
val containsFiles = container.files != null
h2(classes = "accordion-header") {
val ContainerListItemHeader = FC<ContainerListItemProps> { props ->
val containsFiles = props.container.files != null
h2 {
className = ClassName("accordion-header")
var classes = "accordion-button collapsed"
if (!containsFiles) {
classes = "$classes disabled"
}
button(classes = classes) {
attrs["data-bs-toggle"] = "collapse"
attrs["data-bs-target"] = "#module-$id-body"
span(classes = "font-monospace text-truncate me-3") { +container.name }
container.owner?.let { owner -> span(classes = "badge bg-secondary me-3") { +owner } }
button {
asDynamic()["data-bs-toggle"] = "collapse"
asDynamic()["data-bs-target"] = "#module-${props.id}-body"

className = ClassName(classes)

span {
className = ClassName( "font-monospace text-truncate me-3")
+props.container.name
}
props.container.owner?.let { owner ->
span {
className = ClassName( "badge bg-secondary me-3")
+owner
}
}
var sizeClasses = "ms-auto text-nowrap"
if (containsFiles) {
sizeClasses = "$sizeClasses me-3"
}
span(classes = sizeClasses) {
+formatSize(container, sizeType)
span {
className = ClassName(sizeClasses)
+formatSize(props.container, props.sizeType)
}
}
}
}
}}

@RFunction
fun RBuilder.containerListItemBody(id: Int, container: FileContainer, sizeType: Measurable.SizeType) {
div(classes = "accordion-collapse collapse") {
attrs.id = "module-$id-body"
div(classes = "accordion-body p-0") {
fileList(container.files ?: emptyList(), sizeType)
val ContainerListItemBody = FC<ContainerListItemProps> { props ->
div {
className = ClassName("accordion-collapse collapse")
id = "module-${props.id}-body"
div {
className = ClassName("accordion-body p-0")
FileList {
files = props.container.files ?: emptyList()
sizeType = props.sizeType
}
}
}
}

@RFunction
fun RBuilder.fileList(files: List<AppFile>, sizeType: Measurable.SizeType) {
div(classes = "list-group list-group-flush") {
files.forEach { file ->
fileListItem(file, sizeType, file.name)
external interface FileListProps : Props {
var files: List<AppFile>
var sizeType: Measurable.SizeType
}

val FileList = FC<FileListProps> { props ->
div {
className = ClassName("list-group list-group-flush")
props.files.forEach {
FileListItem {
file = it
sizeType = props.sizeType
key = it.name
}
}
}
}

@RFunction
@Suppress("UNUSED_PARAMETER")
fun RBuilder.fileListItem(file: AppFile, sizeType: Measurable.SizeType, @RKey key: String) {
div(classes = "list-group-item d-flex border-0") {
span(classes = "font-monospace text-truncate me-2") { +file.name }
span(classes = "ms-auto me-custom text-nowrap") {
+formatSize(file, sizeType)
external interface FileListItemProps: Props {
var file: AppFile
var sizeType: Measurable.SizeType
}

val FileListItem = FC<FileListItemProps> { props ->
div {
className = ClassName("list-group-item d-flex border-0")
span {
className = ClassName("font-monospace text-truncate me-2")
+props.file.name
}
span {
className = ClassName("ms-auto me-custom text-nowrap")
+formatSize(props.file, props.sizeType)
}
}
}
Loading

0 comments on commit 5023c3c

Please sign in to comment.