Skip to content

Commit

Permalink
Grading Overview: TS/Tremor -> AG/Blueprint Migration (#2893)
Browse files Browse the repository at this point in the history
* added filterable columns in grading overview

* some cleanup code

* moved some grading overview FE components from tremor to blueprint

* missing code from previous commit

* halfway done for porting tanstack/tremor to ag grid/blueprint

* more changes to grading table - animation whilst loading, filter/edit mode, bugfixes

* code refactoring

* filterable columns, backend sorting shell, and some partial removal of tanstack and tremor table

* more component migrations, refactoring and preparation for backend sort

* multi -> single sorting, moved over all ts/tremor components to ag/bp, removal of old code

* fix table cutoff on small horizontal resolution and missing hover effects

* refresh button for table

* fixed richard's comments (mostly), and added a fix for josh's comment and PR

* fixed edge case of attempted/submitted on filter from prev commit

* mock files, change josh's pr 2nd issue to remove non-submitted filters on selecting ungraded, some refactoring

* fixed wrong username and text overflow

* eslint

* prettier checks

* backend mock changes

* minor adjustments and cleanups

* minor ui adjustments for better mobile compatability

* preparation for P2 merge

* eslint prettier

* compile erros

* compile error and eslint

* prettier checks

* minor ui adjustments

* Revert change back to raw strings

* typescript v5 fixes and richard's comments

* more typescript v5 fixes

* prettier

* some refactoring and bug fixing

* null value error in empty cell & wider actions col

* added submitted to unpublished allowed filters

* Fix format

* Fix compile error post-merge

* Refactor GradingFlex

* Add React import
* Remove unnecessary type annotations
* Extract default styles outside component
* Remove unused props

* Refactor GradingText

* Add React import
* Use `classnames` utility
* Use `Classes` object instead of raw string CSS API
* Move constant default styles out of component
* Remove unused props

* Update BackendSaga.ts

* Use strict inequality
* Use `Object.entries` to iterate over both key and value

* Refactor GradingFilterable.tsx

* Refactor GradingActions

* Add React import
* Use `useSession` over `useTypedSelector`
* Use Blueprint's `Tooltip` component over `htmlTitle`
* Remove unnecessary `={true}` in props
* Simplify conditionals with `&&`

* Simplify conditions in conditionals

For better readability.

* Refactor conditions

For readability.

* Refactor GradingColumnCustomHeaders.tsx

* Add React import
* Use `classNames` utility instead of `String`
* Remove unused prop export
* Convert Props interface to type
* Remove unnecessary type annotations and arguments
* Convert conditional to `&&`

* Refactor GradingColumnFilters.tsx

* Add React import

* Refactor GradingBadges.tsx

* Add React import
* Improve typing of badge colors
* Use optional chaining where possible
* Remove unused export

* Add missing React import

Also renamed a type to `Props` as it is unexported.

* Fix imports and format post merge

* hw review changes and child key error fix

* fixed randomly broken grading table headers and merge conflicts

* prettier

* Reformat post-lint updates

* Add TODO

* Remove unused CSS class

* Scope most styles to CSS modules

* Migrate more styles to CSS modules

* Simplify to use new actions format

* Migrate more classes to CSS modules

* Refactor grading badge styles to separate module file

* Remove hardcoded CSS namespace

* Make fix less hacky

* Remove unnecessary default with enum type

* Refactor column builder to separate file

Use dependency injection to avoid needing a hook.

* Remove unnecessary space

* Improve readability

* Remove unused param

* Remove unnecessary `={true}`

* Add TODO

* Refactor grading badge

* Simplify props
* Remove unneded export

---------

Co-authored-by: Richard Dominick <[email protected]>
  • Loading branch information
InfinityTwo and RichDom2185 committed Aug 19, 2024
1 parent 72ea6de commit cfc32e9
Show file tree
Hide file tree
Showing 27 changed files with 1,607 additions and 465 deletions.
12 changes: 11 additions & 1 deletion src/commons/application/ApplicationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DashboardState } from '../../features/dashboard/DashboardTypes';
import { PlaygroundState } from '../../features/playground/PlaygroundTypes';
import { PlaybackStatus, RecordingStatus } from '../../features/sourceRecorder/SourceRecorderTypes';
import { StoriesEnvState, StoriesState } from '../../features/stories/StoriesTypes';
import { freshSortState } from '../../pages/academy/grading/subcomponents/GradingSubmissionsTable';
import { WORKSPACE_BASE_PATHS } from '../../pages/fileSystem/createInBrowserFileSystem';
import { FileSystemState } from '../fileSystem/FileSystemTypes';
import { SideContentManagerState, SideContentState } from '../sideContent/SideContentTypes';
Expand Down Expand Up @@ -441,7 +442,16 @@ export const defaultWorkspaceManager: WorkspaceManagerState = {
},
currentSubmission: undefined,
currentQuestion: undefined,
hasUnsavedChanges: false
hasUnsavedChanges: false,
// TODO: The below should be a separate state
// instead of using the grading workspace state
columnVisiblity: [],
requestCounter: 0,
allColsSortStates: {
currentState: freshSortState,
sortBy: ''
},
hasLoadedBefore: false
},
playground: {
...createDefaultWorkspace('playground'),
Expand Down
14 changes: 11 additions & 3 deletions src/commons/application/actions/SessionActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ import {
paginationToBackendParams,
unpublishedToBackendParams
} from 'src/features/grading/GradingUtils';
import { freshSortState } from 'src/pages/academy/grading/subcomponents/GradingSubmissionsTable';
import { OptionType } from 'src/pages/academy/teamFormation/subcomponents/TeamFormationForm';

import { GradingOverviews, GradingQuery } from '../../../features/grading/GradingTypes';
import {
AllColsSortStates,
GradingOverviews,
GradingQuery
} from '../../../features/grading/GradingTypes';
import { TeamFormationOverview } from '../../../features/teamFormation/TeamFormationTypes';
import {
Assessment,
Expand Down Expand Up @@ -52,13 +57,16 @@ const SessionActions = createActions('session', {
* many entries, starting from what offset, to get
* @param filterParams - param that contains columnFilters converted into JSON for
* processing into query parameters
* @param allColsSortStates - param that contains the sort states of all columns and
* the col it should be sorted by
*/
fetchGradingOverviews: (
filterToGroup = true,
publishedFilter = unpublishedToBackendParams(false),
pageParams = paginationToBackendParams(0, 10),
filterParams = {}
) => ({ filterToGroup, publishedFilter, pageParams, filterParams }),
filterParams = {},
allColsSortStates: AllColsSortStates = { currentState: freshSortState, sortBy: '' }
) => ({ filterToGroup, publishedFilter, pageParams, filterParams, allColsSortStates }),
fetchTeamFormationOverviews: (filterToGroup = true) => filterToGroup,
fetchStudents: () => ({}),
login: (providerId: string) => providerId,
Expand Down
17 changes: 13 additions & 4 deletions src/commons/application/actions/__tests__/SessionActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import {
paginationToBackendParams,
unpublishedToBackendParams
} from 'src/features/grading/GradingUtils';
import { freshSortState } from 'src/pages/academy/grading/subcomponents/GradingSubmissionsTable';

import { GradingOverviews, GradingQuery } from '../../../../features/grading/GradingTypes';
import {
ColumnFields,
GradingOverviews,
GradingQuery
} from '../../../../features/grading/GradingTypes';
import { TeamFormationOverview } from '../../../../features/teamFormation/TeamFormationTypes';
import {
Assessment,
Expand Down Expand Up @@ -89,7 +94,8 @@ test('fetchGradingOverviews generates correct default action object', () => {
filterToGroup: true,
publishedFilter: unpublishedToBackendParams(false),
pageParams: paginationToBackendParams(0, 10),
filterParams: {}
filterParams: {},
allColsSortStates: { currentState: freshSortState, sortBy: '' }
}
});
});
Expand All @@ -99,19 +105,22 @@ test('fetchGradingOverviews generates correct action object', () => {
const publishedFilter = unpublishedToBackendParams(true);
const pageParams = { offset: 123, pageSize: 456 };
const filterParams = { abc: 'xxx', def: 'yyy' };
const allColsSortStates = { currentState: freshSortState, sortBy: ColumnFields.assessmentName };
const action = SessionActions.fetchGradingOverviews(
filterToGroup,
publishedFilter,
pageParams,
filterParams
filterParams,
allColsSortStates
);
expect(action).toEqual({
type: SessionActions.fetchGradingOverviews.type,
payload: {
filterToGroup: filterToGroup,
publishedFilter: publishedFilter,
pageParams: pageParams,
filterParams: filterParams
filterParams: filterParams,
allColsSortStates: allColsSortStates
}
});
});
Expand Down
33 changes: 33 additions & 0 deletions src/commons/grading/GradingFlex.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Property } from 'csstype';
import React from 'react';

