Skip to content

Commit 29a42ea

Browse files
cci: automatically detect revision sorting
1 parent f236b2e commit 29a42ea

File tree

3 files changed

+152
-16
lines changed

3 files changed

+152
-16
lines changed

src/models/ContributionSurveyRow.ts

+120-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import MwApi from '../MwApi';
55
import ContributionSurveyRowParser, {
66
RawContributionSurveyRow
77
} from './ContributionSurveyRowParser';
8+
import { ContributionSurveyRowSort } from './ContributionSurveyRowSort';
89

910
export enum ContributionSurveyRowStatus {
1011
// The row has not been processed yet.
@@ -68,6 +69,122 @@ export default class ContributionSurveyRow {
6869
return ContributionSurveyRowStatus.Unknown;
6970
}
7071

72+
/**
73+
* Guesses the sort order for a given set of revisions.
74+
*
75+
* @param diffs The diffs to guess from.
76+
* @return The sort order
77+
*/
78+
static guessSortOrder(
79+
diffs: Iterable<ContributionSurveyRevision>
80+
): ContributionSurveyRowSort {
81+
let last: ContributionSurveyRevision = null;
82+
let dateScore = 1;
83+
let dateReverseScore = 1;
84+
let byteScore = 1;
85+
for ( const diff of diffs ) {
86+
if ( last == null ) {
87+
last = diff;
88+
} else {
89+
const diffTimestamp = new Date( diff.timestamp ).getTime();
90+
const lastTimestamp = new Date( last.timestamp ).getTime();
91+
dateScore = ( dateScore + (
92+
diffTimestamp > lastTimestamp ? 1 : 0
93+
) ) / 2;
94+
dateReverseScore = ( dateReverseScore + (
95+
diffTimestamp < lastTimestamp ? 1 : 0
96+
) ) / 2;
97+
byteScore = ( byteScore + (
98+
diff.diffsize < last.diffsize ? 1 : 0
99+
) ) / 2;
100+
last = diff;
101+
}
102+
}
103+
104+
// Multiply by weights to remove ties
105+
dateScore *= 1.1;
106+
dateReverseScore *= 1.05;
107+
108+
switch ( Math.max( dateScore, dateReverseScore, byteScore ) ) {
109+
case byteScore:
110+
return ContributionSurveyRowSort.Bytes;
111+
case dateScore:
112+
return ContributionSurveyRowSort.Date;
113+
case dateReverseScore:
114+
return ContributionSurveyRowSort.DateReverse;
115+
}
116+
}
117+
118+
/**
119+
* Gets the sorter function which will sort a set of diffs based on a given
120+
* sort order. This sorts any array containing revisions.
121+
*
122+
* @param sort
123+
* @param mode The sort mode to use.
124+
*/
125+
static getSorterFunction( sort: ContributionSurveyRowSort, mode?: 'array' ):
126+
( a: ContributionSurveyRevision, b: ContributionSurveyRevision ) => number;
127+
/**
128+
* Gets the sorter function which will sort a set of diffs based on a given
129+
* sort order. This sorts any entry array using the first element (the key).
130+
*
131+
* @param sort
132+
* @param mode The sort mode to use.
133+
*/
134+
static getSorterFunction( sort: ContributionSurveyRowSort, mode?: 'key' ):
135+
( a: [ContributionSurveyRevision, any], b: [ContributionSurveyRevision, any] ) => number;
136+
/**
137+
* Gets the sorter function which will sort a set of diffs based on a given
138+
* sort order. This sorts any entry array using the second element (the value).
139+
*
140+
* @param sort
141+
* @param mode The sort mode to use.
142+
*/
143+
static getSorterFunction( sort: ContributionSurveyRowSort, mode?: 'value' ):
144+
( a: [any, ContributionSurveyRevision], b: [any, ContributionSurveyRevision] ) => number;
145+
/**
146+
* Gets the sorter function which will sort a set of diffs based on a given
147+
* sort order.
148+
*
149+
* @param sort
150+
* @param mode The sort mode to use. If `array`, the returned function sorts an
151+
* array of revisions. If `key`, the returned function sorts entries with the first
152+
* entry element (`entry[0]`) being a revision. If `value`, the returned function
153+
* sorts values with the second entry element (`entry[1]`) being a revision.
154+
* @return The sorted array
155+
*/
156+
static getSorterFunction(
157+
sort: ContributionSurveyRowSort,
158+
mode: 'array' | 'key' | 'value' = 'array'
159+
) {
160+
return ( _a: any, _b: any ) => {
161+
let a: ContributionSurveyRevision, b: ContributionSurveyRevision;
162+
switch ( mode ) {
163+
case 'array':
164+
a = _a;
165+
b = _b;
166+
break;
167+
case 'key':
168+
a = _a[ 0 ];
169+
b = _b[ 0 ];
170+
break;
171+
case 'value':
172+
a = _a[ 1 ];
173+
b = _b[ 1 ];
174+
break;
175+
}
176+
177+
switch ( sort ) {
178+
case ContributionSurveyRowSort.Date:
179+
return new Date( a.timestamp ).getTime() - new Date( b.timestamp ).getTime();
180+
case ContributionSurveyRowSort.DateReverse:
181+
return new Date( b.timestamp ).getTime() - new Date( a.timestamp ).getTime();
182+
case ContributionSurveyRowSort.Bytes:
183+
return b.diffsize - a.diffsize;
184+
}
185+
};
186+
}
187+
71188
/**
72189
* The case page of this row.
73190
*/
@@ -121,7 +238,7 @@ export default class ContributionSurveyRow {
121238
}
122239

123240
/**
124-
* The diffs included in this row.
241+
* The diffs included in this row. Mapped by revision IDs.
125242
*/
126243
private diffs?: Map<number, ContributionSurveyRevision>;
127244

@@ -226,9 +343,10 @@ export default class ContributionSurveyRow {
226343
}
227344
);
228345

