diff --git a/modules/app-server/app/src/main/kotlin/app/server/app/Dependencies.kt b/modules/app-server/app/src/main/kotlin/app/server/app/Dependencies.kt index 76e2279f..afa01727 100644 --- a/modules/app-server/app/src/main/kotlin/app/server/app/Dependencies.kt +++ b/modules/app-server/app/src/main/kotlin/app/server/app/Dependencies.kt @@ -49,7 +49,7 @@ val batchExecutionService = BatchExecutionService(batchExecutionDao) val batchExecutionGrpcServiceImpl = BatchExecutionGrpcServiceImpl(batchExecutionService = batchExecutionService) val scriptExecutionDao = ScriptExecutionDao(dslContext) -val scriptExecutionService = ScriptExecutionService(scriptExecutionDao) +val scriptExecutionService = ScriptExecutionService(scriptExecutionDao, environmentService) val scriptExecutionGrpcServiceImpl = ScriptExecutionGrpcServiceImpl(scriptExecutionService) val moduleEnvironmentTokenDao = ModuleEnvironmentTokenDao(dslContext) diff --git a/modules/app-server/dao/src/main/kotlin/dao/execution/script/ScriptExecutionDao.kt b/modules/app-server/dao/src/main/kotlin/dao/execution/script/ScriptExecutionDao.kt index 5dcc4766..16240bba 100644 --- a/modules/app-server/dao/src/main/kotlin/dao/execution/script/ScriptExecutionDao.kt +++ b/modules/app-server/dao/src/main/kotlin/dao/execution/script/ScriptExecutionDao.kt @@ -1,17 +1,19 @@ package dao.execution.script -import dao.utils.toDto -import dao.utils.toOffsetDateTime +import dao.utils.* import execution.INITIAL_STATUS +import execution.Status import execution.script.* import generated.domain.enums.ExecutionStatus +import generated.domain.tables.references.DM_BATCH_EXECUTION import generated.domain.tables.references.DM_SCRIPT import generated.domain.tables.references.DM_SCRIPT_EXECUTION import org.jooq.Condition import org.jooq.DSLContext import org.jooq.impl.DSL -import org.jooq.impl.DSL.`val` +import org.jooq.impl.DSL.* import script.Script +import java.sql.ResultSet import java.util.* class ScriptExecutionDao(val dslContext: DSLContext): ScriptExecutionDaoInterface { @@ -96,6 +98,67 @@ class ScriptExecutionDao(val dslContext: DSLContext): ScriptExecutionDaoInterfac .from(DM_SCRIPT_EXECUTION.join(DM_SCRIPT).on(DM_SCRIPT.CHECKSUM.eq(DM_SCRIPT_EXECUTION.FK_SCRIPT_REF))) .where(searchRequest.toCondition()) .fetchInto(ScriptExecutionListItem::class.java) + + override fun findModuleScriptsExecutionsInformation(moduleRef: UUID): List { + val resultSet = dslContext.select( + DM_SCRIPT.CHECKSUM, + DM_SCRIPT.NAME, + DM_SCRIPT.CONTENT, + DM_SCRIPT_EXECUTION.ID, + DM_SCRIPT_EXECUTION.START_DATE, + DM_SCRIPT_EXECUTION.END_DATE, + DM_SCRIPT_EXECUTION.DURATION_IN_MS, + DM_SCRIPT_EXECUTION.EXECUTION_ORDER_INDEX, + DM_SCRIPT_EXECUTION.OUTPUT, + DM_SCRIPT_EXECUTION.STATUS, + DM_BATCH_EXECUTION.FK_ENVIRONMENT_REF, + ).from( + DM_SCRIPT_EXECUTION + .join(DM_BATCH_EXECUTION.where(DM_BATCH_EXECUTION.FK_MODULE_REF.eq(moduleRef))).on( + DM_BATCH_EXECUTION.ID.eq(DM_SCRIPT_EXECUTION.FK_BATCH_EXECUTION_REF) + ) + .join(DM_SCRIPT).on(DM_SCRIPT.CHECKSUM.eq(DM_SCRIPT_EXECUTION.FK_SCRIPT_REF)) + ) + .orderBy(DM_SCRIPT.CHECKSUM) + .fetchResultSet() + + val scriptsWithAllExecutions = mutableListOf() + var currentScript: Script? = null + var currentScriptExecutions: MutableList = mutableListOf() + while(resultSet.next()) { + val checksum = resultSet.getString(DM_SCRIPT.CHECKSUM.name) + + if (checksum != currentScript?.checksum) { + if (currentScript != null) { + scriptsWithAllExecutions.add( + ScriptWithAllExecutions( + currentScript, + currentScriptExecutions + ) + ) + } + + currentScript = Script( + name = resultSet.getString(DM_SCRIPT.NAME.name), + checksum = checksum, + content = resultSet.getString(DM_SCRIPT.CONTENT.name), + ) + currentScriptExecutions = mutableListOf() + } + currentScriptExecutions.add(resultSet.toScriptExecutionWithModule()) + } + + if (currentScript != null) { + scriptsWithAllExecutions.add( + ScriptWithAllExecutions( + currentScript, + currentScriptExecutions + ) + ) + } + + return scriptsWithAllExecutions + } } fun ScriptExecutionSearchRequest.toCondition(): Condition { @@ -110,4 +173,14 @@ fun ScriptExecutionSearchRequest.toCondition(): Condition { } return condition -} \ No newline at end of file +} + +fun ResultSet.toScriptExecutionWithModule(): ScriptExecutionWithEnvironment = ScriptExecutionWithEnvironment( + id = this.getUUID(DM_SCRIPT_EXECUTION.ID.name), + startDate = this.getOffsetDateTime(DM_SCRIPT_EXECUTION.START_DATE.name), + durationInMs = this.getIntOrNull(DM_SCRIPT_EXECUTION.DURATION_IN_MS.name), + executionOrderIndex = this.getInt(DM_SCRIPT_EXECUTION.EXECUTION_ORDER_INDEX.name), + output = this.getString(DM_SCRIPT_EXECUTION.OUTPUT.name), + status = Status.valueOf(this.getString(DM_SCRIPT_EXECUTION.STATUS.name)), + fkEnvironmentRef = this.getUUID(DM_BATCH_EXECUTION.FK_ENVIRONMENT_REF.name), +) \ No newline at end of file diff --git a/modules/app-server/dao/src/main/kotlin/dao/utils/DaoMappingUtils.kt b/modules/app-server/dao/src/main/kotlin/dao/utils/DaoMappingUtils.kt index 2d7dd0a3..35d37a8d 100644 --- a/modules/app-server/dao/src/main/kotlin/dao/utils/DaoMappingUtils.kt +++ b/modules/app-server/dao/src/main/kotlin/dao/utils/DaoMappingUtils.kt @@ -6,9 +6,11 @@ import execution.batch.Type import generated.domain.enums.BatchExecutionOrigin import generated.domain.enums.BatchExecutionType import generated.domain.enums.ExecutionStatus +import java.sql.ResultSet import java.time.Instant import java.time.OffsetDateTime import java.time.ZoneId +import java.util.* fun Origin.toDto(): BatchExecutionOrigin = when (this) { @@ -40,4 +42,17 @@ fun Status.toDto(): ExecutionStatus = */ fun Instant.toOffsetDateTime(): OffsetDateTime { return OffsetDateTime.ofInstant(this, ZoneId.of("UTC").normalized()) +} + + +fun ResultSet.getOffsetDateTime(key: String): OffsetDateTime? { + val date = this.getTimestamp(key) ?: return null + + return date.toInstant().toOffsetDateTime() +} + +fun ResultSet.getUUID(key: String): UUID = UUID.fromString(this.getString(key)) + +fun ResultSet.getIntOrNull(name: String): Int? { + return this.getString(name)?.toInt() } \ No newline at end of file diff --git a/modules/app-server/dao/src/test/kotlin/UtilsRandom.kt b/modules/app-server/dao/src/test/kotlin/UtilsRandom.kt new file mode 100644 index 00000000..3f261eee --- /dev/null +++ b/modules/app-server/dao/src/test/kotlin/UtilsRandom.kt @@ -0,0 +1,12 @@ +import kotlin.random.Random + +private val charactersAvailableForRandom = listOf( + 'a', 'b', 'c', 'd', 'e', 'f', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z' +) + +fun randomString(length: Int = 10): String { + return (1..length) + .map { Random.nextInt(0, charactersAvailableForRandom.size).let { charactersAvailableForRandom[it] } } + .joinToString("") +} \ No newline at end of file diff --git a/modules/app-server/dao/src/test/kotlin/dao/execution/batch/BatchExecutionDaoTest.kt b/modules/app-server/dao/src/test/kotlin/dao/execution/batch/BatchExecutionDaoTest.kt index ff00aea5..69c13275 100644 --- a/modules/app-server/dao/src/test/kotlin/dao/execution/batch/BatchExecutionDaoTest.kt +++ b/modules/app-server/dao/src/test/kotlin/dao/execution/batch/BatchExecutionDaoTest.kt @@ -12,6 +12,8 @@ import execution.batch.BatchExecutionEndUpdateRequest import execution.batch.BatchExecutionSearchRequest import generated.domain.tables.pojos.DmBatchExecution import generated.domain.tables.references.DM_BATCH_EXECUTION +import generated.domain.tables.references.DM_ENVIRONMENT +import generated.domain.tables.references.DM_PROJECT import module.Module import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Nested diff --git a/modules/app-server/dao/src/test/kotlin/dao/execution/script/ScriptExecutionDaoTest.kt b/modules/app-server/dao/src/test/kotlin/dao/execution/script/ScriptExecutionDaoTest.kt index 1b269504..3f512346 100644 --- a/modules/app-server/dao/src/test/kotlin/dao/execution/script/ScriptExecutionDaoTest.kt +++ b/modules/app-server/dao/src/test/kotlin/dao/execution/script/ScriptExecutionDaoTest.kt @@ -1,26 +1,22 @@ package dao.execution.script import AbstractDaoTest -import dao.execution.batch.BatchExecutionDao -import dao.execution.batch.buildBatchExecutionCreationRequest -import dao.environment.EnvironmentDao import dao.environment.buildEnvironmentCreationRequest -import dao.module.ModuleDao +import dao.execution.batch.buildBatchExecutionCreationRequest import dao.module.buildModuleCreationRequest -import dao.project.ProjectDao import dao.project.buildProjectCreationRequest -import dao.script.ScriptDao import dao.script.buildScriptCreationRequest import dao.utils.toDto import execution.INITIAL_STATUS import execution.Status +import execution.script.ScriptExecutionSearchRequest +import execution.script.ScriptExecutionWithEnvironment import generated.domain.tables.pojos.DmScriptExecution import generated.domain.tables.references.DM_SCRIPT_EXECUTION import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import script.Script -import execution.script.ScriptExecutionSearchRequest import strikt.api.expectThat import strikt.assertions.* import java.time.OffsetDateTime @@ -39,6 +35,7 @@ internal class ScriptExecutionDaoTest : AbstractDaoTest() { private lateinit var batchExecutionRef1: UUID private lateinit var batchExecutionRef2: UUID private lateinit var projectId: UUID + private lateinit var environmentId: UUID private lateinit var moduleId: UUID private lateinit var script1: Script @@ -46,7 +43,7 @@ internal class ScriptExecutionDaoTest : AbstractDaoTest() { @JvmStatic fun insertNeededObjectsInDB() { projectId = projectDao.insert(buildProjectCreationRequest()).id - val environmentId = environmentDao.insert(buildEnvironmentCreationRequest(fkProjectRef = projectId)).id + environmentId = environmentDao.insert(buildEnvironmentCreationRequest(fkProjectRef = projectId)).id moduleId = moduleDao.insert(buildModuleCreationRequest(fkProjectRef = projectId)).id batchExecutionRef1 = batchExecutionDao.insert( buildBatchExecutionCreationRequest( @@ -587,4 +584,114 @@ internal class ScriptExecutionDaoTest : AbstractDaoTest() { } } + @Nested + inner class TestFindModuleScriptsExecutionsInformation { + @Test + fun `load all scripts executed at least once on any environment`() { + // Given + val environment1 = environmentDao.insert(buildEnvironmentCreationRequest(fkProjectRef = projectId)) + val environment2 = environmentDao.insert(buildEnvironmentCreationRequest(fkProjectRef = projectId)) + + val script1 = scriptDao.insert(buildScriptCreationRequest()) + val script2 = scriptDao.insert(buildScriptCreationRequest()) + + val batchExecution1 = batchExecutionDao.insert( + buildBatchExecutionCreationRequest( + fkEnvironmentRef = environment1.id, + fkModuleRef = moduleId + ) + ) + + val batchExecution2 = batchExecutionDao.insert( + buildBatchExecutionCreationRequest( + fkEnvironmentRef = environment2.id, + fkModuleRef = moduleId + ) + ) + scriptExecutionDao.insert( + buildScriptExecutionCreationRequest( + batchExecutionRef = batchExecution1.id, + scriptRef = script1.checksum + ) + ) + scriptExecutionDao.insert( + buildScriptExecutionCreationRequest( + batchExecutionRef = batchExecution2.id, + scriptRef = script2.checksum + ) + ) + + // When + val moduleScriptsExecutionsInformation = scriptExecutionDao.findModuleScriptsExecutionsInformation( + moduleRef = moduleId + ) + + // Then + expectThat(moduleScriptsExecutionsInformation).map { it.script } + .containsExactlyInAnyOrder( + script1, + script2 + ) + } + + @Test + fun `load all executions of one script`() { + // Given + val script1 = scriptDao.insert(buildScriptCreationRequest()) + + val batchExecution1 = batchExecutionDao.insert( + buildBatchExecutionCreationRequest( + fkEnvironmentRef = environmentId, + fkModuleRef = moduleId + ) + ) + + val batchExecution2 = batchExecutionDao.insert( + buildBatchExecutionCreationRequest( + fkEnvironmentRef = environmentId, + fkModuleRef = moduleId + ) + ) + + val scriptExecution1 = scriptExecutionDao.insert( + buildScriptExecutionCreationRequest( + batchExecutionRef = batchExecution1.id, + scriptRef = script1.checksum + ) + ) + val scriptExecution2 = scriptExecutionDao.insert( + buildScriptExecutionCreationRequest( + batchExecutionRef = batchExecution2.id, + scriptRef = script1.checksum + ) + ) + + // When + val moduleScriptsExecutionsInformation = scriptExecutionDao.findModuleScriptsExecutionsInformation( + moduleRef = moduleId + ) + + // Then + expectThat(moduleScriptsExecutionsInformation)[0].get { executions }.containsExactlyInAnyOrder( + ScriptExecutionWithEnvironment( + id = scriptExecution1.id, + startDate = scriptExecution1.startDate, + durationInMs = scriptExecution1.durationInMs, + executionOrderIndex = scriptExecution1.executionOrderIndex, + output = scriptExecution1.output, + status = scriptExecution1.status, + fkEnvironmentRef = environmentId + ), + ScriptExecutionWithEnvironment( + id = scriptExecution2.id, + startDate = scriptExecution2.startDate, + durationInMs = scriptExecution2.durationInMs, + executionOrderIndex = scriptExecution2.executionOrderIndex, + output = scriptExecution2.output, + status = scriptExecution2.status, + fkEnvironmentRef = environmentId + ) + ) + } + } } \ No newline at end of file diff --git a/modules/app-server/dao/src/test/kotlin/dao/script/ScriptBuilder.kt b/modules/app-server/dao/src/test/kotlin/dao/script/ScriptBuilder.kt index df0bbef9..646a48f4 100644 --- a/modules/app-server/dao/src/test/kotlin/dao/script/ScriptBuilder.kt +++ b/modules/app-server/dao/src/test/kotlin/dao/script/ScriptBuilder.kt @@ -1,9 +1,10 @@ package dao.script +import randomString import script.ScriptCreationRequest fun buildScriptCreationRequest( - name: String = "myName", - checksum: String = "checksum", - content: String = "content" + name: String = randomString(), + checksum: String = randomString(), + content: String = randomString() ) = ScriptCreationRequest(name = name, checksum = checksum, content = content) \ No newline at end of file diff --git a/modules/app-server/domain/src/main/kotlin/execution/script/ModuleScriptsExecutionsInformation.kt b/modules/app-server/domain/src/main/kotlin/execution/script/ModuleScriptsExecutionsInformation.kt new file mode 100644 index 00000000..0ca3cd37 --- /dev/null +++ b/modules/app-server/domain/src/main/kotlin/execution/script/ModuleScriptsExecutionsInformation.kt @@ -0,0 +1,27 @@ +package execution.script + +import environment.Environment +import execution.Status +import script.Script +import java.time.OffsetDateTime +import java.util.* + +data class ModuleScriptsExecutionsInformation( + val scriptsWithAllExecutions: List, + val environments: List +) + +data class ScriptExecutionWithEnvironment( + val id: UUID, + val startDate: OffsetDateTime?, + val durationInMs: Int?, + val executionOrderIndex: Int, + val output: String?, + val status: Status?, + val fkEnvironmentRef: UUID +) + +data class ScriptWithAllExecutions( + val script: Script, + val executions: List +) \ No newline at end of file diff --git a/modules/app-server/domain/src/main/kotlin/execution/script/ScriptExecutionDaoInterface.kt b/modules/app-server/domain/src/main/kotlin/execution/script/ScriptExecutionDaoInterface.kt index 1b671004..47e96d80 100644 --- a/modules/app-server/domain/src/main/kotlin/execution/script/ScriptExecutionDaoInterface.kt +++ b/modules/app-server/domain/src/main/kotlin/execution/script/ScriptExecutionDaoInterface.kt @@ -16,4 +16,5 @@ interface ScriptExecutionDaoInterface { fun findOneById(id: UUID): ScriptExecution? fun findOneDetailById(id: UUID): ScriptExecutionDetail? fun find(searchRequest: ScriptExecutionSearchRequest): List + fun findModuleScriptsExecutionsInformation(moduleRef: UUID): List } \ No newline at end of file diff --git a/modules/app-server/domain/src/main/kotlin/execution/script/ScriptExecutionService.kt b/modules/app-server/domain/src/main/kotlin/execution/script/ScriptExecutionService.kt index 33128595..bcea2e89 100644 --- a/modules/app-server/domain/src/main/kotlin/execution/script/ScriptExecutionService.kt +++ b/modules/app-server/domain/src/main/kotlin/execution/script/ScriptExecutionService.kt @@ -1,9 +1,11 @@ package execution.script +import environment.EnvironmentService import java.util.* class ScriptExecutionService( - private val scriptExecutionDao: ScriptExecutionDaoInterface + private val scriptExecutionDao: ScriptExecutionDaoInterface, + private val environmentService: EnvironmentService ) { fun insert(data: ScriptExecutionCreationRequest): ScriptExecution = scriptExecutionDao.insert(data) @@ -27,4 +29,11 @@ class ScriptExecutionService( fun findOneDetailById(id: UUID): ScriptExecutionDetail? = scriptExecutionDao.findOneDetailById(id) fun find(searchRequest: ScriptExecutionSearchRequest): List = scriptExecutionDao.find(searchRequest) + + fun findModuleScriptsExecutionsInformation(projectRef: UUID, moduleRef: UUID): ModuleScriptsExecutionsInformation { + return ModuleScriptsExecutionsInformation( + scriptExecutionDao.findModuleScriptsExecutionsInformation(moduleRef), + environmentService.findAllForProject(projectRef) + ) + } } \ No newline at end of file diff --git a/modules/app-server/rest/src/main/kotlin/rest/v1/route/execution/script/ScriptExecutionRoutesV1.kt b/modules/app-server/rest/src/main/kotlin/rest/v1/route/execution/script/ScriptExecutionRoutesV1.kt index 51782a7e..777c8ed2 100644 --- a/modules/app-server/rest/src/main/kotlin/rest/v1/route/execution/script/ScriptExecutionRoutesV1.kt +++ b/modules/app-server/rest/src/main/kotlin/rest/v1/route/execution/script/ScriptExecutionRoutesV1.kt @@ -6,12 +6,17 @@ import io.ktor.server.routing.* import rest.v1.route.execution.script.dto.toDtoV1 import execution.script.ScriptExecutionSearchRequest import execution.script.ScriptExecutionService +import rest.v1.route.execution.script.dto.toScriptEnvMatrixDtoV1 import rest.v1.route.execution.status import java.util.UUID private const val scriptExecutionId = "scriptExecutionId" +private const val moduleRef = "moduleRef" +private const val projectRef = "projectRef" private fun ApplicationCall.scriptExecutionId() = UUID.fromString(this.parameters[scriptExecutionId]) +private fun ApplicationCall.moduleRef() = UUID.fromString(this.parameters[moduleRef]) +private fun ApplicationCall.projectRef() = UUID.fromString(this.parameters[projectRef]) private fun ApplicationCall.batchExecutionRef() = parameters["batchExecutionRef"]?.let { UUID.fromString(it) } internal fun Route.scriptExecutionV1Routes(scriptExecutionService: ScriptExecutionService) { @@ -29,5 +34,12 @@ internal fun Route.scriptExecutionV1Routes(scriptExecutionService: ScriptExecuti get("/{$scriptExecutionId}") { call.respondNullable(call.scriptExecutionId()?.let { scriptExecutionService.findOneDetailById(it)?.toDtoV1() }) } + + get("/projects/{$projectRef}/modules/{$moduleRef}") { + call.respondNullable(scriptExecutionService.findModuleScriptsExecutionsInformation( + call.projectRef(), + call.moduleRef() + ).toScriptEnvMatrixDtoV1()) + } } } \ No newline at end of file diff --git a/modules/app-server/rest/src/main/kotlin/rest/v1/route/execution/script/dto/ScriptEnvMatrixDtoV1.kt b/modules/app-server/rest/src/main/kotlin/rest/v1/route/execution/script/dto/ScriptEnvMatrixDtoV1.kt new file mode 100644 index 00000000..01b369f3 --- /dev/null +++ b/modules/app-server/rest/src/main/kotlin/rest/v1/route/execution/script/dto/ScriptEnvMatrixDtoV1.kt @@ -0,0 +1,67 @@ +package rest.v1.route.execution.script.dto + +import environment.Environment +import execution.script.ModuleScriptsExecutionsInformation +import execution.script.ScriptWithAllExecutions +import kotlinx.serialization.Serializable +import rest.InstantSerializer +import rest.UUIDSerializer +import rest.v1.route.environment.EnvironmentDtoV1 +import rest.v1.route.environment.toDtoV1 +import java.time.Instant +import java.util.UUID + +@Serializable +data class ScriptEnvMatrixDtoV1( + val entries: List, + val envs: List +) + +fun ModuleScriptsExecutionsInformation.toScriptEnvMatrixDtoV1() = ScriptEnvMatrixDtoV1( + entries = this.scriptsWithAllExecutions.map{ scriptWithAllExecutions -> scriptWithAllExecutions.toScriptEnvEntryDtoV1( + environments.associateBy { it.id } + ) }, + envs = this.environments.map { it.toDtoV1() } +) + +fun ScriptWithAllExecutions.toScriptEnvEntryDtoV1(envsMaps: Map): ScriptEnvEntryDtoV1 { + return ScriptEnvEntryDtoV1( + scriptId = script.checksum, + scriptName = script.name, + envs = this.executions.map { + EnvExecutedScriptEntryDtoV1( + envId = it.fkEnvironmentRef, + execution = ScriptExecutionMetadataDtoV1( + executionId = it.id, + executionDate = it.startDate?.toInstant(), + duration = it.durationInMs?.toLong(), + scriptID = this.script.checksum + ) + ) + } + ) +} + +@Serializable +data class ScriptEnvEntryDtoV1( + val scriptId: String, + val scriptName: String, + val envs: List +) + +@Serializable +data class EnvExecutedScriptEntryDtoV1( + @Serializable(with = UUIDSerializer::class) + val envId: UUID, + val execution : ScriptExecutionMetadataDtoV1 +) + +@Serializable +data class ScriptExecutionMetadataDtoV1( + @Serializable(with = UUIDSerializer::class) + val executionId: UUID, + @Serializable(with = InstantSerializer::class) + val executionDate: Instant?, + val duration: Long?, + val scriptID: String +) \ No newline at end of file diff --git a/modules/ui/package.json b/modules/ui/package.json index 41bf4d12..9b4aafbb 100644 --- a/modules/ui/package.json +++ b/modules/ui/package.json @@ -41,7 +41,9 @@ "type": "module", "dependencies": { "@fontsource/fira-mono": "4.5.0", + "class-transformer": "^0.5.1", "cookie": "0.4.1", + "reflect-metadata": "^0.2.2", "svelte-tooltip-simple": "^1.0.3", "sveltekit-i18n": "2.4.2", "svrollbar": "^0.12.0" diff --git a/modules/ui/src/app.d.ts b/modules/ui/src/app.d.ts index 9ca010a6..6739bc48 100644 --- a/modules/ui/src/app.d.ts +++ b/modules/ui/src/app.d.ts @@ -3,6 +3,7 @@ // See https://kit.svelte.dev/docs/types#app // for information about these interfaces // and what to do when importing types + declare namespace App { interface Locals { userid: string; diff --git a/modules/ui/src/app.html b/modules/ui/src/app.html index a06d92d5..3e0853bd 100644 --- a/modules/ui/src/app.html +++ b/modules/ui/src/app.html @@ -10,6 +10,7 @@ + %sveltekit.body% diff --git a/modules/ui/src/lib/components/organisms/O_matrix/O_matrixScriptEnv.svelte b/modules/ui/src/lib/components/organisms/O_matrix/O_matrixScriptEnv.svelte index 6de27c4b..ae98520e 100644 --- a/modules/ui/src/lib/components/organisms/O_matrix/O_matrixScriptEnv.svelte +++ b/modules/ui/src/lib/components/organisms/O_matrix/O_matrixScriptEnv.svelte @@ -1,5 +1,5 @@ diff --git a/modules/ui/src/lib/components/organisms/O_project/O_projectEdition.svelte b/modules/ui/src/lib/components/organisms/O_project/O_projectEdition.svelte index 222addc8..c0d195ff 100644 --- a/modules/ui/src/lib/components/organisms/O_project/O_projectEdition.svelte +++ b/modules/ui/src/lib/components/organisms/O_project/O_projectEdition.svelte @@ -18,7 +18,7 @@
- + diff --git a/modules/ui/src/lib/domain/ScriptExecutionMetadata.ts b/modules/ui/src/lib/domain/ScriptExecutionMetadata.ts index ad2f61a6..ec98afcd 100644 --- a/modules/ui/src/lib/domain/ScriptExecutionMetadata.ts +++ b/modules/ui/src/lib/domain/ScriptExecutionMetadata.ts @@ -1,5 +1,9 @@ +import {Type} from 'class-transformer'; +import 'reflect-metadata'; + export class ScriptExecutionMetadata { executionId: string + @Type(() => Date) executionDate: Date duration: number scriptId: string | null = null diff --git a/modules/ui/src/lib/domain/script/ScriptEnvMatrix.ts b/modules/ui/src/lib/domain/script/ScriptEnvMatrix.ts index aa4451d4..aa9e2d16 100644 --- a/modules/ui/src/lib/domain/script/ScriptEnvMatrix.ts +++ b/modules/ui/src/lib/domain/script/ScriptEnvMatrix.ts @@ -1,8 +1,10 @@ import type {Env} from "../Env"; -import type {ScriptExecutionMetadata} from "../ScriptExecutionMetadata"; - +import {ScriptExecutionMetadata} from "../ScriptExecutionMetadata"; +import {Type} from 'class-transformer'; +import 'reflect-metadata'; export class ScriptEnvMatrix { + @Type(() => ScriptEnvEntry) entries: ScriptEnvEntry[] envs: Env[] @@ -20,6 +22,7 @@ export class ScriptEnvMatrix { export class ScriptEnvEntry { scriptId: string scriptName: string + @Type(() => EnvExecutedScriptEntry) envs: EnvExecutedScriptEntry[] constructor(scriptId: string, scriptName: string) { @@ -40,6 +43,7 @@ export class ScriptEnvEntry { export class EnvExecutedScriptEntry { envId: string + @Type(() => ScriptExecutionMetadata) execution : ScriptExecutionMetadata constructor(envId: string, envName: string, execution: ScriptExecutionMetadata) { diff --git a/modules/ui/src/lib/services/ExecutionService.ts b/modules/ui/src/lib/services/ExecutionService.ts index f0b28e1a..194fcc26 100644 --- a/modules/ui/src/lib/services/ExecutionService.ts +++ b/modules/ui/src/lib/services/ExecutionService.ts @@ -1,5 +1,7 @@ import type {Execution, ExecutionForDashboard, ExecutionWithReport} from "$lib/domain/execution/Execution"; import {ExecutionMock} from "$lib/mocks/ExecutionMock"; +import {ScriptEnvMatrix} from '$lib/domain/script/ScriptEnvMatrix'; +import {plainToInstance} from 'class-transformer' export type ExecutionSearchRequest= {}; @@ -22,4 +24,9 @@ export class ExecutionService { .find(execution => execution.id === id)); }); } + + public static async scriptEnvMatrixByProjectAndModule(projectId: string, moduleId: string): Promise { + const res = await fetch(`/api/v1/scriptExecutions/projects/${projectId}/modules/${moduleId}`); + return plainToInstance(ScriptEnvMatrix, (await res.json()) as string) + } } diff --git a/modules/ui/src/routes/projects/[project]/modules/[module]/+page.svelte b/modules/ui/src/routes/projects/[project]/modules/[module]/+page.svelte index 31e56e0c..1e7fa7d7 100644 --- a/modules/ui/src/routes/projects/[project]/modules/[module]/+page.svelte +++ b/modules/ui/src/routes/projects/[project]/modules/[module]/+page.svelte @@ -9,11 +9,16 @@ import {ModuleEnvironmentTokenService} from '$lib/services/ModuleEnvironmentTokenService'; import type {ModuleEnvironmentToken} from '$lib/domain/ModuleEnvironmentToken'; import A_button from '$lib/components/atoms/A_button.svelte'; + import {ExecutionService} from '$lib/services/ExecutionService'; + import type {ScriptEnvMatrix} from '$lib/domain/script/ScriptEnvMatrix'; + import type {Project} from '$lib/domain/Project'; + import type {Env} from '$lib/domain/Env'; + import type {Module} from '$lib/domain/Module'; - let project - let env - let modulePromise - let scriptEnvMatrix + let project: Project + let env: Env + let modulePromise: Promise + let scriptEnvMatrix: ScriptEnvMatrix let moduleEnvironmentTokenPromise: Promise $: if($page.params?.project) { @@ -41,8 +46,9 @@ ) } - $: if (project) { - scriptEnvMatrix = ExecutionMock.scriptEnvMatrixByProject(project.id) + $: if (project && moduleRef) { + ExecutionService.scriptEnvMatrixByProjectAndModule(project.id, moduleRef) + .then(res => scriptEnvMatrix = res); } export function regenerateToken() { diff --git a/modules/ui/src/routes/projects/[project]/modules/[module]/edit/+page.svelte b/modules/ui/src/routes/projects/[project]/modules/[module]/edit/+page.svelte index f1f47930..503df738 100644 --- a/modules/ui/src/routes/projects/[project]/modules/[module]/edit/+page.svelte +++ b/modules/ui/src/routes/projects/[project]/modules/[module]/edit/+page.svelte @@ -7,6 +7,7 @@ import M_error from "$lib/components/molecules/M_error.svelte"; import {t} from "$lib/services/I18nService"; import O_moduleEdition from "$lib/components/organisms/O_module/O_moduleEdition.svelte"; + import {ExecutionService} from '$lib/services/ExecutionService'; let project let env @@ -27,11 +28,14 @@ $: if($page.params?.module) { modulePromise = ModuleService.byId($page.params.module); + } - $: if (project) { - scriptEnvMatrix = ExecutionMock.scriptEnvMatrixByProject(project.id) + $: if ($page.params?.module && project) { + ExecutionService.scriptEnvMatrixByProjectAndModule(project.id, $page.params?.module) + .then(res => scriptEnvMatrix = res); } + {#await modulePromise} diff --git a/modules/ui/tsconfig.json b/modules/ui/tsconfig.json index 0f47472f..d3524ce2 100644 --- a/modules/ui/tsconfig.json +++ b/modules/ui/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "./.svelte-kit/tsconfig.json", "compilerOptions": { + "experimentalDecorators": true, "allowJs": true, "checkJs": true, "esModuleInterop": true, diff --git a/modules/ui/yarn.lock b/modules/ui/yarn.lock index 0c54e287..a5aa44d5 100644 --- a/modules/ui/yarn.lock +++ b/modules/ui/yarn.lock @@ -1022,6 +1022,11 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== +class-transformer@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -3002,6 +3007,11 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +reflect-metadata@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== + regexparam@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.1.tgz#c912f5dae371e3798100b3c9ce22b7414d0889fa"