mirror of
https://github.com/wassname/Open-Assistant.git
synced 2026-07-13 00:50:06 +08:00
website: Support new widget types for labelling (#966)
* website: Support new widget types for labelling Adds proper support for yes/no spam style questions as well as a simple interface for flag style labels. Also cleaned up the Task component to fix some rerender issues. * website: Fix some UI text, adjust yes/no button alignment * website: Remove left over console.log Co-authored-by: notmd <33456881+notmd@users.noreply.github.com> --------- Co-authored-by: notmd <33456881+notmd@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useReducer } from "react";
|
||||
import { useMemo, useRef } from "react";
|
||||
import { TaskControls } from "src/components/Survey/TaskControls";
|
||||
import { CreateTask } from "src/components/Tasks/CreateTask";
|
||||
import { EvaluateTask } from "src/components/Tasks/EvaluateTask";
|
||||
@@ -8,15 +9,52 @@ import { TaskCategory, TaskInfo, TaskInfos } from "src/components/Tasks/TaskType
|
||||
import { UnchangedWarning } from "src/components/Tasks/UnchangedWarning";
|
||||
import { post } from "src/lib/api";
|
||||
import { getTypeSafei18nKey } from "src/lib/i18n";
|
||||
import { TaskContent, TaskReplyValidity } from "src/types/Task";
|
||||
import { BaseTask, TaskContent, TaskReplyValidity } from "src/types/Task";
|
||||
import useSWRMutation from "swr/mutation";
|
||||
|
||||
export type TaskStatus = "NOT_SUBMITTABLE" | "DEFAULT" | "VALID" | "REVIEW" | "SUBMITTED";
|
||||
interface EditMode {
|
||||
mode: "EDIT";
|
||||
replyValidity: TaskReplyValidity;
|
||||
}
|
||||
interface ReviewMode {
|
||||
mode: "REVIEW";
|
||||
}
|
||||
interface DefaultWarnMode {
|
||||
mode: "DEFAULT_WARN";
|
||||
}
|
||||
interface SubmittedMode {
|
||||
mode: "SUBMITTED";
|
||||
}
|
||||
|
||||
export interface TaskSurveyProps<T> {
|
||||
// we need a task type
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
task: any;
|
||||
export type TaskStatus = EditMode | DefaultWarnMode | ReviewMode | SubmittedMode;
|
||||
|
||||
interface NewTask {
|
||||
action: "NEW_TASK";
|
||||
}
|
||||
|
||||
interface Review {
|
||||
action: "REVIEW";
|
||||
}
|
||||
|
||||
interface SetSubmitted {
|
||||
action: "SET_SUBMITTED";
|
||||
}
|
||||
|
||||
interface ReturnToEdit {
|
||||
action: "RETURN_EDIT";
|
||||
}
|
||||
|
||||
interface AcceptDefault {
|
||||
action: "ACCEPT_DEFAULT";
|
||||
}
|
||||
|
||||
interface UpdateValidity {
|
||||
action: "UPDATE_VALIDITY";
|
||||
replyValidity: TaskReplyValidity;
|
||||
}
|
||||
|
||||
export interface TaskSurveyProps<TaskType extends BaseTask, T> {
|
||||
task: TaskType;
|
||||
taskType: TaskInfo;
|
||||
isEditable: boolean;
|
||||
isDisabled?: boolean;
|
||||
@@ -26,13 +64,63 @@ export interface TaskSurveyProps<T> {
|
||||
|
||||
export const Task = ({ frontendId, task, trigger, mutate }) => {
|
||||
const { t } = useTranslation("tasks");
|
||||
const [taskStatus, setTaskStatus] = useState<TaskStatus>("NOT_SUBMITTABLE");
|
||||
const [taskStatus, taskEvent] = useReducer(
|
||||
(
|
||||
status: TaskStatus,
|
||||
event: NewTask | UpdateValidity | AcceptDefault | Review | ReturnToEdit | SetSubmitted
|
||||
): TaskStatus => {
|
||||
switch (event.action) {
|
||||
case "NEW_TASK":
|
||||
return { mode: "EDIT", replyValidity: "INVALID" };
|
||||
case "UPDATE_VALIDITY":
|
||||
return status.mode === "EDIT" ? { mode: "EDIT", replyValidity: event.replyValidity } : status;
|
||||
case "ACCEPT_DEFAULT":
|
||||
return status.mode === "DEFAULT_WARN" ? { mode: "REVIEW" } : status;
|
||||
case "REVIEW": {
|
||||
if (status.mode === "EDIT") {
|
||||
switch (status.replyValidity) {
|
||||
case "DEFAULT":
|
||||
return { mode: "DEFAULT_WARN" };
|
||||
case "VALID":
|
||||
return { mode: "REVIEW" };
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
case "RETURN_EDIT": {
|
||||
switch (status.mode) {
|
||||
case "REVIEW":
|
||||
return { mode: "EDIT", replyValidity: "VALID" };
|
||||
case "DEFAULT_WARN":
|
||||
return { mode: "EDIT", replyValidity: "DEFAULT" };
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
}
|
||||
case "SET_SUBMITTED": {
|
||||
return status.mode === "REVIEW" ? { mode: "SUBMITTED" } : status;
|
||||
}
|
||||
}
|
||||
},
|
||||
{ mode: "EDIT", replyValidity: "INVALID" }
|
||||
);
|
||||
|
||||
const replyContent = useRef<TaskContent>(null);
|
||||
const [showUnchangedWarning, setShowUnchangedWarning] = useState(false);
|
||||
const updateValidity = useCallback(
|
||||
(replyValidity: TaskReplyValidity) => taskEvent({ action: "UPDATE_VALIDITY", replyValidity }),
|
||||
[taskEvent]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
taskEvent({ action: "NEW_TASK" });
|
||||
}, [task.id, updateValidity]);
|
||||
|
||||
const rootEl = useRef<HTMLDivElement>(null);
|
||||
|
||||
const taskType = TaskInfos.find((taskType) => taskType.type === task.type && taskType.mode === task.mode);
|
||||
const taskType = useMemo(
|
||||
() => TaskInfos.find((taskType) => taskType.type === task.type && taskType.mode === task.mode),
|
||||
[task.type, task.mode]
|
||||
);
|
||||
|
||||
const { trigger: sendRejection } = useSWRMutation("/api/reject_task", post, {
|
||||
onSuccess: async () => {
|
||||
@@ -47,79 +135,36 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const edit_mode = taskStatus === "NOT_SUBMITTABLE" || taskStatus === "DEFAULT" || taskStatus === "VALID";
|
||||
const submitted = taskStatus === "SUBMITTED";
|
||||
|
||||
const onValidityChanged = (validity: TaskReplyValidity) => {
|
||||
if (!edit_mode) return;
|
||||
switch (validity) {
|
||||
case "DEFAULT":
|
||||
if (taskStatus !== "DEFAULT") setTaskStatus("DEFAULT");
|
||||
break;
|
||||
case "VALID":
|
||||
if (taskStatus !== "VALID") setTaskStatus("VALID");
|
||||
break;
|
||||
case "INVALID":
|
||||
if (taskStatus !== "NOT_SUBMITTABLE") setTaskStatus("NOT_SUBMITTABLE");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const onReplyChanged = (content: TaskContent) => {
|
||||
replyContent.current = content;
|
||||
};
|
||||
|
||||
const reviewResponse = () => {
|
||||
switch (taskStatus) {
|
||||
case "DEFAULT":
|
||||
setShowUnchangedWarning(true);
|
||||
break;
|
||||
case "VALID":
|
||||
setTaskStatus("REVIEW");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const editResponse = () => {
|
||||
switch (taskStatus) {
|
||||
case "REVIEW":
|
||||
setTaskStatus("VALID");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
};
|
||||
const onReplyChanged = useCallback(
|
||||
(content: TaskContent) => {
|
||||
replyContent.current = content;
|
||||
},
|
||||
[replyContent]
|
||||
);
|
||||
|
||||
const submitResponse = () => {
|
||||
switch (taskStatus) {
|
||||
case "REVIEW": {
|
||||
trigger({
|
||||
id: frontendId,
|
||||
update_type: taskType.update_type,
|
||||
content: replyContent.current,
|
||||
});
|
||||
setTaskStatus("SUBMITTED");
|
||||
scrollToTop(rootEl.current);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
if (taskStatus.mode === "REVIEW") {
|
||||
trigger({
|
||||
id: frontendId,
|
||||
update_type: taskType.update_type,
|
||||
content: replyContent.current,
|
||||
});
|
||||
taskEvent({ action: "SET_SUBMITTED" });
|
||||
scrollToTop(rootEl.current);
|
||||
}
|
||||
};
|
||||
|
||||
function taskTypeComponent() {
|
||||
const taskTypeComponent = useMemo(() => {
|
||||
switch (taskType.category) {
|
||||
case TaskCategory.Create:
|
||||
return (
|
||||
<CreateTask
|
||||
task={task}
|
||||
taskType={taskType}
|
||||
isEditable={edit_mode}
|
||||
isDisabled={submitted}
|
||||
isEditable={taskStatus.mode === "EDIT"}
|
||||
isDisabled={taskStatus.mode === "SUBMITTED"}
|
||||
onReplyChanged={onReplyChanged}
|
||||
onValidityChanged={onValidityChanged}
|
||||
onValidityChanged={updateValidity}
|
||||
/>
|
||||
);
|
||||
case TaskCategory.Evaluate:
|
||||
@@ -127,10 +172,10 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
|
||||
<EvaluateTask
|
||||
task={task}
|
||||
taskType={taskType}
|
||||
isEditable={edit_mode}
|
||||
isDisabled={submitted}
|
||||
isEditable={taskStatus.mode === "EDIT"}
|
||||
isDisabled={taskStatus.mode === "SUBMITTED"}
|
||||
onReplyChanged={onReplyChanged}
|
||||
onValidityChanged={onValidityChanged}
|
||||
onValidityChanged={updateValidity}
|
||||
/>
|
||||
);
|
||||
case TaskCategory.Label:
|
||||
@@ -138,37 +183,34 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
|
||||
<LabelTask
|
||||
task={task}
|
||||
taskType={taskType}
|
||||
isEditable={edit_mode}
|
||||
isDisabled={submitted}
|
||||
isEditable={taskStatus.mode === "EDIT"}
|
||||
isDisabled={taskStatus.mode === "SUBMITTED"}
|
||||
onReplyChanged={onReplyChanged}
|
||||
onValidityChanged={onValidityChanged}
|
||||
onValidityChanged={updateValidity}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [task, taskType, taskStatus.mode, onReplyChanged, updateValidity]);
|
||||
|
||||
return (
|
||||
<div ref={rootEl}>
|
||||
{taskTypeComponent()}
|
||||
{taskTypeComponent}
|
||||
<TaskControls
|
||||
task={task}
|
||||
taskStatus={taskStatus}
|
||||
onEdit={editResponse}
|
||||
onReview={reviewResponse}
|
||||
onEdit={() => taskEvent({ action: "RETURN_EDIT" })}
|
||||
onReview={() => taskEvent({ action: "REVIEW" })}
|
||||
onSubmit={submitResponse}
|
||||
onSkip={rejectTask}
|
||||
/>
|
||||
<UnchangedWarning
|
||||
show={showUnchangedWarning}
|
||||
show={taskStatus.mode === "DEFAULT_WARN"}
|
||||
title={t(getTypeSafei18nKey(`${taskType.id}.unchanged_title`)) || t("default.unchanged_title")}
|
||||
message={t(getTypeSafei18nKey(`${taskType.id}.unchanged_message`)) || t("default.unchanged_message")}
|
||||
continueButtonText={"Continue anyway"}
|
||||
onClose={() => setShowUnchangedWarning(false)}
|
||||
onClose={() => taskEvent({ action: "RETURN_EDIT" })}
|
||||
onContinueAnyway={() => {
|
||||
if (taskStatus === "DEFAULT") {
|
||||
setTaskStatus("REVIEW");
|
||||
setShowUnchangedWarning(false);
|
||||
}
|
||||
taskEvent({ action: "ACCEPT_DEFAULT" });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user