-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add vscode slice for message passing with extension #3080
base: master
Are you sure you want to change the base?
Changes from 4 commits
f9a23f9
2a9117d
9b001ad
4e43c66
93424b3
084698d
9e8afad
d92e4fc
c194ddb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,15 @@ | ||
import React from 'react'; | ||
import { useDispatch } from 'react-redux'; | ||
import { Outlet } from 'react-router-dom'; | ||
import Messages, { MessageType, sendToWebview } from 'src/features/vscode/messages'; | ||
|
||
import NavigationBar from '../navigationBar/NavigationBar'; | ||
import Constants from '../utils/Constants'; | ||
import { useLocalStorageState, useSession } from '../utils/Hooks'; | ||
import WorkspaceActions from '../workspace/WorkspaceActions'; | ||
import { defaultWorkspaceSettings, WorkspaceSettingsContext } from '../WorkspaceSettingsContext'; | ||
import SessionActions from './actions/SessionActions'; | ||
import VscodeActions from './actions/VscodeActions'; | ||
|
||
const Application: React.FC = () => { | ||
const dispatch = useDispatch(); | ||
|
@@ -70,6 +73,47 @@ | |
}; | ||
}, [isPWA, isMobile]); | ||
|
||
// Effect to fetch the latest user info and course configurations from the backend on refresh, | ||
// if the user was previously logged in | ||
React.useEffect(() => { | ||
// Polyfill confirm() to instead show as VSCode notification | ||
window.confirm = () => { | ||
console.log('You gotta confirm!'); | ||
return true; | ||
}; | ||
|
||
const message = Messages.WebviewStarted(); | ||
sendToWebview(message); | ||
|
||
window.addEventListener('message', event => { | ||
const message: MessageType = event.data; | ||
// Only accept messages from the vscode webview | ||
if (!event.origin.startsWith('vscode-webview://')) { | ||
return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this is a guard, but shall we log such an event? Technically we might be able to configure our deployment with |
||
} | ||
// console.log(`FRONTEND: Message from ${event.origin}: ${JSON.stringify(message)}`); | ||
switch (message.type) { | ||
case 'WebviewStarted': | ||
console.log('Received WebviewStarted message, will set vsc'); | ||
dispatch(VscodeActions.setVscode()); | ||
break; | ||
case 'Text': | ||
const code = message.code; | ||
console.log(`FRONTEND: TextMessage: ${code}`); | ||
// TODO: Don't change ace editor directly | ||
// const elements = document.getElementsByClassName('react-ace'); | ||
// if (elements.length === 0) { | ||
// return; | ||
// } | ||
// // @ts-expect-error: ace is not available at compile time | ||
// const editor = ace.edit(elements[0]); | ||
// editor.setValue(code); | ||
dispatch(WorkspaceActions.updateEditorValue('assessment', 0, code)); | ||
break; | ||
} | ||
}); | ||
}, []); | ||
|
||
return ( | ||
<WorkspaceSettingsContext.Provider value={[workspaceSettings, setWorkspaceSettings]}> | ||
<div className="Application"> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { createActions } from 'src/commons/redux/utils'; | ||
|
||
const VscodeActions = createActions('vscode', { | ||
setVscode: () => ({}) | ||
heyzec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
|
||
// For compatibility with existing code (actions helper) | ||
export default { | ||
...VscodeActions | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { createReducer, Reducer } from '@reduxjs/toolkit'; | ||
|
||
import { SourceActionType } from '../../utils/ActionsHelper'; | ||
import VscodeActions from '../actions/VscodeActions'; | ||
import { defaultVscode } from '../ApplicationTypes'; | ||
import { VscodeState } from '../types/VscodeTypes'; | ||
|
||
export const VscodeReducer: Reducer<VscodeState, SourceActionType> = ( | ||
state = defaultVscode, | ||
action | ||
) => { | ||
state = newVscodeReducer(state, action); | ||
return state; | ||
}; | ||
|
||
const newVscodeReducer = createReducer(defaultVscode, builder => { | ||
builder.addCase(VscodeActions.setVscode, state => { | ||
return { ...state, ...{ isVscode: true } }; | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export type VscodeState = { | ||
isVscode: boolean; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
import { useNavigate } from 'react-router'; | ||
import { showSimpleConfirmDialog } from 'src/commons/utils/DialogHelper'; | ||
import { onClickProgress } from 'src/features/assessments/AssessmentUtils'; | ||
import Messages, { sendToWebview } from 'src/features/vscode/messages'; | ||
import { mobileOnlyTabIds } from 'src/pages/playground/PlaygroundTabs'; | ||
|
||
import { initSession, log } from '../../features/eventLogging'; | ||
|
@@ -184,11 +185,11 @@ | |
}; | ||
}, [dispatch]); | ||
|
||
useEffect(() => { | ||
// TODO: Hardcoded to make use of the first editor tab. Refactoring is needed for this workspace to enable Folder mode. | ||
handleEditorValueChange(0, ''); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
// useEffect(() => { | ||
// // TODO: Hardcoded to make use of the first editor tab. Refactoring is needed for this workspace to enable Folder mode. | ||
// handleEditorValueChange(0, ''); | ||
// // eslint-disable-next-line react-hooks/exhaustive-deps | ||
// }, []); | ||
Comment on lines
+188
to
+192
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this break anything with assessments? Have you tested locally? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From my local testing, there's no unintended behavior. Assessments still loading as per normal. handleEditorValueChange is ultimately called with the editor contents due to the useEffect here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's just delete and clean up all this unused code then |
||
|
||
useEffect(() => { | ||
if (assessmentOverview && assessmentOverview.maxTeamSize > 1) { | ||
|
@@ -220,28 +221,28 @@ | |
if (!assessment) { | ||
return; | ||
} | ||
// ------------- PLEASE NOTE, EVERYTHING BELOW THIS SEEMS TO BE UNUSED ------------- | ||
// checkWorkspaceReset does exactly the same thing. | ||
let questionId = props.questionId; | ||
if (props.questionId >= assessment.questions.length) { | ||
questionId = assessment.questions.length - 1; | ||
} | ||
|
||
const question = assessment.questions[questionId]; | ||
|
||
let answer = ''; | ||
if (question.type === QuestionTypes.programming) { | ||
if (question.answer) { | ||
answer = (question as IProgrammingQuestion).answer as string; | ||
} else { | ||
answer = (question as IProgrammingQuestion).solutionTemplate; | ||
} | ||
} | ||
|
||
// TODO: Hardcoded to make use of the first editor tab. Refactoring is needed for this workspace to enable Folder mode. | ||
handleEditorValueChange(0, answer); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
// // ------------- PLEASE NOTE, EVERYTHING BELOW THIS SEEMS TO BE UNUSED ------------- | ||
// // checkWorkspaceReset does exactly the same thing. | ||
// let questionId = props.questionId; | ||
// if (props.questionId >= assessment.questions.length) { | ||
// questionId = assessment.questions.length - 1; | ||
// } | ||
|
||
// const question = assessment.questions[questionId]; | ||
|
||
// let answer = ''; | ||
// if (question.type === QuestionTypes.programming) { | ||
// if (question.answer) { | ||
// answer = (question as IProgrammingQuestion).answer as string; | ||
// } else { | ||
// answer = (question as IProgrammingQuestion).solutionTemplate; | ||
// } | ||
// } | ||
|
||
// // TODO: Hardcoded to make use of the first editor tab. Refactoring is needed for this workspace to enable Folder mode. | ||
// handleEditorValueChange(0, answer); | ||
// // eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
Check warning on line 245 in src/commons/assessmentWorkspace/AssessmentWorkspace.tsx
|
||
|
||
/** | ||
* Once there is an update (due to the assessment being fetched), check | ||
|
@@ -415,9 +416,12 @@ | |
); | ||
handleClearContext(question.library, true); | ||
handleUpdateHasUnsavedChanges(false); | ||
sendToWebview(Messages.NewEditor(`assessment${assessment.id}`, props.questionId, '')); | ||
if (options.editorValue) { | ||
// TODO: Hardcoded to make use of the first editor tab. Refactoring is needed for this workspace to enable Folder mode. | ||
handleEditorValueChange(0, options.editorValue); | ||
} else { | ||
handleEditorValueChange(0, ''); | ||
} | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ import { Prompt } from '../ReactRouterPrompt'; | |
import Repl, { ReplProps } from '../repl/Repl'; | ||
import SideBar, { SideBarTab } from '../sideBar/SideBar'; | ||
import SideContent, { SideContentProps } from '../sideContent/SideContent'; | ||
import { useDimensions } from '../utils/Hooks'; | ||
import { useDimensions, useTypedSelector } from '../utils/Hooks'; | ||
|
||
export type WorkspaceProps = DispatchProps & StateProps; | ||
|
||
|
@@ -44,6 +44,7 @@ const Workspace: React.FC<WorkspaceProps> = props => { | |
const [contentContainerWidth] = useDimensions(contentContainerDiv); | ||
const [expandedSideBarWidth, setExpandedSideBarWidth] = useState(200); | ||
const [isSideBarExpanded, setIsSideBarExpanded] = useState(true); | ||
const isVscode = useTypedSelector(state => state.vscode.isVscode); | ||
|
||
const sideBarCollapsedWidth = 40; | ||
|
||
|
@@ -222,7 +223,11 @@ const Workspace: React.FC<WorkspaceProps> = props => { | |
</Resizable> | ||
<div className="row content-parent" ref={contentContainerDiv}> | ||
<div className="editor-divider" ref={editorDividerDiv} /> | ||
<Resizable {...editorResizableProps()}>{createWorkspaceInput(props)}</Resizable> | ||
{isVscode ? ( | ||
<div style={{ width: '0px' }}>{createWorkspaceInput(props)}</div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It must still be visible is it? We can't use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While |
||
) : ( | ||
<Resizable {...editorResizableProps()}>{createWorkspaceInput(props)}</Resizable> | ||
)} | ||
<div className="right-parent" ref={setFullscreenRefs}> | ||
<Tooltip | ||
className="fullscreen-button" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use
if (window.confirm) ...
instead?