Skip to content

Commit

Permalink
merges dev
Browse files Browse the repository at this point in the history
  • Loading branch information
pmarsh-scottlogic committed Oct 19, 2023
2 parents 616e8ad + 11cc184 commit 95441bc
Show file tree
Hide file tree
Showing 19 changed files with 308 additions and 49 deletions.
17 changes: 9 additions & 8 deletions backend/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,14 +249,6 @@ router.post(
chatMessageType: CHAT_MESSAGE_TYPE.BOT_BLOCKED,
infoMessage: chatResponse.defenceInfo.blockedReason,
});

// enable next level when user wins current level
if (chatResponse.wonLevel) {
console.debug("Win conditon met for level: ", currentLevel);
numLevelsCompleted = Math.max(numLevelsCompleted, currentLevel + 1);
req.session.numLevelsCompleted = numLevelsCompleted;
chatResponse.numLevelsCompleted = numLevelsCompleted;
}
}
} else {
handleChatError(res, chatResponse, true, "Missing message");
Expand All @@ -266,6 +258,15 @@ router.post(
handleChatError(res, chatResponse, false, "Failed to get chatGPT reply");
return;
}

// enable next level when user wins current level
if (chatResponse.wonLevel) {
console.debug("Win conditon met for level: ", currentLevel);
numLevelsCompleted = Math.max(numLevelsCompleted, currentLevel + 1);
req.session.numLevelsCompleted = numLevelsCompleted;
chatResponse.numLevelsCompleted = numLevelsCompleted;
}

// log and send the reply with defence info
console.log(chatResponse);
res.send(chatResponse);
Expand Down
15 changes: 14 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function App({ isNewUser }: { isNewUser: boolean }) {
function loadCurrentLevel() {
// get current level from local storage
const currentLevelStr = localStorage.getItem("currentLevel");
if (currentLevelStr) {
if (currentLevelStr && !isNewUser) {
// start the user from where they last left off
return parseInt(currentLevelStr);
} else {
Expand Down Expand Up @@ -80,6 +80,10 @@ function App({ isNewUser }: { isNewUser: boolean }) {
}
}

function openWelcomeOverlay() {
setOverlayType(OVERLAY_TYPE.WELCOME);
}

function openHandbook() {
setOverlayType(OVERLAY_TYPE.HANDBOOK);
}
Expand Down Expand Up @@ -116,6 +120,13 @@ function App({ isNewUser }: { isNewUser: boolean }) {
setDefencesToShow(defences);
}

// set the start level for a user who clicks beginner/expert
async function setStartLevel(startLevel: LEVEL_NAMES) {
console.log(`setting start level to ${startLevel}`);
await setNewLevel(startLevel);
closeOverlay();
}

// for going switching level without clearing progress
async function setNewLevel(newLevel: LEVEL_NAMES) {
console.log(`changing level from ${currentLevel} to ${newLevel}`);
Expand Down Expand Up @@ -228,6 +239,7 @@ function App({ isNewUser }: { isNewUser: boolean }) {
<Overlay
currentLevel={currentLevel}
overlayType={overlayType}
setStartLevel={(level: LEVEL_NAMES) => void setStartLevel(level)}
closeOverlay={closeOverlay}
/>
)}
Expand Down Expand Up @@ -257,6 +269,7 @@ function App({ isNewUser }: { isNewUser: boolean }) {
setDefenceConfiguration={setDefenceConfiguration}
setEmails={setEmails}
setNumCompletedLevels={setNumCompletedLevels}
openWelcomeOverlay={openWelcomeOverlay}
/>
</main>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ChatBox/ChatBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function ChatBox({

function inputKeyUp(event: KeyboardEvent<HTMLTextAreaElement>) {
// shift+enter shouldn't send message
if (event.key === "Enter" && !event.shiftKey) {
if (event.key === "Enter" && !event.shiftKey && !isSendingMessage) {
// asynchronously send the message
void sendChatMessage();
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/DefenceBox/DefenceMechanism.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function DefenceMechanism({
onChange={toggleDefence}
// set checked if defence is active
checked={defenceDetail.isActive}
aria-label="toggle defence"
aria-label={defenceDetail.name}
/>
<span className="slider round"></span>
</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ function isSandbox(name: string) {
return /Sandbox/i.test(name);
}

const storyLevels = LEVELS.filter(({ name }) => !isSandbox(name));

describe("LevelSelectionBox component tests", () => {
test("renders one button per level", () => {
test("renders one button per level, when not in sandbox", () => {
renderComponent();

const levelButtons = screen.getAllByRole("button");
expect(levelButtons).toHaveLength(LEVELS.length);
LEVELS.forEach(({ name }) => {
expect(levelButtons).toHaveLength(storyLevels.length);
storyLevels.forEach(({ name }) => {
expect(screen.getByRole("button", { name })).toBeInTheDocument();
});
});
Expand All @@ -43,23 +45,23 @@ describe("LevelSelectionBox component tests", () => {
expect(selectedButtons[0]).toHaveAccessibleName(currentLevel.name);
});

test("renders buttons ahead of current level disabled, except sandbox", () => {
test("renders buttons ahead of current level disabled", () => {
const numCompletedLevels = 1;
const currentLevel = LEVELS[numCompletedLevels];

renderComponent({ ...defaultProps, numCompletedLevels });

LEVELS.forEach(({ id, name }) => {
storyLevels.forEach(({ id, name }) => {
const button = screen.getByRole("button", { name });
if (id <= currentLevel.id || isSandbox(name)) {
if (id <= currentLevel.id) {
expect(button).toBeEnabled();
} else {
expect(button).toBeDisabled();
}
});
});

test.each(LEVELS)(
test.each(storyLevels)(
`fires callback on click, unless current level [$name] clicked`,
async (level) => {
const currentLevel = LEVELS[0];
Expand Down
12 changes: 7 additions & 5 deletions frontend/src/components/LevelSelectionBox/LevelSelectionBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,26 @@ function LevelSelectionBox({
numCompletedLevels,
setNewLevel,
}: LevelSelectionBoxProps) {
// display levels 1-3
const displayLevels = LEVELS.filter(
(level) => level.id !== LEVEL_NAMES.SANDBOX
);

function handleLevelChange(newLevel: LEVEL_NAMES) {
if (newLevel !== currentLevel) {
setNewLevel(newLevel);
}
}

return (
<div id="level-selection-box">
{LEVELS.map((level: Level, index: number) => {
{displayLevels.map((level: Level, index: number) => {
return (
<ThemedButton
key={level.name}
onClick={() => {
handleLevelChange(level.id);
}}
isDisabled={
index > numCompletedLevels && level.id !== LEVEL_NAMES.SANDBOX
}
isDisabled={index > numCompletedLevels}
isSelected={level.id === currentLevel}
>
{level.name}
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/components/MainComponent/MainBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import EmailBox from "../EmailBox/EmailBox";
import { EmailInfo } from "../../models/email";
import { useState } from "react";
import ControlPanel from "../ControlPanel/ControlPanel";
import SwitchModeButton from "../ThemedButtons/SwitchModeButton";

function MainBody({
currentLevel,
Expand All @@ -24,6 +25,7 @@ function MainBody({
setDefenceConfiguration,
setEmails,
setNumCompletedLevels,
openWelcomeOverlay,
}: {
currentLevel: LEVEL_NAMES;
defences: DefenceInfo[];
Expand All @@ -39,6 +41,7 @@ function MainBody({
) => Promise<boolean>;
setEmails: (emails: EmailInfo[]) => void;
setNumCompletedLevels: (numCompletedLevels: number) => void;
openWelcomeOverlay: () => void;
}) {
const [completedLevels, setCompletedLevels] = useState<Set<LEVEL_NAMES>>(
new Set()
Expand Down Expand Up @@ -71,6 +74,12 @@ function MainBody({
/>
</div>
<div id="centre-area">
<SwitchModeButton
currentLevel={currentLevel}
onClick={() => {
openWelcomeOverlay();
}}
/>
<ChatBox
completedLevels={completedLevels}
currentLevel={currentLevel}
Expand Down
16 changes: 9 additions & 7 deletions frontend/src/components/MainComponent/MainHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ function MainHeader({
<span id="main-header-current-level">{getLevelName(currentLevel)}</span>
</span>
<span id="main-header-right">
<span id="main-header-level-selection">
<LevelSelectionBox
currentLevel={currentLevel}
numCompletedLevels={numCompletedLevels}
setNewLevel={setNewLevel}
/>
</span>
{currentLevel !== LEVEL_NAMES.SANDBOX && (
<span id="main-header-level-selection">
<LevelSelectionBox
currentLevel={currentLevel}
numCompletedLevels={numCompletedLevels}
setNewLevel={setNewLevel}
/>
</span>
)}
<button
className="prompt-injection-min-button handbook-icon"
title="open the handbook"
Expand Down
63 changes: 63 additions & 0 deletions frontend/src/components/MainComponent/ProjectIconDark.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
function ProjectIconDark() {
return (
<svg
width="100%"
height="100%"
viewBox="0 0 385 355"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="24.5"
cy="24.5"
r="24.5"
transform="matrix(0 1 1 0 170 0)"
fill="black"
/>
<circle
cx="20.3538"
cy="20.3538"
r="20.3538"
transform="matrix(0 1 1 0 173.769 4.52295)"
fill="#1FD07B"
/>
<circle
cx="14.3231"
cy="14.3231"
r="14.3231"
transform="matrix(0 1 1 0 179.8 10.5537)"
fill="#FF0080"
/>
<circle
cx="8.29231"
cy="8.29231"
r="8.29231"
transform="matrix(0 1 1 0 185.831 16.5845)"
fill="#FF7524"
/>
<path
d="M28.929 335.409L47.0595 266.56L49.4243 257.58L113.384 306.433L28.929 335.409Z"
fill="black"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M191.775 322.266C285.451 322.266 361.391 265.522 361.391 195.525C361.391 125.528 285.451 68.7837 191.775 68.7837C98.0993 68.7837 22.1599 125.528 22.1599 195.525C22.1599 265.522 98.0993 322.266 191.775 322.266ZM192.151 304.966C275.649 304.966 343.338 261.861 343.338 208.688C343.338 155.514 275.649 112.409 192.151 112.409C108.653 112.409 40.964 155.514 40.964 208.688C40.964 261.861 108.653 304.966 192.151 304.966Z"
fill="black"
/>
<circle cx="20.3087" cy="201.167" r="20.3087" fill="black" />
<circle
cx="20.3087"
cy="20.3087"
r="20.3087"
transform="matrix(-1 0 0 1 385 180.858)"
fill="black"
/>
<circle cx="129" cy="201" r="34.5" stroke="black" strokeWidth="17" />
<circle cx="255" cy="201" r="34.5" stroke="black" strokeWidth="17" />
<line x1="194" y1="46" x2="194" y2="77" stroke="black" strokeWidth="4" />
</svg>
);
}

export default ProjectIconDark;
8 changes: 5 additions & 3 deletions frontend/src/components/Overlay/Overlay.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
background-color: var(--overlay-background-colour);
color: var(--overlay-text-colour);
width: 50%;
height: 50%;
height: 60%;
overflow: visible;
overflow-y: auto;
}
.overlay * {
box-sizing: border-box;
Expand All @@ -35,8 +36,9 @@
}

.overlay-content {
height: 100%;
padding: 1.5rem;
overflow: hidden;
text-align: center;
overflow: hidden;
display: flex;
height: 100%;
}
21 changes: 16 additions & 5 deletions frontend/src/components/Overlay/Overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,42 @@ import { LEVEL_NAMES } from "../../models/level";
import { OVERLAY_TYPE } from "../../models/overlay";
import HandbookOverlay from "../HandbookOverlay/HandbookOverlay";
import MissionInformation from "./MissionInformation";
import HandbookWelcome from "./OverlayWelcome";
import OverlayWelcome from "./OverlayWelcome";

import "./Overlay.css";

function Overlay({
currentLevel,
overlayType,
setStartLevel,
closeOverlay,
}: {
currentLevel: LEVEL_NAMES;
overlayType: OVERLAY_TYPE;
setStartLevel: (startLevel: LEVEL_NAMES) => void;
closeOverlay: () => void;
}) {
const dialogRef = useRef<HTMLDialogElement>(null);
const contentRef = useRef<HTMLDivElement>(null);

function handleClose() {
// close the dialog element first to give focus back to the last focused element
dialogRef.current?.close();
closeOverlay();
}

const handleOverlayClick = useCallback(
(event: MouseEvent) => {
contentRef.current &&
!event.composedPath().includes(contentRef.current) &&
closeOverlay();
handleClose();
},
[closeOverlay, contentRef]
);

const handleEscape = useCallback(
(event: KeyboardEvent) => {
event.code === "Escape" && closeOverlay();
event.code === "Escape" && handleClose();
},
[closeOverlay]
);
Expand Down Expand Up @@ -62,14 +70,17 @@ function Overlay({
) : overlayType === OVERLAY_TYPE.INFORMATION ? (
<MissionInformation currentLevel={currentLevel} />
) : (
<HandbookWelcome />
<OverlayWelcome
currentLevel={currentLevel}
setStartLevel={setStartLevel}
/>
);

return (
<dialog ref={dialogRef} className="overlay">
<button
className="prompt-injection-min-button close-button"
onClick={closeOverlay}
onClick={handleClose}
aria-label="close handbook overlay"
>
X
Expand Down
Loading

0 comments on commit 95441bc

Please sign in to comment.