Skip to content

Commit

Permalink
Merge branch 'master' of github.com:vorpal-research/kotoed into master
Browse files Browse the repository at this point in the history
  • Loading branch information
gagarski committed Dec 7, 2020
2 parents 8a9a831 + 341f59d commit 37d0906
Show file tree
Hide file tree
Showing 25 changed files with 403 additions and 124 deletions.
3 changes: 2 additions & 1 deletion kotoed-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"tinycolor2": "^1.4.1",
"twemoji": "^11.0.1",
"typescript-fsa": "~2.4.0",
"vertx3-eventbus-client": "~3.4.2"
"vertx3-eventbus-client": "~3.4.2",
"natsort": "^2.0.2"
}
}
28 changes: 22 additions & 6 deletions kotoed-js/src/main/ts/code/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import {
Comment, CommentsState, CommentState, FileComments, LineComments, ReviewComments
} from "./state/comments";
import {fetchRootDir, fetchFile, File} from "./remote/code";
import {fetchRootDir, fetchFile, File, FileType} from "./remote/code";
import {FileNotFoundError} from "./errors";
import {push} from "react-router-redux";
import {Dispatch} from "redux";
Expand All @@ -32,6 +32,8 @@ import {fetchSubmission} from "../submissionDetails/remote";
import {fetchAnnotations} from "./remote/annotations";
import {ReviewAnnotations} from "./state/annotations";
import {CommentTemplates, fetchCommentTemplates} from "./remote/templates";
import natsort from "natsort";

const actionCreator = actionCreatorFactory();

