web: implement trigger-submit + transpose weakly associated action list

This commit is contained in:
Quaternions 2025-04-08 13:42:12 -07:00
parent c923a8a076
commit 18abbd92ce
Signed by: Quaternions
GPG Key ID: D0DF5964F79AC131
2 changed files with 58 additions and 34 deletions
web/src/app
mapfixes/[mapfixId]
submissions/[submissionId]

@ -3,13 +3,25 @@ import { MapfixStatus } from "@/app/ts/Mapfix";
import { Button, ButtonOwnProps } from "@mui/material";
import { useState, useEffect } from "react";
type Actions = "Completed" | "Submit" | "Reject" | "Revoke"
type ApiActions = Lowercase<Actions> | "request-changes" | "trigger-validate" | "retry-validate" | "trigger-upload" | "reset-uploading" | "reset-validating"
type Review = Actions | "Request Changes" | "Accept" | "Validate" | "Upload" | "Reset Uploading (fix softlocked status)" | "Reset Validating (fix softlocked status)" | "Request Changes"
interface ReviewAction {
name: string,
action: string,
}
const ReviewActions = {
Submit: {name:"Submit",action:"trigger-submit"} 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 (fix softlocked status)",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 (fix softlocked status)",action:"reset-uploading"} as ReviewAction,
}
interface ReviewButton {
name: Review,
action: ApiActions,
action: ReviewAction,
mapfixId: string,
color: ButtonOwnProps["color"]
}
@ -20,7 +32,7 @@ interface ReviewId {
mapfixSubmitter: number,
}
async function ReviewButtonClicked(action: ApiActions, mapfixId: string) {
async function ReviewButtonClicked(action: string, mapfixId: string) {
try {
const response = await fetch(`/api/mapfixes/${mapfixId}/status/${action}`, {
method: "POST",
@ -46,7 +58,7 @@ function ReviewButton(props: ReviewButton) {
return <Button
color={props.color}
variant="contained"
onClick={() => { ReviewButtonClicked(props.action, props.mapfixId) }}>{props.name}</Button>
onClick={() => { ReviewButtonClicked(props.action.action, props.mapfixId) }}>{props.action.name}</Button>
}
export default function ReviewButtons(props: ReviewId) {
@ -95,10 +107,10 @@ export default function ReviewButtons(props: ReviewId) {
const is_submitter = user === props.mapfixSubmitter;
if (is_submitter) {
if ([MapfixStatus.UnderConstruction, MapfixStatus.ChangesRequested].includes(mapfixStatus!)) {
visibleButtons.push({ name: "Submit", action: "submit", color: "info", mapfixId });
visibleButtons.push({ action: ReviewActions.Submit, color: "info", mapfixId });
}
if ([MapfixStatus.Submitted, MapfixStatus.ChangesRequested].includes(mapfixStatus!)) {
visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", mapfixId });
visibleButtons.push({ action: ReviewActions.Revoke, color: "info", mapfixId });
}
}
@ -106,14 +118,14 @@ export default function ReviewButtons(props: ReviewId) {
// you can't review your own mapfix!
// note that this means there needs to be more than one person with MapfixReview
if (!is_submitter && mapfixStatus === MapfixStatus.Submitted) {
visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", mapfixId });
visibleButtons.push({ name: "Reject", action: "reject", color: "error", mapfixId });
visibleButtons.push({ action: ReviewActions.Accept, color: "info", mapfixId });
visibleButtons.push({ action: ReviewActions.Reject, color: "error", mapfixId });
}
if (mapfixStatus === MapfixStatus.AcceptedUnvalidated) {
visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", mapfixId });
visibleButtons.push({ action: ReviewActions.Validate, color: "info", mapfixId });
}
if (mapfixStatus === MapfixStatus.Validating) {
visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", mapfixId });
visibleButtons.push({ action: ReviewActions.ResetValidating, color: "error", mapfixId });
}
// this button serves the same purpose as Revoke if you are both
// the map submitter and have MapfixReview when status is Submitted
@ -121,16 +133,16 @@ export default function ReviewButtons(props: ReviewId) {
[MapfixStatus.Validated, MapfixStatus.AcceptedUnvalidated].includes(mapfixStatus!)
|| !is_submitter && mapfixStatus == MapfixStatus.Submitted
) {
visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", mapfixId });
visibleButtons.push({ action: ReviewActions.RequestChanges, color: "error", mapfixId });
}
}
if (roles&RolesConstants.MapfixUpload) {
if (mapfixStatus === MapfixStatus.Validated) {
visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", mapfixId });
visibleButtons.push({ action: ReviewActions.Upload, color: "info", mapfixId });
}
if (mapfixStatus === MapfixStatus.Uploading) {
visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", mapfixId });
visibleButtons.push({ action: ReviewActions.ResetUploading, color: "error", mapfixId });
}
}
@ -140,7 +152,7 @@ export default function ReviewButtons(props: ReviewId) {
<p>No available actions</p>
) : (
visibleButtons.map((btn) => (
<ReviewButton key={btn.action} {...btn} />
<ReviewButton key={btn.action.action} {...btn} />
))
)}
</section>

@ -3,13 +3,25 @@ import { SubmissionStatus } from "@/app/ts/Submission";
import { Button, ButtonOwnProps } from "@mui/material";
import { useState, useEffect } from "react";
type Actions = "Completed" | "Submit" | "Reject" | "Revoke"
type ApiActions = Lowercase<Actions> | "request-changes" | "trigger-validate" | "retry-validate" | "trigger-upload" | "reset-uploading" | "reset-validating"
type Review = Actions | "Request Changes" | "Accept" | "Validate" | "Upload" | "Reset Uploading (fix softlocked status)" | "Reset Validating (fix softlocked status)" | "Request Changes"
interface ReviewAction {
name: string,
action: string,
}
const ReviewActions = {
Submit: {name:"Submit",action:"trigger-submit"} 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 (fix softlocked status)",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 (fix softlocked status)",action:"reset-uploading"} as ReviewAction,
}
interface ReviewButton {
name: Review,
action: ApiActions,
action: ReviewAction,
submissionId: string,
color: ButtonOwnProps["color"]
}
@ -20,7 +32,7 @@ interface ReviewId {
submissionSubmitter: number,
}
async function ReviewButtonClicked(action: ApiActions, submissionId: string) {
async function ReviewButtonClicked(action: string, submissionId: string) {
try {
const response = await fetch(`/api/submissions/${submissionId}/status/${action}`, {
method: "POST",
@ -46,7 +58,7 @@ function ReviewButton(props: ReviewButton) {
return <Button
color={props.color}
variant="contained"
onClick={() => { ReviewButtonClicked(props.action, props.submissionId) }}>{props.name}</Button>
onClick={() => { ReviewButtonClicked(props.action.action, props.submissionId) }}>{props.action.name}</Button>
}
export default function ReviewButtons(props: ReviewId) {
@ -95,10 +107,10 @@ export default function ReviewButtons(props: ReviewId) {
const is_submitter = user === props.submissionSubmitter;
if (is_submitter) {
if ([SubmissionStatus.UnderConstruction, SubmissionStatus.ChangesRequested].includes(submissionStatus!)) {
visibleButtons.push({ name: "Submit", action: "submit", color: "info", submissionId });
visibleButtons.push({ action: ReviewActions.Submit, color: "info", submissionId });
}
if ([SubmissionStatus.Submitted, SubmissionStatus.ChangesRequested].includes(submissionStatus!)) {
visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", submissionId });
visibleButtons.push({ action: ReviewActions.Revoke, color: "info", submissionId });
}
}
@ -106,14 +118,14 @@ export default function ReviewButtons(props: ReviewId) {
// you can't review your own submission!
// note that this means there needs to be more than one person with SubmissionReview
if (!is_submitter && submissionStatus === SubmissionStatus.Submitted) {
visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", submissionId });
visibleButtons.push({ name: "Reject", action: "reject", color: "error", submissionId });
visibleButtons.push({ action: ReviewActions.Accept, color: "info", submissionId });
visibleButtons.push({ action: ReviewActions.Reject, color: "error", submissionId });
}
if (submissionStatus === SubmissionStatus.AcceptedUnvalidated) {
visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", submissionId });
visibleButtons.push({ action: ReviewActions.Validate, color: "info", submissionId });
}
if (submissionStatus === SubmissionStatus.Validating) {
visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", submissionId });
visibleButtons.push({ action: ReviewActions.ResetValidating, color: "error", submissionId });
}
// this button serves the same purpose as Revoke if you are both
// the map submitter and have SubmissionReview when status is Submitted
@ -121,17 +133,17 @@ export default function ReviewButtons(props: ReviewId) {
[SubmissionStatus.Validated, SubmissionStatus.AcceptedUnvalidated].includes(submissionStatus!)
|| !is_submitter && submissionStatus == SubmissionStatus.Submitted
) {
visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", submissionId });
visibleButtons.push({ action: ReviewActions.RequestChanges, color: "error", submissionId });
}
}
if (roles&RolesConstants.SubmissionUpload) {
if (submissionStatus === SubmissionStatus.Validated) {
visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", submissionId });
visibleButtons.push({ action: ReviewActions.Upload, color: "info", submissionId });
}
// TODO: hide Reset buttons for 10 seconds
if (submissionStatus === SubmissionStatus.Uploading) {
visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", submissionId });
visibleButtons.push({ action: ReviewActions.ResetUploading, color: "error", submissionId });
}
}
@ -141,7 +153,7 @@ export default function ReviewButtons(props: ReviewId) {
<p>No available actions</p>
) : (
visibleButtons.map((btn) => (
<ReviewButton key={btn.action} {...btn} />
<ReviewButton key={btn.action.action} {...btn} />
))
)}
</section>