Update ui
This commit is contained in:
parent
9c7e42ae29
commit
4d21d06781
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
@ -14,7 +15,6 @@
|
|||||||
<option value="$PROJECT_DIR$/apps/ui" />
|
<option value="$PROJECT_DIR$/apps/ui" />
|
||||||
<option value="$PROJECT_DIR$/shared" />
|
<option value="$PROJECT_DIR$/shared" />
|
||||||
<option value="$PROJECT_DIR$/shared/common" />
|
<option value="$PROJECT_DIR$/shared/common" />
|
||||||
<option value="$PROJECT_DIR$/shared/contract" />
|
|
||||||
<option value="$PROJECT_DIR$/shared/eventi" />
|
<option value="$PROJECT_DIR$/shared/eventi" />
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="azul-17" project-jdk-type="JavaSDK" />
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="azul-17" project-jdk-type="JavaSDK" />
|
||||||
</project>
|
</project>
|
||||||
1078
.idea/workspace.xml
generated
1078
.idea/workspace.xml
generated
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,7 @@ import no.iktdev.exfl.coroutines.CoroutinesIO
|
|||||||
import no.iktdev.exfl.observable.Observables
|
import no.iktdev.exfl.observable.Observables
|
||||||
import no.iktdev.mediaprocessing.shared.common.*
|
import no.iktdev.mediaprocessing.shared.common.*
|
||||||
import no.iktdev.eventi.database.MySqlDataSource
|
import no.iktdev.eventi.database.MySqlDataSource
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.database.cal.EventsManager
|
||||||
import no.iktdev.mediaprocessing.shared.common.database.cal.RunnerManager
|
import no.iktdev.mediaprocessing.shared.common.database.cal.RunnerManager
|
||||||
import no.iktdev.mediaprocessing.shared.common.database.cal.TasksManager
|
import no.iktdev.mediaprocessing.shared.common.database.cal.TasksManager
|
||||||
import no.iktdev.streamit.library.db.tables.*
|
import no.iktdev.streamit.library.db.tables.*
|
||||||
|
|||||||
@ -1,178 +0,0 @@
|
|||||||
package no.iktdev.mediaprocessing.coordinator
|
|
||||||
|
|
||||||
import no.iktdev.eventi.core.PersistentMessageHelper
|
|
||||||
import no.iktdev.eventi.data.eventId
|
|
||||||
import no.iktdev.eventi.data.referenceId
|
|
||||||
import no.iktdev.eventi.data.toJson
|
|
||||||
import no.iktdev.eventi.database.DataSource
|
|
||||||
import no.iktdev.eventi.database.isCausedByDuplicateError
|
|
||||||
import no.iktdev.eventi.database.isExposedSqlException
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.database.tables.allEvents
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.database.tables.events
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.EventsManagerContract
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.data.Event
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.fromJsonWithDeserializer
|
|
||||||
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
|
||||||
import org.jetbrains.exposed.sql.*
|
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
|
||||||
|
|
||||||
class EventsManager(dataSource: DataSource) : EventsManagerContract(dataSource) {
|
|
||||||
|
|
||||||
override fun storeEvent(event: Event): Boolean {
|
|
||||||
|
|
||||||
no.iktdev.eventi.database.withTransaction(dataSource.database) {
|
|
||||||
allEvents.insert {
|
|
||||||
it[referenceId] = event.referenceId()
|
|
||||||
it[eventId] = event.eventId()
|
|
||||||
it[events.event] = event.eventType.event
|
|
||||||
it[data] = event.toJson()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val existing = getEventsWith(event.referenceId())
|
|
||||||
|
|
||||||
val derivedId = event.metadata.derivedFromEventId
|
|
||||||
if (derivedId != null) {
|
|
||||||
val isNewEventOrphan = existing.none { it.eventId() == derivedId }
|
|
||||||
if (isNewEventOrphan) {
|
|
||||||
log.warn { "Message not saved! ${event.referenceId()} with eventId(${event.eventId()}) for event ${event.eventType} has derivedEventId($derivedId) which does not exist!" }
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val exception = no.iktdev.eventi.database.executeOrException(dataSource.database) {
|
|
||||||
events.insert {
|
|
||||||
it[referenceId] = event.referenceId()
|
|
||||||
it[eventId] = event.eventId()
|
|
||||||
it[events.event] = event.eventType.event
|
|
||||||
it[data] = event.toJson()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val success = if (exception != null) {
|
|
||||||
if (exception.isExposedSqlException()) {
|
|
||||||
if ((exception as ExposedSQLException).isCausedByDuplicateError()) {
|
|
||||||
log.debug { "Error is of SQLIntegrityConstraintViolationException" }
|
|
||||||
log.error { exception.message }
|
|
||||||
exception.printStackTrace()
|
|
||||||
} else {
|
|
||||||
log.debug { "Error code is: ${exception.errorCode}" }
|
|
||||||
log.error { exception.message }
|
|
||||||
exception.printStackTrace()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.error { exception.message }
|
|
||||||
exception.printStackTrace()
|
|
||||||
}
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
if (success) {
|
|
||||||
//deleteSupersededEvents(referenceId = event.referenceId(), eventId = event.eventId(), event = event.eventType, derivedFromId = event.derivedFromEventId())
|
|
||||||
}
|
|
||||||
return success
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private val exemptedFromSingleEvent = listOf(
|
|
||||||
Events.EventWorkConvertCreated,
|
|
||||||
Events.EventWorkExtractCreated,
|
|
||||||
Events.EventWorkConvertPerformed,
|
|
||||||
Events.EventWorkExtractPerformed
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun isExempted(event: Events): Boolean {
|
|
||||||
return event in exemptedFromSingleEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun readAvailableEvents(): List<List<Event>> {
|
|
||||||
return no.iktdev.eventi.database.withTransaction(dataSource.database) {
|
|
||||||
events.selectAll()
|
|
||||||
.groupBy { it[events.referenceId] }
|
|
||||||
.mapNotNull { it.value.mapNotNull { v -> v.toEvent() } }.filter { it.none { e -> e.eventType == Events.EventMediaProcessCompleted } }
|
|
||||||
} ?: emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun readAvailableEventsFor(referenceId: String): List<Event> {
|
|
||||||
val events = no.iktdev.eventi.database.withTransaction(dataSource.database) {
|
|
||||||
events.select { events.referenceId eq referenceId }
|
|
||||||
.mapNotNull { it.toEvent() }
|
|
||||||
} ?: emptyList()
|
|
||||||
return if (events.any { it.eventType == Events.EventMediaProcessCompleted }) emptyList() else events
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getAllEvents(): List<List<Event>> {
|
|
||||||
val events = no.iktdev.eventi.database.withTransaction(dataSource.database) {
|
|
||||||
events.selectAll()
|
|
||||||
.groupBy { it[events.referenceId] }
|
|
||||||
.mapNotNull { it.value.mapNotNull { v -> v.toEvent() } }
|
|
||||||
} ?: emptyList()
|
|
||||||
return events.filter { it.none { it.eventType == Events.EventMediaProcessCompleted } }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun getEventsWith(referenceId: String): List<Event> {
|
|
||||||
return no.iktdev.eventi.database.withTransaction(dataSource.database) {
|
|
||||||
events.select {
|
|
||||||
(events.referenceId eq referenceId)
|
|
||||||
}
|
|
||||||
.orderBy(events.created, SortOrder.ASC)
|
|
||||||
.mapNotNull { it.toEvent() }
|
|
||||||
} ?: emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param referenceId Reference
|
|
||||||
* @param eventId Current eventId for the message, required to prevent deletion of itself
|
|
||||||
* @param event Current event for the message
|
|
||||||
*/
|
|
||||||
private fun deleteSupersededEvents(referenceId: String, eventId: String, event: Events, derivedFromId: String?) {
|
|
||||||
val forRemoval = mutableListOf<Event>()
|
|
||||||
|
|
||||||
val present = getEventsWith(referenceId).filter { it.metadata.derivedFromEventId != null }
|
|
||||||
val helper = PersistentMessageHelper<Event>(present)
|
|
||||||
|
|
||||||
val replaced = if (!isExempted(event)) present.find { it.eventId() != eventId && it.eventType == event } else null
|
|
||||||
val orphaned = replaced?.let { helper.getEventsRelatedTo(it.eventId()) }?.toMutableSet() ?: mutableSetOf()
|
|
||||||
//orphaned.addAll(helper.findOrphanedEvents())
|
|
||||||
|
|
||||||
forRemoval.addAll(orphaned)
|
|
||||||
|
|
||||||
deleteSupersededEvents(forRemoval)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the events
|
|
||||||
*/
|
|
||||||
private fun deleteSupersededEvents(superseded: List<Event>) {
|
|
||||||
no.iktdev.eventi.database.withTransaction(dataSource) {
|
|
||||||
superseded.forEach { duplicate ->
|
|
||||||
events.deleteWhere {
|
|
||||||
(referenceId eq duplicate.referenceId()) and
|
|
||||||
(eventId eq duplicate.eventId()) and
|
|
||||||
(event eq duplicate.eventType.event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun ResultRow.toEvent(): Event? {
|
|
||||||
val kev = try {
|
|
||||||
Events.toEvent(this[events.event])
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
return null
|
|
||||||
}?: return null
|
|
||||||
return this[events.data].fromJsonWithDeserializer(kev)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -44,9 +44,8 @@ dependencies {
|
|||||||
implementation ("mysql:mysql-connector-java:8.0.29")
|
implementation ("mysql:mysql-connector-java:8.0.29")
|
||||||
|
|
||||||
implementation("no.iktdev:exfl:0.0.16-SNAPSHOT")
|
implementation("no.iktdev:exfl:0.0.16-SNAPSHOT")
|
||||||
implementation(project(mapOf("path" to ":shared")))
|
implementation(project(mapOf("path" to ":shared:eventi")))
|
||||||
implementation(project(mapOf("path" to ":shared:common")))
|
implementation(project(mapOf("path" to ":shared:common")))
|
||||||
implementation(project(mapOf("path" to ":shared:contract")))
|
|
||||||
|
|
||||||
|
|
||||||
testImplementation(platform("org.junit:junit-bom:5.9.1"))
|
testImplementation(platform("org.junit:junit-bom:5.9.1"))
|
||||||
|
|||||||
@ -2,9 +2,6 @@ package no.iktdev.mediaprocessing.ui
|
|||||||
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.Defaults
|
import no.iktdev.mediaprocessing.shared.common.Defaults
|
||||||
import no.iktdev.mediaprocessing.shared.common.socket.SocketImplementation
|
import no.iktdev.mediaprocessing.shared.common.socket.SocketImplementation
|
||||||
import no.iktdev.mediaprocessing.shared.kafka.core.CoordinatorProducer
|
|
||||||
import no.iktdev.mediaprocessing.shared.kafka.core.DefaultMessageListener
|
|
||||||
import no.iktdev.mediaprocessing.shared.kafka.core.KafkaImplementation
|
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
|
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
|
||||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer
|
import org.springframework.boot.web.server.WebServerFactoryCustomizer
|
||||||
@ -67,8 +64,3 @@ class SocketImplemented: SocketImplementation() {
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
class DefaultConfiguration: Defaults()
|
class DefaultConfiguration: Defaults()
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@Import(CoordinatorProducer::class, DefaultMessageListener::class)
|
|
||||||
class KafkaLocalInit: KafkaImplementation() {
|
|
||||||
}
|
|
||||||
@ -2,40 +2,45 @@ package no.iktdev.mediaprocessing.ui
|
|||||||
|
|
||||||
|
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
|
import no.iktdev.eventi.database.MySqlDataSource
|
||||||
import no.iktdev.exfl.coroutines.CoroutinesDefault
|
import no.iktdev.exfl.coroutines.CoroutinesDefault
|
||||||
import no.iktdev.exfl.coroutines.CoroutinesIO
|
import no.iktdev.exfl.coroutines.CoroutinesIO
|
||||||
import no.iktdev.exfl.observable.ObservableMap
|
import no.iktdev.exfl.observable.ObservableMap
|
||||||
import no.iktdev.exfl.observable.Observables
|
import no.iktdev.exfl.observable.Observables
|
||||||
import no.iktdev.exfl.observable.observableMapOf
|
import no.iktdev.exfl.observable.observableMapOf
|
||||||
import no.iktdev.mediaprocessing.shared.common.DatabaseEnvConfig
|
import no.iktdev.mediaprocessing.shared.common.DatabaseEnvConfig
|
||||||
import no.iktdev.mediaprocessing.shared.common.datasource.MySqlDataSource
|
import no.iktdev.mediaprocessing.shared.common.database.EventsDatabase
|
||||||
import no.iktdev.mediaprocessing.shared.common.persistance.PersistentDataStore
|
import no.iktdev.mediaprocessing.shared.common.database.cal.EventsManager
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.database.cal.TasksManager
|
||||||
import no.iktdev.mediaprocessing.shared.common.toEventsDatabase
|
import no.iktdev.mediaprocessing.shared.common.toEventsDatabase
|
||||||
import no.iktdev.mediaprocessing.ui.dto.ExplorerItem
|
import no.iktdev.mediaprocessing.ui.dto.explore.ExplorerItem
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
import org.springframework.boot.runApplication
|
import org.springframework.boot.runApplication
|
||||||
import org.springframework.context.ApplicationContext
|
import org.springframework.context.ApplicationContext
|
||||||
import java.util.concurrent.CountDownLatch
|
import org.springframework.context.annotation.Bean
|
||||||
|
|
||||||
|
|
||||||
private val logger = KotlinLogging.logger {}
|
private val logger = KotlinLogging.logger {}
|
||||||
val ioCoroutine = CoroutinesIO()
|
val ioCoroutine = CoroutinesIO()
|
||||||
val defaultCoroutine = CoroutinesDefault()
|
val defaultCoroutine = CoroutinesDefault()
|
||||||
|
lateinit var eventsManager: EventsManager
|
||||||
|
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
class UIApplication {
|
class UIApplication {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun eventManager(): EventsManager {
|
||||||
|
return eventsManager
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var eventsDatabase: MySqlDataSource
|
private lateinit var eventsDatabase: EventsDatabase
|
||||||
fun getEventsDatabase(): MySqlDataSource {
|
|
||||||
return eventsDatabase
|
lateinit var taskManager: TasksManager
|
||||||
}
|
|
||||||
|
|
||||||
lateinit var persistentReader: PersistentDataReader
|
|
||||||
lateinit var persistentWriter: PersistentDataStore
|
|
||||||
|
|
||||||
private var context: ApplicationContext? = null
|
private var context: ApplicationContext? = null
|
||||||
private val kafkaClearedLatch = CountDownLatch(1)
|
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun getContext(): ApplicationContext? {
|
fun getContext(): ApplicationContext? {
|
||||||
@ -46,11 +51,10 @@ val fileRegister: ObservableMap<String, ExplorerItem> = observableMapOf()
|
|||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
|
|
||||||
eventsDatabase = DatabaseEnvConfig.toEventsDatabase()
|
eventsDatabase = EventsDatabase().also {
|
||||||
eventsDatabase.connect()
|
eventsManager = EventsManager(it.database)
|
||||||
|
}
|
||||||
|
|
||||||
persistentReader = PersistentDataReader(eventsDatabase)
|
|
||||||
persistentWriter = PersistentDataStore(eventsDatabase)
|
|
||||||
|
|
||||||
|
|
||||||
ioCoroutine.addListener(listener = object: Observables.ObservableValue.ValueListener<Throwable> {
|
ioCoroutine.addListener(listener = object: Observables.ObservableValue.ValueListener<Throwable> {
|
||||||
@ -63,32 +67,6 @@ fun main(args: Array<String>) {
|
|||||||
value.printStackTrace()
|
value.printStackTrace()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
try {
|
|
||||||
/*val admincli = AdminClient.create(mapOf(
|
|
||||||
AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG to KafkaEnv.servers,
|
|
||||||
AdminClientConfig.REQUEST_TIMEOUT_MS_CONFIG to "1000",
|
|
||||||
AdminClientConfig.DEFAULT_API_TIMEOUT_MS_CONFIG to "5000"
|
|
||||||
))
|
|
||||||
val go = admincli.listConsumerGroupOffsets("${KafkaEnv.consumerId}:UIDataComposer")
|
|
||||||
go.partitionsToOffsetAndMetadata().whenComplete { result, throwable ->
|
|
||||||
val partitions = result.entries.filter { it.key.topic() == SharedConfig.kafkaTopic }
|
|
||||||
.map { it.key }
|
|
||||||
val deleteResult = admincli.deleteConsumerGroupOffsets("${KafkaEnv.consumerId}:UIDataComposer", partitions.toSet())
|
|
||||||
deleteResult.all().whenComplete { result, throwable ->
|
|
||||||
kafkaClearedLatch.countDown()
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
// kafkaClearedLatch.countDown()
|
|
||||||
}
|
|
||||||
|
|
||||||
// logger.info { "Waiting for kafka to clear offset!" }
|
|
||||||
// kafkaClearedLatch.await(5, TimeUnit.MINUTES)
|
|
||||||
// logger.info { "Offset cleared!" }
|
|
||||||
// Thread.sleep(10000)
|
|
||||||
context = runApplication<UIApplication>(*args)
|
context = runApplication<UIApplication>(*args)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,6 @@ package no.iktdev.mediaprocessing.ui
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object UIEnv {
|
object UIEnv {
|
||||||
var storedContent: File = if (!System.getenv("DIRECTORY_CONTENT_STORED").isNullOrBlank()) File(System.getenv("DIRECTORY_CONTENT_STORED")) else File("/src/output")
|
|
||||||
val socketEncoder: String = if (System.getenv("EncoderWs").isNullOrBlank()) System.getenv("EncoderWs") else "ws://encoder:8080"
|
val socketEncoder: String = if (System.getenv("EncoderWs").isNullOrBlank()) System.getenv("EncoderWs") else "ws://encoder:8080"
|
||||||
|
|
||||||
val coordinatorUrl: String = if (System.getenv("Coordinator").isNullOrBlank()) System.getenv("Coordinator") else "http://coordinator"
|
val coordinatorUrl: String = if (System.getenv("Coordinator").isNullOrBlank()) System.getenv("Coordinator") else "http://coordinator"
|
||||||
}
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package no.iktdev.mediaprocessing.ui.dto
|
||||||
|
|
||||||
|
data class EventChain(
|
||||||
|
val eventId: String,
|
||||||
|
val eventName: String,
|
||||||
|
val elements: MutableList<EventChain> = mutableListOf()
|
||||||
|
)
|
||||||
@ -1,12 +1,12 @@
|
|||||||
package no.iktdev.mediaprocessing.ui.dto
|
package no.iktdev.mediaprocessing.ui.dto
|
||||||
|
|
||||||
import no.iktdev.mediaprocessing.shared.kafka.core.KafkaEvents
|
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
||||||
|
|
||||||
data class EventSummary(
|
data class EventSummary(
|
||||||
val referenceId: String,
|
val referenceId: String,
|
||||||
val baseName: String? = null,
|
val baseName: String? = null,
|
||||||
val collection: String? = null,
|
val collection: String? = null,
|
||||||
val events: List<KafkaEvents> = emptyList(),
|
val events: List<Events> = emptyList(),
|
||||||
val status: SummaryState = SummaryState.Started,
|
val status: SummaryState = SummaryState.Started,
|
||||||
val activeEvens: Map<String, EventSummarySubItem>
|
val activeEvens: Map<String, EventSummarySubItem>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package no.iktdev.mediaprocessing.ui.dto
|
package no.iktdev.mediaprocessing.ui.dto.explore
|
||||||
|
|
||||||
interface ExplorerAttr {
|
interface ExplorerAttr {
|
||||||
val created: Long
|
val created: Long
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package no.iktdev.mediaprocessing.ui.dto
|
package no.iktdev.mediaprocessing.ui.dto.explore
|
||||||
|
|
||||||
data class ExplorerCursor (
|
data class ExplorerCursor (
|
||||||
val name: String,
|
val name: String,
|
||||||
@ -1,11 +1,10 @@
|
|||||||
package no.iktdev.mediaprocessing.ui.explorer
|
package no.iktdev.mediaprocessing.ui.explorer
|
||||||
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.SharedConfig
|
import no.iktdev.mediaprocessing.shared.common.SharedConfig
|
||||||
import no.iktdev.mediaprocessing.ui.UIEnv
|
import no.iktdev.mediaprocessing.ui.dto.explore.ExplorerAttributes
|
||||||
import no.iktdev.mediaprocessing.ui.dto.ExplorerAttributes
|
import no.iktdev.mediaprocessing.ui.dto.explore.ExplorerCursor
|
||||||
import no.iktdev.mediaprocessing.ui.dto.ExplorerCursor
|
import no.iktdev.mediaprocessing.ui.dto.explore.ExplorerItem
|
||||||
import no.iktdev.mediaprocessing.ui.dto.ExplorerItem
|
import no.iktdev.mediaprocessing.ui.dto.explore.ExplorerItemType
|
||||||
import no.iktdev.mediaprocessing.ui.dto.ExplorerItemType
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileFilter
|
import java.io.FileFilter
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
package no.iktdev.mediaprocessing.ui.service
|
||||||
|
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.database.cal.EventsManager
|
||||||
|
import no.iktdev.mediaprocessing.ui.eventsManager
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@EnableScheduling
|
||||||
|
class AvailableEventsService(
|
||||||
|
@Autowired eventsManager: EventsManager
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun pullAvailableEvents() {
|
||||||
|
eventsManager.readAvailableEvents().onEach {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package no.iktdev.mediaprocessing.ui.service
|
||||||
|
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.database.cal.EventsManager
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@EnableScheduling
|
||||||
|
class CompletedEventsService(
|
||||||
|
@Autowired eventsManager: EventsManager
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package no.iktdev.mediaprocessing.ui.service
|
||||||
|
|
||||||
|
import no.iktdev.eventi.data.derivedFromEventId
|
||||||
|
import no.iktdev.eventi.data.eventId
|
||||||
|
import no.iktdev.eventi.data.referenceId
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.data.Event
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.database.cal.EventsManager
|
||||||
|
import no.iktdev.mediaprocessing.ui.dto.EventChain
|
||||||
|
import no.iktdev.mediaprocessing.ui.eventsManager
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@EnableScheduling
|
||||||
|
class EventExecutionOrderService(
|
||||||
|
@Autowired eventsManager: EventsManager
|
||||||
|
) {
|
||||||
|
|
||||||
|
val collections: MutableMap<String, List<EventChain>> = mutableMapOf()
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 5_000)
|
||||||
|
fun pullAvailableEvents() {
|
||||||
|
eventsManager.getAllEvents().onEach { events ->
|
||||||
|
collections[events.first().referenceId()] = events.chained()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun List<Event>.chained(): List<EventChain> {
|
||||||
|
val eventMap = this.associateBy { it.eventId() }
|
||||||
|
val chains = mutableMapOf<String, EventChain>()
|
||||||
|
|
||||||
|
this.forEach { event ->
|
||||||
|
val chain = EventChain(eventId = event.eventId(), eventName = event.eventType.name)
|
||||||
|
chains[event.eventId()] = chain
|
||||||
|
|
||||||
|
if (event.derivedFromEventId() != null && eventMap.containsKey(event.derivedFromEventId())) {
|
||||||
|
val parentChain = chains[event.derivedFromEventId()]
|
||||||
|
parentChain?.elements?.add(chain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chains.values.filter { it.elements.isNotEmpty() }.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package no.iktdev.mediaprocessing.ui.socket
|
||||||
|
|
||||||
|
import no.iktdev.eventi.data.derivedFromEventId
|
||||||
|
import no.iktdev.eventi.data.eventId
|
||||||
|
import no.iktdev.eventi.data.referenceId
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.contract.data.Event
|
||||||
|
import no.iktdev.mediaprocessing.ui.dto.EventChain
|
||||||
|
import no.iktdev.mediaprocessing.ui.eventsManager
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.messaging.handler.annotation.MessageMapping
|
||||||
|
import org.springframework.messaging.simp.SimpMessagingTemplate
|
||||||
|
import org.springframework.stereotype.Controller
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
class ChainedEventsTopic(
|
||||||
|
@Autowired private val template: SimpMessagingTemplate?
|
||||||
|
) {
|
||||||
|
@MessageMapping("/chained/all")
|
||||||
|
fun sendAllChainedEvents() {
|
||||||
|
val collections: MutableMap<String, List<EventChain>> = mutableMapOf()
|
||||||
|
eventsManager.getAllEvents().onEach { events ->
|
||||||
|
collections[events.first().referenceId()] = events.chained()
|
||||||
|
}
|
||||||
|
template?.convertAndSend("/topic/chained/all",collections)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun List<Event>.chained(): List<EventChain> {
|
||||||
|
val eventMap = this.associateBy { it.eventId() }
|
||||||
|
val chains = mutableMapOf<String, EventChain>()
|
||||||
|
val children = mutableSetOf<String>()
|
||||||
|
|
||||||
|
this.forEach { event ->
|
||||||
|
val eventId = event.metadata.eventId
|
||||||
|
val derivedFromEventId = event.metadata.derivedFromEventId
|
||||||
|
val chain = chains.getOrPut(eventId) { EventChain(eventId, event.eventType.toString()) }
|
||||||
|
|
||||||
|
if (derivedFromEventId != null && eventMap.containsKey(derivedFromEventId)) {
|
||||||
|
val parentChain = chains.getOrPut(derivedFromEventId) {
|
||||||
|
EventChain(derivedFromEventId, eventMap[derivedFromEventId]!!.eventType.toString())
|
||||||
|
}
|
||||||
|
parentChain.elements.add(chain)
|
||||||
|
children.add(eventId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chains.values.filter { it.eventId !in children }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,12 +8,12 @@ import org.springframework.stereotype.Controller
|
|||||||
@Controller
|
@Controller
|
||||||
class EventsTableTopic(
|
class EventsTableTopic(
|
||||||
@Autowired private val template: SimpMessagingTemplate?,
|
@Autowired private val template: SimpMessagingTemplate?,
|
||||||
@Autowired private val persistentEventsTableService: PersistentEventsTableService
|
//@Autowired private val persistentEventsTableService: PersistentEventsTableService
|
||||||
): TopicSupport() {
|
) {
|
||||||
|
|
||||||
@MessageMapping("/persistent/events")
|
@MessageMapping("/persistent/events")
|
||||||
fun readbackEvents() {
|
fun readbackEvents() {
|
||||||
template?.convertAndSend("/topic/persistent/events", persistentEventsTableService.cachedEvents)
|
//template?.convertAndSend("/topic/persistent/events", persistentEventsTableService.cachedEvents)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package no.iktdev.mediaprocessing.ui.socket
|
package no.iktdev.mediaprocessing.ui.socket
|
||||||
|
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import no.iktdev.mediaprocessing.shared.contract.dto.EventRequest
|
import no.iktdev.mediaprocessing.shared.common.contract.dto.EventRequest
|
||||||
import no.iktdev.mediaprocessing.ui.UIEnv
|
import no.iktdev.mediaprocessing.ui.UIEnv
|
||||||
import no.iktdev.mediaprocessing.ui.explorer.ExplorerCore
|
import no.iktdev.mediaprocessing.ui.explorer.ExplorerCore
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
@ -17,7 +17,7 @@ class ExplorerTopic(
|
|||||||
@Autowired private val template: SimpMessagingTemplate?,
|
@Autowired private val template: SimpMessagingTemplate?,
|
||||||
@Autowired private val coordinatorTemplate: RestTemplate,
|
@Autowired private val coordinatorTemplate: RestTemplate,
|
||||||
val explorer: ExplorerCore = ExplorerCore()
|
val explorer: ExplorerCore = ExplorerCore()
|
||||||
): TopicSupport() {
|
) {
|
||||||
|
|
||||||
@MessageMapping("/explorer/home")
|
@MessageMapping("/explorer/home")
|
||||||
fun goHome() {
|
fun goHome() {
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
package no.iktdev.mediaprocessing.ui.socket
|
|
||||||
|
|
||||||
import com.google.gson.Gson
|
|
||||||
|
|
||||||
abstract class TopicSupport {
|
|
||||||
|
|
||||||
fun toJson(item: Any?): String? {
|
|
||||||
return if (item != null) Gson().toJson(item) else null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
58
apps/ui/web/package-lock.json
generated
58
apps/ui/web/package-lock.json
generated
@ -30,6 +30,7 @@
|
|||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-stomp": "^5.1.0",
|
"react-stomp": "^5.1.0",
|
||||||
"react-stomp-hooks": "^2.1.0",
|
"react-stomp-hooks": "^2.1.0",
|
||||||
|
"react-tree-graph": "^8.0.2",
|
||||||
"react-use-websocket": "^4.4.0",
|
"react-use-websocket": "^4.4.0",
|
||||||
"redux": "^4.2.1",
|
"redux": "^4.2.1",
|
||||||
"sockjs-client": "^1.6.1",
|
"sockjs-client": "^1.6.1",
|
||||||
@ -2084,9 +2085,9 @@
|
|||||||
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
|
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.22.15",
|
"version": "7.25.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz",
|
||||||
"integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==",
|
"integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
@ -7142,6 +7143,16 @@
|
|||||||
"type": "^1.0.1"
|
"type": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/d3-ease": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ=="
|
||||||
|
},
|
||||||
|
"node_modules/d3-hierarchy": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-SwIdqM3HxQX2214EG9GTjgmCc/mbSx4mQBn+DuEETubhOw6/U3fmnji4uCVrmzOydMHSO1nZle5gh6HB/wdOzw=="
|
||||||
|
},
|
||||||
"node_modules/damerau-levenshtein": {
|
"node_modules/damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||||
@ -15370,6 +15381,20 @@
|
|||||||
"react-dom": ">=16.6.0"
|
"react-dom": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-tree-graph": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-tree-graph/-/react-tree-graph-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-w3DWXisWvAvESAKO5WMCSIdqUb+LLXKX32ePwuVab98QUDUjrwoHSGsWG10ip6bsxuCyUTmP0YXwNyI8fSiOaQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.24.5",
|
||||||
|
"d3-ease": "^2.0.0",
|
||||||
|
"d3-hierarchy": "^2.0.0",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17 || ^18 || ^19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-use-websocket": {
|
"node_modules/react-use-websocket": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.4.0.tgz",
|
||||||
@ -19838,9 +19863,9 @@
|
|||||||
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
|
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
|
||||||
},
|
},
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
"version": "7.22.15",
|
"version": "7.25.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz",
|
||||||
"integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==",
|
"integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
@ -23432,6 +23457,16 @@
|
|||||||
"type": "^1.0.1"
|
"type": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"d3-ease": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ=="
|
||||||
|
},
|
||||||
|
"d3-hierarchy": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-SwIdqM3HxQX2214EG9GTjgmCc/mbSx4mQBn+DuEETubhOw6/U3fmnji4uCVrmzOydMHSO1nZle5gh6HB/wdOzw=="
|
||||||
|
},
|
||||||
"damerau-levenshtein": {
|
"damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||||
@ -29215,6 +29250,17 @@
|
|||||||
"prop-types": "^15.6.2"
|
"prop-types": "^15.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-tree-graph": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-tree-graph/-/react-tree-graph-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-w3DWXisWvAvESAKO5WMCSIdqUb+LLXKX32ePwuVab98QUDUjrwoHSGsWG10ip6bsxuCyUTmP0YXwNyI8fSiOaQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.24.5",
|
||||||
|
"d3-ease": "^2.0.0",
|
||||||
|
"d3-hierarchy": "^2.0.0",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-use-websocket": {
|
"react-use-websocket": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.4.0.tgz",
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-stomp": "^5.1.0",
|
"react-stomp": "^5.1.0",
|
||||||
"react-stomp-hooks": "^2.1.0",
|
"react-stomp-hooks": "^2.1.0",
|
||||||
|
"react-tree-graph": "^8.0.2",
|
||||||
"react-use-websocket": "^4.4.0",
|
"react-use-websocket": "^4.4.0",
|
||||||
"redux": "^4.2.1",
|
"redux": "^4.2.1",
|
||||||
"sockjs-client": "^1.6.1",
|
"sockjs-client": "^1.6.1",
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { ThemeProvider } from '@mui/material';
|
|||||||
import theme from './theme';
|
import theme from './theme';
|
||||||
import { simpleEventsUpdate } from './app/store/kafka-items-flat-slice';
|
import { simpleEventsUpdate } from './app/store/kafka-items-flat-slice';
|
||||||
import { EventDataObject, SimpleEventDataObject } from './types';
|
import { EventDataObject, SimpleEventDataObject } from './types';
|
||||||
|
import EventsChainPage from './app/page/EventsChainPage';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const client = useStompClient();
|
const client = useStompClient();
|
||||||
@ -62,6 +63,7 @@ function App() {
|
|||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path='/files' element={<ExplorePage />} />
|
<Route path='/files' element={<ExplorePage />} />
|
||||||
|
<Route path='/events' element={<EventsChainPage />} />
|
||||||
<Route path='/' element={<LaunchPage />} />
|
<Route path='/' element={<LaunchPage />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
58
apps/ui/web/src/app/page/EventsChainPage.tsx
Normal file
58
apps/ui/web/src/app/page/EventsChainPage.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { useStompClient } from 'react-stomp-hooks';
|
||||||
|
import { RootState } from "../store";
|
||||||
|
import { useWsSubscription } from "../ws/subscriptions";
|
||||||
|
import { set } from "../store/persistent-events-slice";
|
||||||
|
import { EventsObjectListResponse } from "../../types";
|
||||||
|
import IconRefresh from '@mui/icons-material/Refresh'
|
||||||
|
import { Button } from "@mui/material";
|
||||||
|
|
||||||
|
|
||||||
|
export default function EventsChainPage() {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const client = useStompClient();
|
||||||
|
const cursor = useSelector((state: RootState) => state.persistentEvents)
|
||||||
|
|
||||||
|
function log(data: any) {
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
useWsSubscription("/topic/chained/all", (response) => {
|
||||||
|
console.log(response)
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
|
||||||
|
// Kjør din funksjon her når komponenten lastes inn for første gang
|
||||||
|
// Sjekk om cursor er null
|
||||||
|
if (cursor.items === null && client !== null) {
|
||||||
|
console.log(cursor)
|
||||||
|
// Kjør din funksjon her når cursor er null og client ikke er null
|
||||||
|
client?.publish({
|
||||||
|
destination: "/app/chained/all"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Alternativt, du kan dispatche en Redux handling her
|
||||||
|
// dispatch(fetchDataAction()); // Eksempel på å dispatche en handling
|
||||||
|
}
|
||||||
|
}, [cursor, client, dispatch]);
|
||||||
|
|
||||||
|
const onRefresh = () => {
|
||||||
|
client?.publish({
|
||||||
|
"destination": "/app/chained/all",
|
||||||
|
"body": "Potato"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
startIcon={ <IconRefresh /> }
|
||||||
|
onClick={onRefresh} sx={{
|
||||||
|
borderRadius: 5,
|
||||||
|
textTransform: 'none'
|
||||||
|
}}>Refresh</Button >
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -58,6 +58,7 @@ function getSegmentedNaviagatablePath(navigateTo: (path: string | null) => void,
|
|||||||
console.log(path);
|
console.log(path);
|
||||||
const parts: Array<string> = path?.split(/\\|\//).map((value: string, index: number) => value.replaceAll(":", "")) ?? [];
|
const parts: Array<string> = path?.split(/\\|\//).map((value: string, index: number) => value.replaceAll(":", "")) ?? [];
|
||||||
const segments = parts.map((name: string, index: number) => {
|
const segments = parts.map((name: string, index: number) => {
|
||||||
|
console.log(name)
|
||||||
return (
|
return (
|
||||||
<Box key={index} sx={{
|
<Box key={index} sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@ -65,7 +66,8 @@ function getSegmentedNaviagatablePath(navigateTo: (path: string | null) => void,
|
|||||||
alignItems: "center"
|
alignItems: "center"
|
||||||
}}>
|
}}>
|
||||||
<Button sx={{
|
<Button sx={{
|
||||||
borderRadius: 5
|
borderRadius: 5,
|
||||||
|
textTransform: 'none'
|
||||||
}} onClick={() => navigateTo(getPartFor(path!, index))}>
|
}} onClick={() => navigateTo(getPartFor(path!, index))}>
|
||||||
<Typography>{name}</Typography>
|
<Typography>{name}</Typography>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -3,9 +3,10 @@ import SimpleTable, { TableCellCustomizer, TablePropetyConfig } from "../feature
|
|||||||
import { RootState } from "../store";
|
import { RootState } from "../store";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useStompClient } from "react-stomp-hooks";
|
import { useStompClient } from "react-stomp-hooks";
|
||||||
import { Box, Button, useTheme } from "@mui/material";
|
import { Box, Button, IconButton, Typography, useTheme } from "@mui/material";
|
||||||
import IconRefresh from '@mui/icons-material/Refresh'
|
import IconRefresh from '@mui/icons-material/Refresh'
|
||||||
|
import IconCompleted from '@mui/icons-material/Check'
|
||||||
|
import IconWorking from '@mui/icons-material/Engineering';
|
||||||
|
|
||||||
const columns: Array<TablePropetyConfig> = [
|
const columns: Array<TablePropetyConfig> = [
|
||||||
{ label: "Title", accessor: "givenTitle" },
|
{ label: "Title", accessor: "givenTitle" },
|
||||||
@ -53,11 +54,24 @@ export default function LaunchPage() {
|
|||||||
<Box sx={{
|
<Box sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
}}>
|
}}>
|
||||||
<Button onClick={onRefresh} sx={{
|
<Button
|
||||||
borderRadius: 5
|
startIcon={ <IconRefresh /> }
|
||||||
}}>
|
onClick={onRefresh} sx={{
|
||||||
<IconRefresh />
|
borderRadius: 5,
|
||||||
</Button>
|
textTransform: 'none'
|
||||||
|
}}>Refresh</Button >
|
||||||
|
<Button
|
||||||
|
startIcon={ <IconCompleted /> }
|
||||||
|
onClick={onRefresh} sx={{
|
||||||
|
borderRadius: 5,
|
||||||
|
textTransform: 'none'
|
||||||
|
}}>Completed</Button >
|
||||||
|
<Button
|
||||||
|
startIcon={ <IconWorking /> }
|
||||||
|
onClick={onRefresh} sx={{
|
||||||
|
borderRadius: 5,
|
||||||
|
textTransform: 'none'
|
||||||
|
}}>Working</Button >
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
|
|||||||
@ -27,7 +27,7 @@ object EventToClazzTable {
|
|||||||
Events.EventMediaReadStreamPerformed to MediaFileStreamsReadEvent::class.java,
|
Events.EventMediaReadStreamPerformed to MediaFileStreamsReadEvent::class.java,
|
||||||
Events.EventMediaMetadataSearchPerformed to MediaMetadataReceivedEvent::class.java,
|
Events.EventMediaMetadataSearchPerformed to MediaMetadataReceivedEvent::class.java,
|
||||||
Events.EventMediaReadOutNameAndType to MediaOutInformationConstructedEvent::class.java,
|
Events.EventMediaReadOutNameAndType to MediaOutInformationConstructedEvent::class.java,
|
||||||
Events.EventMediaWorkProceedPermitted to no.iktdev.mediaprocessing.shared.common.contract.data.PermitWorkCreationEvent::class.java,
|
Events.EventMediaWorkProceedPermitted to PermitWorkCreationEvent::class.java,
|
||||||
Events.EventMediaProcessCompleted to MediaProcessCompletedEvent::class.java
|
Events.EventMediaProcessCompleted to MediaProcessCompletedEvent::class.java
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
package no.iktdev.mediaprocessing.shared.common.database
|
||||||
|
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.DatabaseEnvConfig
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.database.tables.allEvents
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.database.tables.events
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.database.tables.runners
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.database.tables.tasks
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.toEventsDatabase
|
||||||
|
|
||||||
|
class EventsDatabase() {
|
||||||
|
val database = DatabaseEnvConfig.toEventsDatabase()
|
||||||
|
val tables = listOf(
|
||||||
|
events, // For kafka
|
||||||
|
allEvents,
|
||||||
|
tasks,
|
||||||
|
runners
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
database.createDatabase()
|
||||||
|
database.createTables(*tables.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -8,20 +8,19 @@ import no.iktdev.eventi.data.toJson
|
|||||||
import no.iktdev.eventi.database.DataSource
|
import no.iktdev.eventi.database.DataSource
|
||||||
import no.iktdev.eventi.database.isCausedByDuplicateError
|
import no.iktdev.eventi.database.isCausedByDuplicateError
|
||||||
import no.iktdev.eventi.database.isExposedSqlException
|
import no.iktdev.eventi.database.isExposedSqlException
|
||||||
|
import no.iktdev.eventi.implementations.EventsManagerImpl
|
||||||
import no.iktdev.mediaprocessing.shared.common.database.tables.allEvents
|
import no.iktdev.mediaprocessing.shared.common.database.tables.allEvents
|
||||||
import no.iktdev.mediaprocessing.shared.common.database.tables.events
|
import no.iktdev.mediaprocessing.shared.common.database.tables.events
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
import no.iktdev.mediaprocessing.shared.common.contract.Events
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.EventsManagerContract
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.data.Event
|
import no.iktdev.mediaprocessing.shared.common.contract.data.Event
|
||||||
import no.iktdev.mediaprocessing.shared.common.contract.fromJsonWithDeserializer
|
import no.iktdev.mediaprocessing.shared.common.contract.fromJsonWithDeserializer
|
||||||
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
|
||||||
open class EventsManager(dataSource: DataSource) : EventsManagerContract(dataSource) {
|
class EventsManager(dataSource: DataSource) : EventsManagerImpl<Event>(dataSource) {
|
||||||
val log = KotlinLogging.logger {}
|
val log = KotlinLogging.logger {}
|
||||||
|
|
||||||
|
|
||||||
override fun storeEvent(event: Event): Boolean {
|
override fun storeEvent(event: Event): Boolean {
|
||||||
|
|
||||||
no.iktdev.eventi.database.withTransaction(dataSource.database) {
|
no.iktdev.eventi.database.withTransaction(dataSource.database) {
|
||||||
@ -114,7 +113,7 @@ open class EventsManager(dataSource: DataSource) : EventsManagerContract(dataSou
|
|||||||
.groupBy { it[events.referenceId] }
|
.groupBy { it[events.referenceId] }
|
||||||
.mapNotNull { it.value.mapNotNull { v -> v.toEvent() } }
|
.mapNotNull { it.value.mapNotNull { v -> v.toEvent() } }
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
return events.filter { it.none { it.eventType == Events.EventMediaProcessCompleted } }
|
return events
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -185,7 +185,6 @@ abstract class EventCoordinator<T : EventImpl, E : EventsManagerImpl<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Ikke implementert enda
|
|
||||||
enum class ActiveMode {
|
enum class ActiveMode {
|
||||||
Active,
|
Active,
|
||||||
Passive
|
Passive
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user