diff --git a/.idea/artifacts/kemence_js_1_0.xml b/.idea/artifacts/kemence_js_1_0.xml index 1fa591a46e0662352205c15d3d1df1bbee3eaaa3..5cfa20872d3eb89461e4fedb0647751d71073de4 100644 --- a/.idea/artifacts/kemence_js_1_0.xml +++ b/.idea/artifacts/kemence_js_1_0.xml @@ -1,8 +1,6 @@ <component name="ArtifactManager"> <artifact type="jar" name="kemence-js-1.0"> <output-path>$PROJECT_DIR$/build/libs</output-path> - <root id="archive" name="kemence-js-1.0.jar"> - <element id="module-output" name="kemence.jsMain" /> - </root> + <root id="archive" name="kemence-js-1.0.jar" /> </artifact> </component> \ No newline at end of file diff --git a/src/jsMain/kotlin/datasources/CSVTable.kt b/src/jsMain/kotlin/datasources/CSVTable.kt index 39dc918852752856cdbc22155483c12488028060..985b6e15952b408f7adaca9f361d86cc7f7b37d2 100644 --- a/src/jsMain/kotlin/datasources/CSVTable.kt +++ b/src/jsMain/kotlin/datasources/CSVTable.kt @@ -3,7 +3,7 @@ package datasources import com.github.doyaaaaaken.kotlincsv.dsl.csvReader import pekstuff.trimAsPrinciple -class CSVTable(data: String) { +class CSVTable(data: String): DataSource { private val rows = csvReader().readAll(data) companion object { private val filterList = listOf( @@ -20,7 +20,7 @@ class CSVTable(data: String) { } .toMap() - val principles get() = principleIndexes.keys + override val principles get() = principleIndexes.keys private val peopleIndexes = rows .mapIndexed { i, p -> p[0] to i } @@ -28,16 +28,9 @@ class CSVTable(data: String) { .filter { it.first.isNotBlank() } .toMap() - val people: List<String> - get() { - val ret = mutableListOf<String>() - rows.drop(1) - .filter { it[0].isNotEmpty() } - .forEach { ret.add(it[0]) } - return ret - } + override val people get() = peopleIndexes.keys - operator fun get(person: String, principle: String): Int { + override operator fun get(person: String, principle: String): Int { val pers = peopleIndexes[person]!! val princ = principleIndexes[principle]!! return rows[pers][princ].toIntOrNull() ?: 0 diff --git a/src/jsMain/kotlin/datasources/DataSource.kt b/src/jsMain/kotlin/datasources/DataSource.kt new file mode 100644 index 0000000000000000000000000000000000000000..b5ebb9ee9cf0d354abf453864e9b110617d1a9dc --- /dev/null +++ b/src/jsMain/kotlin/datasources/DataSource.kt @@ -0,0 +1,13 @@ +package datasources + +interface DataSource { + val principles: Set<String> + val people: Set<String> + operator fun get(person: String, principle: String): Int +} + +interface NoteDataSource { + val principles: Set<String> + val people: Set<String> + fun getNote(person: String, principle: String): String +} \ No newline at end of file diff --git a/src/jsMain/kotlin/datasources/GSheet.kt b/src/jsMain/kotlin/datasources/GSheet.kt index cec5899f78a7b7a1a667cd636b857d8eb666b16f..2b7eb89ee6658d4b38e3231dd2c63e09e74c4735 100644 --- a/src/jsMain/kotlin/datasources/GSheet.kt +++ b/src/jsMain/kotlin/datasources/GSheet.kt @@ -1,48 +1,70 @@ package datasources +import androidx.compose.runtime.NoLiveLiterals import gapi.gapi import gapi.isSignedIn import gapi.sheets +import kotlinx.browser.window +import pekstuff.trimAsPrinciple import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine -class GSheet private constructor() { +class GSheet private constructor(private val sheet: sheets.Spreadsheet): DataSource, NoteDataSource { companion object { + private val filterList = listOf( + "szumma", "színes belépő" + ) + suspend fun new(url: String): GSheet { if (!isSignedIn()) throw Error("You must sign in to get gapi.sheets") - - val sheet = GSheet() - sheet.setUrl(url) - return sheet + val sheet = getSheetFromUrl(url) + window.asDynamic().test = sheet + return GSheet(sheet) } - } - private var _url = "" - suspend fun setUrl(value: String){ - _url = value - loadSheet() - } - - val url: String get() = _url - - private suspend fun getSheetFromUrl() = suspendCoroutine<sheets.Spreadsheet> { cont -> - gapi.client.sheets.spreadsheets.get(object: sheets.SpreadsheetGetType { - override var spreadsheetId = url + @NoLiveLiterals + private suspend fun getSheetFromUrl(url: String) = suspendCoroutine<sheets.Spreadsheet> { cont -> + val obj = js("{}") + obj["spreadsheetId"] = url .removePrefix("https://docs.google.com/spreadsheets/d/") .split("/")[0] - }).execute { - if (it.status != 200) { - cont.resumeWithException(Error("unable to load sheet: ${it.statusText}")) - return@execute Unit + obj["includeGridData"] = true + + gapi.client.sheets.spreadsheets.get(obj).execute { + cont.resume(it.result) } - cont.resume(it.result) } } - private suspend fun loadSheet() { - sheet = getSheetFromUrl() + private val rows = sheet.sheets!![0].data!![0].rowData!! + + private val principleIndexes = rows[0].values!!.mapIndexed { i, data -> + (data.formattedValue?.trimAsPrinciple() ?: "") to i + }.drop(1).filter { + filterList.all { filter -> !it.first.lowercase().contains(filter) } && + it.first.isNotBlank() + }.toMap() + + override val principles get() = principleIndexes.keys + + private val peopleIndexes = rows + .mapIndexed { i, data -> (data.values!![0].formattedValue ?: "") to i } + .drop(1) + .filter { it.first.isNotBlank() } + .toMap() + + override val people get() = peopleIndexes.keys + + override operator fun get(person: String, principle: String): Int { + val pers = peopleIndexes[person]!! + val princ = principleIndexes[principle]!! + return rows[pers].values!![princ].formattedValue!!.toIntOrNull() ?: 0 } - private lateinit var sheet: sheets.Spreadsheet + override fun getNote(person: String, principle: String): String { + val pers = peopleIndexes[person]!! + val princ = principleIndexes[principle]!! + return rows[pers].values!![princ].note ?: "" + } } diff --git a/src/jsMain/kotlin/pekstuff/PekNote.kt b/src/jsMain/kotlin/pekstuff/PekNote.kt new file mode 100644 index 0000000000000000000000000000000000000000..11077af44491a0524980eb8df80ba609b5587451 --- /dev/null +++ b/src/jsMain/kotlin/pekstuff/PekNote.kt @@ -0,0 +1,28 @@ +package pekstuff + +import kotlinx.browser.document +import kotlinx.coroutines.delay +import org.w3c.dom.HTMLInputElement +import org.w3c.dom.HTMLTextAreaElement + +object PekNote { + val noteNameCnt get() = document.querySelector("#comment-container > div.uk-padding.uk-text-center") + val noteName get() = noteNameCnt?.textContent + + val noteCnt get() = document.getElementById("comment-textarea") as? HTMLTextAreaElement + val btn get() = document.querySelector("#new_point_detail_comment > article > div.uk-clearfix > div.uk-float-right > input.uk-button") as? HTMLInputElement + var note + get() = noteCnt!!.value + set(value) { + noteCnt!!.value = value + btn!!.click() + } + + suspend fun waitUntilLoaded(person: String, principle: String) { + val expected = "$person - $principle" + while (noteName != expected) { + println("$noteName != $expected") + delay(100) + } + } +} \ No newline at end of file diff --git a/src/jsMain/kotlin/pekstuff/PekTable.kt b/src/jsMain/kotlin/pekstuff/PekTable.kt index 2da963e33372113179f2f44c4538350d40e759a4..c4511dac503ddfd88a2b54da79b0c2d6a9afb1a4 100644 --- a/src/jsMain/kotlin/pekstuff/PekTable.kt +++ b/src/jsMain/kotlin/pekstuff/PekTable.kt @@ -1,6 +1,7 @@ package pekstuff import kotlinx.browser.document +import kotlinx.browser.window import kotlinx.coroutines.* import org.w3c.dom.Element import org.w3c.dom.HTMLInputElement @@ -59,13 +60,14 @@ object PekTable { elem.style.background = origBg } + elem.click() + if (elem.value.toIntOrNull() == value) { // don't update if up-to-date // sort of ugly workaround, meh. PekDelay.skipNext() return } - elem.click() elem.value = value.toString() elem.trigger() tableElem.click() diff --git a/src/jsMain/kotlin/processing/ProcessCSV.kt b/src/jsMain/kotlin/processing/Process.kt similarity index 82% rename from src/jsMain/kotlin/processing/ProcessCSV.kt rename to src/jsMain/kotlin/processing/Process.kt index 01c9a9d6e85468db4043ba01d4a5a58428955cb0..616f34418d79696ff22915acfe8cd7229ee94b8c 100644 --- a/src/jsMain/kotlin/processing/ProcessCSV.kt +++ b/src/jsMain/kotlin/processing/Process.kt @@ -1,7 +1,10 @@ package processing -import datasources.CSVTable +import datasources.DataSource +import datasources.NoteDataSource +import kotlinx.coroutines.delay import pekstuff.PekDelay +import pekstuff.PekNote import pekstuff.PekTable import kotlin.math.max @@ -12,9 +15,11 @@ class ProcessingError(private val errors: List<String>): Exception(errors.toStri } } -suspend fun CSVTable.process( +suspend fun DataSource.process( progress: (Double) -> Unit = {} ) { + // todo show comment stuff + progress(0.0) val principleMappings = principles.associateWith { PekTable.principles.findClosestMatch(it) @@ -22,7 +27,7 @@ suspend fun CSVTable.process( val errors = mutableListOf<String>() - people.forEachIndexed { i, person -> + people.sorted().forEachIndexed { i, person -> val pekPerson = PekTable.people.findClosestMatch(person) if (pekPerson == null) { @@ -35,6 +40,11 @@ suspend fun CSVTable.process( PekTable[pekPerson, pekPrinciple] = point PekDelay() + if (this is NoteDataSource) { + PekNote.waitUntilLoaded(pekPerson, pekPrinciple) + PekNote.note = getNote(person, principle) + } + progress(calcProgress(i, j, people.size, principles.size)) if (person != pekPerson) { diff --git a/src/jsMain/kotlin/processing/ProcessGSheet.kt b/src/jsMain/kotlin/processing/ProcessGSheet.kt deleted file mode 100644 index 1f5e19f81f3067b436f16a0943ff906288d622db..0000000000000000000000000000000000000000 --- a/src/jsMain/kotlin/processing/ProcessGSheet.kt +++ /dev/null @@ -1 +0,0 @@ -package processing \ No newline at end of file diff --git a/src/jsMain/kotlin/ui/SheetsModal.kt b/src/jsMain/kotlin/ui/SheetsModal.kt index fe9f4c16403ee991112c07b7b649b7c6a5fbeaf5..684e49fe671eacdbb76b6cb9493a4eaaeb99054f 100644 --- a/src/jsMain/kotlin/ui/SheetsModal.kt +++ b/src/jsMain/kotlin/ui/SheetsModal.kt @@ -9,6 +9,7 @@ import org.jetbrains.compose.web.attributes.InputType import org.jetbrains.compose.web.attributes.disabled import org.jetbrains.compose.web.dom.* import org.w3c.dom.HTMLElement +import processing.process private object SheetsModal: ModalType { override val title = "Google Sheets import" @@ -18,7 +19,7 @@ private object SheetsModal: ModalType { closeId: String, setState: (State) -> Unit, hint: String, - setHint: (String) -> Unit + setHint: (String) -> Unit, ) { val scope = rememberCoroutineScope() @@ -33,12 +34,15 @@ private object SheetsModal: ModalType { } } + var sheetUrl by remember { mutableStateOf("") } var sheet by remember { mutableStateOf<GSheet?>(null) } setHint( - if (!signedIn) "Jelentkezz be" - else if (sheet == null) "Adj meg egy Google Sheet URL-t" - else "" + when { + !signedIn -> "Jelentkezz be" + sheetUrl.isBlank() || !sheetUrl.contains("https://docs.google.com/spreadsheets") -> "Adj meg egy Google Sheet URL-t" + else -> "" + } ) withLabel( @@ -72,12 +76,11 @@ private object SheetsModal: ModalType { Br {} - var sheetUrl by remember { mutableStateOf("") } withLabel("Google Sheet URL") { id -> Input(type = InputType.Text, attrs = { id(id) classes("uk-input") - onChange { sheetUrl = it.value } + onInput { sheetUrl = it.value } value(sheetUrl) }) } @@ -87,7 +90,9 @@ private object SheetsModal: ModalType { classes("uk-button", "uk-button-primary") onClick { scope.launch { - println("zsa") + sheet = GSheet.new(sheetUrl) + sheet?.process { setState(ImportInProgress(it)) } + setState(Ready) } (document.getElementById(closeId) as HTMLElement).click() }