Wire up svelte frontend with ktor backend
This commit is contained in:
parent
0c02cdbf3f
commit
9b0178f3cb
8 changed files with 46 additions and 95 deletions
|
@ -4,16 +4,15 @@
|
|||
import { onMount } from "svelte";
|
||||
import Table, { Pagination, Row, Search, Sort } from "./Table.svelte";
|
||||
import { getData } from "./server.js";
|
||||
import { sortNumber, sortString } from "./sorting.js";
|
||||
|
||||
let rows = [];
|
||||
let page = 0; //first page
|
||||
let pageIndex = 0; //first row
|
||||
let pageSize = 3; //optional, 10 by default
|
||||
let pageSize = 10; //optional, 10 by default
|
||||
|
||||
let loading = true;
|
||||
let rowsCount = 0;
|
||||
let text;
|
||||
let text = "";
|
||||
let sorting;
|
||||
|
||||
onMount(async () => {
|
||||
|
@ -57,24 +56,24 @@
|
|||
<tr>
|
||||
<th>
|
||||
Name
|
||||
<Sort key="name" on:sort={onSort} />
|
||||
<Sort key="schoolName" on:sort={onSort} />
|
||||
</th>
|
||||
<th>
|
||||
Lastname
|
||||
<Sort key="lastName" on:sort={onSort} />
|
||||
Short
|
||||
<Sort key="schoolShort" on:sort={onSort} />
|
||||
</th>
|
||||
<th>
|
||||
Age
|
||||
<Sort key="age" on:sort={onSort} />
|
||||
Address
|
||||
<Sort key="schoolAddress" on:sort={onSort} />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each rows2 as row, index (row)}
|
||||
<Row {index} on:click={() => onCellClick(row)}>
|
||||
<td data-label="Name">{row.name}</td>
|
||||
<td data-label="Lastname">{row.lastName}</td>
|
||||
<td data-label="Age">{row.age}</td>
|
||||
<td data-label="Name">{row.schoolName}</td>
|
||||
<td data-label="Short">{row.schoolShort}</td>
|
||||
<td data-label="Address">{row.schoolAddress}</td>
|
||||
</Row>
|
||||
{/each}
|
||||
</tbody>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
export let pageIndex = 0;
|
||||
export let pageSize = 10;
|
||||
export let responsive = true;
|
||||
export let rows;
|
||||
export let rows = [];
|
||||
export let serverSide = false;
|
||||
export let labels = {
|
||||
empty: "No records available",
|
||||
|
@ -38,7 +38,7 @@
|
|||
let buttons = [-2, -1, 0, 1, 2];
|
||||
let pageCount = 0;
|
||||
|
||||
$: filteredRows = rows;
|
||||
$: filteredRows = rows || [];
|
||||
$: visibleRows = filteredRows.slice(pageIndex, pageIndex + pageSize);
|
||||
|
||||
setContext("state", {
|
||||
|
|
|
@ -1,64 +1,5 @@
|
|||
import { sortNumber, sortString } from "./sorting.js";
|
||||
|
||||
function generateData() {
|
||||
const rand = Math.floor(Math.random() * 1000);
|
||||
return [
|
||||
{ name: "a-" + rand.toString(), lastName: "o", age: 12 },
|
||||
{ name: "b", lastName: "n", age: 1 },
|
||||
{ name: "c", lastName: "m", age: 13 },
|
||||
{ name: "d", lastName: "l", age: 21 },
|
||||
{ name: "e", lastName: "k", age: 2 },
|
||||
{ name: "f", lastName: "j", age: 4 }
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
export function getAll(text) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(function() {
|
||||
resolve(generateData());
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
export function getData(page, pageSize, text, sorting) {
|
||||
let originalData = generateData();
|
||||
|
||||
if (sorting) {
|
||||
if (sorting.key === "age") {
|
||||
originalData = sortNumber(originalData, sorting.dir, sorting.key);
|
||||
} else {
|
||||
originalData = sortString(originalData, sorting.dir, sorting.key);
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(function() {
|
||||
let rowsCount = originalData.length;
|
||||
const originalRows = originalData;
|
||||
let rows = [];
|
||||
|
||||
if (text && text.length > 0) {
|
||||
for (let i in originalRows) {
|
||||
for (let j in originalRows[i]) {
|
||||
if (
|
||||
originalRows[i][j]
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.indexOf(text) > -1
|
||||
) {
|
||||
rows.push(originalRows[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rowsCount = rows.length;
|
||||
} else {
|
||||
rows = originalRows;
|
||||
}
|
||||
|
||||
resolve({ rows: rows.slice(0, pageSize), rowsCount: rowsCount - 1 });
|
||||
}, 500);
|
||||
});
|
||||
let options = sorting || { dir: null, key: null };
|
||||
return fetch(`/log/list?page=${page}&pageSize=${pageSize}&text=${text}&sortBy=${options.key}&order=${options.dir}`)
|
||||
.then((res) => res.json());
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
export function sortString(rows, dir, key) {
|
||||
return rows.sort((a, b) =>
|
||||
dir === "asc"
|
||||
? ("" + a[key]).localeCompare(b[key])
|
||||
: ("" + b[key]).localeCompare(a[key])
|
||||
);
|
||||
}
|
||||
|
||||
export function sortNumber(rows, dir, key) {
|
||||
return rows.sort((a, b) =>
|
||||
dir === "asc" ? a[key] - b[key] : b[key] - a[key]
|
||||
);
|
||||
}
|
|
@ -39,6 +39,7 @@ dependencies {
|
|||
implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktor_version")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktor_version")
|
||||
implementation("io.ktor:ktor-server-netty-jvm:$ktor_version")
|
||||
implementation("io.ktor:ktor-server-cors:$ktor_version")
|
||||
implementation("ch.qos.logback:logback-classic:$logback_version")
|
||||
implementation("io.ktor:ktor-server-auth:$ktor_version")
|
||||
implementation("com.google.apis:google-api-services-playintegrity:v1-rev20230910-2.0.0")
|
||||
|
|
|
@ -5,10 +5,7 @@ import io.github.wulkanowy.schools.model.LoginEvent
|
|||
import io.github.wulkanowy.schools.model.LoginEvents
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
import org.jetbrains.exposed.sql.insert
|
||||
import org.jetbrains.exposed.sql.insertIgnore
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import java.time.Instant
|
||||
|
||||
|
@ -25,8 +22,15 @@ class LoginEventDao {
|
|||
uuid = row[LoginEvents.uuid],
|
||||
)
|
||||
|
||||
suspend fun allLoginEvents(): List<LoginEvent> = dbQuery {
|
||||
LoginEvents.selectAll().map(::resultRowToLoginEvent)
|
||||
suspend fun allLoginEvents(page: Long, pageSize: Int): List<LoginEvent> = dbQuery {
|
||||
LoginEvents
|
||||
.selectAll()
|
||||
.limit(pageSize, page * pageSize)
|
||||
.map(::resultRowToLoginEvent)
|
||||
}
|
||||
|
||||
suspend fun getLoginEventsCount(): Long = dbQuery {
|
||||
LoginEvents.selectAll().count()
|
||||
}
|
||||
|
||||
suspend fun addLoginEvent(event: LoginEvent) = withContext(Dispatchers.IO) {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package io.github.wulkanowy.schools.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ListResponse(
|
||||
val rows: List<LoginEvent>,
|
||||
val rowsCount: Long,
|
||||
)
|
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.schools.plugins
|
|||
|
||||
import io.github.wulkanowy.schools.dao.LoginEventDao
|
||||
import io.github.wulkanowy.schools.integrity.*
|
||||
import io.github.wulkanowy.schools.model.ListResponse
|
||||
import io.github.wulkanowy.schools.model.LoginEvent
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
|
@ -38,7 +39,16 @@ fun Application.configureRouting() {
|
|||
}
|
||||
}
|
||||
get("/log/list") {
|
||||
call.respond(loginEventDao.allLoginEvents())
|
||||
val params = call.request.queryParameters
|
||||
call.respond(
|
||||
ListResponse(
|
||||
rows = loginEventDao.allLoginEvents(
|
||||
page = params["page"]?.toLongOrNull() ?: 0,
|
||||
pageSize = params["pageSize"]?.toIntOrNull() ?: 10,
|
||||
),
|
||||
rowsCount = loginEventDao.getLoginEventsCount(),
|
||||
)
|
||||
)
|
||||
}
|
||||
singlePageApplication {
|
||||
useResources = true
|
||||
|
|
Loading…
Reference in a new issue