const defaultStyles: React.CSSProperties = {
display: 'flex'
};

type Props = {
justifyContent?: Property.JustifyContent;
alignItems?: Property.AlignItems;
flexDirection?: Property.FlexDirection;
children?: React.ReactNode;
style?: React.CSSProperties;
className?: string;
};

const GradingFlex: React.FC<Props> = ({
justifyContent,
alignItems,
flexDirection,
children,
style,
className
}) => {
const styles: React.CSSProperties = { ...style, justifyContent, alignItems, flexDirection };
return (
<div className={className} style={{ ...defaultStyles, ...styles }}>
{children}
</div>
);
};

export default GradingFlex;
28 changes: 28 additions & 0 deletions src/commons/grading/GradingText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Classes, Text } from '@blueprintjs/core';
import classNames from 'classnames';
import React from 'react';

const defaultStyles: React.CSSProperties = {
width: 'max-content',
margin: 'auto 0'
};

type Props = {
children?: React.ReactNode;
style?: React.CSSProperties;
isSecondaryText?: boolean;
className?: string;
};

const GradingText: React.FC<Props> = ({ children, style, isSecondaryText, className }) => {
return (
<Text
className={classNames(Classes.UI_TEXT, className, isSecondaryText && Classes.TEXT_MUTED)}
style={{ ...defaultStyles, ...style }}
>
{children}
</Text>
);
};

