From aa1756724a3db8b2efbfdb2df6f86087e2aad61e Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 1 Mar 2021 22:42:15 +0600 Subject: [PATCH 1/6] add and web target --- extensions.gradle | 1 + mppJsProject.gradle | 32 +++++++++++ settings.gradle | 3 +- web/build.gradle | 6 +++ web/src/jsMain/resources/index.html | 83 +++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 mppJsProject.gradle create mode 100644 web/build.gradle create mode 100644 web/src/jsMain/resources/index.html diff --git a/extensions.gradle b/extensions.gradle index 0c108ed..2e89947 100644 --- a/extensions.gradle +++ b/extensions.gradle @@ -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" diff --git a/mppJsProject.gradle b/mppJsProject.gradle new file mode 100644 index 0000000..9911a72 --- /dev/null +++ b/mppJsProject.gradle @@ -0,0 +1,32 @@ +project.version = "$version" + System.getenv("additional_version") +project.group = "$group" + +// apply from: "$publishGradlePath" + +kotlin { + js (IR) { + browser() + 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') + } + } + } +} diff --git a/settings.gradle b/settings.gradle index b1eed1e..29bbdc6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -9,7 +9,8 @@ rootProject.name = 'kmppscriptbuilder' String[] includes = [ ":core", - ":desktop" + ":desktop", + ":web" ] diff --git a/web/build.gradle b/web/build.gradle new file mode 100644 index 0000000..00115fe --- /dev/null +++ b/web/build.gradle @@ -0,0 +1,6 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" +} + +apply from: "$mppJsProjectPresetPath" diff --git a/web/src/jsMain/resources/index.html b/web/src/jsMain/resources/index.html new file mode 100644 index 0000000..520add9 --- /dev/null +++ b/web/src/jsMain/resources/index.html @@ -0,0 +1,83 @@ + + + + + Kotlin Publication Scripts Builder + + + + +
+ +
+
+
+ Project type +
+ +
+ Licenses +
+
+ +
+ +
+ + Project information + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ +
+
+ +
+
+ + Developers info +
+ +
+ + Repositories info +
+ +
+
+
+ + + + + \ No newline at end of file From 7aa30ef46c11b436a8b0d97448c636d58121a85f Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 2 Mar 2021 02:43:30 +0600 Subject: [PATCH 2/6] temporal state --- .github/workflows/commit-release.yml | 2 - mppAndroidProject.gradle | 2 +- mppJavaProject.gradle | 2 +- mppJsProject.gradle | 6 +- web/build.gradle | 11 ++++ .../dev/inmo/kmppscriptbuilder/web/main.kt | 15 +++++ .../kmppscriptbuilder/web/utils/UkActive.kt | 13 ++++ .../web/views/DevelopersView.kt | 35 +++++++++++ .../kmppscriptbuilder/web/views/ListView.kt | 62 +++++++++++++++++++ .../web/views/MavenProjectInfoView.kt | 44 +++++++++++++ .../web/views/ProjectTypeView.kt | 33 ++++++++++ .../inmo/kmppscriptbuilder/web/views/View.kt | 3 + .../web/views/ViewElements.kt | 30 +++++++++ web/src/jsMain/resources/index.html | 5 +- 14 files changed, 255 insertions(+), 8 deletions(-) create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/UkActive.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ProjectTypeView.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/View.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt diff --git a/.github/workflows/commit-release.yml b/.github/workflows/commit-release.yml index cc9cfad..96a1667 100644 --- a/.github/workflows/commit-release.yml +++ b/.github/workflows/commit-release.yml @@ -17,8 +17,6 @@ jobs: run: echo "version=` cat gradle.properties | grep ^version= | grep -o [\\.0-9]* `" >> $GITHUB_ENV - name: Build run: ./gradlew packageUberJarForCurrentOS - env: - additional_version: "" - name: Create Release id: create_release uses: actions/create-release@v1 diff --git a/mppAndroidProject.gradle b/mppAndroidProject.gradle index 20b6516..97ddb3c 100644 --- a/mppAndroidProject.gradle +++ b/mppAndroidProject.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" diff --git a/mppJavaProject.gradle b/mppJavaProject.gradle index 2f64097..e2d5a08 100644 --- a/mppJavaProject.gradle +++ b/mppJavaProject.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" diff --git a/mppJsProject.gradle b/mppJsProject.gradle index 9911a72..6ee908a 100644 --- a/mppJsProject.gradle +++ b/mppJsProject.gradle @@ -1,11 +1,13 @@ -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" kotlin { js (IR) { - browser() + browser { + binaries.executable() + } nodejs() } diff --git a/web/build.gradle b/web/build.gradle index 00115fe..7a3b6b1 100644 --- a/web/build.gradle +++ b/web/build.gradle @@ -4,3 +4,14 @@ plugins { } apply from: "$mppJsProjectPresetPath" + +kotlin { + sourceSets { + commonMain { + dependencies { + implementation project(":kmppscriptbuilder.core") + implementation "dev.inmo:micro_utils.common:$micro_utils_version" + } + } + } +} diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt new file mode 100644 index 0000000..7d6d374 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt @@ -0,0 +1,15 @@ +package dev.inmo.kmppscriptbuilder.web + +import dev.inmo.kmppscriptbuilder.web.views.MavenProjectInfoView +import dev.inmo.kmppscriptbuilder.web.views.ProjectTypeView +import kotlinx.browser.document + +fun main() { + document.addEventListener( + "DOMContentLoaded", + { + val projectTypeView = ProjectTypeView() + val mavenInfoTypeView = MavenProjectInfoView() + } + ) +} diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/UkActive.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/UkActive.kt new file mode 100644 index 0000000..5871e05 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/UkActive.kt @@ -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") + } + } diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt new file mode 100644 index 0000000..38ac510 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt @@ -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) : ListView(rootElement, "Add developer", "Remove developer") { + private val HTMLElement.usernameElement: HTMLInputElement + get() = children[0] as HTMLInputElement + private val HTMLElement.nameElement: HTMLInputElement + get() = children[1] as HTMLInputElement + private val HTMLElement.emailElement: HTMLInputElement + get() = children[2] as HTMLInputElement + + var developers: List + get() = elements.values.map { + Developer(it.usernameElement.value, it.nameElement.value, it.emailElement.value) + } + set(value) { + data = value + } + + override fun createPlainObject(): Developer = Developer("", "", "") + + override fun HTMLElement.placeElement(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 + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt new file mode 100644 index 0000000..f402162 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt @@ -0,0 +1,62 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import dev.inmo.micro_utils.common.calculateDiff +import kotlinx.browser.document +import kotlinx.dom.appendElement +import org.w3c.dom.HTMLElement + +abstract class ListView( + private val rootElement: HTMLElement, + addButtonText: String = "Add", + private val removeButtonText: String = "Remove" +) : View { + protected val elements = mutableMapOf() + protected var data: List = emptyList() + set(value) { + val old = field + field = value + val diff = old.calculateDiff(value) + diff.removed.forEach { + rootElement.removeChild(elements[it.value] ?: return@forEach) + } + diff.added.forEach { + val element = instantiateElement() + element.placeElement(it.value) + elements[it.value] = element + element.addRemoveButton(it.value) + } + diff.replaced.forEach { (old, new) -> + val element = elements[old.value] ?.also { it.updateElement(old.value, new.value) } + if (element == null) { + val newElement = instantiateElement() + newElement.placeElement(new.value) + elements[new.value] = newElement + } + } + } + + init { + rootElement.createButton(addButtonText).apply { + onclick = { + data += createPlainObject() + Unit + } + } + } + + protected abstract fun createPlainObject(): T + protected abstract fun HTMLElement.placeElement(value: T) + protected abstract fun HTMLElement.updateElement(from: T, to: T) + + private fun HTMLElement.addRemoveButton(value: T) { + createButton(removeButtonText).onclick = { + data = data.filter { + it != value + } + Unit + } + } + private fun instantiateElement() = rootElement.appendElement("div") { + classList.add("uk-padding-small") + } as HTMLElement +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt new file mode 100644 index 0000000..4964806 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt @@ -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) + + var mavenConfig: MavenConfig + get() = MavenConfig( + nameElement.value, + descriptionElement.value, + urlElement.value, + vcsUrlElement.value, + includeGpgElement.checked, + developersView.developers,// TODO:: Add developers + // TODO:: Add 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 + // TODO:: Add repositories + val reposWithoutSonatype = value.repositories.filter { it != SonatypeRepository } + includeMavenCentralElement.checked = value.repositories.size != reposWithoutSonatype.size + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ProjectTypeView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ProjectTypeView.kt new file mode 100644 index 0000000..accaaa7 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ProjectTypeView.kt @@ -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 + } + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/View.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/View.kt new file mode 100644 index 0000000..cf07625 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/View.kt @@ -0,0 +1,3 @@ +package dev.inmo.kmppscriptbuilder.web.views + +interface View diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt new file mode 100644 index 0000000..4398718 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt @@ -0,0 +1,30 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import kotlinx.dom.appendElement +import org.w3c.dom.* +import kotlin.random.Random + +fun HTMLElement.createTextField( + label: String, + placeholder: String +): HTMLInputElement { + val uuid = "r" + Random.nextLong() + return appendElement("div") { + classList.add("uk-margin", "uk-width-1-1") + appendElement("label") { + classList.add("uk-form-label") + setAttribute("for", uuid) + innerText = label + } + }.appendElement("input") { + id = uuid + classList.add("uk-input", "uk-width-expand") + setAttribute("type", "text") + setAttribute("placeholder", placeholder) + } as HTMLInputElement +} + +fun HTMLElement.createButton(text: String): HTMLButtonElement = appendElement("button") { + classList.add("uk-button", "uk-button-primary") + innerHTML = text +} as HTMLButtonElement diff --git a/web/src/jsMain/resources/index.html b/web/src/jsMain/resources/index.html index 520add9..7b94609 100644 --- a/web/src/jsMain/resources/index.html +++ b/web/src/jsMain/resources/index.html @@ -66,8 +66,7 @@ Developers info -
- +
Repositories info @@ -79,5 +78,7 @@ + + \ No newline at end of file From 0c8eef971a1d5f3443c7271c69453460aecdb2f9 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 2 Mar 2021 12:13:05 +0600 Subject: [PATCH 3/6] whole view complete, files handling left --- .../dev/inmo/kmppscriptbuilder/web/main.kt | 10 +- .../web/utils/keepScrolling.kt | 10 ++ .../web/views/BuilderView.kt | 23 ++++ .../web/views/DevelopersView.kt | 12 +- .../web/views/LicensesView.kt | 113 ++++++++++++++++++ .../kmppscriptbuilder/web/views/ListView.kt | 80 ++++++------- .../web/views/MavenProjectInfoView.kt | 8 +- .../web/views/MutableListView.kt | 41 +++++++ .../web/views/RepositoriesView.kt | 31 +++++ .../web/views/ViewElements.kt | 37 +++--- web/src/jsMain/resources/index.html | 41 +++---- 11 files changed, 311 insertions(+), 95 deletions(-) create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/keepScrolling.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/BuilderView.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/LicensesView.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MutableListView.kt create mode 100644 web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/RepositoriesView.kt diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt index 7d6d374..2f6822d 100644 --- a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt @@ -1,15 +1,17 @@ package dev.inmo.kmppscriptbuilder.web -import dev.inmo.kmppscriptbuilder.web.views.MavenProjectInfoView -import dev.inmo.kmppscriptbuilder.web.views.ProjectTypeView +import dev.inmo.kmppscriptbuilder.web.views.* import kotlinx.browser.document fun main() { document.addEventListener( "DOMContentLoaded", { - val projectTypeView = ProjectTypeView() - val mavenInfoTypeView = MavenProjectInfoView() + val builderView = BuilderView() + document.body ?.onclick = { + println(builderView.config) + Unit + } } ) } diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/keepScrolling.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/keepScrolling.kt new file mode 100644 index 0000000..00d7b0e --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/keepScrolling.kt @@ -0,0 +1,10 @@ +package dev.inmo.kmppscriptbuilder.web.utils + +import kotlinx.browser.document + +inline fun keepScrolling(crossinline block: () -> R): R = document.body ?.let { + val (x, y) = (it.scrollLeft to it.scrollTop) + return block().also { _ -> + it.scrollTo(x, y) + } +} ?: block() diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/BuilderView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/BuilderView.kt new file mode 100644 index 0000000..ee06ba5 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/BuilderView.kt @@ -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 + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt index 38ac510..2fdc7bd 100644 --- a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt @@ -3,16 +3,16 @@ package dev.inmo.kmppscriptbuilder.web.views import dev.inmo.kmppscriptbuilder.core.models.Developer import org.w3c.dom.* -class DevelopersView(rootElement: HTMLElement) : ListView(rootElement, "Add developer", "Remove developer") { +class DevelopersView(rootElement: HTMLElement) : MutableListView(rootElement, "Add developer", "Remove developer") { private val HTMLElement.usernameElement: HTMLInputElement - get() = children[0] as HTMLInputElement + get() = getElementsByTagName("input")[0] as HTMLInputElement private val HTMLElement.nameElement: HTMLInputElement - get() = children[1] as HTMLInputElement + get() = getElementsByTagName("input")[1] as HTMLInputElement private val HTMLElement.emailElement: HTMLInputElement - get() = children[2] as HTMLInputElement + get() = getElementsByTagName("input")[2] as HTMLInputElement var developers: List - get() = elements.values.map { + get() = elements.map { Developer(it.usernameElement.value, it.nameElement.value, it.emailElement.value) } set(value) { @@ -21,7 +21,7 @@ class DevelopersView(rootElement: HTMLElement) : ListView(rootElement override fun createPlainObject(): Developer = Developer("", "", "") - override fun HTMLElement.placeElement(value: 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 diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/LicensesView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/LicensesView.kt new file mode 100644 index 0000000..9588e26 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/LicensesView.kt @@ -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(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(rootElement, useSimpleDiffStrategy = true) { + private var licensesTemplates: List = emptyList() + + init { + scope.launch { + licensesTemplates = client.getLicenses().values.toList() + changeActor.send(Unit) // update list of searches + } + } + + private val changeActor: SendChannel = scope.run { + val onChangeActor = Channel(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 + 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 ?: "" + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt index f402162..700b325 100644 --- a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt @@ -1,61 +1,57 @@ package dev.inmo.kmppscriptbuilder.web.views -import dev.inmo.micro_utils.common.calculateDiff -import kotlinx.browser.document +import dev.inmo.micro_utils.common.calculateStrictDiff import kotlinx.dom.appendElement import org.w3c.dom.HTMLElement abstract class ListView( - private val rootElement: HTMLElement, - addButtonText: String = "Add", - private val removeButtonText: String = "Remove" + protected val rootElement: HTMLElement, + useSimpleDiffStrategy: Boolean = false ) : View { - protected val elements = mutableMapOf() + protected val elements = mutableListOf() + private val diffHandling: (old: List, new: List) -> 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 = emptyList() set(value) { val old = field field = value - val diff = old.calculateDiff(value) - diff.removed.forEach { - rootElement.removeChild(elements[it.value] ?: return@forEach) - } - diff.added.forEach { - val element = instantiateElement() - element.placeElement(it.value) - elements[it.value] = element - element.addRemoveButton(it.value) - } - diff.replaced.forEach { (old, new) -> - val element = elements[old.value] ?.also { it.updateElement(old.value, new.value) } - if (element == null) { - val newElement = instantiateElement() - newElement.placeElement(new.value) - elements[new.value] = newElement - } - } + diffHandling(old, value) } - init { - rootElement.createButton(addButtonText).apply { - onclick = { - data += createPlainObject() - Unit - } - } - } - - protected abstract fun createPlainObject(): T protected abstract fun HTMLElement.placeElement(value: T) protected abstract fun HTMLElement.updateElement(from: T, to: T) - private fun HTMLElement.addRemoveButton(value: T) { - createButton(removeButtonText).onclick = { - data = data.filter { - it != value - } - Unit - } - } private fun instantiateElement() = rootElement.appendElement("div") { classList.add("uk-padding-small") } as HTMLElement diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt index 4964806..b9cbddc 100644 --- a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt @@ -14,6 +14,7 @@ class MavenProjectInfoView : View { 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( @@ -22,9 +23,8 @@ class MavenProjectInfoView : View { urlElement.value, vcsUrlElement.value, includeGpgElement.checked, - developersView.developers,// TODO:: Add developers - // TODO:: Add repositories - if (includeMavenCentralElement.checked) { + developersView.developers, + repositoriesView.repositories + if (includeMavenCentralElement.checked) { listOf(SonatypeRepository) } else { emptyList() @@ -37,8 +37,8 @@ class MavenProjectInfoView : View { vcsUrlElement.value = value.vcsUrl includeGpgElement.checked = value.includeGpgSigning developersView.developers = value.developers - // TODO:: Add repositories val reposWithoutSonatype = value.repositories.filter { it != SonatypeRepository } includeMavenCentralElement.checked = value.repositories.size != reposWithoutSonatype.size + repositoriesView.repositories = value.repositories } } \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MutableListView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MutableListView.kt new file mode 100644 index 0000000..05d7ee9 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MutableListView.kt @@ -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( + rootElement: HTMLElement, + addButtonText: String = "Add", + private val removeButtonText: String = "Remove" +) : ListView(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 + } + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/RepositoriesView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/RepositoriesView.kt new file mode 100644 index 0000000..93234ca --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/RepositoriesView.kt @@ -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(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 + 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 + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt index 4398718..7f70fdc 100644 --- a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt @@ -2,29 +2,34 @@ package dev.inmo.kmppscriptbuilder.web.views import kotlinx.dom.appendElement import org.w3c.dom.* -import kotlin.random.Random fun HTMLElement.createTextField( label: String, placeholder: String ): HTMLInputElement { - val uuid = "r" + Random.nextLong() return appendElement("div") { classList.add("uk-margin", "uk-width-1-1") - appendElement("label") { - classList.add("uk-form-label") - setAttribute("for", uuid) - innerText = label - } - }.appendElement("input") { - id = uuid - classList.add("uk-input", "uk-width-expand") - setAttribute("type", "text") - setAttribute("placeholder", placeholder) - } as HTMLInputElement + }.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.createButton(text: String): HTMLButtonElement = appendElement("button") { +fun HTMLElement.createPrimaryButton(text: String): HTMLButtonElement = (appendElement("button") { classList.add("uk-button", "uk-button-primary") - innerHTML = text -} as HTMLButtonElement +} 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 +} diff --git a/web/src/jsMain/resources/index.html b/web/src/jsMain/resources/index.html index 7b94609..3f798e4 100644 --- a/web/src/jsMain/resources/index.html +++ b/web/src/jsMain/resources/index.html @@ -7,19 +7,17 @@ -
- -
+
Project type @@ -30,11 +28,11 @@
Licenses -
-
- -
- +
+ + + +
Project information @@ -66,13 +64,10 @@
Developers info -
-
+
Repositories info -
- -
+
From 881d268ea920cbcfac0d068a9685d61fefa2ab0c Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 2 Mar 2021 13:44:33 +0600 Subject: [PATCH 4/6] complete main part --- .../dev/inmo/kmppscriptbuilder/web/main.kt | 72 ++++++++++++++++++- web/src/jsMain/resources/index.html | 5 +- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt index 2f6822d..36e52f8 100644 --- a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt @@ -1,16 +1,82 @@ 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.body ?.onclick = { - println(builderView.config) - Unit + + (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 } } ) diff --git a/web/src/jsMain/resources/index.html b/web/src/jsMain/resources/index.html index 3f798e4..4f3a5ea 100644 --- a/web/src/jsMain/resources/index.html +++ b/web/src/jsMain/resources/index.html @@ -13,8 +13,9 @@
    -
  • -
  • +
  • +
  • +
From 2bbfe99ff4f7e8687ab6dd82073451bb147f1aa7 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 2 Mar 2021 13:53:12 +0600 Subject: [PATCH 5/6] add web publish step --- .github/workflows/commit-release.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/commit-release.yml b/.github/workflows/commit-release.yml index 96a1667..5f36de2 100644 --- a/.github/workflows/commit-release.yml +++ b/.github/workflows/commit-release.yml @@ -16,7 +16,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 + 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 From 4ec7d3847fcaf2ef231afcd8ca0a82c084b4e6cb Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 2 Mar 2021 14:02:57 +0600 Subject: [PATCH 6/6] update workflows --- .github/workflows/build.yml | 17 +++++++++++++++++ .github/workflows/commit-release.yml | 5 ++++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..6f2a4a6 --- /dev/null +++ b/.github/workflows/build.yml @@ -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 diff --git a/.github/workflows/commit-release.yml b/.github/workflows/commit-release.yml index 5f36de2..98ce813 100644 --- a/.github/workflows/commit-release.yml +++ b/.github/workflows/commit-release.yml @@ -1,4 +1,7 @@ -on: [push] +on: + push: + branches: + - master name: Commit release