mirror of
				https://github.com/InsanusMokrassar/KotlinPublicationScriptsBuilder.git
				synced 2025-11-04 13:10:06 +00:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			rewrite_on
			...
			rewrite_wi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 4ec7d3847f | |||
| 2bbfe99ff4 | |||
| 881d268ea9 | |||
| 0c8eef971a | |||
| 7aa30ef46c | |||
| aa1756724a | |||
| 741ee98e35 | 
							
								
								
									
										17
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
on: [push]
 | 
			
		||||
 | 
			
		||||
name: Build
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  build-ubuntu:
 | 
			
		||||
    name: Commit release
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout code
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
      - name: Setup JDK
 | 
			
		||||
        uses: actions/setup-java@v1
 | 
			
		||||
        with:
 | 
			
		||||
          java-version: 11
 | 
			
		||||
      - name: Build
 | 
			
		||||
        run: ./gradlew build packageUberJarForCurrentOS
 | 
			
		||||
							
								
								
									
										15
									
								
								.github/workflows/commit-release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.github/workflows/commit-release.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,7 @@
 | 
			
		||||
on: [push]
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - master
 | 
			
		||||
 | 
			
		||||
name: Commit release
 | 
			
		||||
 | 
			
		||||
@@ -16,9 +19,13 @@ jobs:
 | 
			
		||||
      - name: Set version from gradle.properties
 | 
			
		||||
        run: echo "version=` cat gradle.properties | grep ^version= | grep -o [\\.0-9]* `" >> $GITHUB_ENV
 | 
			
		||||
      - name: Build
 | 
			
		||||
        run: ./gradlew packageUberJarForCurrentOS
 | 
			
		||||
        env:
 | 
			
		||||
          additional_version: ""
 | 
			
		||||
        run: ./gradlew build packageUberJarForCurrentOS
 | 
			
		||||
      - name: Publish Web
 | 
			
		||||
        uses: peaceiris/actions-gh-pages@v3
 | 
			
		||||
        with:
 | 
			
		||||
          github_token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
          publish_dir: ./web/build/distributions
 | 
			
		||||
          publish_branch: site
 | 
			
		||||
      - name: Create Release
 | 
			
		||||
        id: create_release
 | 
			
		||||
        uses: actions/create-release@v1
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ allprojects {
 | 
			
		||||
 | 
			
		||||
        mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle"
 | 
			
		||||
        mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle"
 | 
			
		||||
        mppJsProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJsProject.gradle"
 | 
			
		||||
        mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle"
 | 
			
		||||
 | 
			
		||||
        defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
project.version = "$version" + System.getenv("additional_version")
 | 
			
		||||
project.version = "$version" + (System.getenv("additional_version") != null ? System.getenv("additional_version") : "")
 | 
			
		||||
project.group = "$group"
 | 
			
		||||
 | 
			
		||||
// apply from: "$publishGradlePath"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
project.version = "$version" + System.getenv("additional_version")
 | 
			
		||||
project.version = "$version" + (System.getenv("additional_version") != null ? System.getenv("additional_version") : "")
 | 
			
		||||
project.group = "$group"
 | 
			
		||||
 | 
			
		||||
// apply from: "$publishGradlePath"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								mppJsProject.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								mppJsProject.gradle
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
project.version = "$version" + (System.getenv("additional_version") != null ? System.getenv("additional_version") : "")
 | 
			
		||||
project.group = "$group"
 | 
			
		||||
 | 
			
		||||
// apply from: "$publishGradlePath"
 | 
			
		||||
 | 
			
		||||
kotlin {
 | 
			
		||||
    js (IR) {
 | 
			
		||||
        browser {
 | 
			
		||||
            binaries.executable()
 | 
			
		||||
        }
 | 
			
		||||
        nodejs()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sourceSets {
 | 
			
		||||
        commonMain {
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation kotlin('stdlib')
 | 
			
		||||
                api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        commonTest {
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation kotlin('test-common')
 | 
			
		||||
                implementation kotlin('test-annotations-common')
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        jsTest {
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation kotlin('test-js')
 | 
			
		||||
                implementation kotlin('test-junit')
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -9,7 +9,8 @@ rootProject.name = 'kmppscriptbuilder'
 | 
			
		||||
 | 
			
		||||
String[] includes = [
 | 
			
		||||
        ":core",
 | 
			
		||||
        ":desktop"
 | 
			
		||||
        ":desktop",
 | 
			
		||||
        ":web"
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								web/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								web/build.gradle
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
plugins {
 | 
			
		||||
    id "org.jetbrains.kotlin.multiplatform"
 | 
			
		||||
    id "org.jetbrains.kotlin.plugin.serialization"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply from: "$mppJsProjectPresetPath"
 | 
			
		||||
 | 
			
		||||
kotlin {
 | 
			
		||||
    sourceSets {
 | 
			
		||||
        commonMain {
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation project(":kmppscriptbuilder.core")
 | 
			
		||||
                implementation "dev.inmo:micro_utils.common:$micro_utils_version"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.utils.serialFormat
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.web.views.*
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
import kotlinx.dom.appendElement
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
import org.w3c.dom.url.URL
 | 
			
		||||
import org.w3c.files.*
 | 
			
		||||
 | 
			
		||||
fun saveFile(content: String, filename: String) {
 | 
			
		||||
    val a = document.body!!.appendElement("a") {
 | 
			
		||||
        setAttribute("style", "visibility:hidden; display: none")
 | 
			
		||||
    } as HTMLAnchorElement
 | 
			
		||||
    val blob = Blob(arrayOf(content), BlobPropertyBag(
 | 
			
		||||
        "text/plain;charset=utf-8"
 | 
			
		||||
    ))
 | 
			
		||||
    val url = URL.createObjectURL(blob)
 | 
			
		||||
    a.href = url
 | 
			
		||||
    a.download = filename
 | 
			
		||||
    a.target = "_blank"
 | 
			
		||||
    a.click()
 | 
			
		||||
    URL.revokeObjectURL(url)
 | 
			
		||||
    a.remove()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun main() {
 | 
			
		||||
    document.addEventListener(
 | 
			
		||||
        "DOMContentLoaded",
 | 
			
		||||
        {
 | 
			
		||||
            val builderView = BuilderView()
 | 
			
		||||
 | 
			
		||||
            (document.getElementById("openConfig") as HTMLElement).onclick = {
 | 
			
		||||
                val targetInput = document.body!!.appendElement("input") {
 | 
			
		||||
                    setAttribute("style", "visibility:hidden; display: none")
 | 
			
		||||
                } as HTMLInputElement
 | 
			
		||||
                targetInput.type = "file"
 | 
			
		||||
                targetInput.onchange = {
 | 
			
		||||
                    targetInput.files ?.also { files ->
 | 
			
		||||
                        for (i in (0 until files.length) ) {
 | 
			
		||||
                            files[i] ?.also { file ->
 | 
			
		||||
                                val reader = FileReader()
 | 
			
		||||
 | 
			
		||||
                                reader.onload = {
 | 
			
		||||
                                    val content = it.target.asDynamic().result as String
 | 
			
		||||
                                    builderView.config = serialFormat.decodeFromString(Config.serializer(), content)
 | 
			
		||||
                                    false
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                reader.readAsText(file)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                targetInput.click()
 | 
			
		||||
                targetInput.remove()
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
            (document.getElementById("saveConfig") as HTMLElement).onclick = {
 | 
			
		||||
                val filename = "publish.kpsb"
 | 
			
		||||
                val content = serialFormat.encodeToString(Config.serializer(), builderView.config)
 | 
			
		||||
 | 
			
		||||
                saveFile(content, filename)
 | 
			
		||||
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
            (document.getElementById("exportScript") as HTMLElement).onclick = {
 | 
			
		||||
                val filename = "publish.gradle"
 | 
			
		||||
 | 
			
		||||
                val content = builderView.config.run {
 | 
			
		||||
                    type.buildMavenGradleConfig(
 | 
			
		||||
                        mavenConfig,
 | 
			
		||||
                        licenses
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                saveFile(content, filename)
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.utils
 | 
			
		||||
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
var HTMLElement.ukActive: Boolean
 | 
			
		||||
    get() = classList.contains("uk-active")
 | 
			
		||||
    set(value) {
 | 
			
		||||
        if (value) {
 | 
			
		||||
            classList.add("uk-active")
 | 
			
		||||
        } else {
 | 
			
		||||
            classList.remove("uk-active")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.utils
 | 
			
		||||
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
 | 
			
		||||
inline fun <R> keepScrolling(crossinline block: () -> R): R = document.body ?.let {
 | 
			
		||||
    val (x, y) = (it.scrollLeft to it.scrollTop)
 | 
			
		||||
    return block().also { _ ->
 | 
			
		||||
        it.scrollTo(x, y)
 | 
			
		||||
    }
 | 
			
		||||
} ?: block()
 | 
			
		||||
@@ -0,0 +1,23 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
class BuilderView : View {
 | 
			
		||||
    private val projectTypeView = ProjectTypeView()
 | 
			
		||||
    private val licensesView = LicensesView(document.getElementById("licensesListDiv") as HTMLElement)
 | 
			
		||||
    private val mavenInfoTypeView = MavenProjectInfoView()
 | 
			
		||||
 | 
			
		||||
    var config: Config
 | 
			
		||||
        get() = Config(
 | 
			
		||||
            licensesView.licenses,
 | 
			
		||||
            mavenInfoTypeView.mavenConfig,
 | 
			
		||||
            projectTypeView.projectType
 | 
			
		||||
        )
 | 
			
		||||
        set(value) {
 | 
			
		||||
            licensesView.licenses = value.licenses
 | 
			
		||||
            mavenInfoTypeView.mavenConfig = value.mavenConfig
 | 
			
		||||
            projectTypeView.projectType = value.type
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Developer
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
 | 
			
		||||
class DevelopersView(rootElement: HTMLElement) : MutableListView<Developer>(rootElement, "Add developer", "Remove developer") {
 | 
			
		||||
    private val HTMLElement.usernameElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[0] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.nameElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[1] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.emailElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[2] as HTMLInputElement
 | 
			
		||||
 | 
			
		||||
    var developers: List<Developer>
 | 
			
		||||
        get() = elements.map {
 | 
			
		||||
            Developer(it.usernameElement.value, it.nameElement.value, it.emailElement.value)
 | 
			
		||||
        }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            data = value
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun createPlainObject(): Developer = Developer("", "", "")
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.addContentBeforeRemoveButton(value: Developer) {
 | 
			
		||||
        createTextField("Developer ID", "Developer username").value = value.id
 | 
			
		||||
        createTextField("Developer name", "").value = value.name
 | 
			
		||||
        createTextField("Developer E-Mail", "").value = value.eMail
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.updateElement(from: Developer, to: Developer) {
 | 
			
		||||
        usernameElement.value = to.id
 | 
			
		||||
        nameElement.value = to.name
 | 
			
		||||
        emailElement.value = to.eMail
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,113 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.License
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.getLicenses
 | 
			
		||||
import dev.inmo.micro_utils.coroutines.safeActor
 | 
			
		||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import kotlinx.coroutines.*
 | 
			
		||||
import kotlinx.coroutines.channels.Channel
 | 
			
		||||
import kotlinx.coroutines.channels.SendChannel
 | 
			
		||||
import kotlinx.coroutines.flow.consumeAsFlow
 | 
			
		||||
import kotlinx.coroutines.flow.debounce
 | 
			
		||||
import kotlinx.dom.appendElement
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
 | 
			
		||||
class LicensesView(
 | 
			
		||||
    rootElement: HTMLElement,
 | 
			
		||||
    client: HttpClient = HttpClient(),
 | 
			
		||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
			
		||||
) : MutableListView<License>(rootElement, "Add empty license", "Remove license") {
 | 
			
		||||
    private val HTMLElement.idElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[0] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.titleElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[1] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.urlElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[2] as HTMLInputElement
 | 
			
		||||
 | 
			
		||||
    private class LicenseOfferList(
 | 
			
		||||
        rootElement: HTMLElement,
 | 
			
		||||
        private val licensesView: LicensesView,
 | 
			
		||||
        client: HttpClient,
 | 
			
		||||
        scope: CoroutineScope
 | 
			
		||||
    ) : ListView<License>(rootElement, useSimpleDiffStrategy = true) {
 | 
			
		||||
        private var licensesTemplates: List<License> = emptyList()
 | 
			
		||||
 | 
			
		||||
        init {
 | 
			
		||||
            scope.launch {
 | 
			
		||||
                licensesTemplates = client.getLicenses().values.toList()
 | 
			
		||||
                changeActor.send(Unit) // update list of searches
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private val changeActor: SendChannel<Unit> = scope.run {
 | 
			
		||||
            val onChangeActor = Channel<Unit>(Channel.CONFLATED)
 | 
			
		||||
            onChangeActor.consumeAsFlow().subscribeSafelyWithoutExceptions(scope) {
 | 
			
		||||
                val lowercased = searchString
 | 
			
		||||
                data = if (lowercased.isEmpty()) {
 | 
			
		||||
                    emptyList()
 | 
			
		||||
                } else {
 | 
			
		||||
                    licensesTemplates.filter {
 | 
			
		||||
                        val lowercasedTitle = it.title.toLowerCase()
 | 
			
		||||
                        lowercased.all { it in lowercasedTitle }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            onChangeActor
 | 
			
		||||
        }
 | 
			
		||||
        private val searchElement = rootElement.createTextField("Quick add", "Type some license name part to find it").apply {
 | 
			
		||||
            oninput = {
 | 
			
		||||
                changeActor.offer(Unit)
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        private var searchString: String
 | 
			
		||||
            get() = searchElement.value.toLowerCase()
 | 
			
		||||
            set(value) {
 | 
			
		||||
                searchElement.value = value
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        override fun HTMLElement.placeElement(value: License) {
 | 
			
		||||
            createCommonButton(value.title).onclick = {
 | 
			
		||||
                searchString = ""
 | 
			
		||||
                licensesView.licenses += value
 | 
			
		||||
                changeActor.offer(Unit)
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun HTMLElement.updateElement(from: License, to: License) {
 | 
			
		||||
            getElementsByTagName("button")[0] ?.remove()
 | 
			
		||||
            placeElement(to)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val licensesOffersList = LicenseOfferList(
 | 
			
		||||
        rootElement.appendElement("div") { classList.add("uk-padding-small") } as HTMLElement,
 | 
			
		||||
        this,
 | 
			
		||||
        client,
 | 
			
		||||
        scope
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    var licenses: List<License>
 | 
			
		||||
        get() = elements.map {
 | 
			
		||||
            License(it.idElement.value, it.titleElement.value, it.urlElement.value)
 | 
			
		||||
        }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            data = value
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun createPlainObject(): License = License("", "", "")
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.addContentBeforeRemoveButton(value: License) {
 | 
			
		||||
        createTextField("License Id", "Short name like \"Apache-2.0\"").value = value.id
 | 
			
		||||
        createTextField("License Title", "Official title of license (like \"Apache Software License 2.0\")").value = value.title
 | 
			
		||||
        createTextField("License URL", "Link to your LICENSE file OR official license file (like \"https://opensource.org/licenses/Apache-2.0\")").value = value.url ?: ""
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.updateElement(from: License, to: License) {
 | 
			
		||||
        idElement.value = to.id
 | 
			
		||||
        titleElement.value = to.title
 | 
			
		||||
        urlElement.value = to.url ?: ""
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,58 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.micro_utils.common.calculateStrictDiff
 | 
			
		||||
import kotlinx.dom.appendElement
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
abstract class ListView<T>(
 | 
			
		||||
    protected val rootElement: HTMLElement,
 | 
			
		||||
    useSimpleDiffStrategy: Boolean = false
 | 
			
		||||
) : View {
 | 
			
		||||
    protected val elements = mutableListOf<HTMLElement>()
 | 
			
		||||
    private val diffHandling: (old: List<T>, new: List<T>) -> Unit = if (useSimpleDiffStrategy) {
 | 
			
		||||
        { _, new ->
 | 
			
		||||
            elements.forEach { it.remove() }
 | 
			
		||||
            elements.clear()
 | 
			
		||||
            new.forEach {
 | 
			
		||||
                val element = instantiateElement()
 | 
			
		||||
                elements.add(element)
 | 
			
		||||
                element.placeElement(it)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        {  old, new ->
 | 
			
		||||
            val diff = old.calculateStrictDiff(new)
 | 
			
		||||
            diff.removed.forEach {
 | 
			
		||||
                elements[it.index].remove()
 | 
			
		||||
                elements.removeAt(it.index)
 | 
			
		||||
                println(it.value)
 | 
			
		||||
            }
 | 
			
		||||
            diff.added.forEach {
 | 
			
		||||
                val element = instantiateElement()
 | 
			
		||||
                elements.add(element)
 | 
			
		||||
                element.placeElement(it.value)
 | 
			
		||||
            }
 | 
			
		||||
            diff.replaced.forEach { (old, new) ->
 | 
			
		||||
                val element = elements.getOrNull(old.index) ?.also { it.updateElement(old.value, new.value) }
 | 
			
		||||
                if (element == null) {
 | 
			
		||||
                    val newElement = instantiateElement()
 | 
			
		||||
                    newElement.placeElement(new.value)
 | 
			
		||||
                    elements[new.index] = newElement
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    protected var data: List<T> = emptyList()
 | 
			
		||||
        set(value) {
 | 
			
		||||
            val old = field
 | 
			
		||||
            field = value
 | 
			
		||||
            diffHandling(old, value)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    protected abstract fun HTMLElement.placeElement(value: T)
 | 
			
		||||
    protected abstract fun HTMLElement.updateElement(from: T, to: T)
 | 
			
		||||
 | 
			
		||||
    private fun instantiateElement() = rootElement.appendElement("div") {
 | 
			
		||||
        classList.add("uk-padding-small")
 | 
			
		||||
    } as HTMLElement
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.MavenConfig
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.SonatypeRepository
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
import org.w3c.dom.HTMLInputElement
 | 
			
		||||
 | 
			
		||||
class MavenProjectInfoView : View {
 | 
			
		||||
    private val nameElement = document.getElementById("projectNameInput") as HTMLInputElement
 | 
			
		||||
    private val descriptionElement = document.getElementById("projectDescriptionInput") as HTMLInputElement
 | 
			
		||||
    private val urlElement = document.getElementById("projectUrlInput") as HTMLInputElement
 | 
			
		||||
    private val vcsUrlElement = document.getElementById("projectVCSUrlInput") as HTMLInputElement
 | 
			
		||||
    private val includeGpgElement = document.getElementById("includeGpgSignToggle") as HTMLInputElement
 | 
			
		||||
    private val includeMavenCentralElement = document.getElementById("includeMavenCentralTargetRepoToggle") as HTMLInputElement
 | 
			
		||||
    private val developersView = DevelopersView(document.getElementById("developersListDiv") as HTMLElement)
 | 
			
		||||
    private val repositoriesView = RepositoriesView(document.getElementById("repositoriesListDiv") as HTMLElement)
 | 
			
		||||
 | 
			
		||||
    var mavenConfig: MavenConfig
 | 
			
		||||
        get() = MavenConfig(
 | 
			
		||||
            nameElement.value,
 | 
			
		||||
            descriptionElement.value,
 | 
			
		||||
            urlElement.value,
 | 
			
		||||
            vcsUrlElement.value,
 | 
			
		||||
            includeGpgElement.checked,
 | 
			
		||||
            developersView.developers,
 | 
			
		||||
            repositoriesView.repositories + if (includeMavenCentralElement.checked) {
 | 
			
		||||
                listOf(SonatypeRepository)
 | 
			
		||||
            } else {
 | 
			
		||||
                emptyList()
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        set(value) {
 | 
			
		||||
            nameElement.value = value.name
 | 
			
		||||
            descriptionElement.value = value.description
 | 
			
		||||
            urlElement.value = value.url
 | 
			
		||||
            vcsUrlElement.value = value.vcsUrl
 | 
			
		||||
            includeGpgElement.checked = value.includeGpgSigning
 | 
			
		||||
            developersView.developers = value.developers
 | 
			
		||||
            val reposWithoutSonatype = value.repositories.filter { it != SonatypeRepository }
 | 
			
		||||
            includeMavenCentralElement.checked = value.repositories.size != reposWithoutSonatype.size
 | 
			
		||||
            repositoriesView.repositories = value.repositories
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.web.utils.keepScrolling
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
abstract class MutableListView<T>(
 | 
			
		||||
    rootElement: HTMLElement,
 | 
			
		||||
    addButtonText: String = "Add",
 | 
			
		||||
    private val removeButtonText: String = "Remove"
 | 
			
		||||
) : ListView<T>(rootElement) {
 | 
			
		||||
    init {
 | 
			
		||||
        rootElement.createPrimaryButton(addButtonText).apply {
 | 
			
		||||
            onclick = {
 | 
			
		||||
                keepScrolling {
 | 
			
		||||
                    val newObject = createPlainObject()
 | 
			
		||||
                    data += newObject
 | 
			
		||||
                }
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract fun createPlainObject(): T
 | 
			
		||||
    protected open fun HTMLElement.addContentBeforeRemoveButton(value: T) {}
 | 
			
		||||
    protected open fun HTMLElement.addContentAfterRemoveButton(value: T) {}
 | 
			
		||||
    final override fun HTMLElement.placeElement(value: T) {
 | 
			
		||||
        addContentBeforeRemoveButton(value)
 | 
			
		||||
        addRemoveButton()
 | 
			
		||||
        addContentAfterRemoveButton(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun HTMLElement.addRemoveButton() {
 | 
			
		||||
        val button = createPrimaryButton(removeButtonText)
 | 
			
		||||
        button.onclick = {
 | 
			
		||||
            elements.indexOf(button.parentElement).takeIf { it > -1 } ?.also {
 | 
			
		||||
                data -= data[it]
 | 
			
		||||
            } ?: rootElement.removeChild(this@addRemoveButton)
 | 
			
		||||
            false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.*
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.web.utils.ukActive
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
class ProjectTypeView : View {
 | 
			
		||||
    private val mppProjectTypeElement = document.getElementById("mppProjectType") as HTMLElement
 | 
			
		||||
    private val jvmProjectTypeElement = document.getElementById("jvmProjectType") as HTMLElement
 | 
			
		||||
 | 
			
		||||
    var projectType: ProjectType
 | 
			
		||||
        get() = if (jvmProjectTypeElement.ukActive) {
 | 
			
		||||
            JVMProjectType
 | 
			
		||||
        } else {
 | 
			
		||||
            MultiplatformProjectType
 | 
			
		||||
        }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            mppProjectTypeElement.ukActive = value == MultiplatformProjectType
 | 
			
		||||
            jvmProjectTypeElement.ukActive = value == JVMProjectType
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        mppProjectTypeElement.onclick = {
 | 
			
		||||
            projectType = MultiplatformProjectType
 | 
			
		||||
            Unit
 | 
			
		||||
        }
 | 
			
		||||
        jvmProjectTypeElement.onclick = {
 | 
			
		||||
            projectType = JVMProjectType
 | 
			
		||||
            Unit
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
 | 
			
		||||
class RepositoriesView(rootElement: HTMLElement) : MutableListView<MavenPublishingRepository>(rootElement, "Add repository", "Remove repository") {
 | 
			
		||||
    private val HTMLElement.nameElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[0] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.urlElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[1] as HTMLInputElement
 | 
			
		||||
 | 
			
		||||
    var repositories: List<MavenPublishingRepository>
 | 
			
		||||
        get() = elements.map {
 | 
			
		||||
            MavenPublishingRepository(it.nameElement.value, it.urlElement.value)
 | 
			
		||||
        }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            data = value
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun createPlainObject(): MavenPublishingRepository = MavenPublishingRepository("", "")
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.addContentBeforeRemoveButton(value: MavenPublishingRepository) {
 | 
			
		||||
        createTextField("Repository name", "This name will be used to identify repository in grade").value = value.name
 | 
			
		||||
        createTextField("Repository URL", "For example: https://repo.maven.apache.org/maven2/").value = value.name
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.updateElement(from: MavenPublishingRepository, to: MavenPublishingRepository) {
 | 
			
		||||
        nameElement.value = to.name
 | 
			
		||||
        urlElement.value = to.url
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
interface View
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import kotlinx.dom.appendElement
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
 | 
			
		||||
fun HTMLElement.createTextField(
 | 
			
		||||
    label: String,
 | 
			
		||||
    placeholder: String
 | 
			
		||||
): HTMLInputElement {
 | 
			
		||||
    return appendElement("div") {
 | 
			
		||||
        classList.add("uk-margin", "uk-width-1-1")
 | 
			
		||||
    }.appendElement("label") {
 | 
			
		||||
        classList.add("uk-form-label")
 | 
			
		||||
        innerHTML = label
 | 
			
		||||
    }.run {
 | 
			
		||||
        val input = appendElement("input") {
 | 
			
		||||
            classList.add("uk-input", "uk-width-expand")
 | 
			
		||||
            setAttribute("type", "text")
 | 
			
		||||
            setAttribute("placeholder", placeholder)
 | 
			
		||||
        } as HTMLInputElement
 | 
			
		||||
        input
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun HTMLElement.createPrimaryButton(text: String): HTMLButtonElement = (appendElement("button") {
 | 
			
		||||
    classList.add("uk-button", "uk-button-primary")
 | 
			
		||||
} as HTMLButtonElement).apply {
 | 
			
		||||
    innerText = text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun HTMLElement.createCommonButton(text: String): HTMLButtonElement = (appendElement("button") {
 | 
			
		||||
    classList.add("uk-button", "uk-button-default")
 | 
			
		||||
} as HTMLButtonElement).apply {
 | 
			
		||||
    innerText = text
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										80
									
								
								web/src/jsMain/resources/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								web/src/jsMain/resources/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <title>Kotlin Publication Scripts Builder</title>
 | 
			
		||||
    <!-- UIkit CSS -->
 | 
			
		||||
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/css/uikit.min.css" />
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <nav class="uk-navbar-container" uk-navbar>
 | 
			
		||||
        <div class="uk-navbar-left">
 | 
			
		||||
            <div class="uk-padding-small uk-text-lead">Kotlin Publication Scripts Builder</div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="uk-navbar-right">
 | 
			
		||||
            <ul class="uk-navbar-nav">
 | 
			
		||||
                <li uk-tooltip="title: Open config" id="openConfig"><a href="#"><span uk-icon="icon: pull"></span></a></li><!--Open file-->
 | 
			
		||||
                <li uk-tooltip="title: Save config" id="saveConfig"><a href="#"><span uk-icon="icon: push"></span></a></li><!--Save file-->
 | 
			
		||||
                <li uk-tooltip="title: Export script" id="exportScript"><a href="#"><span uk-icon="icon: upload"></span></a></li><!--Save file-->
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
    </nav>
 | 
			
		||||
    <form class="uk-padding-small">
 | 
			
		||||
        <fieldset class="uk-fieldset">
 | 
			
		||||
            <legend class="uk-legend">Project type</legend>
 | 
			
		||||
            <div class="uk-padding-small">
 | 
			
		||||
                <ul class="uk-subnav uk-subnav-pill">
 | 
			
		||||
                    <li id="mppProjectType" class="uk-active"><a href="#">Multiplatform</a></li>
 | 
			
		||||
                    <li id="jvmProjectType"><a href="#">JVM</a></li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
            <legend class="uk-legend">Licenses</legend>
 | 
			
		||||
            <div id="licensesListDiv" class="uk-padding-small">
 | 
			
		||||
<!--                <div class="uk-margin uk-width-1-1">-->
 | 
			
		||||
<!--                    <input id="searchFilterInput" class="uk-input uk-width-expand" type="text" placeholder="License search filter">-->
 | 
			
		||||
<!--                </div>-->
 | 
			
		||||
<!--                <button class="uk-button uk-button-primary">Add empty license</button>-->
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <legend class="uk-legend">Project information</legend>
 | 
			
		||||
 | 
			
		||||
            <div class="uk-padding-small">
 | 
			
		||||
                <div class="uk-margin uk-width-1-1">
 | 
			
		||||
                    <label class="uk-form-label" for="projectNameInput">Public project name</label>
 | 
			
		||||
                    <input id="projectNameInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="uk-margin uk-width-1-1">
 | 
			
		||||
                    <label class="uk-form-label" for="projectDescriptionInput">Public project description</label>
 | 
			
		||||
                    <input id="projectDescriptionInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="uk-margin uk-width-1-1">
 | 
			
		||||
                    <label class="uk-form-label" for="projectUrlInput">Public project URL</label>
 | 
			
		||||
                    <input id="projectUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github or other source with readme">
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="uk-margin uk-width-1-1">
 | 
			
		||||
                    <label class="uk-form-label" for="projectVCSUrlInput">Public project VCS URL (with .git)</label>
 | 
			
		||||
                    <input id="projectVCSUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github .git file">
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="uk-margin">
 | 
			
		||||
                    <label><input id="includeGpgSignToggle" class="uk-checkbox" type="checkbox" checked> Include GPG Signing</label>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="uk-margin">
 | 
			
		||||
                    <label><input id="includeMavenCentralTargetRepoToggle" class="uk-checkbox" type="checkbox"> Include publication to MavenCentral</label>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <legend class="uk-legend">Developers info</legend>
 | 
			
		||||
            <div id="developersListDiv" class="uk-padding-small"></div>
 | 
			
		||||
 | 
			
		||||
            <legend class="uk-legend">Repositories info</legend>
 | 
			
		||||
            <div id="repositoriesListDiv" class="uk-padding-small"></div>
 | 
			
		||||
        </fieldset>
 | 
			
		||||
    </form>
 | 
			
		||||
    <!-- UIkit JS -->
 | 
			
		||||
    <script src="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/js/uikit.min.js"></script>
 | 
			
		||||
    <script src="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/js/uikit-icons.min.js"></script>
 | 
			
		||||
    <!-- Internal JS -->
 | 
			
		||||
    <script src="kmppscriptbuilder.web.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
		Reference in New Issue
	
	Block a user