export default GradingText;
23 changes: 20 additions & 3 deletions src/commons/mocks/BackendMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import DashboardActions from 'src/features/dashboard/DashboardActions';
import {
GradingOverviews,
GradingQuery,
GradingQuestion
GradingQuestion,
SortStates
} from '../../features/grading/GradingTypes';
import SessionActions from '../application/actions/SessionActions';
import {
Expand Down Expand Up @@ -166,9 +167,25 @@ export function* mockBackendSaga(): SagaIterator {
SessionActions.fetchGradingOverviews.type,
function* (action: ReturnType<typeof actions.fetchGradingOverviews>): any {
const accessToken = yield select((state: OverallState) => state.session.accessToken);
const { filterToGroup, pageParams, filterParams } = action.payload;
const { filterToGroup, pageParams, filterParams, allColsSortStates } = action.payload;
const sortedBy = {
sortBy: allColsSortStates.sortBy,
sortDirection: ''
};

Object.keys(allColsSortStates.currentState).forEach(key => {
if (allColsSortStates.sortBy === key && key) {
if (allColsSortStates.currentState[key] !== SortStates.NONE) {
sortedBy.sortDirection = allColsSortStates.currentState[key];
} else {
sortedBy.sortBy = '';
sortedBy.sortDirection = '';
}
}
});

const gradingOverviews = yield call(() =>
mockFetchGradingOverview(accessToken, filterToGroup, pageParams, filterParams)
mockFetchGradingOverview(accessToken, filterToGroup, pageParams, filterParams, sortedBy)
);
if (gradingOverviews !== null) {
yield put(actions.updateGradingOverviews(gradingOverviews));
Expand Down
3 changes: 2 additions & 1 deletion src/commons/mocks/GradingMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ export const mockFetchGradingOverview = (
accessToken: string,
group: boolean,
pageParams: { offset: number; pageSize: number },
backendParams: object
backendParams: object,
sortedBy: { sortBy: string; sortDirection: string }
): GradingOverview[] | null => {
// mocks backend role fetching
const permittedRoles: Role[] = [Role.Admin, Role.Staff];
Expand Down
25 changes: 22 additions & 3 deletions src/commons/sagas/BackendSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
GradingOverview,
GradingOverviews,
GradingQuery,
GradingQuestion
GradingQuestion,
SortStates
} from '../../features/grading/GradingTypes';
import { SourcecastData } from '../../features/sourceRecorder/SourceRecorderTypes';
import SourcereelActions from '../../features/sourceRecorder/sourcereel/SourcereelActions';
Expand Down Expand Up @@ -358,15 +359,33 @@ const newBackendSagaOne = combineSagaHandlers(sagaActions, {
return;
}

const { filterToGroup, publishedFilter, pageParams, filterParams } = action.payload;
const { filterToGroup, publishedFilter, pageParams, filterParams, allColsSortStates } =
action.payload;

const sortedBy = {
sortBy: allColsSortStates.sortBy,
sortDirection: ''
};

Object.entries(allColsSortStates.currentState).forEach(([key, value]) => {
if (allColsSortStates.sortBy === key && key !== '') {
if (value !== SortStates.NONE) {
sortedBy.sortDirection = value;
} else {
sortedBy.sortBy = '';
sortedBy.sortDirection = '';
}
}
});

const gradingOverviews: GradingOverviews | null = yield call(
getGradingOverviews,
tokens,
filterToGroup,
publishedFilter,
pageParams,
filterParams
filterParams,
sortedBy
);
if (gradingOverviews) {
yield put(actions.updateGradingOverviews(gradingOverviews));
Expand Down
87 changes: 41 additions & 46 deletions src/commons/sagas/RequestsSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -625,10 +625,11 @@ export const getGradingOverviews = async (
group: boolean,
graded: Record<string, any> | undefined,
pageParams: Record<string, any>,
filterParams: Record<string, any>
filterParams: Record<string, any>,
sortedBy: Record<string, any>
): Promise<GradingOverviews | null> => {
// gradedQuery placed behind filterQuery to override progress filter if any
const params = new URLSearchParams({ ...pageParams, ...filterParams, ...graded });
const params = new URLSearchParams({ ...pageParams, ...filterParams, ...graded, ...sortedBy });
params.append('group', `${group}`);

const resp = await request(`${courseId()}/admin/grading?${params.toString()}`, 'GET', {
Expand All @@ -641,50 +642,44 @@ export const getGradingOverviews = async (

return {
count: gradingOverviews.count,
data: gradingOverviews.data
.map((overview: any) => {
const gradingOverview: GradingOverview = {
assessmentId: overview.assessment.id,
assessmentNumber: overview.assessment.assessmentNumber,
assessmentName: overview.assessment.title,
assessmentType: overview.assessment.type,
studentId: overview.student ? overview.student.id : -1,
studentName: overview.student ? overview.student.name : undefined,
studentNames: overview.team
? overview.team.team_members.map((member: { name: any }) => member.name)
: undefined,
studentUsername: overview.student ? overview.student.username : undefined,
studentUsernames: overview.team
? overview.team.team_members.map((member: { username: any }) => member.username)
: undefined,
submissionId: overview.id,
submissionStatus: overview.status,
groupName: overview.student ? overview.student.groupName : '-',
groupLeaderId: overview.student ? overview.student.groupLeaderId : undefined,
isGradingPublished: overview.isGradingPublished,
progress: backendParamsToProgressStatus(
overview.assessment.isManuallyGraded,
overview.isGradingPublished,
overview.status,
overview.gradedCount,
overview.assessment.questionCount
),
questionCount: overview.assessment.questionCount,
gradedCount: overview.gradedCount,
// XP
initialXp: overview.xp,
xpAdjustment: overview.xpAdjustment,
currentXp: overview.xp + overview.xpAdjustment,
maxXp: overview.assessment.maxXp,
xpBonus: overview.xpBonus
};
return gradingOverview;
})
.sort((subX: GradingOverview, subY: GradingOverview) =>
subX.assessmentId !== subY.assessmentId
? subY.assessmentId - subX.assessmentId
: subY.submissionId - subX.submissionId
)
data: gradingOverviews.data.map((overview: any) => {
const gradingOverview: GradingOverview = {
assessmentId: overview.assessment.id,
assessmentNumber: overview.assessment.assessmentNumber,
assessmentName: overview.assessment.title,
assessmentType: overview.assessment.type,
studentId: overview.student ? overview.student.id : -1,
studentName: overview.student ? overview.student.name : undefined,
studentNames: overview.team
? overview.team.team_members.map((member: { name: any }) => member.name)
: undefined,
studentUsername: overview.student ? overview.student.username : undefined,
studentUsernames: overview.team
? overview.team.team_members.map((member: { username: any }) => member.username)
: undefined,
submissionId: overview.id,
submissionStatus: overview.status,
groupName: overview.student ? overview.student.groupName : '-',
groupLeaderId: overview.student ? overview.student.groupLeaderId : undefined,
isGradingPublished: overview.isGradingPublished,
progress: backendParamsToProgressStatus(
overview.assessment.isManuallyGraded,
overview.isGradingPublished,
overview.status,
overview.gradedCount,
overview.assessment.questionCount
),
questionCount: overview.assessment.questionCount,
gradedCount: overview.gradedCount,
// XP
initialXp: overview.xp,
xpAdjustment: overview.xpAdjustment,
currentXp: overview.xp + overview.xpAdjustment,
maxXp: overview.assessment.maxXp,
xpBonus: overview.xpBonus
};
return gradingOverview;
})
};
};

Expand Down
9 changes: 8 additions & 1 deletion src/commons/workspace/WorkspaceActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createAction } from '@reduxjs/toolkit';
import { Context, Result } from 'js-slang';
import { Chapter, Variant } from 'js-slang/dist/types';

import { AllColsSortStates, GradingColumnVisibility } from '../../features/grading/GradingTypes';
import { SALanguage } from '../application/ApplicationTypes';
import { ExternalLibraryName } from '../application/types/ExternalTypes';
import { Library } from '../assessment/AssessmentTypes';
Expand Down Expand Up @@ -264,7 +265,13 @@ const newActions = createActions('workspace', {
updateChangePointSteps: (changepointSteps: number[], workspaceLocation: WorkspaceLocation) => ({
changepointSteps,
workspaceLocation
})
}),
// For grading table
increaseRequestCounter: 0,
decreaseRequestCounter: 0,
setGradingHasLoadedBefore: () => true,
updateAllColsSortStates: (sortStates: AllColsSortStates) => ({ sortStates }),
updateGradingColumnVisibility: (filters: GradingColumnVisibility) => ({ filters })
});

export const updateLastDebuggerResult = createAction(
Expand Down
Loading

0 comments on commit cfc32e9

Please sign in to comment.