From 1f9c089b537c97d055d7baf1a4c87776a4179021 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 14:05:40 +0800 Subject: [PATCH 01/18] Create new InterpreterOutput type in repl for notifications --- src/commons/application/ApplicationTypes.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/commons/application/ApplicationTypes.ts b/src/commons/application/ApplicationTypes.ts index b1f9895c09..e65c455a8c 100644 --- a/src/commons/application/ApplicationTypes.ts +++ b/src/commons/application/ApplicationTypes.ts @@ -88,7 +88,17 @@ export type ErrorOutput = { consoleLogs: string[]; }; -export type InterpreterOutput = RunningOutput | CodeOutput | ResultOutput | ErrorOutput; +/** + * An output which represents a message being displayed to the user. Not a true + * result from the program, but rather a customised notification meant to highlight + * events that occur outside execution of the program. + */ +export type NotificationOutput = { + type: 'notification'; + consoleLog: string; +}; + +export type InterpreterOutput = RunningOutput | CodeOutput | ResultOutput | ErrorOutput | NotificationOutput; export enum Role { Student = 'student', From 7d1ae610bc88d1be344bc3f2d02a7a7bf0eb7815 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 14:07:05 +0800 Subject: [PATCH 02/18] Add notification card in Repl component --- src/commons/repl/Repl.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/commons/repl/Repl.tsx b/src/commons/repl/Repl.tsx index acf1588770..26559fd04a 100644 --- a/src/commons/repl/Repl.tsx +++ b/src/commons/repl/Repl.tsx @@ -122,6 +122,12 @@ export const Output: React.FC = (props: OutputProps) => { ); } + case 'notification': + return ( + +
{"💡 " + props.output.consoleLog}
+
+ ); default: return ''; } From 58ff3ad1b1ca73da84e1ec3620b2bcb080d0bc62 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 14:09:59 +0800 Subject: [PATCH 03/18] Add style to notification ReplOutput --- src/styles/_workspace.scss | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/styles/_workspace.scss b/src/styles/_workspace.scss index 5bd5033131..b33b3802cf 100755 --- a/src/styles/_workspace.scss +++ b/src/styles/_workspace.scss @@ -2,6 +2,8 @@ $code-color-code: #ced9e0; $code-color-log: #dd8c60; $code-color-result: #ffffff; $code-color-error: #ff4444; +$code-background-color-notification: #f1b80f; +$code-color-notification: #f9f0d7; .workspace { height: 100%; @@ -766,6 +768,10 @@ $code-color-error: #ff4444; overflow-y: auto; margin: 0 0.5rem 0 0; + .#{$ns}-card:has(.notification-output) { + background-color: $code-background-color-notification; + } + .#{$ns}-card { background-color: $cadet-color-2; padding: 0.4rem 0.6rem 0.4rem 0.6rem; @@ -822,6 +828,10 @@ $code-color-error: #ff4444; .error-output { color: $code-color-error; } + + .notification-output { + color: $code-color-notification; + } } /* flush to align with editor bottom */ From 8376a62f6df09f12a9c22211b8498650b0e8243b Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 14:12:40 +0800 Subject: [PATCH 04/18] Add fields to workspace state for storing notification string --- src/commons/application/ApplicationTypes.ts | 2 ++ src/commons/workspace/WorkspaceTypes.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/commons/application/ApplicationTypes.ts b/src/commons/application/ApplicationTypes.ts index e65c455a8c..96a460017a 100644 --- a/src/commons/application/ApplicationTypes.ts +++ b/src/commons/application/ApplicationTypes.ts @@ -369,6 +369,8 @@ export const createDefaultWorkspace = (workspaceLocation: WorkspaceLocation): Wo originalValue: '' }, replValue: '', + hasTokenCounter: true, + customNotification: '', sharedbConnected: false, stepLimit: 1000, globals: [], diff --git a/src/commons/workspace/WorkspaceTypes.ts b/src/commons/workspace/WorkspaceTypes.ts index 5fb1a0e243..030d8bc6c4 100644 --- a/src/commons/workspace/WorkspaceTypes.ts +++ b/src/commons/workspace/WorkspaceTypes.ts @@ -136,6 +136,8 @@ export type WorkspaceState = { readonly externalLibrary: ExternalLibraryName; readonly replHistory: ReplHistory; readonly replValue: string; + readonly hasTokenCounter: boolean; + readonly customNotification: string; readonly sharedbConnected: boolean; readonly sideContentHeight?: number; readonly stepLimit: number; From 9d4282d5dba7c04eb6c8caaf707946c383b09446 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 14:16:37 +0800 Subject: [PATCH 05/18] Create logic for handling custom notifications and token counter string --- src/commons/workspace/WorkspaceReducer.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/commons/workspace/WorkspaceReducer.ts b/src/commons/workspace/WorkspaceReducer.ts index eaec3bdb0d..b434bebffc 100644 --- a/src/commons/workspace/WorkspaceReducer.ts +++ b/src/commons/workspace/WorkspaceReducer.ts @@ -10,6 +10,7 @@ import { defaultWorkspaceManager, ErrorOutput, InterpreterOutput, + NotificationOutput, ResultOutput } from '../application/ApplicationTypes'; import { LOG_OUT } from '../application/types/CommonsTypes'; @@ -360,10 +361,25 @@ export const WorkspaceReducer: Reducer = ( lastOutput = state[workspaceLocation].output.slice(-1)[0]; if (lastOutput !== undefined && lastOutput.type === 'running') { - newOutput = state[workspaceLocation].output.slice(0, -1).concat({ + const newOutputEntryWithLogs = { consoleLogs: lastOutput.consoleLogs, ...newOutputEntry - } as ResultOutput); + } as ResultOutput; + const notificationOutputs: NotificationOutput[] = []; + if (state[workspaceLocation].hasTokenCounter) { + notificationOutputs.push({ + consoleLog: "You have this ___ tokens in your code", + type: "notification" + }); + } + const customNotif = state[workspaceLocation].customNotification; + if (customNotif !== '') { + notificationOutputs.push({ + consoleLog: customNotif, + type: "notification" + }); + } + newOutput = state[workspaceLocation].output.slice(0, -1).concat([...notificationOutputs, newOutputEntryWithLogs]); } else { newOutput = state[workspaceLocation].output.concat({ consoleLogs: [], From 8b1137a9fc0bb5ac32c1f8d118c1615f94802eeb Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 15:17:20 +0800 Subject: [PATCH 06/18] Create button in ground control enable/disable token counter --- .../subcomponents/GroundControlDropzone.tsx | 38 +++++++++++++++---- src/styles/_groundcontrol.scss | 6 ++- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx b/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx index 95ed442d43..e8a09752f2 100644 --- a/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx +++ b/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx @@ -22,6 +22,7 @@ const MaterialDropzone: React.FunctionComponent = props => { const [file, setFile] = React.useState(undefined); const [isWarningShown, setPromptShown] = React.useState(false); const [forceUpdate, setForceUpdate] = React.useState(false); + const [hasTokenCounter, setHasTokenCounter] = React.useState(false); const [assessmentConfigId, setAssessmentConfigId] = React.useState(-1); React.useEffect(() => { @@ -83,7 +84,7 @@ const MaterialDropzone: React.FunctionComponent = props => { ); }, [isFocused, isDragActive, isDragAccept, isDragReject]); - const handleSwitchOnChange = React.useCallback(() => { + const handleForceUpdateSwitchOnChange = React.useCallback(() => { if (!forceUpdate) { setPromptShown(true); } else { @@ -91,13 +92,13 @@ const MaterialDropzone: React.FunctionComponent = props => { } }, [forceUpdate, setPromptShown, setForceUpdate]); - const toggleButton = React.useMemo( + const forceUpdateToggleButton = React.useMemo( () => (
- +
), - [forceUpdate, handleSwitchOnChange] + [forceUpdate, handleForceUpdateSwitchOnChange] ); const handleConfirmForceUpdate = React.useCallback(() => { @@ -108,6 +109,23 @@ const MaterialDropzone: React.FunctionComponent = props => { setPromptShown(false); }, [setPromptShown]); + const handleHasTokenCounterSwitchOnChange = React.useCallback(() => { + if (!hasTokenCounter) { + setHasTokenCounter(true); + } else { + setHasTokenCounter(false); + } + }, [hasTokenCounter, setHasTokenCounter]); + + const tokenCounterToggleButton = React.useMemo( + () => ( +
+ +
+ ), + [hasTokenCounter, handleHasTokenCounterSwitchOnChange] + ); + const confirmationPrompt = React.useMemo( () => (
@@ -160,9 +178,15 @@ const MaterialDropzone: React.FunctionComponent = props => { options={{ minimal: false }} />
-
-

Force update opened assessment

- {toggleButton} +
+
+

Force update opened assessment

+ {forceUpdateToggleButton} +
+
+

Enable token counter notification 

+ {tokenCounterToggleButton} +
)} diff --git a/src/styles/_groundcontrol.scss b/src/styles/_groundcontrol.scss index 859b2c78f2..fa2b65f6d1 100644 --- a/src/styles/_groundcontrol.scss +++ b/src/styles/_groundcontrol.scss @@ -35,7 +35,7 @@ .dropzone-prompt { & > * { - margin-top: 12px; + margin-top: 5px; } } @@ -54,6 +54,10 @@ } } + .toggle-buttons { + margin-top: 15px; + } + .date-cell-text { margin-right: 4px; } From b087c55b7e90212ffcce8567721e02611ff88c0c Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 15:35:38 +0800 Subject: [PATCH 07/18] Edit upload assessment form data to include hasTokenCounter field --- src/commons/sagas/BackendSaga.ts | 3 ++- src/features/groundControl/GroundControlActions.ts | 4 ++-- src/pages/academy/groundControl/GroundControl.tsx | 2 +- .../groundControl/subcomponents/GroundControlDropzone.tsx | 7 ++++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/commons/sagas/BackendSaga.ts b/src/commons/sagas/BackendSaga.ts index afaf380889..6d305d4275 100644 --- a/src/commons/sagas/BackendSaga.ts +++ b/src/commons/sagas/BackendSaga.ts @@ -1114,12 +1114,13 @@ function* BackendSaga(): SagaIterator { UPLOAD_ASSESSMENT, function* (action: ReturnType): any { const tokens: Tokens = yield selectTokens(); - const { file, forceUpdate, assessmentConfigId } = action.payload; + const { file, forceUpdate, hasTokenCounter, assessmentConfigId } = action.payload; const resp: Response | null = yield uploadAssessment( file, tokens, forceUpdate, + hasTokenCounter, assessmentConfigId ); if (!resp || !resp.ok) { diff --git a/src/features/groundControl/GroundControlActions.ts b/src/features/groundControl/GroundControlActions.ts index ec19de4826..960230e7a5 100644 --- a/src/features/groundControl/GroundControlActions.ts +++ b/src/features/groundControl/GroundControlActions.ts @@ -15,5 +15,5 @@ export const deleteAssessment = (id: number) => action(DELETE_ASSESSMENT, id); export const publishAssessment = (togglePublishTo: boolean, id: number) => action(PUBLISH_ASSESSMENT, { id, togglePublishTo }); -export const uploadAssessment = (file: File, forceUpdate: boolean, assessmentConfigId: number) => - action(UPLOAD_ASSESSMENT, { file, forceUpdate, assessmentConfigId }); +export const uploadAssessment = (file: File, forceUpdate: boolean, hasTokenCounter: boolean, assessmentConfigId: number) => + action(UPLOAD_ASSESSMENT, { file, forceUpdate, hasTokenCounter, assessmentConfigId }); diff --git a/src/pages/academy/groundControl/GroundControl.tsx b/src/pages/academy/groundControl/GroundControl.tsx index 06a09c2af8..7ca145544c 100644 --- a/src/pages/academy/groundControl/GroundControl.tsx +++ b/src/pages/academy/groundControl/GroundControl.tsx @@ -23,7 +23,7 @@ export type GroundControlProps = DispatchProps & StateProps; export type DispatchProps = { handleAssessmentOverviewFetch: () => void; handleDeleteAssessment: (id: number) => void; - handleUploadAssessment: (file: File, forceUpdate: boolean, assessmentConfigId: number) => void; + handleUploadAssessment: (file: File, forceUpdate: boolean, hasTokenCounter: boolean, assessmentConfigId: number) => void; handlePublishAssessment: (togglePublishTo: boolean, id: number) => void; handleAssessmentChangeDate: (id: number, openAt: string, closeAt: string) => void; handleFetchCourseConfigs: () => void; diff --git a/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx b/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx index e8a09752f2..881202419e 100644 --- a/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx +++ b/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx @@ -11,7 +11,7 @@ import { showWarningMessage } from '../../../../commons/utils/notifications/Noti export type DropzoneProps = DispatchProps & StateProps; type DispatchProps = { - handleUploadAssessment: (file: File, forceUpdate: boolean, assessmentConfigId: number) => void; + handleUploadAssessment: (file: File, forceUpdate: boolean, hasTokenCounter: boolean, assessmentConfigId: number) => void; }; type StateProps = { @@ -48,11 +48,12 @@ const MaterialDropzone: React.FunctionComponent = props => { return; } if (file) { - handleUploadAssessment(file, forceUpdate, assessmentConfigId); + handleUploadAssessment(file, forceUpdate, hasTokenCounter, assessmentConfigId); setForceUpdate(false); + setHasTokenCounter(false); } setFile(undefined); - }, [file, forceUpdate, handleUploadAssessment, assessmentConfigId]); + }, [file, forceUpdate, hasTokenCounter, handleUploadAssessment, assessmentConfigId]); const handleCancelUpload = React.useCallback(() => setFile(undefined), [setFile]); const handleDropAccepted = React.useCallback( From 63613e1878cac8c639457e958d23b6d86c7be115 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 20:33:23 +0800 Subject: [PATCH 08/18] Add workspace actions to handle enabling token counter --- src/commons/application/ApplicationTypes.ts | 2 +- src/commons/assessment/AssessmentTypes.ts | 1 + .../AssessmentWorkspace.tsx | 21 +++++++++++++++---- src/commons/sagas/RequestsSaga.ts | 2 ++ src/commons/workspace/WorkspaceActions.ts | 4 ++++ src/commons/workspace/WorkspaceReducer.ts | 15 ++++++++++--- src/commons/workspace/WorkspaceTypes.ts | 1 + 7 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/commons/application/ApplicationTypes.ts b/src/commons/application/ApplicationTypes.ts index 96a460017a..1c437fc96a 100644 --- a/src/commons/application/ApplicationTypes.ts +++ b/src/commons/application/ApplicationTypes.ts @@ -369,7 +369,7 @@ export const createDefaultWorkspace = (workspaceLocation: WorkspaceLocation): Wo originalValue: '' }, replValue: '', - hasTokenCounter: true, + hasTokenCounter: false, customNotification: '', sharedbConnected: false, stepLimit: 1000, diff --git a/src/commons/assessment/AssessmentTypes.ts b/src/commons/assessment/AssessmentTypes.ts index 0169f52ad0..bfbc2d2b31 100644 --- a/src/commons/assessment/AssessmentTypes.ts +++ b/src/commons/assessment/AssessmentTypes.ts @@ -81,6 +81,7 @@ export type Assessment = { type: AssessmentType; globalDeployment?: Library; // For mission control graderDeployment?: Library; // For mission control + hasTokenCounter?: boolean; id: number; longSummary: string; missionPDF: string; diff --git a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx index 6aa3fd43c9..e9436923f4 100644 --- a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx +++ b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx @@ -76,6 +76,7 @@ import { changeExecTime, changeSideContentHeight, clearReplOutput, + enableTokenCounter, evalEditor, evalRepl, evalTestcase, @@ -111,6 +112,7 @@ const AssessmentWorkspace: React.FC = props => { const { isMobileBreakpoint } = useResponsive(); const assessment = useTypedSelector(state => state.session.assessments.get(props.assessmentId)); + const [selectedTab, setSelectedTab] = useState( assessment?.questions[props.questionId].grader !== undefined ? SideContentType.grading @@ -149,7 +151,8 @@ const AssessmentWorkspace: React.FC = props => { handleEditorUpdateBreakpoints, handleReplEval, handleSave, - handleUpdateHasUnsavedChanges + handleUpdateHasUnsavedChanges, + handleEnableTokenCounter } = useMemo(() => { return { handleTestcaseEval: (id: number) => dispatch(evalTestcase(workspaceLocation, id)), @@ -173,7 +176,9 @@ const AssessmentWorkspace: React.FC = props => { handleSave: (id: number, answer: number | string | ContestEntry[]) => dispatch(submitAnswer(id, answer)), handleUpdateHasUnsavedChanges: (hasUnsavedChanges: boolean) => - dispatch(updateHasUnsavedChanges(workspaceLocation, hasUnsavedChanges)) + dispatch(updateHasUnsavedChanges(workspaceLocation, hasUnsavedChanges)), + handleEnableTokenCounter: () => + dispatch(enableTokenCounter(workspaceLocation)) }; }, [dispatch]); @@ -238,6 +243,15 @@ const AssessmentWorkspace: React.FC = props => { checkWorkspaceReset(); }); + /** + * Handles toggling enabling token counter depending on assessment properties + */ + useEffect(() => { + if (true) { + handleEnableTokenCounter(); + } + }, [props, handleEnableTokenCounter]); + /** * Handles toggling of relevant SideContentTabs when mobile breakpoint it hit */ @@ -705,7 +719,7 @@ const AssessmentWorkspace: React.FC = props => { const workspaceHandlers = useMemo(() => { return { handleSideContentHeightChange: (heightChange: number) => - dispatch(changeSideContentHeight(heightChange, workspaceLocation)) + dispatch(changeSideContentHeight(heightChange, workspaceLocation)), }; }, [dispatch]); @@ -839,7 +853,6 @@ const AssessmentWorkspace: React.FC = props => { sideBarProps: sideBarProps, mobileSideContentProps: mobileSideContentProps(questionId) }; - return (
{overlay} diff --git a/src/commons/sagas/RequestsSaga.ts b/src/commons/sagas/RequestsSaga.ts index 8242cce90b..0a8e8d54a2 100644 --- a/src/commons/sagas/RequestsSaga.ts +++ b/src/commons/sagas/RequestsSaga.ts @@ -924,11 +924,13 @@ export const uploadAssessment = async ( file: File, tokens: Tokens, forceUpdate: boolean, + hasTokenCounter: boolean, assessmentConfigId: number ): Promise => { const formData = new FormData(); formData.append('assessment[file]', file); formData.append('forceUpdate', String(forceUpdate)); + formData.append('hasTokenCounter', String(hasTokenCounter)); formData.append('assessmentConfigId', String(assessmentConfigId)); const resp = await request(`${courseId()}/admin/assessments`, 'POST', { ...tokens, diff --git a/src/commons/workspace/WorkspaceActions.ts b/src/commons/workspace/WorkspaceActions.ts index d1966135a9..0854fa18b3 100644 --- a/src/commons/workspace/WorkspaceActions.ts +++ b/src/commons/workspace/WorkspaceActions.ts @@ -28,6 +28,7 @@ import { CLEAR_REPL_OUTPUT, CLEAR_REPL_OUTPUT_LAST, EditorTabState, + ENABLE_TOKEN_COUNTER, END_CLEAR_CONTEXT, EVAL_EDITOR, EVAL_EDITOR_AND_TESTCASES, @@ -178,6 +179,9 @@ export const evalTestcase = (workspaceLocation: WorkspaceLocation, testcaseId: n export const runAllTestcases = (workspaceLocation: WorkspaceLocation) => action(EVAL_EDITOR_AND_TESTCASES, { workspaceLocation }); +export const enableTokenCounter = (workspaceLocation: WorkspaceLocation) => + action(ENABLE_TOKEN_COUNTER, { workspaceLocation }); + export const toggleFolderMode = (workspaceLocation: WorkspaceLocation) => action(TOGGLE_FOLDER_MODE, { workspaceLocation }); diff --git a/src/commons/workspace/WorkspaceReducer.ts b/src/commons/workspace/WorkspaceReducer.ts index b434bebffc..200b90f61f 100644 --- a/src/commons/workspace/WorkspaceReducer.ts +++ b/src/commons/workspace/WorkspaceReducer.ts @@ -45,6 +45,7 @@ import { CLEAR_REPL_OUTPUT, CLEAR_REPL_OUTPUT_LAST, EditorTabState, + ENABLE_TOKEN_COUNTER, END_CLEAR_CONTEXT, EVAL_EDITOR, EVAL_REPL, @@ -335,6 +336,14 @@ export const WorkspaceReducer: Reducer = ( ...defaultWorkspaceManager, playground: playgroundWorkspace }; + case ENABLE_TOKEN_COUNTER: + return { + ...state, + [workspaceLocation]: { + ...state[workspaceLocation], + hasTokenCounter: true + } + } case EVAL_EDITOR: return { ...state, @@ -372,10 +381,10 @@ export const WorkspaceReducer: Reducer = ( type: "notification" }); } - const customNotif = state[workspaceLocation].customNotification; - if (customNotif !== '') { + const customNotification = state[workspaceLocation].customNotification; + if (customNotification !== '') { notificationOutputs.push({ - consoleLog: customNotif, + consoleLog: customNotification, type: "notification" }); } diff --git a/src/commons/workspace/WorkspaceTypes.ts b/src/commons/workspace/WorkspaceTypes.ts index 030d8bc6c4..a9a6e9925c 100644 --- a/src/commons/workspace/WorkspaceTypes.ts +++ b/src/commons/workspace/WorkspaceTypes.ts @@ -21,6 +21,7 @@ export const CLEAR_REPL_INPUT = 'CLEAR_REPL_INPUT'; export const CLEAR_REPL_OUTPUT = 'CLEAR_REPL_OUTPUT'; export const CLEAR_REPL_OUTPUT_LAST = 'CLEAR_REPL_OUTPUT_LAST'; export const END_CLEAR_CONTEXT = 'END_CLEAR_CONTEXT'; +export const ENABLE_TOKEN_COUNTER = 'ENABLE_TOKEN_COUNTER'; export const EVAL_EDITOR = 'EVAL_EDITOR'; export const EVAL_REPL = 'EVAL_REPL'; export const PROMPT_AUTOCOMPLETE = 'PROMPT_AUTOCOMPLETE'; From 729d8ea5fe3e083f0243f944633c7e4f98fc4eb6 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 22:54:28 +0800 Subject: [PATCH 09/18] Revert "Edit upload assessment form data to include hasTokenCounter field" This reverts commit b087c55b7e90212ffcce8567721e02611ff88c0c. --- src/commons/sagas/BackendSaga.ts | 3 +-- src/features/groundControl/GroundControlActions.ts | 4 ++-- src/pages/academy/groundControl/GroundControl.tsx | 2 +- .../groundControl/subcomponents/GroundControlDropzone.tsx | 7 +++---- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/commons/sagas/BackendSaga.ts b/src/commons/sagas/BackendSaga.ts index 6d305d4275..afaf380889 100644 --- a/src/commons/sagas/BackendSaga.ts +++ b/src/commons/sagas/BackendSaga.ts @@ -1114,13 +1114,12 @@ function* BackendSaga(): SagaIterator { UPLOAD_ASSESSMENT, function* (action: ReturnType): any { const tokens: Tokens = yield selectTokens(); - const { file, forceUpdate, hasTokenCounter, assessmentConfigId } = action.payload; + const { file, forceUpdate, assessmentConfigId } = action.payload; const resp: Response | null = yield uploadAssessment( file, tokens, forceUpdate, - hasTokenCounter, assessmentConfigId ); if (!resp || !resp.ok) { diff --git a/src/features/groundControl/GroundControlActions.ts b/src/features/groundControl/GroundControlActions.ts index 960230e7a5..ec19de4826 100644 --- a/src/features/groundControl/GroundControlActions.ts +++ b/src/features/groundControl/GroundControlActions.ts @@ -15,5 +15,5 @@ export const deleteAssessment = (id: number) => action(DELETE_ASSESSMENT, id); export const publishAssessment = (togglePublishTo: boolean, id: number) => action(PUBLISH_ASSESSMENT, { id, togglePublishTo }); -export const uploadAssessment = (file: File, forceUpdate: boolean, hasTokenCounter: boolean, assessmentConfigId: number) => - action(UPLOAD_ASSESSMENT, { file, forceUpdate, hasTokenCounter, assessmentConfigId }); +export const uploadAssessment = (file: File, forceUpdate: boolean, assessmentConfigId: number) => + action(UPLOAD_ASSESSMENT, { file, forceUpdate, assessmentConfigId }); diff --git a/src/pages/academy/groundControl/GroundControl.tsx b/src/pages/academy/groundControl/GroundControl.tsx index 7ca145544c..06a09c2af8 100644 --- a/src/pages/academy/groundControl/GroundControl.tsx +++ b/src/pages/academy/groundControl/GroundControl.tsx @@ -23,7 +23,7 @@ export type GroundControlProps = DispatchProps & StateProps; export type DispatchProps = { handleAssessmentOverviewFetch: () => void; handleDeleteAssessment: (id: number) => void; - handleUploadAssessment: (file: File, forceUpdate: boolean, hasTokenCounter: boolean, assessmentConfigId: number) => void; + handleUploadAssessment: (file: File, forceUpdate: boolean, assessmentConfigId: number) => void; handlePublishAssessment: (togglePublishTo: boolean, id: number) => void; handleAssessmentChangeDate: (id: number, openAt: string, closeAt: string) => void; handleFetchCourseConfigs: () => void; diff --git a/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx b/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx index 881202419e..e8a09752f2 100644 --- a/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx +++ b/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx @@ -11,7 +11,7 @@ import { showWarningMessage } from '../../../../commons/utils/notifications/Noti export type DropzoneProps = DispatchProps & StateProps; type DispatchProps = { - handleUploadAssessment: (file: File, forceUpdate: boolean, hasTokenCounter: boolean, assessmentConfigId: number) => void; + handleUploadAssessment: (file: File, forceUpdate: boolean, assessmentConfigId: number) => void; }; type StateProps = { @@ -48,12 +48,11 @@ const MaterialDropzone: React.FunctionComponent = props => { return; } if (file) { - handleUploadAssessment(file, forceUpdate, hasTokenCounter, assessmentConfigId); + handleUploadAssessment(file, forceUpdate, assessmentConfigId); setForceUpdate(false); - setHasTokenCounter(false); } setFile(undefined); - }, [file, forceUpdate, hasTokenCounter, handleUploadAssessment, assessmentConfigId]); + }, [file, forceUpdate, handleUploadAssessment, assessmentConfigId]); const handleCancelUpload = React.useCallback(() => setFile(undefined), [setFile]); const handleDropAccepted = React.useCallback( From d064e89b59347bee6b6e2633d2fc22b034787d1b Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 22:54:50 +0800 Subject: [PATCH 10/18] Revert "Create button in ground control enable/disable token counter" This reverts commit 8b1137a9fc0bb5ac32c1f8d118c1615f94802eeb. --- .../subcomponents/GroundControlDropzone.tsx | 38 ++++--------------- src/styles/_groundcontrol.scss | 6 +-- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx b/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx index e8a09752f2..95ed442d43 100644 --- a/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx +++ b/src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx @@ -22,7 +22,6 @@ const MaterialDropzone: React.FunctionComponent = props => { const [file, setFile] = React.useState(undefined); const [isWarningShown, setPromptShown] = React.useState(false); const [forceUpdate, setForceUpdate] = React.useState(false); - const [hasTokenCounter, setHasTokenCounter] = React.useState(false); const [assessmentConfigId, setAssessmentConfigId] = React.useState(-1); React.useEffect(() => { @@ -84,7 +83,7 @@ const MaterialDropzone: React.FunctionComponent = props => { ); }, [isFocused, isDragActive, isDragAccept, isDragReject]); - const handleForceUpdateSwitchOnChange = React.useCallback(() => { + const handleSwitchOnChange = React.useCallback(() => { if (!forceUpdate) { setPromptShown(true); } else { @@ -92,13 +91,13 @@ const MaterialDropzone: React.FunctionComponent = props => { } }, [forceUpdate, setPromptShown, setForceUpdate]); - const forceUpdateToggleButton = React.useMemo( + const toggleButton = React.useMemo( () => (
- +
), - [forceUpdate, handleForceUpdateSwitchOnChange] + [forceUpdate, handleSwitchOnChange] ); const handleConfirmForceUpdate = React.useCallback(() => { @@ -109,23 +108,6 @@ const MaterialDropzone: React.FunctionComponent = props => { setPromptShown(false); }, [setPromptShown]); - const handleHasTokenCounterSwitchOnChange = React.useCallback(() => { - if (!hasTokenCounter) { - setHasTokenCounter(true); - } else { - setHasTokenCounter(false); - } - }, [hasTokenCounter, setHasTokenCounter]); - - const tokenCounterToggleButton = React.useMemo( - () => ( -
- -
- ), - [hasTokenCounter, handleHasTokenCounterSwitchOnChange] - ); - const confirmationPrompt = React.useMemo( () => (
@@ -178,15 +160,9 @@ const MaterialDropzone: React.FunctionComponent = props => { options={{ minimal: false }} />
-
-
-

Force update opened assessment

- {forceUpdateToggleButton} -
-
-

Enable token counter notification 

- {tokenCounterToggleButton} -
+
+

Force update opened assessment

+ {toggleButton}
)} diff --git a/src/styles/_groundcontrol.scss b/src/styles/_groundcontrol.scss index fa2b65f6d1..859b2c78f2 100644 --- a/src/styles/_groundcontrol.scss +++ b/src/styles/_groundcontrol.scss @@ -35,7 +35,7 @@ .dropzone-prompt { & > * { - margin-top: 5px; + margin-top: 12px; } } @@ -54,10 +54,6 @@ } } - .toggle-buttons { - margin-top: 15px; - } - .date-cell-text { margin-right: 4px; } From 6be90d15c7e900626495cd887a886ce56b7fee48 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Sat, 3 Feb 2024 23:12:24 +0800 Subject: [PATCH 11/18] Add hasTokenCount toggle button on assessment configuration panel --- src/commons/assessment/AssessmentTypes.ts | 1 + src/commons/mocks/AssessmentMocks.ts | 8 ++++++++ src/commons/sagas/BackendSaga.ts | 1 + src/commons/sagas/RequestsSaga.ts | 2 -- .../AssessmentConfigPanel.tsx | 19 +++++++++++++++++++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/commons/assessment/AssessmentTypes.ts b/src/commons/assessment/AssessmentTypes.ts index bfbc2d2b31..e7732f04a2 100644 --- a/src/commons/assessment/AssessmentTypes.ts +++ b/src/commons/assessment/AssessmentTypes.ts @@ -95,6 +95,7 @@ export type AssessmentConfiguration = { isManuallyGraded: boolean; displayInDashboard: boolean; hoursBeforeEarlyXpDecay: number; + hasTokenCounter: boolean; earlySubmissionXp: number; }; diff --git a/src/commons/mocks/AssessmentMocks.ts b/src/commons/mocks/AssessmentMocks.ts index c79600441c..b92648b1ce 100644 --- a/src/commons/mocks/AssessmentMocks.ts +++ b/src/commons/mocks/AssessmentMocks.ts @@ -22,6 +22,7 @@ export const mockAssessmentConfigurations: AssessmentConfiguration[][] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 }, { @@ -30,6 +31,7 @@ export const mockAssessmentConfigurations: AssessmentConfiguration[][] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 }, { @@ -38,6 +40,7 @@ export const mockAssessmentConfigurations: AssessmentConfiguration[][] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 }, { @@ -46,6 +49,7 @@ export const mockAssessmentConfigurations: AssessmentConfiguration[][] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: true, earlySubmissionXp: 200 }, { @@ -54,6 +58,7 @@ export const mockAssessmentConfigurations: AssessmentConfiguration[][] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 } ], @@ -64,6 +69,7 @@ export const mockAssessmentConfigurations: AssessmentConfiguration[][] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 }, { @@ -72,6 +78,7 @@ export const mockAssessmentConfigurations: AssessmentConfiguration[][] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 }, { @@ -80,6 +87,7 @@ export const mockAssessmentConfigurations: AssessmentConfiguration[][] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 } ] diff --git a/src/commons/sagas/BackendSaga.ts b/src/commons/sagas/BackendSaga.ts index afaf380889..729ec5fcd4 100644 --- a/src/commons/sagas/BackendSaga.ts +++ b/src/commons/sagas/BackendSaga.ts @@ -952,6 +952,7 @@ function* BackendSaga(): SagaIterator { isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 0, + hasTokenCounter: false, earlySubmissionXp: 0 } ]; diff --git a/src/commons/sagas/RequestsSaga.ts b/src/commons/sagas/RequestsSaga.ts index 0a8e8d54a2..8242cce90b 100644 --- a/src/commons/sagas/RequestsSaga.ts +++ b/src/commons/sagas/RequestsSaga.ts @@ -924,13 +924,11 @@ export const uploadAssessment = async ( file: File, tokens: Tokens, forceUpdate: boolean, - hasTokenCounter: boolean, assessmentConfigId: number ): Promise => { const formData = new FormData(); formData.append('assessment[file]', file); formData.append('forceUpdate', String(forceUpdate)); - formData.append('hasTokenCounter', String(hasTokenCounter)); formData.append('assessmentConfigId', String(assessmentConfigId)); const resp = await request(`${courseId()}/admin/assessments`, 'POST', { ...tokens, diff --git a/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx b/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx index 5c58c045ad..bf2f245aed 100644 --- a/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx +++ b/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx @@ -49,6 +49,15 @@ const AssessmentConfigPanel: React.FC = props => { gridApi.current?.getDisplayedRowAtIndex(index)?.setDataValue('displayInDashboard', value); }; + const setHasTokenCounter = (index: number, value: boolean) => { + const temp = [...assessmentConfig.current]; + temp[index] = { + ...temp[index], + hasTokenCounter: value + }; + setAssessmentConfig(temp); + } + const setEarlyXp = (index: number, value: number) => { const temp = [...assessmentConfig.current]; temp[index] = { @@ -82,6 +91,7 @@ const AssessmentConfigPanel: React.FC = props => { isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 0, + hasTokenCounter: false, earlySubmissionXp: 0 }); setAssessmentConfig(temp); @@ -126,6 +136,15 @@ const AssessmentConfigPanel: React.FC = props => { field: 'displayInDashboard' } }, + { + headerName: 'Has Token Counter', + field: 'hasTokenCounter', + cellRenderer: BooleanCell, + cellRendererParams: { + setStateHandler: setHasTokenCounter, + field: 'hasTokenCounter' + } + }, { headerName: 'Max Bonus XP', field: 'earlySubmissionXp', From d71214257540250f6d562556b514f0940e88f5c4 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Tue, 6 Feb 2024 10:53:33 +0800 Subject: [PATCH 12/18] Integrate token counter --- src/commons/application/ApplicationTypes.ts | 1 + src/commons/sagas/WorkspaceSaga.ts | 12 +++++++++++- src/commons/sagas/__tests__/BackendSaga.ts | 6 ++++++ src/commons/workspace/WorkspaceActions.ts | 4 ++++ src/commons/workspace/WorkspaceReducer.ts | 14 +++++++++++++- src/commons/workspace/WorkspaceTypes.ts | 2 ++ 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/commons/application/ApplicationTypes.ts b/src/commons/application/ApplicationTypes.ts index 1c437fc96a..cfd4735a51 100644 --- a/src/commons/application/ApplicationTypes.ts +++ b/src/commons/application/ApplicationTypes.ts @@ -370,6 +370,7 @@ export const createDefaultWorkspace = (workspaceLocation: WorkspaceLocation): Wo }, replValue: '', hasTokenCounter: false, + tokenCount: 0, customNotification: '', sharedbConnected: false, stepLimit: 1000, diff --git a/src/commons/sagas/WorkspaceSaga.ts b/src/commons/sagas/WorkspaceSaga.ts index 1bcb791aab..4dc0f8edeb 100644 --- a/src/commons/sagas/WorkspaceSaga.ts +++ b/src/commons/sagas/WorkspaceSaga.ts @@ -1,3 +1,4 @@ +import { tokenizer } from 'acorn'; import { FSModule } from 'browserfs/dist/node/core/FS'; import { Context, @@ -10,7 +11,7 @@ import { runFilesInContext, runInContext } from 'js-slang'; -import { TRY_AGAIN } from 'js-slang/dist/constants'; +import { ACORN_PARSE_OPTIONS, TRY_AGAIN } from 'js-slang/dist/constants'; import { defineSymbol } from 'js-slang/dist/createContext'; import { InterruptedError } from 'js-slang/dist/errors/errors'; import { parse } from 'js-slang/dist/parser/parser'; @@ -1272,6 +1273,14 @@ export function* evalCode( yield* dumpDisplayBuffer(workspaceLocation, isStoriesBlock, storyEnv); + // Change token count if its assessment and EVAL_EDITOR + if (actionType === EVAL_EDITOR && workspaceLocation === "assessment") { + let tokenCounter = 0; + const tokens = [...tokenizer(entrypointCode, ACORN_PARSE_OPTIONS)]; + tokenCounter = tokens.length; + yield put(actions.addTokenCount(workspaceLocation, tokenCounter)); + } + // Do not write interpreter output to REPL, if executing chunks (e.g. prepend/postpend blocks) if (actionType !== EVAL_SILENT) { if (!isStoriesBlock) { @@ -1282,6 +1291,7 @@ export function* evalCode( } } + // For EVAL_EDITOR and EVAL_REPL, we send notification to workspace that a program has been evaluated if (actionType === EVAL_EDITOR || actionType === EVAL_REPL || actionType === DEBUG_RESUME) { if (context.errors.length > 0) { diff --git a/src/commons/sagas/__tests__/BackendSaga.ts b/src/commons/sagas/__tests__/BackendSaga.ts index 164d0d57ff..3bc5e8112f 100644 --- a/src/commons/sagas/__tests__/BackendSaga.ts +++ b/src/commons/sagas/__tests__/BackendSaga.ts @@ -216,6 +216,7 @@ const mockAssessmentConfigurations: AssessmentConfiguration[] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 }, { @@ -224,6 +225,7 @@ const mockAssessmentConfigurations: AssessmentConfiguration[] = [ isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 }, { @@ -232,6 +234,7 @@ const mockAssessmentConfigurations: AssessmentConfiguration[] = [ isManuallyGraded: false, displayInDashboard: false, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 }, { @@ -240,6 +243,7 @@ const mockAssessmentConfigurations: AssessmentConfiguration[] = [ isManuallyGraded: false, displayInDashboard: false, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: true, earlySubmissionXp: 200 }, { @@ -248,6 +252,7 @@ const mockAssessmentConfigurations: AssessmentConfiguration[] = [ isManuallyGraded: true, displayInDashboard: false, hoursBeforeEarlyXpDecay: 48, + hasTokenCounter: false, earlySubmissionXp: 200 } ]; @@ -998,6 +1003,7 @@ describe('Test CREATE_COURSE action', () => { isManuallyGraded: true, displayInDashboard: true, hoursBeforeEarlyXpDecay: 0, + hasTokenCounter: false, earlySubmissionXp: 0 } ]; diff --git a/src/commons/workspace/WorkspaceActions.ts b/src/commons/workspace/WorkspaceActions.ts index 0854fa18b3..07c78942ae 100644 --- a/src/commons/workspace/WorkspaceActions.ts +++ b/src/commons/workspace/WorkspaceActions.ts @@ -15,6 +15,7 @@ import { NOTIFY_PROGRAM_EVALUATED } from '../sideContent/SideContentTypes'; import { ADD_EDITOR_TAB, ADD_HTML_CONSOLE_ERROR, + ADD_TOKEN_COUNT, BEGIN_CLEAR_CONTEXT, BROWSE_REPL_HISTORY_DOWN, BROWSE_REPL_HISTORY_UP, @@ -73,6 +74,9 @@ import { WorkspaceState } from './WorkspaceTypes'; +export const addTokenCount = (workspaceLocation: WorkspaceLocation, tokenCount: number) => + action(ADD_TOKEN_COUNT, { workspaceLocation, tokenCount }); + export const browseReplHistoryDown = (workspaceLocation: WorkspaceLocation) => action(BROWSE_REPL_HISTORY_DOWN, { workspaceLocation }); diff --git a/src/commons/workspace/WorkspaceReducer.ts b/src/commons/workspace/WorkspaceReducer.ts index 200b90f61f..6ea5f79f2d 100644 --- a/src/commons/workspace/WorkspaceReducer.ts +++ b/src/commons/workspace/WorkspaceReducer.ts @@ -35,6 +35,7 @@ import Constants from '../utils/Constants'; import { createContext } from '../utils/JsSlangHelper'; import { ADD_EDITOR_TAB, + ADD_TOKEN_COUNT, BROWSE_REPL_HISTORY_DOWN, BROWSE_REPL_HISTORY_UP, CHANGE_EXEC_TIME, @@ -124,6 +125,16 @@ export const WorkspaceReducer: Reducer = ( } switch (action.type) { + + case ADD_TOKEN_COUNT: + return { + ...state, + [workspaceLocation]: { + ...state[workspaceLocation], + tokenCount: action.payload.tokenCount + } + } + case BROWSE_REPL_HISTORY_DOWN: if (state[workspaceLocation].replHistory.browseIndex === null) { // Not yet started browsing history, nothing to do @@ -363,6 +374,7 @@ export const WorkspaceReducer: Reducer = ( }; case EVAL_INTERPRETER_SUCCESS: const execType = state[workspaceLocation].context.executionMethod; + const tokens = state[workspaceLocation].tokenCount; const newOutputEntry: Partial = { type: action.payload.type as 'result' | undefined, value: execType === 'interpreter' ? action.payload.value : stringify(action.payload.value) @@ -377,7 +389,7 @@ export const WorkspaceReducer: Reducer = ( const notificationOutputs: NotificationOutput[] = []; if (state[workspaceLocation].hasTokenCounter) { notificationOutputs.push({ - consoleLog: "You have this ___ tokens in your code", + consoleLog: `This program has ${tokens} tokens in your code`, type: "notification" }); } diff --git a/src/commons/workspace/WorkspaceTypes.ts b/src/commons/workspace/WorkspaceTypes.ts index a9a6e9925c..f2f3ffd2ea 100644 --- a/src/commons/workspace/WorkspaceTypes.ts +++ b/src/commons/workspace/WorkspaceTypes.ts @@ -9,6 +9,7 @@ import { AutogradingResult, Testcase } from '../assessment/AssessmentTypes'; import { HighlightedLines, Position } from '../editor/EditorTypes'; export const ADD_HTML_CONSOLE_ERROR = 'ADD_HTML_CONSOLE_ERROR'; +export const ADD_TOKEN_COUNT = 'ADD_TOKEN_COUNT'; export const BEGIN_CLEAR_CONTEXT = 'BEGIN_CLEAR_CONTEXT'; export const BROWSE_REPL_HISTORY_DOWN = 'BROWSE_REPL_HISTORY_DOWN'; export const BROWSE_REPL_HISTORY_UP = 'BROWSE_REPL_HISTORY_UP'; @@ -138,6 +139,7 @@ export type WorkspaceState = { readonly replHistory: ReplHistory; readonly replValue: string; readonly hasTokenCounter: boolean; + readonly tokenCount: integer; readonly customNotification: string; readonly sharedbConnected: boolean; readonly sideContentHeight?: number; From d22544beaebf45d930f93f9b2e4df6b7e43b673e Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Tue, 6 Feb 2024 19:19:33 +0800 Subject: [PATCH 13/18] Conditionally render token counter depending on assessment config --- src/commons/assessment/AssessmentTypes.ts | 2 +- src/commons/assessmentWorkspace/AssessmentWorkspace.tsx | 2 +- src/commons/sagas/BackendSaga.ts | 2 +- .../assessmentConfigPanel/AssessmentConfigPanel.tsx | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/commons/assessment/AssessmentTypes.ts b/src/commons/assessment/AssessmentTypes.ts index e7732f04a2..fa8f91f841 100644 --- a/src/commons/assessment/AssessmentTypes.ts +++ b/src/commons/assessment/AssessmentTypes.ts @@ -95,8 +95,8 @@ export type AssessmentConfiguration = { isManuallyGraded: boolean; displayInDashboard: boolean; hoursBeforeEarlyXpDecay: number; - hasTokenCounter: boolean; earlySubmissionXp: number; + hasTokenCounter: boolean; }; export interface IProgrammingQuestion extends BaseQuestion { diff --git a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx index e9436923f4..83965a4841 100644 --- a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx +++ b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx @@ -247,7 +247,7 @@ const AssessmentWorkspace: React.FC = props => { * Handles toggling enabling token counter depending on assessment properties */ useEffect(() => { - if (true) { + if (props.assessmentConfiguration.hasTokenCounter) { handleEnableTokenCounter(); } }, [props, handleEnableTokenCounter]); diff --git a/src/commons/sagas/BackendSaga.ts b/src/commons/sagas/BackendSaga.ts index 729ec5fcd4..e29d7bc208 100644 --- a/src/commons/sagas/BackendSaga.ts +++ b/src/commons/sagas/BackendSaga.ts @@ -754,7 +754,7 @@ function* BackendSaga(): SagaIterator { getAssessmentConfigs, tokens ); - + console.log(assessmentConfigs); if (assessmentConfigs) { yield put(actions.setAssessmentConfigurations(assessmentConfigs)); } diff --git a/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx b/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx index bf2f245aed..3b3be0474b 100644 --- a/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx +++ b/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx @@ -56,6 +56,7 @@ const AssessmentConfigPanel: React.FC = props => { hasTokenCounter: value }; setAssessmentConfig(temp); + gridApi.current?.getDisplayedRowAtIndex(index)?.setDataValue('hasTokenCounter', value); } const setEarlyXp = (index: number, value: number) => { From 88355781db8b18b856cfe56169378a9ef0da37e7 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Mon, 12 Feb 2024 15:37:44 +0800 Subject: [PATCH 14/18] Remove console.log --- src/commons/sagas/BackendSaga.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/commons/sagas/BackendSaga.ts b/src/commons/sagas/BackendSaga.ts index e29d7bc208..6070f9e09e 100644 --- a/src/commons/sagas/BackendSaga.ts +++ b/src/commons/sagas/BackendSaga.ts @@ -754,7 +754,6 @@ function* BackendSaga(): SagaIterator { getAssessmentConfigs, tokens ); - console.log(assessmentConfigs); if (assessmentConfigs) { yield put(actions.setAssessmentConfigurations(assessmentConfigs)); } From a0aa6fbfb4443a807a508f5eba939d95201f4e22 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Mon, 12 Feb 2024 16:04:39 +0800 Subject: [PATCH 15/18] Fix bug where turning off token counter would not work in repl --- .../assessmentWorkspace/AssessmentWorkspace.tsx | 14 ++++++++++---- src/commons/workspace/WorkspaceActions.ts | 4 ++++ src/commons/workspace/WorkspaceReducer.ts | 11 ++++++++++- src/commons/workspace/WorkspaceTypes.ts | 1 + 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx index 83965a4841..6afffc8934 100644 --- a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx +++ b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx @@ -76,6 +76,7 @@ import { changeExecTime, changeSideContentHeight, clearReplOutput, + disableTokenCounter, enableTokenCounter, evalEditor, evalRepl, @@ -152,7 +153,8 @@ const AssessmentWorkspace: React.FC = props => { handleReplEval, handleSave, handleUpdateHasUnsavedChanges, - handleEnableTokenCounter + handleEnableTokenCounter, + handleDisableTokenCounter } = useMemo(() => { return { handleTestcaseEval: (id: number) => dispatch(evalTestcase(workspaceLocation, id)), @@ -178,7 +180,9 @@ const AssessmentWorkspace: React.FC = props => { handleUpdateHasUnsavedChanges: (hasUnsavedChanges: boolean) => dispatch(updateHasUnsavedChanges(workspaceLocation, hasUnsavedChanges)), handleEnableTokenCounter: () => - dispatch(enableTokenCounter(workspaceLocation)) + dispatch(enableTokenCounter(workspaceLocation)), + handleDisableTokenCounter: () => + dispatch(disableTokenCounter(workspaceLocation)) }; }, [dispatch]); @@ -244,13 +248,15 @@ const AssessmentWorkspace: React.FC = props => { }); /** - * Handles toggling enabling token counter depending on assessment properties + * Handles toggling enabling and disabling token counter depending on assessment properties */ useEffect(() => { if (props.assessmentConfiguration.hasTokenCounter) { handleEnableTokenCounter(); + } else { + handleDisableTokenCounter(); } - }, [props, handleEnableTokenCounter]); + }, [props, handleEnableTokenCounter, handleDisableTokenCounter]); /** * Handles toggling of relevant SideContentTabs when mobile breakpoint it hit diff --git a/src/commons/workspace/WorkspaceActions.ts b/src/commons/workspace/WorkspaceActions.ts index 0f58d25108..4ddcc713da 100644 --- a/src/commons/workspace/WorkspaceActions.ts +++ b/src/commons/workspace/WorkspaceActions.ts @@ -28,6 +28,7 @@ import { CLEAR_REPL_INPUT, CLEAR_REPL_OUTPUT, CLEAR_REPL_OUTPUT_LAST, + DISABLE_TOKEN_COUNTER, EditorTabState, ENABLE_TOKEN_COUNTER, END_CLEAR_CONTEXT, @@ -186,6 +187,9 @@ export const runAllTestcases = (workspaceLocation: WorkspaceLocation) => export const enableTokenCounter = (workspaceLocation: WorkspaceLocation) => action(ENABLE_TOKEN_COUNTER, { workspaceLocation }); +export const disableTokenCounter = (workspaceLocation: WorkspaceLocation) => + action(DISABLE_TOKEN_COUNTER, { workspaceLocation }); + export const toggleFolderMode = (workspaceLocation: WorkspaceLocation) => action(TOGGLE_FOLDER_MODE, { workspaceLocation }); diff --git a/src/commons/workspace/WorkspaceReducer.ts b/src/commons/workspace/WorkspaceReducer.ts index 018b74e9af..f6ed10ef92 100644 --- a/src/commons/workspace/WorkspaceReducer.ts +++ b/src/commons/workspace/WorkspaceReducer.ts @@ -45,6 +45,7 @@ import { CLEAR_REPL_INPUT, CLEAR_REPL_OUTPUT, CLEAR_REPL_OUTPUT_LAST, + DISABLE_TOKEN_COUNTER, EditorTabState, ENABLE_TOKEN_COUNTER, END_CLEAR_CONTEXT, @@ -354,7 +355,15 @@ export const WorkspaceReducer: Reducer = ( ...state[workspaceLocation], hasTokenCounter: true } - } + }; + case DISABLE_TOKEN_COUNTER: + return { + ...state, + [workspaceLocation]: { + ...state[workspaceLocation], + hasTokenCounter: false + } + }; case EVAL_EDITOR: return { ...state, diff --git a/src/commons/workspace/WorkspaceTypes.ts b/src/commons/workspace/WorkspaceTypes.ts index f2f3ffd2ea..3bb04b317a 100644 --- a/src/commons/workspace/WorkspaceTypes.ts +++ b/src/commons/workspace/WorkspaceTypes.ts @@ -23,6 +23,7 @@ export const CLEAR_REPL_OUTPUT = 'CLEAR_REPL_OUTPUT'; export const CLEAR_REPL_OUTPUT_LAST = 'CLEAR_REPL_OUTPUT_LAST'; export const END_CLEAR_CONTEXT = 'END_CLEAR_CONTEXT'; export const ENABLE_TOKEN_COUNTER = 'ENABLE_TOKEN_COUNTER'; +export const DISABLE_TOKEN_COUNTER = 'DISABLE_TOKEN_COUNTER'; export const EVAL_EDITOR = 'EVAL_EDITOR'; export const EVAL_REPL = 'EVAL_REPL'; export const PROMPT_AUTOCOMPLETE = 'PROMPT_AUTOCOMPLETE'; From 32d9e1d6f171ae3488c5b0f1b4fe9cc35802c209 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Mon, 12 Feb 2024 23:59:04 +0800 Subject: [PATCH 16/18] Fix compile time errors --- src/commons/application/ApplicationTypes.ts | 7 ++++++- .../actions/__tests__/SessionActions.ts | 9 ++++++++ .../assessment/__tests__/Assessment.tsx | 1 + .../AssessmentWorkspace.tsx | 8 +++---- .../__tests__/AssessmentWorkspace.tsx | 1 + src/commons/profile/__tests__/Profile.tsx | 1 + src/commons/repl/Repl.tsx | 2 +- src/commons/sagas/WorkspaceSaga.ts | 7 +++---- src/commons/workspace/WorkspaceActions.ts | 6 +++--- src/commons/workspace/WorkspaceReducer.ts | 21 ++++++++++--------- .../AssessmentConfigPanel.tsx | 2 +- 11 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/commons/application/ApplicationTypes.ts b/src/commons/application/ApplicationTypes.ts index 5a06006110..e6c4978ba3 100644 --- a/src/commons/application/ApplicationTypes.ts +++ b/src/commons/application/ApplicationTypes.ts @@ -98,7 +98,12 @@ export type NotificationOutput = { consoleLog: string; }; -export type InterpreterOutput = RunningOutput | CodeOutput | ResultOutput | ErrorOutput | NotificationOutput; +export type InterpreterOutput = + | RunningOutput + | CodeOutput + | ResultOutput + | ErrorOutput + | NotificationOutput; export enum Role { Student = 'student', diff --git a/src/commons/application/actions/__tests__/SessionActions.ts b/src/commons/application/actions/__tests__/SessionActions.ts index 9e3773434a..ff15090d99 100644 --- a/src/commons/application/actions/__tests__/SessionActions.ts +++ b/src/commons/application/actions/__tests__/SessionActions.ts @@ -274,6 +274,7 @@ test('setAssessmentConfigurations generates correct action object', () => { type: 'Mission1', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 }, @@ -282,6 +283,7 @@ test('setAssessmentConfigurations generates correct action object', () => { type: 'Mission2', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 }, @@ -290,6 +292,7 @@ test('setAssessmentConfigurations generates correct action object', () => { type: 'Mission3', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 } @@ -640,6 +643,7 @@ test('updateAssessmentTypes generates correct action object', () => { type: 'Missions', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 }, @@ -648,6 +652,7 @@ test('updateAssessmentTypes generates correct action object', () => { type: 'Quests', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 }, @@ -656,6 +661,7 @@ test('updateAssessmentTypes generates correct action object', () => { type: 'Paths', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 }, @@ -664,6 +670,7 @@ test('updateAssessmentTypes generates correct action object', () => { type: 'Contests', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 }, @@ -672,6 +679,7 @@ test('updateAssessmentTypes generates correct action object', () => { type: 'Others', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 } @@ -689,6 +697,7 @@ test('deleteAssessmentConfig generates correct action object', () => { type: 'Mission1', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 }; diff --git a/src/commons/assessment/__tests__/Assessment.tsx b/src/commons/assessment/__tests__/Assessment.tsx index 18eb8dcb85..bb7aee31c9 100644 --- a/src/commons/assessment/__tests__/Assessment.tsx +++ b/src/commons/assessment/__tests__/Assessment.tsx @@ -17,6 +17,7 @@ const mockAssessmentProps = assertType()({ type: 'Missions', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 } diff --git a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx index 6afffc8934..07e93eb52c 100644 --- a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx +++ b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx @@ -179,10 +179,8 @@ const AssessmentWorkspace: React.FC = props => { dispatch(submitAnswer(id, answer)), handleUpdateHasUnsavedChanges: (hasUnsavedChanges: boolean) => dispatch(updateHasUnsavedChanges(workspaceLocation, hasUnsavedChanges)), - handleEnableTokenCounter: () => - dispatch(enableTokenCounter(workspaceLocation)), - handleDisableTokenCounter: () => - dispatch(disableTokenCounter(workspaceLocation)) + handleEnableTokenCounter: () => dispatch(enableTokenCounter(workspaceLocation)), + handleDisableTokenCounter: () => dispatch(disableTokenCounter(workspaceLocation)) }; }, [dispatch]); @@ -725,7 +723,7 @@ const AssessmentWorkspace: React.FC = props => { const workspaceHandlers = useMemo(() => { return { handleSideContentHeightChange: (heightChange: number) => - dispatch(changeSideContentHeight(heightChange, workspaceLocation)), + dispatch(changeSideContentHeight(heightChange, workspaceLocation)) }; }, [dispatch]); diff --git a/src/commons/assessmentWorkspace/__tests__/AssessmentWorkspace.tsx b/src/commons/assessmentWorkspace/__tests__/AssessmentWorkspace.tsx index 35d4fe14ac..6ffcf33954 100644 --- a/src/commons/assessmentWorkspace/__tests__/AssessmentWorkspace.tsx +++ b/src/commons/assessmentWorkspace/__tests__/AssessmentWorkspace.tsx @@ -26,6 +26,7 @@ const defaultProps = assertType()({ type: 'Missions', isManuallyGraded: true, displayInDashboard: true, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 48, earlySubmissionXp: 200 }, diff --git a/src/commons/profile/__tests__/Profile.tsx b/src/commons/profile/__tests__/Profile.tsx index 7a75913f24..55583cb291 100644 --- a/src/commons/profile/__tests__/Profile.tsx +++ b/src/commons/profile/__tests__/Profile.tsx @@ -25,6 +25,7 @@ const assessmentConfigurations: AssessmentConfiguration[] = [ type: c, isManuallyGraded: false, displayInDashboard: false, + hasTokenCounter: false, hoursBeforeEarlyXpDecay: 0, earlySubmissionXp: 0 })); diff --git a/src/commons/repl/Repl.tsx b/src/commons/repl/Repl.tsx index 26559fd04a..07bc19aaea 100644 --- a/src/commons/repl/Repl.tsx +++ b/src/commons/repl/Repl.tsx @@ -125,7 +125,7 @@ export const Output: React.FC = (props: OutputProps) => { case 'notification': return ( -
{"💡 " + props.output.consoleLog}
+
{'💡 ' + props.output.consoleLog}
); default: diff --git a/src/commons/sagas/WorkspaceSaga.ts b/src/commons/sagas/WorkspaceSaga.ts index 942be332e9..582d654e4d 100644 --- a/src/commons/sagas/WorkspaceSaga.ts +++ b/src/commons/sagas/WorkspaceSaga.ts @@ -1257,14 +1257,14 @@ export function* evalCode( yield* dumpDisplayBuffer(workspaceLocation, isStoriesBlock, storyEnv); - // Change token count if its assessment and EVAL_EDITOR - if (actionType === EVAL_EDITOR && workspaceLocation === "assessment") { + // Change token count if its assessment and EVAL_EDITOR + if (actionType === EVAL_EDITOR && workspaceLocation === 'assessment') { let tokenCounter = 0; const tokens = [...tokenizer(entrypointCode, ACORN_PARSE_OPTIONS)]; tokenCounter = tokens.length; yield put(actions.addTokenCount(workspaceLocation, tokenCounter)); } - + // Do not write interpreter output to REPL, if executing chunks (e.g. prepend/postpend blocks) if (actionType !== EVAL_SILENT) { if (!isStoriesBlock) { @@ -1275,7 +1275,6 @@ export function* evalCode( } } - // For EVAL_EDITOR and EVAL_REPL, we send notification to workspace that a program has been evaluated if (actionType === EVAL_EDITOR || actionType === EVAL_REPL || actionType === DEBUG_RESUME) { if (context.errors.length > 0) { diff --git a/src/commons/workspace/WorkspaceActions.ts b/src/commons/workspace/WorkspaceActions.ts index 4ddcc713da..2f96de6f34 100644 --- a/src/commons/workspace/WorkspaceActions.ts +++ b/src/commons/workspace/WorkspaceActions.ts @@ -75,7 +75,7 @@ import { WorkspaceState } from './WorkspaceTypes'; -export const addTokenCount = (workspaceLocation: WorkspaceLocation, tokenCount: number) => +export const addTokenCount = (workspaceLocation: WorkspaceLocation, tokenCount: number) => action(ADD_TOKEN_COUNT, { workspaceLocation, tokenCount }); export const browseReplHistoryDown = (workspaceLocation: WorkspaceLocation) => @@ -184,10 +184,10 @@ export const evalTestcase = (workspaceLocation: WorkspaceLocation, testcaseId: n export const runAllTestcases = (workspaceLocation: WorkspaceLocation) => action(EVAL_EDITOR_AND_TESTCASES, { workspaceLocation }); -export const enableTokenCounter = (workspaceLocation: WorkspaceLocation) => +export const enableTokenCounter = (workspaceLocation: WorkspaceLocation) => action(ENABLE_TOKEN_COUNTER, { workspaceLocation }); -export const disableTokenCounter = (workspaceLocation: WorkspaceLocation) => +export const disableTokenCounter = (workspaceLocation: WorkspaceLocation) => action(DISABLE_TOKEN_COUNTER, { workspaceLocation }); export const toggleFolderMode = (workspaceLocation: WorkspaceLocation) => diff --git a/src/commons/workspace/WorkspaceReducer.ts b/src/commons/workspace/WorkspaceReducer.ts index f6ed10ef92..369511add0 100644 --- a/src/commons/workspace/WorkspaceReducer.ts +++ b/src/commons/workspace/WorkspaceReducer.ts @@ -126,15 +126,14 @@ export const WorkspaceReducer: Reducer = ( } switch (action.type) { - case ADD_TOKEN_COUNT: return { ...state, - [workspaceLocation]: { - ...state[workspaceLocation], - tokenCount: action.payload.tokenCount - } - } + [workspaceLocation]: { + ...state[workspaceLocation], + tokenCount: action.payload.tokenCount + } + }; case BROWSE_REPL_HISTORY_DOWN: if (state[workspaceLocation].replHistory.browseIndex === null) { @@ -363,7 +362,7 @@ export const WorkspaceReducer: Reducer = ( ...state[workspaceLocation], hasTokenCounter: false } - }; + }; case EVAL_EDITOR: return { ...state, @@ -399,17 +398,19 @@ export const WorkspaceReducer: Reducer = ( if (state[workspaceLocation].hasTokenCounter) { notificationOutputs.push({ consoleLog: `This program has ${tokens} tokens in your code`, - type: "notification" + type: 'notification' }); } const customNotification = state[workspaceLocation].customNotification; if (customNotification !== '') { notificationOutputs.push({ consoleLog: customNotification, - type: "notification" + type: 'notification' }); } - newOutput = state[workspaceLocation].output.slice(0, -1).concat([...notificationOutputs, newOutputEntryWithLogs]); + newOutput = state[workspaceLocation].output + .slice(0, -1) + .concat([...notificationOutputs, newOutputEntryWithLogs]); } else { newOutput = state[workspaceLocation].output.concat({ consoleLogs: [], diff --git a/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx b/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx index 3b3be0474b..0e471efac7 100644 --- a/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx +++ b/src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx @@ -57,7 +57,7 @@ const AssessmentConfigPanel: React.FC = props => { }; setAssessmentConfig(temp); gridApi.current?.getDisplayedRowAtIndex(index)?.setDataValue('hasTokenCounter', value); - } + }; const setEarlyXp = (index: number, value: number) => { const temp = [...assessmentConfig.current]; From bd076a64a393ca26f0715c660dbbbaabed0a4ab3 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Tue, 13 Feb 2024 00:14:31 +0800 Subject: [PATCH 17/18] Make token count message more concise --- src/commons/workspace/WorkspaceReducer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commons/workspace/WorkspaceReducer.ts b/src/commons/workspace/WorkspaceReducer.ts index 369511add0..b2e855e478 100644 --- a/src/commons/workspace/WorkspaceReducer.ts +++ b/src/commons/workspace/WorkspaceReducer.ts @@ -397,7 +397,7 @@ export const WorkspaceReducer: Reducer = ( const notificationOutputs: NotificationOutput[] = []; if (state[workspaceLocation].hasTokenCounter) { notificationOutputs.push({ - consoleLog: `This program has ${tokens} tokens in your code`, + consoleLog: `This program has ${tokens} tokens.`, type: 'notification' }); } From cf045be2ddf6b7273fa6bf493f43e2ad78c7a802 Mon Sep 17 00:00:00 2001 From: positivelyjon Date: Wed, 14 Feb 2024 00:22:47 +0800 Subject: [PATCH 18/18] Refactor code for readability and css best practices --- src/commons/assessmentWorkspace/AssessmentWorkspace.tsx | 6 +++++- src/commons/repl/Repl.tsx | 2 +- src/commons/sagas/WorkspaceSaga.ts | 5 ++--- src/commons/workspace/WorkspaceActions.ts | 6 +++--- src/commons/workspace/WorkspaceReducer.ts | 4 ++-- src/commons/workspace/WorkspaceTypes.ts | 2 +- src/styles/_workspace.scss | 8 ++++---- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx index 07e93eb52c..d2b37d179b 100644 --- a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx +++ b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx @@ -254,7 +254,11 @@ const AssessmentWorkspace: React.FC = props => { } else { handleDisableTokenCounter(); } - }, [props, handleEnableTokenCounter, handleDisableTokenCounter]); + }, [ + props.assessmentConfiguration.hasTokenCounter, + handleEnableTokenCounter, + handleDisableTokenCounter + ]); /** * Handles toggling of relevant SideContentTabs when mobile breakpoint it hit diff --git a/src/commons/repl/Repl.tsx b/src/commons/repl/Repl.tsx index 07bc19aaea..7f30da1b89 100644 --- a/src/commons/repl/Repl.tsx +++ b/src/commons/repl/Repl.tsx @@ -124,7 +124,7 @@ export const Output: React.FC = (props: OutputProps) => { } case 'notification': return ( - +
{'💡 ' + props.output.consoleLog}
); diff --git a/src/commons/sagas/WorkspaceSaga.ts b/src/commons/sagas/WorkspaceSaga.ts index 582d654e4d..ad1bb1c3f7 100644 --- a/src/commons/sagas/WorkspaceSaga.ts +++ b/src/commons/sagas/WorkspaceSaga.ts @@ -1259,10 +1259,9 @@ export function* evalCode( // Change token count if its assessment and EVAL_EDITOR if (actionType === EVAL_EDITOR && workspaceLocation === 'assessment') { - let tokenCounter = 0; const tokens = [...tokenizer(entrypointCode, ACORN_PARSE_OPTIONS)]; - tokenCounter = tokens.length; - yield put(actions.addTokenCount(workspaceLocation, tokenCounter)); + const tokenCounter = tokens.length; + yield put(actions.setTokenCount(workspaceLocation, tokenCounter)); } // Do not write interpreter output to REPL, if executing chunks (e.g. prepend/postpend blocks) diff --git a/src/commons/workspace/WorkspaceActions.ts b/src/commons/workspace/WorkspaceActions.ts index 2f96de6f34..664382ab8a 100644 --- a/src/commons/workspace/WorkspaceActions.ts +++ b/src/commons/workspace/WorkspaceActions.ts @@ -15,7 +15,6 @@ import { NOTIFY_PROGRAM_EVALUATED } from '../sideContent/SideContentTypes'; import { ADD_EDITOR_TAB, ADD_HTML_CONSOLE_ERROR, - ADD_TOKEN_COUNT, BEGIN_CLEAR_CONTEXT, BROWSE_REPL_HISTORY_DOWN, BROWSE_REPL_HISTORY_UP, @@ -49,6 +48,7 @@ import { RESET_WORKSPACE, SEND_REPL_INPUT_TO_OUTPUT, SET_FOLDER_MODE, + SET_TOKEN_COUNT, SHIFT_EDITOR_TAB, SubmissionsTableFilters, TOGGLE_EDITOR_AUTORUN, @@ -75,8 +75,8 @@ import { WorkspaceState } from './WorkspaceTypes'; -export const addTokenCount = (workspaceLocation: WorkspaceLocation, tokenCount: number) => - action(ADD_TOKEN_COUNT, { workspaceLocation, tokenCount }); +export const setTokenCount = (workspaceLocation: WorkspaceLocation, tokenCount: number) => + action(SET_TOKEN_COUNT, { workspaceLocation, tokenCount }); export const browseReplHistoryDown = (workspaceLocation: WorkspaceLocation) => action(BROWSE_REPL_HISTORY_DOWN, { workspaceLocation }); diff --git a/src/commons/workspace/WorkspaceReducer.ts b/src/commons/workspace/WorkspaceReducer.ts index b2e855e478..29fdcf3dbd 100644 --- a/src/commons/workspace/WorkspaceReducer.ts +++ b/src/commons/workspace/WorkspaceReducer.ts @@ -35,7 +35,6 @@ import Constants from '../utils/Constants'; import { createContext } from '../utils/JsSlangHelper'; import { ADD_EDITOR_TAB, - ADD_TOKEN_COUNT, BROWSE_REPL_HISTORY_DOWN, BROWSE_REPL_HISTORY_UP, CHANGE_EXEC_TIME, @@ -61,6 +60,7 @@ import { RESET_WORKSPACE, SEND_REPL_INPUT_TO_OUTPUT, SET_FOLDER_MODE, + SET_TOKEN_COUNT, SHIFT_EDITOR_TAB, TOGGLE_EDITOR_AUTORUN, TOGGLE_UPDATE_ENV, @@ -126,7 +126,7 @@ export const WorkspaceReducer: Reducer = ( } switch (action.type) { - case ADD_TOKEN_COUNT: + case SET_TOKEN_COUNT: return { ...state, [workspaceLocation]: { diff --git a/src/commons/workspace/WorkspaceTypes.ts b/src/commons/workspace/WorkspaceTypes.ts index 3bb04b317a..81998af787 100644 --- a/src/commons/workspace/WorkspaceTypes.ts +++ b/src/commons/workspace/WorkspaceTypes.ts @@ -9,7 +9,6 @@ import { AutogradingResult, Testcase } from '../assessment/AssessmentTypes'; import { HighlightedLines, Position } from '../editor/EditorTypes'; export const ADD_HTML_CONSOLE_ERROR = 'ADD_HTML_CONSOLE_ERROR'; -export const ADD_TOKEN_COUNT = 'ADD_TOKEN_COUNT'; export const BEGIN_CLEAR_CONTEXT = 'BEGIN_CLEAR_CONTEXT'; export const BROWSE_REPL_HISTORY_DOWN = 'BROWSE_REPL_HISTORY_DOWN'; export const BROWSE_REPL_HISTORY_UP = 'BROWSE_REPL_HISTORY_UP'; @@ -36,6 +35,7 @@ export const PLAYGROUND_EXTERNAL_SELECT = 'PLAYGROUND_EXTERNAL_SELECT '; export const RESET_TESTCASE = 'RESET_TESTCASE'; export const RESET_WORKSPACE = 'RESET_WORKSPACE'; export const SEND_REPL_INPUT_TO_OUTPUT = 'SEND_REPL_INPUT_TO_OUTPUT'; +export const SET_TOKEN_COUNT = 'SET_TOKEN_COUNT'; export const TOGGLE_EDITOR_AUTORUN = 'TOGGLE_EDITOR_AUTORUN'; export const TOGGLE_USING_SUBST = 'TOGGLE_USING_SUBST'; export const TOGGLE_USING_ENV = 'TOGGLE_USING_ENV'; diff --git a/src/styles/_workspace.scss b/src/styles/_workspace.scss index 735c2037f8..867945d9f0 100755 --- a/src/styles/_workspace.scss +++ b/src/styles/_workspace.scss @@ -768,10 +768,6 @@ $code-color-notification: #f9f0d7; overflow-y: auto; margin: 0 0.5rem 0 0; - .#{$ns}-card:has(.notification-output) { - background-color: $code-background-color-notification; - } - .#{$ns}-card { background-color: $cadet-color-2; padding: 0.4rem 0.6rem 0.4rem 0.6rem; @@ -834,6 +830,10 @@ $code-color-notification: #f9f0d7; } } + .notification-output-container { + background-color: $code-background-color-notification; + } + /* flush to align with editor bottom */ .repl-input-parent { padding: 0;