Skip to content

Commit

Permalink
🏗️ Remove concept of unranked projects and move to batch submission
Browse files Browse the repository at this point in the history
Towards addressing issue #1.

Under the new system (not yet developed) unranked teams will not exist
and rankings will be submitted in batches.
  • Loading branch information
tameTNT committed Sep 10, 2024
1 parent 926f673 commit 5126e0f
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 34 deletions.
2 changes: 1 addition & 1 deletion client/src/components/judge/ProjectEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const ProjectEntry = ({ project }: ProjectEntryProps) => {
if (project.id === -1) {
return (
<div>
<h3 className="text-xl grow mt-4">Unsorted Projects below here...</h3>
<h3 className="text-xl grow mt-4">Unranked projects below here...</h3>
</div>
);
}
Expand Down
43 changes: 42 additions & 1 deletion client/src/pages/admin/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const AdminSettings = () => {
const [dropPopup, setDropPopup] = useState(false);
const [judgingTimer, setJudgingTimer] = useState('');
const [categories, setCategories] = useState('');
const [rankingBatchSize, setRankingBatchSize] = useState(8);
const [loading, setLoading] = useState(true);

async function getOptions() {
Expand All @@ -45,6 +46,10 @@ const AdminSettings = () => {
const cats = res.data?.categories.join(', ');
setCategories(cats ?? '');

// Set ranking batch size
const rbs = res.data?.ranking_batch_size;
setRankingBatchSize(rbs ?? 8)

setLoading(false);
}

Expand Down Expand Up @@ -111,6 +116,19 @@ const AdminSettings = () => {
getOptions();
};

const updateRankingBatchSize = async () => {
const res = await postRequest<OkResponse>('/admin/categories', 'admin', {
ranking_batch_size: rankingBatchSize,
});
if (res.status !== 200 || res.data?.ok !== 1) {
errorAlert(res);
return;
}

alert('Ranking Batch Size updated!');
getOptions();
}

const resetClock = async () => {
const res = await postRequest<OkResponse>('/admin/clock/reset', 'admin', null);
if (res.status !== 200 || res.data?.ok !== 1) {
Expand Down Expand Up @@ -234,11 +252,34 @@ const AdminSettings = () => {
<Button
type="primary"
onClick={updateCategories}
className="mt-4 w-auto md:w-auto px-4 py-2"
className="mt-4 w-auto md:w-auto px-4 py-2 mb-8" // lucatodo: add white inner outline to buttons on focus?
>
Update Categories
</Button>

<SubSection>Set Ranking Batch Size</SubSection>
<Description>
Set how many projects judges rank at a time (must be at least 2 obviously).
Judges can rank and reorder projects freely before submitting a batch of the specified size.
</Description>
<input
className="w-full h-14 px-4 text-2xl border-lightest border-2 rounded-sm focus:border-primary focus:border-4 focus:outline-none"
type="number"
min="2"
placeholder="8"
value={rankingBatchSize}
onChange={(e) => {
setRankingBatchSize(parseInt(e.target.value));
}}
/>
<Button
type="primary"
onClick={updateRankingBatchSize}
className="mt-4 w-auto md:w-auto px-4 py-2"
>
Update Ranking Batch Size
</Button>

<Section>Project Numbers</Section>

<SubSection>Reassign Project Numbers</SubSection>
Expand Down
28 changes: 24 additions & 4 deletions client/src/pages/judge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const Judge = () => {
const navigate = useNavigate();
const [judge, setJudge] = useState<Judge | null>(null);
const [projects, setProjects] = useState<SortableJudgedProject[]>([]);
const [allRanked, setAllRanked] = useState(false)
const [loaded, setLoaded] = useState(false);
const [projCount, setProjCount] = useState(0);
const [activeId, setActiveId] = useState<number | null>(null);
Expand Down Expand Up @@ -125,6 +126,8 @@ const Judge = () => {
const combinedProjects = [...rankedProjects, dummy, ...unrankedProjects];

setProjects(combinedProjects);
setAllRanked(rankedProjects.length === 3); // lucatodo: use rank batch size variable;
// lucatodo: rankedProjects won't be variable we want to find length of. new variable probable: batchProjects?
setLoaded(true);
}, [judge]);

Expand Down Expand Up @@ -169,6 +172,7 @@ const Judge = () => {
const saveSort = async (newProjects: SortableJudgedProject[]) => {
// Split index
const splitIndex = newProjects.findIndex((p) => p.id === -1);
setAllRanked(newProjects.length>0 && splitIndex === newProjects.length-1); // lucatodo: use rank batch size variable equality, not >0

// Get the ranked projects
const rankedProjects = newProjects.slice(0, splitIndex);
Expand All @@ -189,6 +193,7 @@ const Judge = () => {
<Container noCenter className="px-2 pb-4">
<h1 className="text-2xl my-2">Welcome, {judge?.name}!</h1>
<div className="w-full mb-6">
{/* lucatodo: disable button if all projects in batch seen */}
<Button type="primary" full square href="/judge/live">
Next Project
</Button>
Expand All @@ -199,10 +204,12 @@ const Judge = () => {
</div>
</div>
<div className="flex justify-evenly">
<StatBlock name="Seen" value={judge?.seen_projects.length as number} />
<StatBlock name="Total Projects" value={projCount} />
<StatBlock name="Seen" value={judge?.seen_projects.length as number}/>
<StatBlock name="Total Projects" value={projCount}/>
</div>
<h2 className="text-primary text-xl font-bold mt-4">Rank Projects</h2>
{/* lucatodo: only update scores on submission? query this (only relevant if prioritisation implemented, issue #5 */}
<p className="italic text-light">NB: Relative project order is tracked on the admin panel even before your submit a batch.</p>
<div className="h-[1px] w-full bg-light my-2"></div>
<DndContext
sensors={sensors}
Expand All @@ -212,15 +219,28 @@ const Judge = () => {
>
<SortableContext items={projects} strategy={verticalListSortingStrategy}>
{projects.map((item) => (
<SortableItem key={item.id} item={item} />
<SortableItem key={item.id} item={item}/>
))}
</SortableContext>
<DragOverlay>
{activeId ? (
<SortableItem item={projects.find((p) => p.id === activeId)} />
<SortableItem item={projects.find((p) => p.id === activeId)}/>
) : null}
</DragOverlay>
</DndContext>
<div className="w-full mt-4">
<div className="flex justify-center italic text-light text-center">
{/* lucatodo: update X with variable limit */}
{/* lucatodo: text updates if judging is ended manually to allow 'early' submission (see issue #4) */}
Please rank all your projects.<br/>
You can only submit rankings in batches of X projects.
</div>
<Button type="primary" full square href="" disabled={!allRanked}>
{/* lucatodo: add button functionality (inc. alert to confirm submission) */}
Submit Rankings
<p className="text-sm italic">And move onto next batch</p>
</Button>
</div>
</Container>
</>
);
Expand Down
1 change: 1 addition & 0 deletions client/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ interface Options {
clock: ClockState;
judging_timer: number;
categories: string[];
ranking_batch_size: number;
}

interface FetchResponse<T> {
Expand Down
24 changes: 13 additions & 11 deletions server/models/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ package models
import "go.mongodb.org/mongo-driver/bson/primitive"

type Options struct {
Id primitive.ObjectID `bson:"_id,omitempty" json:"id"`
Ref int64 `bson:"ref" json:"ref"`
CurrTableNum int64 `bson:"curr_table_num" json:"curr_table_num"`
Clock ClockState `bson:"clock" json:"clock"`
JudgingTimer int64 `bson:"judging_timer" json:"judging_timer"`
Categories []string `bson:"categories" json:"categories"`
Id primitive.ObjectID `bson:"_id,omitempty" json:"id"`
Ref int64 `bson:"ref" json:"ref"`
CurrTableNum int64 `bson:"curr_table_num" json:"curr_table_num"`
Clock ClockState `bson:"clock" json:"clock"`
JudgingTimer int64 `bson:"judging_timer" json:"judging_timer"`
Categories []string `bson:"categories" json:"categories"`
RankingBatchSize int64 `bson:"ranking_batch_size" json:"ranking_batch_size"`
}

func NewOptions() *Options {
return &Options{
Ref: 0,
CurrTableNum: 0,
JudgingTimer: 300,
Clock: *NewClockState(),
Categories: []string{"Creativity/Innovation", "Technical Competence/Execution", "Research/Design", "Presentation"},
Ref: 0,
CurrTableNum: 0,
JudgingTimer: 300,
Clock: *NewClockState(),
Categories: []string{"Creativity/Innovation", "Technical Competence/Execution", "Research/Design", "Presentation"},
RankingBatchSize: 8,
}
}
12 changes: 6 additions & 6 deletions server/ranking/borda.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

type JudgeRanking struct {
Rankings []primitive.ObjectID `json:"rankings"`
Unranked []primitive.ObjectID `json:"unranked"`
//Unranked []primitive.ObjectID `json:"unranked"`
}

type RankedObject struct {
Expand All @@ -34,11 +34,11 @@ func rankingToPairwise(judgeRanking JudgeRanking) []Comparison {
}

// Loop through each project in the ranking and compare it to all the unranked projects
for _, winner := range judgeRanking.Rankings {
for _, loser := range judgeRanking.Unranked {
pairwise = append(pairwise, Comparison{winner, loser})
}
}
//for _, winner := range judgeRanking.Rankings {
// for _, loser := range judgeRanking.Unranked {
// pairwise = append(pairwise, Comparison{winner, loser})
// }
//}

return pairwise
}
Expand Down
8 changes: 4 additions & 4 deletions server/ranking/borda_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ func TestCalcRanking(t *testing.T) {
jrs := []ranking.JudgeRanking{
{
Rankings: []primitive.ObjectID{obj1, obj5, obj3},
Unranked: []primitive.ObjectID{obj4, obj2},
//Unranked: []primitive.ObjectID{obj4, obj2},
},
{
Rankings: []primitive.ObjectID{obj5, obj4, obj2},
Unranked: []primitive.ObjectID{obj3, obj1},
//Unranked: []primitive.ObjectID{obj3, obj1},
},
{
Rankings: []primitive.ObjectID{obj1, obj5, obj2},
Unranked: []primitive.ObjectID{obj3, obj4},
//Unranked: []primitive.ObjectID{obj3, obj4},
},
{
Rankings: []primitive.ObjectID{obj2, obj1, obj5},
Unranked: []primitive.ObjectID{obj5, obj3},
//Unranked: []primitive.ObjectID{obj5, obj3},
},
}

Expand Down
13 changes: 6 additions & 7 deletions server/router/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,16 +393,15 @@ func GetScores(ctx *gin.Context) {
// Create an array of {Rankings: [], Unranked: []}
judgeRankings := make([]ranking.JudgeRanking, 0)
for _, judge := range judges {
unranked := make([]primitive.ObjectID, 0)
for _, proj := range judge.SeenProjects {
if !contains(judge.Rankings, proj.ProjectId) {
unranked = append(unranked, proj.ProjectId)
}
}
//for _, proj := range judge.SeenProjects {
// if !contains(judge.Rankings, proj.ProjectId) {
// unranked = append(unranked, proj.ProjectId)
// }
//}

judgeRankings = append(judgeRankings, ranking.JudgeRanking{
Rankings: judge.Rankings,
Unranked: unranked,
//Unranked: unranked,
})
}

Expand Down

0 comments on commit 5126e0f

Please sign in to comment.