From 84e2ee5fdbf56887546237eccea6cb8ab5e5a5fd Mon Sep 17 00:00:00 2001 From: itzaname Date: Sat, 27 Dec 2025 10:07:31 -0500 Subject: [PATCH 1/5] Add dialogues and better button groups --- .../app/_components/review/ReviewButtons.tsx | 366 ++++++++++++++---- 1 file changed, 292 insertions(+), 74 deletions(-) diff --git a/web/src/app/_components/review/ReviewButtons.tsx b/web/src/app/_components/review/ReviewButtons.tsx index 2af8273..62781c0 100644 --- a/web/src/app/_components/review/ReviewButtons.tsx +++ b/web/src/app/_components/review/ReviewButtons.tsx @@ -1,13 +1,17 @@ -import React from 'react'; -import { Button, Stack } from '@mui/material'; +import React, { useState } from 'react'; +import { Button, Stack, Dialog, DialogTitle, DialogContent, DialogActions, Typography, Box, Tooltip } from '@mui/material'; import {MapfixInfo } from "@/app/ts/Mapfix"; import {hasRole, Roles, RolesConstants} from "@/app/ts/Roles"; import {SubmissionInfo} from "@/app/ts/Submission"; import {Status, StatusMatches} from "@/app/ts/Status"; interface ReviewAction { - name: string, - action: string, + name: string; + action: string; + description: string; + confirmTitle?: string; + confirmMessage?: string; + requiresConfirmation: boolean; } interface ReviewButtonsProps { @@ -19,20 +23,116 @@ interface ReviewButtonsProps { } const ReviewActions = { - Submit: {name:"Submit",action:"trigger-submit"} as ReviewAction, - AdminSubmit: {name:"Admin Submit",action:"trigger-submit"} as ReviewAction, - SubmitUnchecked: {name:"Submit Unchecked", action:"trigger-submit-unchecked"} as ReviewAction, - ResetSubmitting: {name:"Reset Submitting",action:"reset-submitting"} as ReviewAction, - Revoke: {name:"Revoke",action:"revoke"} as ReviewAction, - Accept: {name:"Accept",action:"trigger-validate"} as ReviewAction, - Reject: {name:"Reject",action:"reject"} as ReviewAction, - Validate: {name:"Validate",action:"retry-validate"} as ReviewAction, - ResetValidating: {name:"Reset Validating",action:"reset-validating"} as ReviewAction, - RequestChanges: {name:"Request Changes",action:"request-changes"} as ReviewAction, - Upload: {name:"Upload",action:"trigger-upload"} as ReviewAction, - ResetUploading: {name:"Reset Uploading",action:"reset-uploading"} as ReviewAction, - Release: {name:"Release",action:"trigger-release"} as ReviewAction, - ResetReleasing: {name:"Reset Releasing",action:"reset-releasing"} as ReviewAction, + Submit: { + name: "Submit for Review", + action: "trigger-submit", + description: "Ready to submit? Your work will be sent to reviewers for approval.", + confirmTitle: "Submit for Review", + confirmMessage: "Are you ready to submit this for review? You can revoke it later if needed.", + requiresConfirmation: true + } as ReviewAction, + AdminSubmit: { + name: "Submit on Behalf of User", + action: "trigger-submit", + description: "Submit this work on behalf of the original submitter.", + confirmTitle: "Admin Submit", + confirmMessage: "This will submit the work as if the original submitter did it. Continue?", + requiresConfirmation: true + } as ReviewAction, + SubmitUnchecked: { + name: "Approve Without Validation", + action: "trigger-submit-unchecked", + description: "Bypass validation and approve this submission.", + confirmTitle: "Skip Validation", + confirmMessage: "This will approve the submission without running validation checks. Only use this if you're certain the work is correct.", + requiresConfirmation: true + } as ReviewAction, + ResetSubmitting: { + name: "Reset Submission Process", + action: "reset-submitting", + description: "This will cancel the current submission process.", + confirmTitle: "Reset Submission", + confirmMessage: "This will cancel the current submission process. The submission will return to 'Under Construction' status.", + requiresConfirmation: true + } as ReviewAction, + Revoke: { + name: "Revoke Submission", + action: "revoke", + description: "Pull back your submission to make changes.", + confirmTitle: "Revoke Submission", + confirmMessage: "This will withdraw your submission from review and return it to 'Under Construction' status.", + requiresConfirmation: true + } as ReviewAction, + Accept: { + name: "Accept & Validate", + action: "trigger-validate", + description: "This looks good! Accept and run validation checks.", + confirmTitle: "Accept Submission", + confirmMessage: "This will accept the submission and trigger validation. The work will proceed to the next stage.", + requiresConfirmation: true + } as ReviewAction, + Reject: { + name: "Reject Submission", + action: "reject", + description: "This submission doesn't meet requirements and should be rejected.", + confirmTitle: "Reject Submission", + confirmMessage: "This will permanently reject the submission. The submitter will need to create a new submission. Are you sure?", + requiresConfirmation: true + } as ReviewAction, + Validate: { + name: "Run Validation", + action: "retry-validate", + description: "Run validation checks on this accepted submission.", + requiresConfirmation: false + } as ReviewAction, + ResetValidating: { + name: "Reset Validation Process", + action: "reset-validating", + description: "The validation process appears stuck. Reset it to try again.", + confirmTitle: "Reset Validation", + confirmMessage: "This will cancel the current validation process so you can retry.", + requiresConfirmation: true + } as ReviewAction, + RequestChanges: { + name: "Request Changes", + action: "request-changes", + description: "Send back to submitter with change requests.", + confirmTitle: "Request Changes", + confirmMessage: "This will return the submission to the submitter and change the status to 'Changes Requested'.", + requiresConfirmation: true + } as ReviewAction, + Upload: { + name: "Upload to Roblox", + action: "trigger-upload", + description: "Validation passed! Upload this work to the Roblox group.", + confirmTitle: "Upload to Roblox Group", + confirmMessage: "This will upload the validated work to the Roblox group. Continue?", + requiresConfirmation: true + } as ReviewAction, + ResetUploading: { + name: "Reset Upload Process", + action: "reset-uploading", + description: "The upload process appears stuck. Reset it to try again.", + confirmTitle: "Reset Upload", + confirmMessage: "This will cancel the current upload process so you can retry.", + requiresConfirmation: true + } as ReviewAction, + Release: { + name: "Release to Public", + action: "trigger-release", + description: "Upload complete! Release this mapfix to the public.", + confirmTitle: "Release to Public", + confirmMessage: "This will make the mapfix publicly available. This is the final step!", + requiresConfirmation: true + } as ReviewAction, + ResetReleasing: { + name: "Reset Release Process", + action: "reset-releasing", + description: "The release process appears stuck. Reset it to try again.", + confirmTitle: "Reset Release", + confirmMessage: "This will cancel the current release process so you can retry.", + requiresConfirmation: true + } as ReviewAction, } const ReviewButtons: React.FC = ({ @@ -42,16 +142,46 @@ const ReviewButtons: React.FC = ({ roles, type, }) => { - const getVisibleButtons = () => { - if (!item || userId === null) return []; + const [confirmDialog, setConfirmDialog] = useState<{ + open: boolean; + action: ReviewAction | null; + }>({ open: false, action: null }); + + const handleButtonClick = (action: ReviewAction) => { + if (action.requiresConfirmation) { + setConfirmDialog({ open: true, action }); + } else { + onClick(action.action, item.ID); + } + }; + + const handleConfirm = () => { + if (confirmDialog.action) { + onClick(confirmDialog.action.action, item.ID); + } + setConfirmDialog({ open: false, action: null }); + }; + + const handleCancel = () => { + setConfirmDialog({ open: false, action: null }); + }; + + const getVisibleButtons = () => { + if (!item || userId === null) return { primary: [], secondary: [], submitter: [], reviewer: [], admin: [] }; - // Define a type for the button type ReviewButton = { action: ReviewAction; color: "primary" | "error" | "success" | "info" | "warning"; + variant?: "contained" | "outlined"; + isPrimary?: boolean; }; - const buttons: ReviewButton[] = []; + const primaryButtons: ReviewButton[] = []; + const secondaryButtons: ReviewButton[] = []; + const submitterButtons: ReviewButton[] = []; + const reviewerButtons: ReviewButton[] = []; + const adminButtons: ReviewButton[] = []; + const is_submitter = userId === item.Submitter; const status = item.StatusID; @@ -59,133 +189,221 @@ const ReviewButtons: React.FC = ({ const uploadRole = type === "submission" ? RolesConstants.SubmissionUpload : RolesConstants.MapfixUpload; const releaseRole = type === "submission" ? RolesConstants.SubmissionRelease : RolesConstants.MapfixRelease; + // Submitter actions if (is_submitter) { if (StatusMatches(status, [Status.UnderConstruction, Status.ChangesRequested])) { - buttons.push({ + submitterButtons.push({ action: ReviewActions.Submit, - color: "primary" + color: "success" }); } if (StatusMatches(status, [Status.Submitted, Status.ChangesRequested])) { - buttons.push({ + submitterButtons.push({ action: ReviewActions.Revoke, - color: "error" + color: "warning", + variant: "outlined" }); } if (status === Status.Submitting) { - buttons.push({ + adminButtons.push({ action: ReviewActions.ResetSubmitting, - color: "warning" + color: "error", + variant: "outlined" }); } } - // Buttons for review role + // Reviewer actions if (hasRole(roles, reviewRole)) { if (status === Status.Submitted && !is_submitter) { - buttons.push( - { - action: ReviewActions.Accept, - color: "success" - }, - { - action: ReviewActions.Reject, - color: "error" - } - ); + reviewerButtons.push({ + action: ReviewActions.Accept, + color: "success" + }); + reviewerButtons.push({ + action: ReviewActions.Reject, + color: "error", + variant: "outlined" + }); } if (status === Status.AcceptedUnvalidated) { - buttons.push({ + reviewerButtons.push({ action: ReviewActions.Validate, - color: "info" + color: "primary" }); } if (status === Status.Validating) { - buttons.push({ + adminButtons.push({ action: ReviewActions.ResetValidating, - color: "warning" + color: "error", + variant: "outlined" }); } if (StatusMatches(status, [Status.Validated, Status.AcceptedUnvalidated, Status.Submitted]) && !is_submitter) { - buttons.push({ + reviewerButtons.push({ action: ReviewActions.RequestChanges, - color: "warning" + color: "warning", + variant: "outlined" }); } if (status === Status.ChangesRequested) { - buttons.push({ + adminButtons.push({ action: ReviewActions.SubmitUnchecked, - color: "warning" + color: "warning", + variant: "outlined" }); - // button only exists for submissions - // submitter has normal submit button if (type === "submission" && !is_submitter) { - buttons.push({ + adminButtons.push({ action: ReviewActions.AdminSubmit, - color: "primary" + color: "info", + variant: "outlined" }); } } } - // Buttons for upload role + // Upload role actions if (hasRole(roles, uploadRole)) { if (status === Status.Validated) { - buttons.push({ + reviewerButtons.push({ action: ReviewActions.Upload, color: "success" }); } if (status === Status.Uploading) { - buttons.push({ + adminButtons.push({ action: ReviewActions.ResetUploading, - color: "warning" + color: "error", + variant: "outlined" }); } } - // Buttons for release role + // Release role actions if (hasRole(roles, releaseRole)) { - // submissions do not have a release button if (type === "mapfix" && status === Status.Uploaded) { - buttons.push({ + reviewerButtons.push({ action: ReviewActions.Release, color: "success" }); } if (status === Status.Releasing) { - buttons.push({ + adminButtons.push({ action: ReviewActions.ResetReleasing, - color: "warning" + color: "error", + variant: "outlined" }); } } - return buttons; + return { + primary: primaryButtons, + secondary: secondaryButtons, + submitter: submitterButtons, + reviewer: reviewerButtons, + admin: adminButtons + }; + }; + + const buttons = getVisibleButtons(); + const hasAnyButtons = buttons.submitter.length > 0 || buttons.reviewer.length > 0 || buttons.admin.length > 0; + + if (!hasAnyButtons) return null; + + const ActionCard = ({ title, actions, isFirst = false }: { title: string; actions: any[]; isFirst?: boolean }) => { + if (actions.length === 0) return null; + + return ( + + + {title} + + + {actions.map((button, index) => ( + + + + ))} + + + ); }; return ( - - {getVisibleButtons().map((button, index) => ( - - ))} - + <> + + + + + + + {/* Confirmation Dialog */} + + + {confirmDialog.action?.confirmTitle || confirmDialog.action?.name} + + + + {confirmDialog.action?.confirmMessage || "Are you sure you want to proceed?"} + + + + + + + + ); }; -- 2.49.1 From 8e60e2b7d7dae5674f48bd8667aadb32abb68fa8 Mon Sep 17 00:00:00 2001 From: itzaname Date: Sat, 27 Dec 2025 18:56:18 -0500 Subject: [PATCH 2/5] Remove tool tip and make descriptions agnostic to fix/submission --- .../app/_components/review/ReviewButtons.tsx | 85 +++++++------------ 1 file changed, 32 insertions(+), 53 deletions(-) diff --git a/web/src/app/_components/review/ReviewButtons.tsx b/web/src/app/_components/review/ReviewButtons.tsx index 62781c0..921d4fa 100644 --- a/web/src/app/_components/review/ReviewButtons.tsx +++ b/web/src/app/_components/review/ReviewButtons.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Button, Stack, Dialog, DialogTitle, DialogContent, DialogActions, Typography, Box, Tooltip } from '@mui/material'; +import { Button, Stack, Dialog, DialogTitle, DialogContent, DialogActions, Typography, Box } from '@mui/material'; import {MapfixInfo } from "@/app/ts/Mapfix"; import {hasRole, Roles, RolesConstants} from "@/app/ts/Roles"; import {SubmissionInfo} from "@/app/ts/Submission"; @@ -8,7 +8,6 @@ import {Status, StatusMatches} from "@/app/ts/Status"; interface ReviewAction { name: string; action: string; - description: string; confirmTitle?: string; confirmMessage?: string; requiresConfirmation: boolean; @@ -26,7 +25,6 @@ const ReviewActions = { Submit: { name: "Submit for Review", action: "trigger-submit", - description: "Ready to submit? Your work will be sent to reviewers for approval.", confirmTitle: "Submit for Review", confirmMessage: "Are you ready to submit this for review? You can revoke it later if needed.", requiresConfirmation: true @@ -34,61 +32,53 @@ const ReviewActions = { AdminSubmit: { name: "Submit on Behalf of User", action: "trigger-submit", - description: "Submit this work on behalf of the original submitter.", confirmTitle: "Admin Submit", - confirmMessage: "This will submit the work as if the original submitter did it. Continue?", + confirmMessage: "This will submit the work as if the original user did it. Continue?", requiresConfirmation: true } as ReviewAction, SubmitUnchecked: { name: "Approve Without Validation", action: "trigger-submit-unchecked", - description: "Bypass validation and approve this submission.", confirmTitle: "Skip Validation", - confirmMessage: "This will approve the submission without running validation checks. Only use this if you're certain the work is correct.", + confirmMessage: "This will approve without running validation checks. Only use this if you're certain the work is correct.", requiresConfirmation: true } as ReviewAction, ResetSubmitting: { - name: "Reset Submission Process", + name: "Reset Submit Process", action: "reset-submitting", - description: "This will cancel the current submission process.", - confirmTitle: "Reset Submission", - confirmMessage: "This will cancel the current submission process. The submission will return to 'Under Construction' status.", + confirmTitle: "Reset Submit", + confirmMessage: "This will cancel the current submit process and return to 'Under Construction' status.", requiresConfirmation: true } as ReviewAction, Revoke: { - name: "Revoke Submission", + name: "Revoke", action: "revoke", - description: "Pull back your submission to make changes.", - confirmTitle: "Revoke Submission", - confirmMessage: "This will withdraw your submission from review and return it to 'Under Construction' status.", + confirmTitle: "Revoke", + confirmMessage: "This will withdraw from review and return to 'Under Construction' status.", requiresConfirmation: true } as ReviewAction, Accept: { name: "Accept & Validate", action: "trigger-validate", - description: "This looks good! Accept and run validation checks.", - confirmTitle: "Accept Submission", - confirmMessage: "This will accept the submission and trigger validation. The work will proceed to the next stage.", + confirmTitle: "Accept", + confirmMessage: "This will accept and trigger validation. The work will proceed to the next stage.", requiresConfirmation: true } as ReviewAction, Reject: { - name: "Reject Submission", + name: "Reject", action: "reject", - description: "This submission doesn't meet requirements and should be rejected.", - confirmTitle: "Reject Submission", - confirmMessage: "This will permanently reject the submission. The submitter will need to create a new submission. Are you sure?", + confirmTitle: "Reject", + confirmMessage: "This will permanently reject. The user will need to create a new one. Are you sure?", requiresConfirmation: true } as ReviewAction, Validate: { name: "Run Validation", action: "retry-validate", - description: "Run validation checks on this accepted submission.", requiresConfirmation: false } as ReviewAction, ResetValidating: { name: "Reset Validation Process", action: "reset-validating", - description: "The validation process appears stuck. Reset it to try again.", confirmTitle: "Reset Validation", confirmMessage: "This will cancel the current validation process so you can retry.", requiresConfirmation: true @@ -96,15 +86,13 @@ const ReviewActions = { RequestChanges: { name: "Request Changes", action: "request-changes", - description: "Send back to submitter with change requests.", confirmTitle: "Request Changes", - confirmMessage: "This will return the submission to the submitter and change the status to 'Changes Requested'.", + confirmMessage: "This will return to the submitter and change the status to 'Changes Requested'.", requiresConfirmation: true } as ReviewAction, Upload: { name: "Upload to Roblox", action: "trigger-upload", - description: "Validation passed! Upload this work to the Roblox group.", confirmTitle: "Upload to Roblox Group", confirmMessage: "This will upload the validated work to the Roblox group. Continue?", requiresConfirmation: true @@ -112,23 +100,20 @@ const ReviewActions = { ResetUploading: { name: "Reset Upload Process", action: "reset-uploading", - description: "The upload process appears stuck. Reset it to try again.", confirmTitle: "Reset Upload", confirmMessage: "This will cancel the current upload process so you can retry.", requiresConfirmation: true } as ReviewAction, Release: { - name: "Release to Public", + name: "Release to Game", action: "trigger-release", - description: "Upload complete! Release this mapfix to the public.", - confirmTitle: "Release to Public", - confirmMessage: "This will make the mapfix publicly available. This is the final step!", + confirmTitle: "Release to Game", + confirmMessage: "This will make the work available in game. This is the final step!", requiresConfirmation: true } as ReviewAction, ResetReleasing: { name: "Reset Release Process", action: "reset-releasing", - description: "The release process appears stuck. Reset it to try again.", confirmTitle: "Reset Release", confirmMessage: "This will cancel the current release process so you can retry.", requiresConfirmation: true @@ -338,28 +323,22 @@ const ReviewButtons: React.FC = ({ {actions.map((button, index) => ( - handleButtonClick(button.action)} + sx={{ + textTransform: 'none', + fontSize: '1rem', + fontWeight: 600, + py: 1.5 + }} > - - + {button.action.name} + ))} -- 2.49.1 From fc2fd529c25aec26490ef1d2e640669585873e15 Mon Sep 17 00:00:00 2001 From: itzaname Date: Sat, 27 Dec 2025 19:17:00 -0500 Subject: [PATCH 3/5] Change request msg --- web/src/app/_components/review/ReviewButtons.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/app/_components/review/ReviewButtons.tsx b/web/src/app/_components/review/ReviewButtons.tsx index 921d4fa..dbb6aaf 100644 --- a/web/src/app/_components/review/ReviewButtons.tsx +++ b/web/src/app/_components/review/ReviewButtons.tsx @@ -87,7 +87,7 @@ const ReviewActions = { name: "Request Changes", action: "request-changes", confirmTitle: "Request Changes", - confirmMessage: "This will return to the submitter and change the status to 'Changes Requested'.", + confirmMessage: "Request that the submitter make changes. Make sure you've explained which changes are requested in a comment.", requiresConfirmation: true } as ReviewAction, Upload: { -- 2.49.1 From 7695feb19339e2290a57b3896aefedc1c88b4d6b Mon Sep 17 00:00:00 2001 From: itzaname Date: Sat, 27 Dec 2025 19:24:24 -0500 Subject: [PATCH 4/5] Make reset actions have scary warnings --- web/src/app/_components/review/ReviewButtons.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/src/app/_components/review/ReviewButtons.tsx b/web/src/app/_components/review/ReviewButtons.tsx index dbb6aaf..143c454 100644 --- a/web/src/app/_components/review/ReviewButtons.tsx +++ b/web/src/app/_components/review/ReviewButtons.tsx @@ -47,7 +47,7 @@ const ReviewActions = { name: "Reset Submit Process", action: "reset-submitting", confirmTitle: "Reset Submit", - confirmMessage: "This will cancel the current submit process and return to 'Under Construction' status.", + confirmMessage: "This will force-cancel the submission process and return to 'Under Construction' status. Only use this if you're certain the backend encountered a catastrophic failure. Misuse will corrupt the workflow.", requiresConfirmation: true } as ReviewAction, Revoke: { @@ -80,7 +80,7 @@ const ReviewActions = { name: "Reset Validation Process", action: "reset-validating", confirmTitle: "Reset Validation", - confirmMessage: "This will cancel the current validation process so you can retry.", + confirmMessage: "This will force-abort the validation process so you can retry. Only use this if you're certain the backend encountered a catastrophic failure. Misuse will corrupt the workflow.", requiresConfirmation: true } as ReviewAction, RequestChanges: { @@ -101,7 +101,7 @@ const ReviewActions = { name: "Reset Upload Process", action: "reset-uploading", confirmTitle: "Reset Upload", - confirmMessage: "This will cancel the current upload process so you can retry.", + confirmMessage: "This will force-abort the upload to Roblox so you can retry. Only use this if you're certain the backend encountered a catastrophic failure. Misuse will corrupt the workflow.", requiresConfirmation: true } as ReviewAction, Release: { @@ -115,7 +115,7 @@ const ReviewActions = { name: "Reset Release Process", action: "reset-releasing", confirmTitle: "Reset Release", - confirmMessage: "This will cancel the current release process so you can retry.", + confirmMessage: "This will force-abort the release to the game so you can retry. Only use this if you're certain the backend encountered a catastrophic failure. Misuse will corrupt the workflow.", requiresConfirmation: true } as ReviewAction, } -- 2.49.1 From 661b56907516d14b9073c33992838660c6720bae Mon Sep 17 00:00:00 2001 From: itzaname Date: Sat, 27 Dec 2025 19:32:02 -0500 Subject: [PATCH 5/5] Update submit --- web/src/app/_components/review/ReviewButtons.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/app/_components/review/ReviewButtons.tsx b/web/src/app/_components/review/ReviewButtons.tsx index 143c454..40c91b8 100644 --- a/web/src/app/_components/review/ReviewButtons.tsx +++ b/web/src/app/_components/review/ReviewButtons.tsx @@ -26,7 +26,7 @@ const ReviewActions = { name: "Submit for Review", action: "trigger-submit", confirmTitle: "Submit for Review", - confirmMessage: "Are you ready to submit this for review? You can revoke it later if needed.", + confirmMessage: "Are you ready to submit this for review? The model version is locked in once submitted, but you can revoke it later if needed.", requiresConfirmation: true } as ReviewAction, AdminSubmit: { -- 2.49.1