Loading analyst/src/components/ExerciseSelector/index.tsx +5 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import { useTranslationFrontend } from '@inject/locale' import { dialogBody, maximizedDialog } from '@inject/shared' import type { FC } from 'react' import { useState } from 'react' import { FilePageRoute } from '../../routes/_layout/$exerciseId/file.$fileId' interface ExerciseSelectorProps { buttonProps?: ButtonProps | undefined Loading Loading @@ -51,6 +52,10 @@ export const ExerciseSelector: FC<ExerciseSelectorProps> = ({ }, type: 'selecting', isSelected: exercise => isSelected(exercise), getFileLink: (exercise, fileId) => ({ to: FilePageRoute.to, params: { exerciseId: exercise.id, fileId }, }), t, })} /> Loading frontend/src/components/ExerciseCard/InstructorExerciseCard.tsx +5 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ import type { ExerciseSimple } from '@inject/graphql' import type { FC } from 'react' import { ExerciseCard } from '.' import { ExerciseAssignmentRoute } from '../../routes/_protected/_navbar/exercise-panel/exercise.$exerciseId' import { InstructorFilePageRoute } from '../../routes/_protected/instructor/$exerciseId/file.$fileId' import { InstructorSelectTeamRoute } from '../../routes/_protected/instructor/$exerciseId/select' import { ExerciseButtons } from '../ExerciseList/ExerciseButtons' Loading @@ -28,6 +29,10 @@ export const InstructorExerciseCard: FC<InstructorExerciseCardProps> = ({ to: ExerciseAssignmentRoute.to, params: { exerciseId: exercise.id }, }} getFileLink={fileId => ({ to: InstructorFilePageRoute.to, params: { exerciseId: exercise.id, fileId }, })} /> } sandbox={exercise.technical} Loading frontend/src/components/ExerciseList/ExerciseButtons/NotesButton/index.tsx 0 → 100644 +81 −0 Original line number Diff line number Diff line import type { Intent } from '@blueprintjs/core' import { Button, Dialog, DialogBody } from '@blueprintjs/core' import { GetInstructorNotes, useTypedQuery } from '@inject/graphql' import { useTranslationFrontend } from '@inject/locale' import { CenteredSpinner, dialogBody, variableHeightMaximizedDialog, } from '@inject/shared' import type { NavigateOptions } from '@tanstack/react-router' import { useState, type FC } from 'react' import { AttachmentsRow } from '../../../AttachmentsRow' import { RenderedContent } from '../../../RenderedContent' interface NotesButtonProps { exerciseId: string intent?: Intent getFileLink: (fileId: string) => NavigateOptions } export const NotesButton: FC<NotesButtonProps> = ({ exerciseId, intent, getFileLink, }) => { const [dialogOpen, setDialogOpen] = useState(false) const { t } = useTranslationFrontend() const [{ data: instructorNotesData, fetching }] = useTypedQuery({ query: GetInstructorNotes, variables: { exerciseId }, }) if (fetching || !instructorNotesData?.exerciseId) { return <CenteredSpinner /> } return ( <> <Button icon='book' title={t('instructorNotes.title')} active={dialogOpen} onClick={() => setDialogOpen(true)} intent={intent} /> <Dialog isOpen={dialogOpen} onClose={() => setDialogOpen(false)} title={ <span title={`${t('instructorNotes.title')} ${instructorNotesData.exerciseId.name}`} >{`${t('instructorNotes.title')} - ${instructorNotesData.exerciseId.name}`}</span> } className={variableHeightMaximizedDialog} > <DialogBody className={dialogBody}> {instructorNotesData && instructorNotesData.exerciseId.config.instructorNotes ? ( <> <RenderedContent renderedContent={ instructorNotesData.exerciseId.config.instructorNotes.rendered } exerciseId={exerciseId} /> <AttachmentsRow attachments={ instructorNotesData.exerciseId.config.instructorNotes .attachments } getFileLink={getFileLink} /> </> ) : ( <p>{t('instructorNotes.notFound')}</p> )} </DialogBody> </Dialog> </> ) } frontend/src/components/ExerciseList/ExerciseButtons/index.tsx +8 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import type { NavigateOptions } from '@tanstack/react-router' import { useMemo, type FC } from 'react' import { InfoButton } from './InfoButton' import { ManagingExerciseButtons } from './ManagingExerciseButtons' import { NotesButton } from './NotesButton' const buttonGroup = css` .${Classes.BUTTON} { Loading @@ -17,6 +18,7 @@ const buttonGroup = css` type ExerciseButtonsProps = { isSelected?: boolean exercise: ExerciseSimple getFileLink: (fileId: string) => NavigateOptions large?: boolean } & ( | { Loading @@ -34,6 +36,7 @@ export const ExerciseButtons: FC<ExerciseButtonsProps> = ({ onSelect, assignmentLink, large, getFileLink, }) => { const intent: Intent | undefined = useMemo(() => { if (exercise.onDemand) { Loading Loading @@ -66,6 +69,11 @@ export const ExerciseButtons: FC<ExerciseButtonsProps> = ({ /> )} <InfoButton intent={intent} exerciseId={exercise.id} /> <NotesButton intent={intent} exerciseId={exercise.id} getFileLink={getFileLink} /> </ButtonGroup> ) } frontend/src/components/ExerciseList/ExerciseColumns.tsx +3 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ const hideOnSmallScreen = css` type ExerciseColumnsProps = { isSelected?: (exercise: ExerciseSimple) => boolean t: ReturnType<typeof useTranslationFrontend>['t'] getFileLink: (exercise: ExerciseSimple, fileId: string) => NavigateOptions } & ( | { type: 'selecting' Loading @@ -46,6 +47,7 @@ export const getExerciseColumns = ({ type, assignmentLink, t, getFileLink, }: ExerciseColumnsProps): Column<ExerciseSimple>[] => [ { id: 'name', Loading Loading @@ -183,6 +185,7 @@ export const getExerciseColumns = ({ <ExerciseButtons isSelected={isSelected?.(exercise)} exercise={exercise} getFileLink={fileId => getFileLink(exercise, fileId)} {...(type === 'selecting' ? { type: 'selecting', onSelect: () => onSelect(exercise) } : { Loading Loading
analyst/src/components/ExerciseSelector/index.tsx +5 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import { useTranslationFrontend } from '@inject/locale' import { dialogBody, maximizedDialog } from '@inject/shared' import type { FC } from 'react' import { useState } from 'react' import { FilePageRoute } from '../../routes/_layout/$exerciseId/file.$fileId' interface ExerciseSelectorProps { buttonProps?: ButtonProps | undefined Loading Loading @@ -51,6 +52,10 @@ export const ExerciseSelector: FC<ExerciseSelectorProps> = ({ }, type: 'selecting', isSelected: exercise => isSelected(exercise), getFileLink: (exercise, fileId) => ({ to: FilePageRoute.to, params: { exerciseId: exercise.id, fileId }, }), t, })} /> Loading
frontend/src/components/ExerciseCard/InstructorExerciseCard.tsx +5 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ import type { ExerciseSimple } from '@inject/graphql' import type { FC } from 'react' import { ExerciseCard } from '.' import { ExerciseAssignmentRoute } from '../../routes/_protected/_navbar/exercise-panel/exercise.$exerciseId' import { InstructorFilePageRoute } from '../../routes/_protected/instructor/$exerciseId/file.$fileId' import { InstructorSelectTeamRoute } from '../../routes/_protected/instructor/$exerciseId/select' import { ExerciseButtons } from '../ExerciseList/ExerciseButtons' Loading @@ -28,6 +29,10 @@ export const InstructorExerciseCard: FC<InstructorExerciseCardProps> = ({ to: ExerciseAssignmentRoute.to, params: { exerciseId: exercise.id }, }} getFileLink={fileId => ({ to: InstructorFilePageRoute.to, params: { exerciseId: exercise.id, fileId }, })} /> } sandbox={exercise.technical} Loading
frontend/src/components/ExerciseList/ExerciseButtons/NotesButton/index.tsx 0 → 100644 +81 −0 Original line number Diff line number Diff line import type { Intent } from '@blueprintjs/core' import { Button, Dialog, DialogBody } from '@blueprintjs/core' import { GetInstructorNotes, useTypedQuery } from '@inject/graphql' import { useTranslationFrontend } from '@inject/locale' import { CenteredSpinner, dialogBody, variableHeightMaximizedDialog, } from '@inject/shared' import type { NavigateOptions } from '@tanstack/react-router' import { useState, type FC } from 'react' import { AttachmentsRow } from '../../../AttachmentsRow' import { RenderedContent } from '../../../RenderedContent' interface NotesButtonProps { exerciseId: string intent?: Intent getFileLink: (fileId: string) => NavigateOptions } export const NotesButton: FC<NotesButtonProps> = ({ exerciseId, intent, getFileLink, }) => { const [dialogOpen, setDialogOpen] = useState(false) const { t } = useTranslationFrontend() const [{ data: instructorNotesData, fetching }] = useTypedQuery({ query: GetInstructorNotes, variables: { exerciseId }, }) if (fetching || !instructorNotesData?.exerciseId) { return <CenteredSpinner /> } return ( <> <Button icon='book' title={t('instructorNotes.title')} active={dialogOpen} onClick={() => setDialogOpen(true)} intent={intent} /> <Dialog isOpen={dialogOpen} onClose={() => setDialogOpen(false)} title={ <span title={`${t('instructorNotes.title')} ${instructorNotesData.exerciseId.name}`} >{`${t('instructorNotes.title')} - ${instructorNotesData.exerciseId.name}`}</span> } className={variableHeightMaximizedDialog} > <DialogBody className={dialogBody}> {instructorNotesData && instructorNotesData.exerciseId.config.instructorNotes ? ( <> <RenderedContent renderedContent={ instructorNotesData.exerciseId.config.instructorNotes.rendered } exerciseId={exerciseId} /> <AttachmentsRow attachments={ instructorNotesData.exerciseId.config.instructorNotes .attachments } getFileLink={getFileLink} /> </> ) : ( <p>{t('instructorNotes.notFound')}</p> )} </DialogBody> </Dialog> </> ) }
frontend/src/components/ExerciseList/ExerciseButtons/index.tsx +8 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import type { NavigateOptions } from '@tanstack/react-router' import { useMemo, type FC } from 'react' import { InfoButton } from './InfoButton' import { ManagingExerciseButtons } from './ManagingExerciseButtons' import { NotesButton } from './NotesButton' const buttonGroup = css` .${Classes.BUTTON} { Loading @@ -17,6 +18,7 @@ const buttonGroup = css` type ExerciseButtonsProps = { isSelected?: boolean exercise: ExerciseSimple getFileLink: (fileId: string) => NavigateOptions large?: boolean } & ( | { Loading @@ -34,6 +36,7 @@ export const ExerciseButtons: FC<ExerciseButtonsProps> = ({ onSelect, assignmentLink, large, getFileLink, }) => { const intent: Intent | undefined = useMemo(() => { if (exercise.onDemand) { Loading Loading @@ -66,6 +69,11 @@ export const ExerciseButtons: FC<ExerciseButtonsProps> = ({ /> )} <InfoButton intent={intent} exerciseId={exercise.id} /> <NotesButton intent={intent} exerciseId={exercise.id} getFileLink={getFileLink} /> </ButtonGroup> ) }
frontend/src/components/ExerciseList/ExerciseColumns.tsx +3 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ const hideOnSmallScreen = css` type ExerciseColumnsProps = { isSelected?: (exercise: ExerciseSimple) => boolean t: ReturnType<typeof useTranslationFrontend>['t'] getFileLink: (exercise: ExerciseSimple, fileId: string) => NavigateOptions } & ( | { type: 'selecting' Loading @@ -46,6 +47,7 @@ export const getExerciseColumns = ({ type, assignmentLink, t, getFileLink, }: ExerciseColumnsProps): Column<ExerciseSimple>[] => [ { id: 'name', Loading Loading @@ -183,6 +185,7 @@ export const getExerciseColumns = ({ <ExerciseButtons isSelected={isSelected?.(exercise)} exercise={exercise} getFileLink={fileId => getFileLink(exercise, fileId)} {...(type === 'selecting' ? { type: 'selecting', onSelect: () => onSelect(exercise) } : { Loading