Skip to content

Commit

Permalink
Refactoring vulnerability view to move header menu to the separate fi…
Browse files Browse the repository at this point in the history
…le (#2527)

- Just simple refactoring: moved a block of of code to a separate FC
- Also fixed links to /vuln/collection on some pages
  • Loading branch information
orchestr7 authored Sep 2, 2023
1 parent 22239f2 commit 44860b3
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 201 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ private val vulnerabilityTable: FC<TableProps<VulnerabilityDto>> = tableComponen
Fragment.create {
td {
Link {
to = "/${FrontendRoutes.VULN}/${cellContext.row.original.identifier}"
to = "/${FrontendRoutes.VULNERABILITY_SINGLE}/${cellContext.row.original.identifier}"
+cellContext.value
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ val renderVulnerabilityTableForProfileView: FC<UserProfileVulnerabilitiesTabProp
Fragment.create {
td {
Link {
to = "/${FrontendRoutes.VULN}/${cellContext.row.original.identifier}"
to = "/${FrontendRoutes.VULNERABILITY_SINGLE}/${cellContext.row.original.identifier}"
+cellContext.value
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
/**
* Review and administration buttons on the vulnerability view
*/

@file:Suppress("FILE_NAME_MATCH_CLASS")

package com.saveourtool.save.frontend.components.views.vuln

import com.saveourtool.save.entities.CommentDto
import com.saveourtool.save.entities.vulnerability.VulnerabilityDto
import com.saveourtool.save.entities.vulnerability.VulnerabilityStatus
import com.saveourtool.save.frontend.components.inputform.InputTypes
import com.saveourtool.save.frontend.components.modal.displayModal
import com.saveourtool.save.frontend.components.modal.mediumTransparentModalStyle
import com.saveourtool.save.frontend.components.views.contests.tab
import com.saveourtool.save.frontend.externals.fontawesome.faImage
import com.saveourtool.save.frontend.externals.fontawesome.faPlus
import com.saveourtool.save.frontend.externals.fontawesome.faTable
import com.saveourtool.save.frontend.externals.fontawesome.faTrash
import com.saveourtool.save.frontend.utils.*
import com.saveourtool.save.frontend.utils.isSuperAdmin
import com.saveourtool.save.info.UserInfo
import com.saveourtool.save.validation.FrontendRoutes

import js.core.jso
import react.FC
import react.Props
import react.StateSetter
import react.dom.aria.ariaDescribedBy
import react.dom.html.ReactHTML.div
import react.dom.html.ReactHTML.h6
import react.dom.html.ReactHTML.textarea
import react.router.useNavigate
import react.useState
import web.cssom.ClassName
import web.cssom.Height

import kotlinx.browser.window
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

internal val headerMenu: FC<HeaderMenuProps> = FC { props ->
val rejectVulnerabilityWindowOpenness = useWindowOpenness()
val navigate = useNavigate()
val (rejectComment, setRejectComment) = useState(CommentDto.empty)
val deleteVulnerabilityWindowOpenness = useWindowOpenness()

// ======================= requests ================================================================================

val enrollUpdateRequest = useDeferredRequest {
val vulnerabilityUpdate = props.vulnerability.copy(status = VulnerabilityStatus.APPROVED)
val response = post(
url = "$apiUrl/vulnerabilities/approve",
headers = jsonHeaders,
body = Json.encodeToString(vulnerabilityUpdate),
loadingHandler = ::loadingHandler,
)
if (response.ok) {
navigate(to = "/${FrontendRoutes.VULNERABILITIES}")
}
}

val enrollRejectRequest = useDeferredRequest {
if (rejectComment.message.isNotEmpty()) {
val commentNew = rejectComment.copy(section = window.location.pathname)
post(
url = "$apiUrl/comments/save",
headers = jsonHeaders,
body = Json.encodeToString(commentNew),
loadingHandler = ::loadingHandler,
responseHandler = ::noopResponseHandler,
)
}

val vulnerabilityUpdate = props.vulnerability.copy(status = VulnerabilityStatus.REJECTED)
val response = post(
url = "$apiUrl/vulnerabilities/reject",
headers = jsonHeaders,
body = Json.encodeToString(vulnerabilityUpdate),
loadingHandler = ::loadingHandler,
)
if (response.ok) {
navigate(to = "/${FrontendRoutes.VULNERABILITIES}")
}
}

val enrollDeleteRequest = useDeferredRequest {
val response = delete(
url = "$apiUrl/vulnerabilities/delete?identifier=${props.vulnerability.identifier}",
headers = jsonHeaders,
loadingHandler = ::loadingHandler,
)
if (response.ok) {
navigate(to = "/${FrontendRoutes.VULNERABILITIES}")
}
}

// ======================= modals ==================================================================================

displayModal(
deleteVulnerabilityWindowOpenness.isOpen(),
"Deletion of vulnerability",
"Are you sure you want to remove this vulnerability?",
mediumTransparentModalStyle,
deleteVulnerabilityWindowOpenness.closeWindowAction(),
) {
buttonBuilder("Ok") {
enrollDeleteRequest()
deleteVulnerabilityWindowOpenness.closeWindow()
}
buttonBuilder("Close", "secondary") {
deleteVulnerabilityWindowOpenness.closeWindow()
}
}

displayModal(
rejectVulnerabilityWindowOpenness.isOpen(),
"Reject of vulnerability",
bodyBuilder = {
div {
h6 {
className = ClassName("modal-title")
+"Are you sure you want to reject this vulnerability?"
}
textarea {
className = ClassName("border-secondary form-control p-3 border-1")
onChange = { event -> setRejectComment { it.copy(message = event.target.value) } }
value = rejectComment.message
ariaDescribedBy = "${InputTypes.COMMENT.name}Span"
rows = 5
id = InputTypes.COMMENT.name
required = true
placeholder = "Write a comment"
}
}
},
modalStyle = mediumTransparentModalStyle,
onCloseButtonPressed = rejectVulnerabilityWindowOpenness.closeWindowAction(),
) {
buttonBuilder("Ok") {
enrollRejectRequest()
rejectVulnerabilityWindowOpenness.closeWindow()
}
buttonBuilder("Close", "secondary") {
rejectVulnerabilityWindowOpenness.closeWindow()
}
}

// ======================= rendering ===============================================================================

div {
className = ClassName("col-3 mr-3")
vulnerabilityBadge {
this.vulnerability = props.vulnerability
}
}
div {
className = ClassName("col-6")
div {
className = ClassName("card shadow")
style = jso {
height = HEADER_HEIGHT.unsafeCast<Height>()
}
tab(
props.selectedMenu.name,
VulnerabilityTab.values().map { it.name },
"nav nav-tabs mt-3"
) { value -> props.setSelectedMenu { VulnerabilityTab.valueOf(value) } }

val isAbleToEdit =
props.currentUserInfo.isSuperAdmin() || props.currentUserInfo in props.vulnerability.getAllParticipants()

// separate it to button menu
div {
className = ClassName("row justify-content-center mt-3")
div {
className = ClassName("d-flex justify-content-end my-2")
if (props.selectedMenu == VulnerabilityTab.INFO) {
if (isAbleToEdit) {
buttonBuilder(
faPlus,
classes = "mr-2",
isOutline = true,
title = "Add more info"
) {
props.addProjectWindowOpenness.openWindow()
}
}

buttonBuilder(
if (props.isTableView) faImage else faTable,
"secondary",
classes = "mr-2",
isOutline = true,
title = "Change to ${if (props.isTableView) "card" else "table"} mode"
) {
props.setIsTableView { !it }
}
}

if (props.permissions.isSuperAdmin ||
(props.permissions.isOwner && props.vulnerability.status != VulnerabilityStatus.APPROVED)
) {
buttonBuilder(
faTrash,
"danger",
isOutline = true,
title = "Delete vulnerability",
classes = "mr-2"
) {
deleteVulnerabilityWindowOpenness.openWindow()
}
}

if (props.permissions.isSuperAdmin && props.vulnerability.status != VulnerabilityStatus.APPROVED) {
buttonBuilder(label = "Approve", classes = "mr-2 btn-sm", style = "success") {
enrollUpdateRequest()
}
buttonBuilder(label = "Reject", classes = "mr-2 btn-sm", style = "warning") {
rejectVulnerabilityWindowOpenness.openWindow()
}
}
}
}
}
}
}

/**
* [Props] for a header with menu buttons on the vulnerability view
*/
@Suppress("MISSING_KDOC_CLASS_ELEMENTS")
internal external interface HeaderMenuProps : Props {
var selectedMenu: VulnerabilityTab
var vulnerability: VulnerabilityDto
var currentUserInfo: UserInfo?
var permissions: Permissions
var isTableView: Boolean
var setSelectedMenu: StateSetter<VulnerabilityTab>
var setIsTableView: StateSetter<Boolean>
var addProjectWindowOpenness: WindowOpenness
}
Loading

0 comments on commit 44860b3

Please sign in to comment.