interface SubmissionPayload {
Expand Down Expand Up @@ -94,7 +96,6 @@ interface CommentEmphasizePayload {
}



interface ExpandedResetForLinePayload {
file: string
line: number
Expand Down Expand Up @@ -209,6 +210,10 @@ export function loadLostFound(payload: SubmissionPayload) {
}
}

// Lower numbers are displayed first
const fileTypeDisplayOrder = {directory: 1, file: 2}
const naturalSorter = natsort()
const typeSorter = (a: File, b: File) => fileTypeDisplayOrder[a.type] - fileTypeDisplayOrder[b.type]

export function fetchRootDirIfNeeded(payload: SubmissionPayload) {
return (dispatch: Dispatch<CodeReviewState>, getState: () => CodeReviewState) => {
Expand All @@ -220,6 +225,18 @@ export function fetchRootDirIfNeeded(payload: SubmissionPayload) {
}));

return fetchRootDir(payload.submissionId).then((root) => {
const recursiveSorter = (node: File) => {
if (node.children == null) {
return
}
node.children.sort((a: File, b: File) =>
typeSorter(a, b) || naturalSorter(a.name, b.name)
)
for (let child of node.children) {
recursiveSorter(child)
}
}
recursiveSorter(root)
dispatch(rootFetch.done({
params: {
submissionId: payload.submissionId
Expand All @@ -237,7 +254,7 @@ export function expandAndLoadIfNeeded(payload: SubmissionPayload & FilePathPaylo
let numPath: NodePath;
try {
numPath = getNodePath(getState().fileTreeState.root, payload.filename);
} catch(e) {
} catch (e) {
numPath = [];
console.warn(e);
}
Expand Down Expand Up @@ -322,7 +339,7 @@ export function loadFileToEditor(payload: FilePathPayload & SubmissionPayload) {

export function fetchAnnotationsIfNeeded(payload: number) {
return async (dispatch: Dispatch<CodeReviewState>, getState: () => CodeReviewState) => {
if(!getState().codeAnnotationsState.loading)
if (!getState().codeAnnotationsState.loading)
return;

dispatch(annotationsFetch.started(payload)); // Not used yet
Expand All @@ -338,7 +355,7 @@ export function fetchAnnotationsIfNeeded(payload: number) {

export function fetchCommentTemplatesIfNeeded() {
return async (dispatch: Dispatch<CodeReviewState>, getState: () => CodeReviewState) => {
if(!getState().commentTemplateState.loading)
if (!getState().commentTemplateState.loading)
return;

dispatch(commentTemplateFetch.started({}));
Expand Down Expand Up @@ -478,7 +495,6 @@ export function emphasizeComment(payload: CommentEmphasizePayload) {
}



export function resetExpandedForLine(payload: ExpandedResetForLinePayload) {
return (dispatch: Dispatch<CodeReviewState>, getState: () => CodeReviewState) => {
dispatch(expandedResetForLine(payload));
Expand Down
2 changes: 2 additions & 0 deletions kotoed-js/src/main/ts/data/submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export interface BloatSubmission extends SubmissionToRead {
// This is here because of possible problems with cyclic imports
export interface JumboProject extends BloatProject {
openSubmissions: Array<SubmissionToRead & WithVerificationData>
permanentAdjustment: number
permanentAdjustmentSubmissions: Array<SubmissionToRead & WithVerificationData>
}

export interface CreateRequest {
Expand Down
59 changes: 37 additions & 22 deletions kotoed-js/src/main/ts/projects/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,25 +67,37 @@ class ProjectComponent extends React.PureComponent<ProjectWithVer> {
handleSearchableClick = (word: string) => {
const searchState = this.props.cb();
// XXX: we can do better
if(!searchState.oldKey.includes(word)) {
if (!searchState.oldKey.includes(word)) {
searchState.toggleSearch(searchState.oldKey + " " + word)
}
};

private renderPermanentAdjustment = (): JSX.Element => {
const adj = this.props.permanentAdjustment
return <span>{adj != null && adj != 0 &&
<p>Permanent adjustment {adj} by
{(this.props.permanentAdjustmentSubmissions || [])
.map((sub) =>
<span> {linkToSubmissionDetails(sub)}</span>
)
}</p>}
</span>
}

private renderOpenSubmissions = (): JSX.Element => {
if (this.props.openSubmissions.length === 0)
return <span>&mdash;</span>;
else {
// Yes, super-minimalistic table
return <table>
<tbody>
{this.props.openSubmissions.map((sub) => <tr className="roomy-tr" key={`submission-${sub.id}`}>
<td>{linkToSubmissionDetails(sub)}</td>
<td>{linkToSubmissionResults(sub)}</td>
<td>{linkToSubmissionReview(sub)}</td>
<td>{renderSubmissionIcon(sub)}</td>
<td>{renderSubmissionTags(sub, this.handleSearchableClick)}</td>
</tr>)}
{this.props.openSubmissions.map((sub) => <tr className="roomy-tr" key={`submission-${sub.id}`}>
<td>{linkToSubmissionDetails(sub)}</td>
<td>{linkToSubmissionResults(sub)}</td>
<td>{linkToSubmissionReview(sub)}</td>
<td>{renderSubmissionIcon(sub)}</td>
<td>{renderSubmissionTags(sub, this.handleSearchableClick)}</td>
</tr>)}
</tbody>
</table>
}
Expand Down Expand Up @@ -116,7 +128,8 @@ class ProjectComponent extends React.PureComponent<ProjectWithVer> {
<a href={Kotoed.UrlPattern.reverse(Kotoed.UrlPattern.Profile.Index, {id: denizen.id})}>
{fullName || `#${denizen.id}`}
</a>;
let groupLink = group && <a style={{cursor: "pointer"}} onClick={() => this.handleSearchableClick(group)}>{group}</a>;
let groupLink = group &&
<a style={{cursor: "pointer"}} onClick={() => this.handleSearchableClick(group)}>{group}</a>;

return <span>
({nameLink}{groupLink && <span>, {groupLink}</span> || null})
Expand All @@ -139,7 +152,7 @@ class ProjectComponent extends React.PureComponent<ProjectWithVer> {
<td>{this.linkify(truncateString(this.props.name || "", 30))}{" "}{this.renderIcon()}</td>
<td>{this.renderProfileLinks(this.props.denizen)}</td>
<td><a href={this.props.repoUrl}>Link</a></td>
<td>{this.renderOpenSubmissions()}</td>
<td>{this.renderPermanentAdjustment()}{this.renderOpenSubmissions()}</td>
</tr>
}

Expand All @@ -153,7 +166,7 @@ interface ProjectSearchState {
}

class ProjectsSearchTable extends ChoosyByVerDataSearchTable<JumboProject & WithVerificationData,
{withVerificationData: true, find: {courseId: number }}> {
{ withVerificationData: true, find: { courseId: number } }> {

protected isGoodEnough(data: (JumboProject & WithVerificationData)[]) {
return super.isGoodEnough(data) &&
Expand Down Expand Up @@ -200,16 +213,16 @@ class ProjectsSearch extends React.Component<{}, ProjectSearchState> {

toolbarButtons = (cb: SearchCallback) => {
return <ButtonToolbar>
{ this.state.canEditCourse &&
<Button bsStyle={"link"} href={UrlPattern.reverse(UrlPattern.Course.Edit, {id: id_})}>
Edit course
</Button>
{this.state.canEditCourse &&
<Button bsStyle={"link"} href={UrlPattern.reverse(UrlPattern.Course.Edit, {id: id_})}>
Edit course
</Button>
}
{ this.state.canCreateProject &&
<ProjectCreate onCreate={() => {
const search = cb();
search.toggleSearch(search.oldKey)
}} courseId={id_}/>
{this.state.canCreateProject &&
<ProjectCreate onCreate={() => {
const search = cb();
search.toggleSearch(search.oldKey)
}} courseId={id_}/>
}
</ButtonToolbar>;
};
Expand Down Expand Up @@ -293,7 +306,9 @@ class ProjectsSearch extends React.Component<{}, ProjectSearchState> {
}
}}
wrapResults={this.renderTable}
elementComponent={(key, c: ProjectWithVer, cb: SearchCallback) => <ProjectComponent {...c} key={key} cb={cb} />}
elementComponent={(key, c: ProjectWithVer, cb: SearchCallback) => <ProjectComponent {...c}
key={key}
cb={cb}/>}
toolbarComponent={this.toolbar}
/>
</Row>
Expand All @@ -310,7 +325,7 @@ if (params == null) {

let id = params.get("id");

if (id === undefined ) {
if (id === undefined) {
snafuDialog();
throw new Error("Cannot resolve course id")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,27 @@ export default class SubmissionDetails extends React.Component<SubmissionDetails
private renderStateChange = () => {
if (!this.props.permissions.changeState)
return null;
else if (this.props.submission.record.state === "open")
return <Button bsStyle="danger" onClick={this.props.onClose}>Close</Button>;
else if (this.props.submission.record.state === "closed")
else if (this.props.submission.record.state === "open") {
const adjustmentTagsAdded = this.props.tags.some(value => !isNaN(Number(value.name)))
const persistentTagAdded = this.props.tags.some(value => value.name === "permanent")
if (adjustmentTagsAdded == persistentTagAdded) {
return <Button bsStyle="danger" onClick={this.props.onClose}>Close</Button>;
} else {
return <OverlayTrigger trigger="click" placement="bottom" overlay={
<Popover id="can-close-popover">
<strong>Are you sure?</strong>
<br/>
<Button bsStyle="danger"
block
onClick={this.props.onClose}>
Close
</Button>
</Popover>
}>
<Button bsStyle="danger">Close</Button>
</OverlayTrigger>;
}
} else if (this.props.submission.record.state === "closed")
return <Button bsStyle="success" onClick={this.props.onReopen}>Reopen</Button>;
};

Expand Down
7 changes: 6 additions & 1 deletion kotoed-js/src/main/ts/submissionDetails/remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {WithId} from "../data/common";
import {CommentAggregate} from "../code/remote/comments";
import {CourseToRead} from "../data/course";
import {sendAsync} from "../views/components/common";
import natsort from "natsort";

export interface SubmissionPermissions {
editOwnComments: boolean
Expand Down Expand Up @@ -84,9 +85,13 @@ export async function fetchTagList(submissionId: number): Promise<Tag[]> {
}

export async function fetchAvailableTags(): Promise<Tag[]> {
const sorter = natsort();

return sendAsync(Kotoed.Address.Api.Tag.List, undefined)
.then(tags => {
return _.sortBy(tags, t => t.name);
return tags.sort((a: Tag, b: Tag) =>
// Sort negative numbers as if they were positive
sorter(_.trimStart(a.name, '-'), _.trimStart(b.name, '-')));
});
}

Expand Down
7 changes: 6 additions & 1 deletion kotoed-js/src/main/ts/views/submissionResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {

import {fetchPermissions} from "../submissionDetails/remote";
import {Kotoed} from "../util/kotoed-api";
import natsort from "natsort";

export class SubmissionResultTable<ResultT> extends ResultListHolder<any> {
constructor(props: ResultListHolderProps<ResultT>, context: undefined) {
Expand All @@ -34,10 +35,14 @@ export class SubmissionResultTable<ResultT> extends ResultListHolder<any> {
let subReport = sendAsync(Kotoed.Address.Api.Submission.Report, {"id": this.props.id});

return Promise.all([subResults, subReport]).then(([res, rep]) => {
const sorter = natsort({insensitive: true}); // Total row should be the last one
const sortedRep = rep.data.sort((a: string[], b: string[]) =>
sorter(a[0], b[0])
);
const sum: GenericResponse<ResultT> = {
records: _.concat(res.records, {
type: "submission.statistics",
data: rep.data
data: sortedRep
} as any),
verificationData: res.verificationData
};
Expand Down
4 changes: 4 additions & 0 deletions kotoed-js/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3149,6 +3149,10 @@ nanomatch@^1.2.0:
snapdragon "^0.8.1"
to-regex "^3.0.1"

natsort@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/natsort/-/natsort-2.0.2.tgz#3358b7af00f155c8ce181289ede79e18d81e6c52"

node-fetch@^1.0.1:
version "1.7.2"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.2.tgz#c54e9aac57e432875233525f3c891c4159ffefd7"
Expand Down
Loading

0 comments on commit 37d0906

Please sign in to comment.