Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make overview template more robust #811

Merged
merged 1 commit into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 27 additions & 10 deletions backend/src/main/kotlin/hu/bme/sch/cmsch/admin/GenerateOverview.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,33 @@ fun GenerateOverview.sorter(): String {
}
}

fun GenerateOverview.extra(): String {
fun GenerateOverview.formatValue(value: Any?): Any =
if (renderer == OVERVIEW_TYPE_CDN_IMAGE) {
if (value is String && value.isNotBlank())
"/cdn/${cdnImageFolder}/${value}"
else
"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" // empty image
} else if (renderer == OVERVIEW_TYPE_TEXT || renderer == OVERVIEW_TYPE_ICON) {
value ?: ""
} else {
value ?: 0
}

fun GenerateOverview.extra(): Array<Pair<String, Any>> {
return when (this.renderer) {
OVERVIEW_TYPE_ID -> ", \"width\":100, \"vertAlign\":\"middle\", \"visible\":false"
OVERVIEW_TYPE_TEXT -> ", \"vertAlign\":\"middle\""
OVERVIEW_TYPE_DATE -> ", \"vertAlign\":\"middle\",\"formatter\":\"datetime\""
OVERVIEW_TYPE_BOOLEAN -> ", \"formatter\":\"tickCross\", \"width\":120"
OVERVIEW_TYPE_CDN_IMAGE -> ", \"formatter\":\"image\", \"width\":120, \"formatterParams\":{\"height\":\"100px\"}"
OVERVIEW_TYPE_TIME -> ", \"vertAlign\":\"middle\""
OVERVIEW_TYPE_NUMBER -> ", \"vertAlign\":\"middle\""
OVERVIEW_TYPE_ICON -> ", \"vertAlign\":\"middle\", \"formatter\":\"enumIconsFormatter\", \"width\":120"
else -> ""
OVERVIEW_TYPE_ID -> arrayOf("width" to 100, "vertAlign" to "middle", "visible" to false)
OVERVIEW_TYPE_TEXT -> arrayOf("vertAlign" to "middle")
OVERVIEW_TYPE_DATE -> arrayOf("vertAlign" to "middle", "formatter" to "datetime")
OVERVIEW_TYPE_BOOLEAN -> arrayOf("formatter" to "tickCross", "width" to 120)
OVERVIEW_TYPE_CDN_IMAGE -> arrayOf(
"formatter" to "image",
"width" to 120,
"formatterParams" to mapOf("height" to "100px")
)

OVERVIEW_TYPE_TIME -> arrayOf("vertAlign" to "middle")
OVERVIEW_TYPE_NUMBER -> arrayOf("vertAlign" to "middle")
OVERVIEW_TYPE_ICON -> arrayOf("vertAlign" to "middle", "formatter" to "enumIconsFormatter", "width" to 120)
else -> emptyArray()
}
}
68 changes: 22 additions & 46 deletions backend/src/main/kotlin/hu/bme/sch/cmsch/admin/OverviewBuilder.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package hu.bme.sch.cmsch.admin

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import hu.bme.sch.cmsch.controller.admin.ControlAction
import java.io.ByteArrayOutputStream
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1
Expand All @@ -15,65 +12,44 @@ class OverviewBuilder<T : Any>(val type: KClass<T>) {

private fun getColumnDefinitions(): List<Pair<KProperty1<T, *>, GenerateOverview>> {
return type.memberProperties.asSequence()
.filter { it.findAnnotation<GenerateOverview>() != null }
.map { Pair(it, it.findAnnotation<GenerateOverview>()!!) }
.filter { it.second.visible }
.sortedBy { it.second.order }
.toList()
.filter { it.findAnnotation<GenerateOverview>() != null }
.map { Pair(it, it.findAnnotation<GenerateOverview>()!!) }
.filter { it.second.visible }
.sortedBy { it.second.order }
.toList()
}

fun getColumnsAsJson(): String {
return "[" + (getColumnDefinitions().joinToString(",") {
"{\"title\":\"${it.second.columnName}\", " +
"\"field\":\"${it.first.name}\", " +
"\"hozAlign\":\"${it.second.alignment()}\", " +
"\"sorter\":\"${it.second.sorter()}\"" +
it.second.extra() +
"}"
}) + "]"
fun getColumns(): List<Map<String, Any>> = getColumnDefinitions().map {
mapOf(
"title" to it.second.columnName,
"field" to it.first.name,
"hozAlign" to it.second.alignment(),
"sorter" to it.second.sorter(),
*it.second.extra()
)
}

private fun formatValue(type: GenerateOverview, value: Any?): String {
return if (type.renderer == OVERVIEW_TYPE_CDN_IMAGE) {
if (value is String && !value.isNullOrBlank())
"\"/cdn/${type.cdnImageFolder}/${value}\""
else
"\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\"" // empty image
} else if (type.renderer == OVERVIEW_TYPE_TEXT || type.renderer == OVERVIEW_TYPE_ICON) {
"\"${(value ?: "").toString().replace("\"", "")}\""
} else {
(value ?: "0").toString().replace("\"", "")
}
}

fun getTableDataAsJson(overview: Iterable<T>): String {
fun getTableData(overview: Iterable<T>): List<Map<String, Any>> {
val fields = getColumnDefinitions()
return "[" + (overview.toList()
.map { row -> fields.map { "\"${it.first.name}\":${formatValue(it.second, it.first.get(row))}" } }
.joinToString(",") { row -> "{${row.joinToString(",")}}" }) + "]"
return overview.map { row ->
fields.map { it.first.name to it.second.formatValue(it.first.get(row)) }.toMap()
}
}

fun getInputs(): List<Pair<KProperty1<out Any, *>, GenerateInput>> {
return type.memberProperties.asSequence()
.filter { it.findAnnotation<GenerateInput>() != null }
.map { Pair(it, it.findAnnotation<GenerateInput>()!!) }
.filter { it.second.visible }
.sortedBy { it.second.order }
.toList()
.filter { it.findAnnotation<GenerateInput>() != null }
.map { Pair(it, it.findAnnotation<GenerateInput>()!!) }
.filter { it.second.visible }
.sortedBy { it.second.order }
.toList()
}

fun exportToCsv(entities: List<T>): String {
val outputStream = ByteArrayOutputStream()
csv.exportToCsv(entities, outputStream)
return outputStream.toString().trim()
}

fun toJson(list: List<ControlAction>, objectMapper: ObjectMapper): String {
return objectMapper
.writerFor(object : TypeReference<List<ControlAction>>() {})
.writeValueAsString(list)
}

}

object DetailsHelper {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,11 @@ class MenuAdminController(
model.addAttribute("description", description)
model.addAttribute("view", view)

model.addAttribute("columnData", overviewDescriptor.getColumnsAsJson())
model.addAttribute("tableData", overviewDescriptor.getTableDataAsJson(fetchOverview()))
model.addAttribute("columnData", overviewDescriptor.getColumns())
model.addAttribute("tableData", overviewDescriptor.getTableData(fetchOverview()))

model.addAttribute("user", user)
model.addAttribute("controlActions", overviewDescriptor.toJson(
controlActions.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", controlActions.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", controlActions)
model.addAttribute("buttonActions", buttonActions)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,14 @@ class TaskAdminRateController(
model.addAttribute("titleSingular", titleSingular)
model.addAttribute("view", view)

model.addAttribute("columnData", descriptor.getColumnsAsJson())
model.addAttribute("columnData", descriptor.getColumns())
val submissions = transactionManager.transaction(readOnly = true) {
submittedRepository.findByTask_IdAndRejectedIsFalseAndApprovedIsFalseWithoutLobs(id)
}
model.addAttribute("tableData", descriptor.getTableDataAsJson(submissions))
model.addAttribute("tableData", descriptor.getTableData(submissions))

model.addAttribute("user", user)
model.addAttribute("controlActions", descriptor.toJson(
rateControlActions.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", rateControlActions.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", rateControlActions)
model.addAttribute("buttonActions", buttonActions.filter { it.permission.validate(user) })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,11 @@ class FilesByViewController(
model.addAttribute("description", description)
model.addAttribute("view", view)

model.addAttribute("columnData", overviewDescriptor.getColumnsAsJson())
model.addAttribute("tableData", overviewDescriptor.getTableDataAsJson(fetchOverview()))
model.addAttribute("columnData", overviewDescriptor.getColumns())
model.addAttribute("tableData", overviewDescriptor.getTableData(fetchOverview()))

model.addAttribute("user", user)
model.addAttribute("controlActions", overviewDescriptor.toJson(
controlActions.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", controlActions.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", controlActions)
model.addAttribute("buttonActions", listOf<ButtonAction>())

Expand Down Expand Up @@ -126,8 +124,8 @@ class FilesByViewController(
model.addAttribute("description", description)
model.addAttribute("view", view)

model.addAttribute("columnData", submittedDescriptor.getColumnsAsJson())
model.addAttribute("tableData", submittedDescriptor.getTableDataAsJson(listFilesInView(id)))
model.addAttribute("columnData", submittedDescriptor.getColumns())
model.addAttribute("tableData", submittedDescriptor.getTableData(listFilesInView(id)))

model.addAttribute("user", user)
val controlActionForCategory = listOf(
Expand All @@ -152,9 +150,7 @@ class FilesByViewController(
basic = true
)
)
model.addAttribute("controlActions", overviewDescriptor.toJson(
controlActionForCategory.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", controlActionForCategory.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", controlActionForCategory)
model.addAttribute("buttonActions", listOf<ButtonAction>())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,14 +283,12 @@ open class OneDeepEntityPage<T : IdentifiableEntity>(
model.addAttribute("description", description)
model.addAttribute("view", view)

model.addAttribute("columnData", descriptor.getColumnsAsJson())
model.addAttribute("columnData", descriptor.getColumns())
val overview = transactionManager.transaction(readOnly = true) { fetchOverview(user) }
model.addAttribute("tableData", descriptor.getTableDataAsJson(filterOverview(user, overview)))
model.addAttribute("tableData", descriptor.getTableData(filterOverview(user, overview)))

model.addAttribute("user", user)
model.addAttribute("controlActions", descriptor.toJson(
controlActions.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", controlActions.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", controlActions)
model.addAttribute("buttonActions", buttonActions.filter { it.permission.validate(user) })
model.addAttribute("searchSettings", searchSettings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,12 @@ abstract class TwoDeepEntityPage<OUTER : IdentifiableEntity, INNER: Identifiable
model.addAttribute("description", description)
model.addAttribute("view", view)

model.addAttribute("columnData", outerDescriptor.getColumnsAsJson())
model.addAttribute("columnData", outerDescriptor.getColumns())
val overview = transactionManager.transaction(readOnly = true) { fetchOuterOverview() }
model.addAttribute("tableData", outerDescriptor.getTableDataAsJson(overview))
model.addAttribute("tableData", outerDescriptor.getTableData(overview))

model.addAttribute("user", user)
model.addAttribute("controlActions", outerDescriptor.toJson(
outerControlActions.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", outerControlActions.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", outerControlActions)
model.addAttribute("buttonActions", buttonActions.filter { it.permission.validate(user) })

Expand Down Expand Up @@ -174,14 +172,12 @@ abstract class TwoDeepEntityPage<OUTER : IdentifiableEntity, INNER: Identifiable
model.addAttribute("description", description)
model.addAttribute("view", view)

model.addAttribute("columnData", descriptor.getColumnsAsJson())
model.addAttribute("columnData", descriptor.getColumns())
val overview = transactionManager.transaction(readOnly = true) { filterOverview(user, fetchSublist(id)) }
model.addAttribute("tableData", descriptor.getTableDataAsJson(overview))
model.addAttribute("tableData", descriptor.getTableData(overview))

model.addAttribute("user", user)
model.addAttribute("controlActions", descriptor.toJson(
controlActions.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", controlActions.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", controlActions)
model.addAttribute("buttonActions", buttonActions.filter { it.permission.validate(user) })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,11 @@ class AuditLogController(
model.addAttribute("description", description)
model.addAttribute("view", view)

model.addAttribute("columnData", descriptor.getColumnsAsJson())
model.addAttribute("tableData", descriptor.getTableDataAsJson(listFilesInView()))
model.addAttribute("columnData", descriptor.getColumns())
model.addAttribute("tableData", descriptor.getTableData(listFilesInView()))

model.addAttribute("user", user)
model.addAttribute("controlActions", descriptor.toJson(
controlActions.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", controlActions.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", controlActions)
model.addAttribute("buttonActions", listOf<ButtonAction>())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class PermissionGroupAssignPage(
model.addAttribute("description", "Válassz, hogy melyik felhasználó kapja meg a(z) ${permissionGroup.displayName} jogkört")
model.addAttribute("view", view)

model.addAttribute("columnData", descriptor.getColumnsAsJson())
model.addAttribute("columnData", descriptor.getColumns())
val overview = transactionManager.transaction(readOnly = true) {
userRepository.findAll()
.filter { permissionGroup.key.isNotEmpty() && !it.permissionGroups.split(",").contains(permissionGroup.key) }
Expand All @@ -143,12 +143,10 @@ class PermissionGroupAssignPage(
)
}
}
model.addAttribute("tableData", descriptor.getTableDataAsJson(filterOverview(user, overview)))
model.addAttribute("tableData", descriptor.getTableData(filterOverview(user, overview)))

model.addAttribute("user", user)
model.addAttribute("controlActions", descriptor.toJson(
controlActionsForView.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", controlActionsForView.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", controlActionsForView)
model.addAttribute("buttonActions", buttonActionsForView.filter { it.permission.validate(user) })
model.addAttribute("searchSettings", searchSettings)
Expand Down Expand Up @@ -188,4 +186,3 @@ class PermissionGroupAssignPage(
fun redirectToUsersView(@PathVariable id: Int) = "redirect:/admin/control/permission-groups-for-users/${id}"

}

Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class PermissionGroupUserListPage(
model.addAttribute("description", description)
model.addAttribute("view", view)

model.addAttribute("columnData", descriptor.getColumnsAsJson())
model.addAttribute("columnData", descriptor.getColumns())
val overview = transactionManager.transaction(readOnly = true) {
userRepository.findAllByPermissionGroupsNot("")
.filter { permissionGroup.key.isNotEmpty() && it.permissionGroups.split(",").contains(permissionGroup.key) }
Expand All @@ -154,12 +154,10 @@ class PermissionGroupUserListPage(
)
}
}
model.addAttribute("tableData", descriptor.getTableDataAsJson(filterOverview(user, overview)))
model.addAttribute("tableData", descriptor.getTableData(filterOverview(user, overview)))

model.addAttribute("user", user)
model.addAttribute("controlActions", descriptor.toJson(
controlActionsForView.filter { it.permission.validate(user) },
objectMapper))
model.addAttribute("controlActions", controlActionsForView.filter { it.permission.validate(user) })
model.addAttribute("allControlActions", controlActionsForView)
model.addAttribute("buttonActions", buttonActionsForView.filter { it.permission.validate(user) })
model.addAttribute("searchSettings", searchSettings)
Expand Down Expand Up @@ -201,4 +199,3 @@ class PermissionGroupUserListPage(
fun redirectToUsersView() = "redirect:/admin/control/permission-groups"

}

6 changes: 3 additions & 3 deletions backend/src/main/resources/templates/overview4.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ <h5 th:text="${action.usageString}">Usage text</h5>
return dt.toFormat("yyyy-MM-dd HH:mm");
}

const buttons = JSON.parse(/*[[${controlActions}]]*/ "[]");
let tableData = JSON.parse(/*[[${tableData}]]*/ "[]");
const buttons = /*[[${controlActions}]]*/ [];
let tableData = /*[[${tableData}]]*/ [];
let view = /*[[${view}]]*/ "";
for (let rowId in tableData) {
const row = tableData[rowId];
Expand Down Expand Up @@ -140,7 +140,7 @@ <h5 th:text="${action.usageString}">Usage text</h5>
return enumElementMap[value] || "";
}

let columData = JSON.parse(/*[[${columnData}]]*/ "[]");
let columData = /*[[${columnData}]]*/ [];
for (let columnId in columData) {
if (columData[columnId].formatter === 'tickCross') {
columData[columnId]['formatterParams'] = {
Expand Down
Loading