Prompt for reason for skipping.

Note: skipping is only half implemented for labelling and summarisation tasks as those probably need to be changed to use the new Task component.
This commit is contained in:
Adrian Cowan
2023-01-09 00:02:43 +11:00
parent b554f8b68b
commit f277e2da0f
15 changed files with 210 additions and 38 deletions
+59 -5
View File
@@ -1,9 +1,63 @@
import { Button, ButtonProps } from "@chakra-ui/react";
import {
Button,
ButtonProps,
Menu,
MenuButton,
MenuItem,
MenuList,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Textarea,
useDisclosure,
} from "@chakra-ui/react";
import { useState } from "react";
import { FaChevronDown } from "react-icons/fa";
interface SkipButtonProps extends ButtonProps {
onSkip: (reason: string) => void;
}
export const SkipButton = ({ onSkip, ...props }: SkipButtonProps) => {
const { isOpen, onOpen: showModal, onClose: closeModal } = useDisclosure();
const [value, setValue] = useState("");
const onSubmit = () => {
onSkip(value);
setValue("");
closeModal();
};
export const SkipButton = ({ children, ...props }: ButtonProps) => {
return (
<Button size="lg" variant="outline" {...props}>
{children}
</Button>
<>
<Button size="lg" variant="outline" onClick={showModal} {...props}>
Skip
</Button>
<Modal isOpen={isOpen} onClose={closeModal}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Skip</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Textarea
value={value}
onChange={(e) => setValue(e.target.value)}
resize="none"
placeholder="Any feedback on this task?"
/>
</ModalBody>
<ModalFooter>
<Button colorScheme="blue" mr={3} onClick={onSubmit}>
Send
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
};
@@ -11,7 +11,8 @@ export interface TaskControlsProps {
tasks: any[];
className?: string;
onSubmitResponse: (task: { id: string }) => void;
onSkip: () => void;
onSkipTask: (task: { id: string }, reason: string) => void;
onNextTask: () => void;
}
export const TaskControls = (props: TaskControlsProps) => {
@@ -31,13 +32,17 @@ export const TaskControls = (props: TaskControlsProps) => {
>
<TaskInfo id={props.tasks[0].id} output="Submit your answer" />
<Flex justify="center" ml="auto" gap={2}>
<SkipButton>Skip</SkipButton>
<SkipButton
onSkip={(reason: string) => {
props.onSkipTask(props.tasks[0], reason);
}}
/>
{endTask.task.type !== "task_done" ? (
<SubmitButton colorScheme="blue" data-cy="submit" onClick={() => props.onSubmitResponse(props.tasks[0])}>
Submit
</SubmitButton>
) : (
<SubmitButton colorScheme="green" data-cy="next-task" onClick={props.onSkip}>
<SubmitButton colorScheme="green" data-cy="next-task" onClick={props.onNextTask}>
Next Task
</SubmitButton>
)}
+22 -7
View File
@@ -1,10 +1,22 @@
import { useState } from "react";
import { Messages } from "src/components/Messages";
import { TaskControls } from "src/components/Survey/TaskControls";
import { TrackedTextarea } from "src/components/Survey/TrackedTextarea";
import { TwoColumnsWithCards } from "src/components/Survey/TwoColumnsWithCards";
import { TaskType } from "./TaskTypes";
export const CreateTask = ({ tasks, taskType, trigger, mutate, mainBgClasses }) => {
export interface CreateTaskProps {
// we need a task type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
tasks: any[];
taskType: TaskType;
trigger: (update: { id: string; update_type: string; content: { text: string } }) => void;
onSkipTask: (task: { id: string }, reason: string) => void;
onNextTask: () => void;
mainBgClasses: string;
}
export const CreateTask = ({ tasks, taskType, trigger, onSkipTask, onNextTask, mainBgClasses }: CreateTaskProps) => {
const task = tasks[0].task;
const [inputText, setInputText] = useState("");
@@ -20,11 +32,6 @@ export const CreateTask = ({ tasks, taskType, trigger, mutate, mainBgClasses })
});
};
const fetchNextTask = () => {
setInputText("");
mutate();
};
const textChangeHandler = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setInputText(event.target.value);
};
@@ -48,7 +55,15 @@ export const CreateTask = ({ tasks, taskType, trigger, mutate, mainBgClasses })
</>
</TwoColumnsWithCards>
<TaskControls tasks={tasks} onSubmitResponse={submitResponse} onSkip={fetchNextTask} />
<TaskControls
tasks={tasks}
onSubmitResponse={submitResponse}
onSkipTask={(task, reason) => {
setInputText("");
onSkipTask(task, reason);
}}
onNextTask={onNextTask}
/>
</div>
);
};
+16 -6
View File
@@ -5,7 +5,17 @@ import { TaskControlsOverridable } from "src/components/Survey/TaskControlsOverr
import { MessageTable } from "../Messages/MessageTable";
export const EvaluateTask = ({ tasks, trigger, mutate, mainBgClasses }) => {
export interface EvaluateTaskProps {
// we need a task type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
tasks: any[];
trigger: (update: { id: string; update_type: string; content: { ranking: number[] } }) => void;
onSkipTask: (task: { id: string }, reason: string) => void;
onNextTask: () => void;
mainBgClasses: string;
}
export const EvaluateTask = ({ tasks, trigger, onSkipTask, onNextTask, mainBgClasses }: EvaluateTaskProps) => {
const [ranking, setRanking] = useState<number[]>([]);
const submitResponse = (task) => {
trigger({
@@ -17,10 +27,6 @@ export const EvaluateTask = ({ tasks, trigger, mutate, mainBgClasses }) => {
});
};
const fetchNextTask = () => {
setRanking([]);
mutate();
};
let messages = null;
if (tasks[0].task.conversation) {
messages = tasks[0].task.conversation.messages;
@@ -45,7 +51,11 @@ export const EvaluateTask = ({ tasks, trigger, mutate, mainBgClasses }) => {
isValid={ranking.length == tasks[0].task[sortables].length}
prepareForSubmit={() => setRanking(tasks[0].task[sortables].map((_, idx) => idx))}
onSubmitResponse={submitResponse}
onSkip={fetchNextTask}
onSkipTask={(task, reason) => {
setRanking([]);
onSkipTask(task, reason);
}}
onNextTask={onNextTask}
/>
</div>
);
+26 -2
View File
@@ -1,10 +1,25 @@
import { CreateTask } from "./CreateTask";
import { EvaluateTask } from "./EvaluateTask";
import { TaskCategory, TaskTypes } from "./TaskTypes";
import useSWRMutation from "swr/mutation";
import poster from "src/lib/poster";
export const Task = ({ tasks, trigger, mutate, mainBgClasses }) => {
const task = tasks[0].task;
const { trigger: sendRejection } = useSWRMutation("/api/reject_task", poster, {
onSuccess: async () => {
mutate();
},
});
const rejectTask = (task: { id: string }, reason: string) => {
sendRejection({
id: task.id,
reason,
});
};
function taskTypeComponent(type) {
const taskType = TaskTypes.find((taskType) => taskType.type === type);
const category = taskType.category;
@@ -14,13 +29,22 @@ export const Task = ({ tasks, trigger, mutate, mainBgClasses }) => {
<CreateTask
tasks={tasks}
trigger={trigger}
mutate={mutate}
onSkipTask={rejectTask}
onNextTask={mutate}
taskType={taskType}
mainBgClasses={mainBgClasses}
/>
);
case TaskCategory.Evaluate:
return <EvaluateTask tasks={tasks} trigger={trigger} mutate={mutate} mainBgClasses={mainBgClasses} />;
return (
<EvaluateTask
tasks={tasks}
trigger={trigger}
onSkipTask={rejectTask}
onNextTask={mutate}
mainBgClasses={mainBgClasses}
/>
);
}
}
+11 -1
View File
@@ -4,7 +4,17 @@ export enum TaskCategory {
Label = "Label",
}
export const TaskTypes = [
export interface TaskType {
label: string;
desc: string;
category: TaskCategory;
pathname: string;
type: string;
overview?: string;
instruction?: string;
}
export const TaskTypes: TaskType[] = [
// create
{
label: "Create Initial Prompts",