Merge branch 'main' into dark-mode-implementation

This commit is contained in:
Desmond Grealy
2023-01-02 00:49:03 -08:00
158 changed files with 10576 additions and 3799 deletions
+13
View File
@@ -0,0 +1,13 @@
import React from "react";
import { Container } from "./Container";
describe("<Container />", () => {
it("renders", () => {
// see: https://on.cypress.io/mounting-react
const className = "my-class";
const text = "test_container";
cy.mount(<Container className={className}>{text}</Container>);
cy.get(`div.${className}`).should("have.class", className).should("be.visible").should("contain", text);
});
});
+216
View File
@@ -0,0 +1,216 @@
import {
Button,
Checkbox,
Flex,
Popover,
PopoverAnchor,
PopoverArrow,
PopoverBody,
PopoverCloseButton,
PopoverContent,
PopoverTrigger,
Slider,
SliderFilledTrack,
SliderThumb,
SliderTrack,
Spacer,
useBoolean,
} from "@chakra-ui/react";
import { FlagIcon, QuestionMarkCircleIcon } from "@heroicons/react/20/solid";
import { useState } from "react";
import poster from "src/lib/poster";
import useSWRMutation from "swr/mutation";
export const FlaggableElement = (props) => {
const [isEditing, setIsEditing] = useBoolean();
const { trigger } = useSWRMutation("/api/v1/text_labels", poster, {
onSuccess: () => {
setIsEditing.off;
},
});
const submitResponse = () => {
const label_map: Map<string, number> = new Map();
TEXT_LABEL_FLAGS.forEach((flag, i) => {
if (checkboxValues[i]) {
label_map.set(flag.attributeName, sliderValues[i]);
}
});
trigger({ post_id: props.post_id, label_map: Object.fromEntries(label_map), text: props.text });
};
const [checkboxValues, setCheckboxValues] = useState(new Array(TEXT_LABEL_FLAGS.length).fill(false));
const [sliderValues, setSliderValues] = useState(new Array(TEXT_LABEL_FLAGS.length).fill(1));
const handleCheckboxState = (isChecked, idx) => {
setCheckboxValues(
checkboxValues.map((val, i) => {
return i == idx ? isChecked : val;
})
);
};
const handleSliderState = (newVal, idx) => {
setSliderValues(
sliderValues.map((val, i) => {
return i == idx ? newVal : val;
})
);
};
return (
<Popover
isOpen={isEditing}
onOpen={setIsEditing.on}
onClose={setIsEditing.off}
closeOnBlur={false}
isLazy
lazyBehavior="keepMounted"
>
<div className="inline-block float-left">
<PopoverAnchor>{props.children}</PopoverAnchor>
<PopoverTrigger>
<Button color="transparent">
<FlagIcon
className="h-5 w-5 ml-3 align-center text-gray-400 group-hover:text-gray-500"
aria-hidden="true"
/>
</Button>
</PopoverTrigger>
</div>
<PopoverContent width="fit-content">
<PopoverArrow />
<PopoverCloseButton />
<div className="flex mt-3 ">
<PopoverBody>
<ul>
{TEXT_LABEL_FLAGS.map((option, i) => {
return (
<FlagCheckboxLi
option={option}
key={i}
idx={i}
checkboxValues={checkboxValues}
sliderValues={sliderValues}
checkboxHandler={handleCheckboxState}
sliderHandler={handleSliderState}
></FlagCheckboxLi>
);
})}
</ul>
<div className="flex justify-center ml-auto">
<Button
isDisabled={
!checkboxValues.reduce((all, current) => {
return all | current;
}, false)
}
onClick={() => submitResponse()}
className="bg-indigo-600 text-black hover:bg-indigo-700"
>
Report
</Button>
</div>
</PopoverBody>
</div>
</PopoverContent>
</Popover>
);
};
function FlagCheckboxLi(props: {
option: textFlagLabels;
idx: number;
checkboxValues: boolean[];
sliderValues: number[];
checkboxHandler: (newVal: boolean, idx: number) => void;
sliderHandler: (newVal: number, idx: number) => void;
}): JSX.Element {
let AdditionalExplanation = null;
if (props.option.additionalExplanation) {
AdditionalExplanation = (
<a href="#" className="group flex items-center space-x-2.5 text-sm ">
<QuestionMarkCircleIcon
className="flex h-5 w-5 ml-3 text-gray-400 group-hover:text-gray-500"
aria-hidden="true"
/>
</a>
);
}
return (
<li>
<Flex>
<Checkbox
onChange={(e) => {
props.checkboxHandler(e.target.checked, props.idx);
}}
/>
<label
className=" ml-1 mr-1 text-sm form-check-label hover:cursor-pointer"
htmlFor={props.option.attributeName}
>
<span className="text-gray-800 hover:text-blue-700 float-left">{props.option.labelText}</span>
{AdditionalExplanation}
</label>
<Spacer />
<Slider
width="100px"
isDisabled={!props.checkboxValues[props.idx]}
defaultValue={100}
onChangeEnd={(val) => {
props.sliderHandler(val / 100, props.idx);
}}
>
<SliderTrack>
<SliderFilledTrack />
<SliderThumb />
</SliderTrack>
</Slider>
</Flex>
</li>
);
}
interface textFlagLabels {
attributeName: string;
labelText: string;
additionalExplanation?: string;
}
const TEXT_LABEL_FLAGS: textFlagLabels[] = [
// For the time being this list is configured on the FE.
// In the future it may be provided by the API.
{
attributeName: "fails_task",
labelText: "Fails to follow the correct instruction / task",
additionalExplanation: "__TODO__",
},
{
attributeName: "not_customer_assistant_appropriate",
labelText: "Inappropriate for customer assistant",
additionalExplanation: "__TODO__",
},
{
attributeName: "contains_sexual_content",
labelText: "Contains sexual content",
},
{
attributeName: "contains_violent_content",
labelText: "Contains violent content",
},
{
attributeName: "encourages_violence",
labelText: "Encourages or fails to discourage violence/abuse/terrorism/self-harm",
},
{
attributeName: "denigrates_a_protected_class",
labelText: "Denigrates a protected class",
},
{
attributeName: "gives_harmful_advice",
labelText: "Fails to follow the correct instruction / task",
additionalExplanation:
"The advice given in the output is harmful or counter-productive. This may be in addition to, but is distinct from the question about encouraging violence/abuse/terrorism/self-harm.",
},
{
attributeName: "expresses_moral_judgement",
labelText: "Expresses moral judgement",
},
];
+48 -38
View File
@@ -5,11 +5,11 @@ import { useColorMode } from "@chakra-ui/react";
export function Footer() {
const { colorMode } = useColorMode();
const bgColorClass = colorMode === "light" ? "bg-transparent" : "bg-gray-800";
const borderClass = colorMode === "light" ? "border-slate-200" : "border-gray-900";
const borderClass = colorMode === "light" ? "border-slate-200" : "border-transparent";
return (
<footer className={bgColorClass}>
<div className={`flex justify-evenly py-10 px-10 border-t ${borderClass}`}>
<div className={`flex mx-auto max-w-7xl justify-between py-10 px-10 border-t ${borderClass}`}>
<div className="flex items-center pr-8">
<Link href="/" aria-label="Home" className="flex items-center">
<Image src="/images/logos/logo.svg" className="mx-auto object-fill" width="52" height="52" alt="logo" />
@@ -20,18 +20,7 @@ export function Footer() {
<p className="text-sm">Conversational AI for everyone.</p>
</div>
</div>
<nav className="flex justify-center gap-20">
<div className="flex flex-col text-sm leading-7">
<b>Information</b>
<div className="flex flex-col leading-5">
<Link href="#" aria-label="Our Team" className="hover:underline underline-offset-2">
Our Team
</Link>
<Link href="#join-us" aria-label="Join Us" className="hover:underline underline-offset-2">
Join Us
</Link>
</div>
</div>
<nav className="flex justify-center gap-20">
<div className="flex flex-col text-sm leading-7">
<b>Information</b>
@@ -44,30 +33,51 @@ export function Footer() {
</Link>
</div>
</div>
</nav>
<div className="flex flex-col text-sm leading-7">
<b>Connect</b>
<div className="flex flex-col leading-5">
<Link
href="https://github.com/LAION-AI/Open-Assistant"
rel="noopener noreferrer nofollow"
target="_blank"
aria-label="Privacy Policy"
className="hover:underline underline-offset-2"
>
Github
</Link>
<Link
href="https://discord.gg/pXtnYk9c"
rel="noopener noreferrer nofollow"
target="_blank"
aria-label="Terms of Service"
className="hover:underline underline-offset-2"
>
Discord
</Link>
</div>
</div>
<nav className="flex justify-center gap-20">
<div className="flex flex-col text-sm leading-7">
<b>Legal</b>
<div className="flex flex-col leading-5">
<Link
href="/privacy-policy"
aria-label="Privacy Policy"
className="hover:underline underline-offset-2"
>
Privacy Policy
</Link>
<Link
href="/terms-of-service"
aria-label="Terms of Service"
className="hover:underline underline-offset-2"
>
Terms of Service
</Link>
</div>
</div>
<div className="flex flex-col text-sm leading-7">
<b>Connect</b>
<div className="flex flex-col leading-5">
<Link
href="https://github.com/LAION-AI/Open-Assistant"
rel="noopener noreferrer nofollow"
target="_blank"
aria-label="Privacy Policy"
className="hover:underline underline-offset-2"
>
Github
</Link>
<Link
href="https://discord.gg/pXtnYk9c"
rel="noopener noreferrer nofollow"
target="_blank"
aria-label="Terms of Service"
className="hover:underline underline-offset-2"
>
Discord
</Link>
</div>
</div>
</nav>
{/* </div> */}
</nav>
</div>
</footer>
@@ -3,6 +3,7 @@ import React from "react";
import { Header } from "./Header";
// eslint-disable-next-line import/no-anonymous-default-export
export default {
title: "Header/Header",
component: Header,
+1
View File
@@ -1,5 +1,6 @@
import { Button, Box } from "@chakra-ui/react";
import { Popover } from "@headlessui/react";
import clsx from "clsx";
import { AnimatePresence, motion } from "framer-motion";
import Image from "next/image";
import Link from "next/link";
@@ -1,5 +1,6 @@
import { NavLinks } from "./NavLinks";
// eslint-disable-next-line import/no-anonymous-default-export
export default {
title: "Header/NavLinks",
component: NavLinks,
+2 -2
View File
@@ -1,6 +1,6 @@
import { useState } from "react";
import Link from "next/link";
import { AnimatePresence, motion } from "framer-motion";
import Link from "next/link";
import { useState } from "react";
import { useColorMode } from "@chakra-ui/react";
@@ -3,6 +3,7 @@ import React from "react";
import UserMenu from "./UserMenu";
// eslint-disable-next-line import/no-anonymous-default-export
export default {
title: "Header/UserMenu",
component: UserMenu,
+3 -4
View File
@@ -1,8 +1,8 @@
import React from "react";
import { signOut, useSession } from "next-auth/react";
import Image from "next/image";
import { Popover } from "@headlessui/react";
import { AnimatePresence, motion } from "framer-motion";
import Image from "next/image";
import { signOut, useSession } from "next-auth/react";
import React from "react";
import { FaCog, FaSignOutAlt } from "react-icons/fa";
import { Box, useColorModeValue } from "@chakra-ui/react";
@@ -14,7 +14,6 @@ export function UserMenu() {
return <></>;
}
if (session && session.user) {
const email = session.user.email;
const accountOptions = [
{
name: "Account Settings",
+1 -1
View File
@@ -1,3 +1,3 @@
export { Header } from "./Header";
export { UserMenu } from "./UserMenu";
export { NavLinks } from "./NavLinks";
export { UserMenu } from "./UserMenu";
+1 -2
View File
@@ -1,7 +1,6 @@
import { useId } from "react";
import Image from "next/image";
import { useColorMode } from "@chakra-ui/react";
import { useId } from "react";
import { Container } from "./Container";
function BackgroundIllustration(props) {
+1 -1
View File
@@ -1,9 +1,9 @@
// https://nextjs.org/docs/basic-features/layouts
import type { NextPage } from "next";
import { Header } from "src/components/Header";
import { Footer } from "./Footer";
import { Header } from "src/components/Header";
export type NextPageWithLayout<P = unknown, IP = P> = NextPage<P, IP> & {
getLayout?: (page: React.ReactElement) => React.ReactNode;
@@ -1,5 +1,6 @@
import { LoadingScreen } from "./LoadingScreen";
// eslint-disable-next-line import/no-anonymous-default-export
export default {
title: "Example/LoadingScreen",
component: LoadingScreen,
+12 -3
View File
@@ -1,3 +1,5 @@
import { FlaggableElement } from "./FlaggableElement";
export interface Message {
text: string;
is_assistant: boolean;
@@ -5,11 +7,18 @@ export interface Message {
const getColor = (isAssistant: boolean) => (isAssistant ? "bg-slate-800" : "bg-sky-900");
export const Messages = ({ messages }: { messages: Message[] }) => {
export const Messages = ({ messages, post_id }: { messages: Message[]; post_id: string }) => {
const items = messages.map(({ text, is_assistant }: Message, i: number) => {
return (
<div key={i + text} className={`${getColor(is_assistant)} p-4 my-1 rounded-xl text-white whitespace-pre-wrap`}>
{text}
<div className="flex" key={i + text}>
<FlaggableElement text={text} post_id={post_id}>
<div
key={i + text}
className={`${getColor(is_assistant)} p-4 my-1 rounded-xl text-white whitespace-pre-wrap float-left mr-3`}
>
{text}
</div>
</FlaggableElement>
</div>
);
});
+2 -2
View File
@@ -2,8 +2,8 @@ const RankItem = ({ username, score }) => {
return (
<div className="flex flex-row justify-between p-6 border-2 border-slate-100 text-left font-semibold hover:bg-sky-50">
<div>1</div>
<div>@username</div>
<div>20.5</div>
<div>{username}</div>
<div>{score}</div>
<div>gold</div>
</div>
);
+1 -1
View File
@@ -1,7 +1,7 @@
import { Box, HStack, useRadio, useRadioGroup } from "@chakra-ui/react";
const RatingRadioButton = (props) => {
const { state, getInputProps, getCheckboxProps } = useRadio(props);
const { getInputProps, getCheckboxProps } = useRadio(props);
const input = getInputProps();
const checkbox = getCheckboxProps();
+70 -33
View File
@@ -1,4 +1,23 @@
import { Flex } from "@chakra-ui/react";
import {
closestCenter,
DndContext,
PointerSensor,
TouchSensor,
KeyboardSensor,
useSensor,
useSensors,
} from "@dnd-kit/core";
import type { DragEndEvent } from "@dnd-kit/core/dist/types/events";
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
import {
arrayMove,
SortableContext,
sortableKeyboardCoordinates,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { ReactNode, useEffect, useState } from "react";
import { SortableItem } from "./SortableItem";
export interface SortableProps {
@@ -6,43 +25,61 @@ export interface SortableProps {
onChange: (newSortedIndices: number[]) => void;
}
export const Sortable = ({ items, onChange }) => {
const [sortOrder, setSortOrder] = useState<number[]>([]);
interface SortableItems {
id: number;
originalIndex: number;
item: ReactNode;
}
const update = (newRanking: number[]) => {
setSortOrder(newRanking);
onChange(newRanking);
};
export const Sortable = ({ items, onChange }: SortableProps) => {
const [itemsWithIds, setItemsWithIds] = useState<SortableItems[]>([]);
useEffect(() => {
const indices = Array.from({ length: items.length }).map((_, i) => i);
setSortOrder(indices);
onChange(indices);
}, [items, onChange]);
setItemsWithIds(
items.map((item, idx) => ({
item,
id: idx + 1, // +1 because dndtoolkit has problem with "falsy" ids
originalIndex: idx,
}))
);
}, [items]);
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(TouchSensor),
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
);
return (
<ul className="flex flex-col gap-4">
{sortOrder.map((rank, i) => (
<SortableItem
key={`${rank}`}
canIncrement={i > 0}
onIncrement={() => {
const newRanking = sortOrder.slice();
const newIdx = i - 1;
[newRanking[i], newRanking[newIdx]] = [newRanking[newIdx], newRanking[i]];
update(newRanking);
}}
canDecrement={i < sortOrder.length - 1}
onDecrement={() => {
const newRanking = sortOrder.slice();
const newIdx = i + 1;
[newRanking[i], newRanking[newIdx]] = [newRanking[newIdx], newRanking[i]];
update(newRanking);
}}
>
{items[rank]}
</SortableItem>
))}
</ul>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
modifiers={[restrictToVerticalAxis]}
>
<SortableContext items={itemsWithIds} strategy={verticalListSortingStrategy}>
<Flex direction="column" gap={2}>
{itemsWithIds.map(({ id, item }) => (
<SortableItem key={id} id={id}>
{item}
</SortableItem>
))}
</Flex>
</SortableContext>
</DndContext>
);
function handleDragEnd(event: DragEndEvent) {
const { active, over } = event;
if (active.id === over.id) {
return;
}
setItemsWithIds((items) => {
const oldIndex = items.findIndex((x) => x.id === active.id);
const newIndex = items.findIndex((x) => x.id === over.id);
const newArray = arrayMove(items, oldIndex, newIndex);
onChange(newArray.map((item) => item.originalIndex));
return newArray;
});
}
};
@@ -1,40 +1,32 @@
<<<<<<< HEAD
import { ArrowDownIcon, ArrowUpIcon } from "@heroicons/react/20/solid";
=======
>>>>>>> main
import { Button } from "@chakra-ui/react";
import clsx from "clsx";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { RxDragHandleDots2 } from "react-icons/rx";
import { PropsWithChildren } from "react";
export interface SortableItemProps {
canIncrement: boolean;
canDecrement: boolean;
onIncrement: () => void;
onDecrement: () => void;
children: React.ReactNode;
}
export const SortableItem = ({ children, id }: PropsWithChildren<{ id: number }>) => {
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
const style = {
transform: CSS.Transform.toString(transform),
transition,
touchAction: "none",
};
export const SortableItem = ({ canIncrement, canDecrement, onIncrement, onDecrement, children }: SortableItemProps) => {
return (
<li className="grid grid-cols-[min-content_1fr] items-center rounded-lg shadow-md gap-x-2 p-2">
<ArrowButton active={canIncrement} onClick={onIncrement}>
<ArrowUpIcon width={28} />
</ArrowButton>
<span style={{ gridRow: "span 2" }}>{children}</span>
<ArrowButton active={canDecrement} onClick={onDecrement}>
<ArrowDownIcon width={28} />
</ArrowButton>
<li
className="grid grid-cols-[min-content_1fr] items-center rounded-lg shadow-md gap-x-2 p-2 bg-white hover:bg-slate-50"
ref={setNodeRef}
style={style}
>
<Button justifyContent="center" variant="ghost" {...attributes} {...listeners}>
<RxDragHandleDots2 />
</Button>
{children}
</li>
);
};
interface ArrowButtonProps {
active: boolean;
onClick: () => void;
children: React.ReactNode;
}
const ArrowButton = ({ children, active, onClick }: ArrowButtonProps) => {
return (
<Button justifyContent="center" variant="ghost" onClick={onClick} disabled={!active}>
{children}
</Button>
);
};
+1 -1
View File
@@ -1,4 +1,4 @@
export const TaskInfo = ({ id, output }: { id: string; output: any }) => {
export const TaskInfo = ({ id, output }: { id: string; output: string }) => {
return (
<div className="grid grid-cols-[min-content_auto] gap-x-2 ">
<b>Prompt</b>
@@ -1,11 +1,20 @@
import React from "react";
import { TaskOptions } from "./TaskOptions";
import { Flex } from "@chakra-ui/react";
import React from "react";
import { useColorMode } from "@chakra-ui/react";
import { TaskOption } from "./TaskOption";
import { TaskOptions } from "./TaskOptions";
export const TaskSelection = () => {
const { colorMode } = useColorMode();
const bgColorClass = colorMode === "light" ? "bg-gray-50" : "bg-gray-600";
const buttonBgColor = colorMode === "light" ? "#2563eb" : "#2563eb";
const borderClass = colorMode === "light" ? "border-slate-200" : "border-transparent";
return (
<Flex gap={10} wrap="wrap" justifyContent="space-evenly" width="full" height="full" alignItems={"center"}>
<Flex gap={10} wrap="wrap" justifyContent="space-evenly" width="full" height="full" alignItems={"center"} className={bgColorClass}>
<TaskOptions key="create" title="Create">
{/* <TaskOption
alt="Summarize Stories"
@@ -22,7 +31,9 @@ export const TaskSelection = () => {
/>
</TaskOptions>
<TaskOptions key="evaluate" title="Evaluate">
{/* <TaskOption
{/*
Commented out while the backend does not support them.
<TaskOption
alt="Rate Prompts"
img="/images/logos/logo.svg"
title="Rate Prompts"
@@ -1,3 +1,3 @@
export { TaskSelection } from "./TaskSelection";
export { TaskOptions } from "./TaskOptions";
export { TaskOption } from "./TaskOption";
export { TaskOptions } from "./TaskOptions";
export { TaskSelection } from "./TaskSelection";