-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactoring vulnerability view to move header menu to the separate fi…
…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
Showing
4 changed files
with
272 additions
and
201 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
242 changes: 242 additions & 0 deletions
242
...rc/main/kotlin/com/saveourtool/save/frontend/components/views/vuln/VulnerabilityHeader.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.