346+
const sortOrder = ContributionSurveyRow.guessSortOrder( revisionData.values() );
229347
// Sort from most bytes to least.
230348
return this.diffs = new Map( [ ...revisionData.entries() ].sort(
231-
( a, b ) => b[ 1 ].diffsize - a[ 1 ].diffsize
349+
ContributionSurveyRow.getSorterFunction( sortOrder, 'value' )
232350
) );
233351
}
234352

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export enum ContributionSurveyRowSort {
2+
// Chronological
3+
Date,
4+
// Reverse chronological
5+
DateReverse,
6+
// New size - old size
7+
Bytes
8+
}

src/ui/root/DeputyContributionSurveyRow.tsx

+24-14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
DeputyPageStatusRequestMessage
1919
} from '../../DeputyCommunications';
2020
import DeputyCCIStatusDropdown from '../shared/DeputyCCIStatusDropdown';
21+
import { ContributionSurveyRowSort } from '../../models/ContributionSurveyRowSort';
2122

2223
export enum DeputyContributionSurveyRowState {
2324
/*
@@ -83,6 +84,10 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
8384
* Whether this row was originally finished upon loading.
8485
*/
8586
wasFinished: boolean;
87+
/**
88+
* Sort order of this row. Automatically guessed when loaded.
89+
*/
90+
sortOrder: ContributionSurveyRowSort;
8691
/**
8792
* This row's main root element. Does not get swapped.
8893
*/
@@ -242,8 +247,10 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
242247
const unfinishedDiffs = this.revisions?.filter(
243248
( v ) => !v.completed
244249
)?.sort(
245-
( a, b ) => ( b.revision.diffsize - a.revision.diffsize ) ||
246-
( b.revision.revid - a.revision.revid )
250+
( a, b ) => ContributionSurveyRow.getSorterFunction( this.sortOrder )(
251+
a.revision,
252+
b.revision
253+
)
247254
) ?? [];
248255

249256
if ( unfinishedDiffs.length > 0 ) {
@@ -322,6 +329,17 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
322329
return result;
323330
}
324331

332+
/**
333+
* @return The hash used for autosave keys
334+
*/
335+
get autosaveHash(): string {
336+
return `CASE--${
337+
this.row.casePage.title.getPrefixedDb()
338+
}+PAGE--${
339+
this.row.title.getPrefixedDb()
340+
}`;
341+
}
342+
325343
/**
326344
* Creates a new DeputyContributionSurveyRow object.
327345
*
@@ -349,6 +367,7 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
349367
async loadData() {
350368
try {
351369
const diffs = await this.row.getDiffs();
370+
this.sortOrder = ContributionSurveyRow.guessSortOrder( diffs.values() );
352371

353372
this.wasFinished = this.row.completed;
354373

@@ -387,17 +406,6 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
387406
}
388407
}
389408

390-
/**
391-
* @return The hash used for autosave keys
392-
*/
393-
get autosaveHash(): string {
394-
return `CASE--${
395-
this.row.casePage.title.getPrefixedDb()
396-
}+PAGE--${
397-
this.row.title.getPrefixedDb()
398-
}`;
399-
}
400-
401409
/**
402410
* Perform UI updates and recheck possible values.
403411
*/
@@ -640,7 +648,9 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
640648
// Identify largest diff
641649
const largestDiff = diffs.get(
642650
Array.from( diffs.values() )
643-
.sort( ( a, b ) => b.diffsize - a.diffsize )[ 0 ]
651+
.sort( ContributionSurveyRow.getSorterFunction(
652+
ContributionSurveyRowSort.Bytes
653+
) )[ 0 ]
644654
.revid
645655
);
646656

0 commit comments

Comments
 (0)