Skip to content

Commit 4b8f1c2

Browse files
cci: add new "expand all diffs" button
1 parent c086f5b commit 4b8f1c2

4 files changed

Lines changed: 192 additions & 12 deletions

File tree

i18n/core/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
"deputy.session.row.history": "Open page history",
6666
"deputy.session.row.checkAll": "Mark all revisions as finished",
6767
"deputy.session.row.checkAll.confirm": "Mark all revisions as finished?",
68+
"deputy.session.row.expandAll": "Toggle comparison (diff) view for all revisions",
69+
"deputy.session.row.expandAll.cancel": "Cancel loading comparison (diff) views for all revisions",
70+
"deputy.session.row.expandAll.close": "Hide comparison (diff) views for all revisions",
6871
"deputy.session.row.additionalComments": "Discussion",
6972
"deputy.session.row.closeComments": "Closing comments",
7073
"deputy.session.row.close.sigFound": "The closing comment had a signature. It will not be automatically removed when saved.",

src/css/deputy.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ p.dp-messageWidget-message {
6666
background-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2220%22 height=%2220%22 viewBox=%220 0 20 20%22%3E%3Ctitle%3E check all %3C/title%3E%3Cpath fill=%22%23d73333%22 d=%22m.29 12.71 1.42-1.42 2.22 2.22 8.3-10.14 1.54 1.26-9.7 11.86zM12 10h5v2h-5zm-3 4h5v2H9zm6-8h5v2h-5z%22/%3E%3C/svg%3E");
6767
}
6868

69+
.oo-ui-progressBarWidget.oo-ui-widget-enabled.dp-progress-failed .oo-ui-progressBarWidget-bar {
70+
/*noinspection CssUnresolvedCustomProperty*/
71+
background-color: var(--background-color-destructive, #d73333);
72+
}
73+
6974
/*
7075
===============================================================================
7176
@@ -285,6 +290,10 @@ body.mediawiki.rtl .dp-cs-row-head > :not(:first-child):not(:last-child) {
285290
margin-right: 8px !important;
286291
}
287292

293+
.dp-cs-row-buttons .oo-ui-buttonWidget {
294+
margin-right: 0;
295+
}
296+
288297
.dp-cs-row-title {
289298
font-weight: bold;
290299
font-size: 1.2em;

src/session/DeputyRootSession.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ export default class DeputyRootSession {
423423
'oojs-ui.styles.icons-interactions',
424424
'oojs-ui.styles.icons-media',
425425
'oojs-ui.styles.icons-movement',
426+
'oojs-ui.styles.icons-layout',
426427
'ext.discussionTools.init',
427428
'jquery.makeCollapsible'
428429
], async ( require ) => {

src/ui/root/DeputyContributionSurveyRow.tsx

Lines changed: 179 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import warn from '../../util/warn';
2222
import error from '../../util/error';
2323
import { ContributionSurveyRowStatus } from '../../models/ContributionSurveyRowStatus';
2424
import dangerModeConfirm from '../../util/dangerModeConfirm';
25+
import any = jasmine.any;
2526

2627
export enum DeputyContributionSurveyRowState {
2728
/*
@@ -39,6 +40,31 @@ export enum DeputyContributionSurveyRowState {
3940
Closed
4041
}
4142

43+
enum DiffExpandStateType {
44+
/**
45+
* Diffs are not expanded.
46+
*/
47+
Unexpanded,
48+
/**
49+
* Diffs are actively expanding.
50+
*/
51+
Expanding,
52+
/**
53+
* Diffs are completely expanded.
54+
*/
55+
Expanded,
56+
/**
57+
* The expansion was cancelled, but loaded diffs remain open.
58+
* The next click will unexpand diffs, which can then lead them to being expanded again.
59+
* Since the diff HTML is saved and cached, we don't have to worry about re-loading diffs.
60+
*/
61+
Cancelled
62+
}
63+
64+
type DiffExpandState =
65+
| { type: Exclude<DiffExpandStateType, DiffExpandStateType.Expanding> }
66+
| { type: DiffExpandStateType.Expanding, progress: [number, number] }
67+
4268
/**
4369
* A UI element used for denoting the following aspects of a page in the contribution
4470
* survey:
@@ -115,6 +141,14 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
115141
* Button that checks all revisions of this row
116142
*/
117143
checkAllButton: OO.ui.ButtonWidget;
144+
/**
145+
* Button that opens all diff previews for this row
146+
*/
147+
expandAllButton: OO.ui.ButtonWidget;
148+
/**
149+
* Progress bar for diff preview expansion. Only shown when diffs are actively expanding.
150+
*/
151+
expandAllProgress: OO.ui.ProgressBarWidget;
118152
/**
119153
* Message box displayed when a user has set a status but not yet cleared all diffs.
120154
*/
@@ -128,6 +162,7 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
128162
* finished.
129163
*/
130164
finishedRow: DeputyFinishedContributionSurveyRow;
165+
private diffExpandState: DiffExpandState;
131166

132167
/**
133168
* OOUI DropdownWidget for the current row status
@@ -664,15 +699,18 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
664699
<i>{ mw.msg( 'deputy.session.row.pageonly' ) }</i>
665700
</div> );
666701
} else {
702+
let anyExpanded = false;
667703
const cciConfig = window.deputy.config.cci;
668704
const maxSize = cciConfig.maxSizeToAutoShowDiff.get();
669705
for ( const revision of diffs.values() ) {
706+
const expanded = cciConfig.autoShowDiff.get() &&
707+
diffs.size < cciConfig.maxRevisionsToAutoShowDiff.get() &&
708+
( maxSize === -1 || Math.abs( revision.diffsize ) < maxSize );
709+
if ( expanded ) {
710+
anyExpanded = true;
711+
}
670712
const revisionUIEl = new DeputyContributionSurveyRevision(
671-
revision, this, {
672-
expanded: cciConfig.autoShowDiff.get() &&
673-
diffs.size < cciConfig.maxRevisionsToAutoShowDiff.get() &&
674-
( maxSize === -1 || Math.abs( revision.diffsize ) < maxSize )
675-
}
713+
revision, this, { expanded }
676714
);
677715

678716
revisionUIEl.addEventListener(
@@ -687,6 +725,11 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
687725
revisionList.appendChild( revisionUIEl.render() );
688726
this.revisions.push( revisionUIEl );
689727
}
728+
this.diffExpandState = {
729+
type: anyExpanded ?
730+
DiffExpandStateType.Expanded : DiffExpandStateType.Unexpanded
731+
};
732+
this.updateDiffExpandButton();
690733
}
691734

692735
return revisionList;
@@ -697,8 +740,8 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
697740
*
698741
* @return An HTML element
699742
*/
700-
renderLinks(): JSX.Element {
701-
return <span class="dp-cs-row-links">
743+
renderLinks(): JSX.Element[] {
744+
return [
702745
<a
703746
class="dp-cs-row-link dp-cs-row-edit"
704747
target="_blank"
@@ -714,7 +757,7 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
714757
icon: 'edit',
715758
framed: false
716759
} ) ) }
717-
</a>
760+
</a>,
718761
<a
719762
class="dp-cs-row-link dp-cs-row-talk"
720763
target="_blank"
@@ -729,7 +772,7 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
729772
icon: 'speechBubbles',
730773
framed: false
731774
} ) ) }
732-
</a>
775+
</a>,
733776
<a
734777
class="dp-cs-row-link dp-cs-row-history"
735778
target="_blank"
@@ -746,7 +789,7 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
746789
framed: false
747790
} ) ) }
748791
</a>
749-
</span>;
792+
];
750793
}
751794

752795
/**
@@ -875,6 +918,27 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
875918
);
876919
} );
877920

921+
// Build expand all button
922+
this.expandAllButton = new OO.ui.ButtonWidget( {
923+
icon: 'viewDetails',
924+
label: mw.msg( 'deputy.session.row.expandAll' ),
925+
title: mw.msg( 'deputy.session.row.expandAll' ),
926+
invisibleLabel: true,
927+
framed: false
928+
} );
929+
this.expandAllButton.on( 'click', async () => {
930+
await this.handleDiffExpansion();
931+
} );
932+
// TODO: @types/oojs-ui limitation
933+
// https://github.com/DefinitelyTyped/DefinitelyTyped/pull/74902
934+
this.expandAllProgress = new ( OO.ui.ProgressBarWidget as any )( {
935+
progress: false,
936+
inline: true
937+
} );
938+
this.expandAllButton.$element.append( this.expandAllProgress.$element );
939+
940+
this.updateDiffExpandButton();
941+
878942
// Build content toggler
879943
const contentToggle = new OO.ui.ButtonWidget( {
880944
classes: [ 'dp-cs-row-toggle' ],
@@ -927,8 +991,13 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
927991
{ this.row.title.getPrefixedText() }
928992
</a>
929993
{ diffs && this.renderDetails( diffs ) }
930-
{ this.renderLinks() }
931-
{ !this.wasFinished && diffs && diffs.size > 0 && unwrapWidget( this.checkAllButton ) }
994+
<span class="dp-cs-row-buttons">
995+
{ this.renderLinks() }
996+
{ !this.wasFinished && diffs && diffs.size > 0 && [
997+
unwrapWidget( this.checkAllButton ),
998+
unwrapWidget( this.expandAllButton )
999+
] }
1000+
</span>
9321001
{ !contentContainer.classList.contains( 'dp-cs-row-content-empty' ) &&
9331002
unwrapWidget( contentToggle ) }
9341003
</div>;
@@ -1106,4 +1175,102 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
11061175
}
11071176
}
11081177

1178+
/**
1179+
* Updates the expand all button based on the current state of diff expansion.
1180+
*/
1181+
updateDiffExpandButton() {
1182+
if ( !this.expandAllButton || !this.diffExpandState || !this.expandAllProgress ) {
1183+
return;
1184+
}
1185+
const state = this.diffExpandState;
1186+
const type = state.type;
1187+
switch ( type ) {
1188+
case DiffExpandStateType.Unexpanded:
1189+
this.expandAllButton.setTitle( mw.msg( 'deputy.session.row.expandAll' ) );
1190+
this.expandAllButton.setLabel( mw.msg( 'deputy.session.row.expandAll' ) );
1191+
this.expandAllButton.setIcon( 'viewDetails' );
1192+
this.expandAllButton.clearFlags();
1193+
this.expandAllProgress.toggle( false );
1194+
break;
1195+
case DiffExpandStateType.Expanding:
1196+
this.expandAllButton.setTitle( mw.msg( 'deputy.session.row.expandAll.cancel' ) );
1197+
this.expandAllButton.setLabel( mw.msg( 'deputy.session.row.expandAll.cancel' ) );
1198+
this.expandAllButton.setIcon( 'cancel' );
1199+
this.expandAllButton.setFlags( [ 'destructive' ] );
1200+
this.expandAllProgress.toggle( true );
1201+
this.expandAllProgress.setProgress(
1202+
( state.progress[ 0 ] / state.progress[ 1 ] ) * 100
1203+
);
1204+
unwrapWidget( this.expandAllProgress ).classList
1205+
.toggle( 'dp-progress-failed', false );
1206+
break;
1207+
case DiffExpandStateType.Expanded:
1208+
case DiffExpandStateType.Cancelled:
1209+
this.expandAllButton.setTitle( mw.msg( 'deputy.session.row.expandAll.close' ) );
1210+
this.expandAllButton.setLabel( mw.msg( 'deputy.session.row.expandAll.close' ) );
1211+
this.expandAllButton.setIcon( {
1212+
[ DiffExpandStateType.Expanded ]: 'menu',
1213+
[ DiffExpandStateType.Cancelled ]: 'reload'
1214+
}[ type ] );
1215+
this.expandAllButton.clearFlags();
1216+
this.expandAllProgress.toggle( type === DiffExpandStateType.Cancelled );
1217+
this.expandAllProgress.setProgress( 100 );
1218+
unwrapWidget( this.expandAllProgress ).classList
1219+
.toggle( 'dp-progress-failed', type === DiffExpandStateType.Cancelled );
1220+
break;
1221+
}
1222+
}
1223+
1224+
/**
1225+
* Handle the diff expansion process.
1226+
*/
1227+
async handleDiffExpansion() {
1228+
if ( !this.expandAllButton || !this.diffExpandState ) {
1229+
return;
1230+
}
1231+
const status = this.diffExpandState.type;
1232+
switch ( status ) {
1233+
case DiffExpandStateType.Unexpanded:
1234+
if ( this.revisions ) {
1235+
this.diffExpandState = {
1236+
type: DiffExpandStateType.Expanding,
1237+
progress: [ 0, this.revisions.length ]
1238+
};
1239+
for ( const i in this.revisions ) {
1240+
this.updateDiffExpandButton();
1241+
const revision = this.revisions[ i ];
1242+
await revision.handleDiffToggle( true );
1243+
// @ts-expect-error `this.diffExpandState` can change values in the middle
1244+
// of this loop, because the user can press the button and change the state
1245+
// mid-execution.
1246+
if ( this.diffExpandState.type === DiffExpandStateType.Cancelled ) {
1247+
// User cancelled the expansion. Stop expanding more diffs now.
1248+
return;
1249+
}
1250+
this.diffExpandState = {
1251+
type: DiffExpandStateType.Expanding,
1252+
progress: [ +i + 1, this.revisions.length ]
1253+
};
1254+
}
1255+
this.diffExpandState = {
1256+
type: DiffExpandStateType.Expanded
1257+
};
1258+
this.updateDiffExpandButton();
1259+
}
1260+
break;
1261+
case DiffExpandStateType.Expanding:
1262+
this.diffExpandState = { type: DiffExpandStateType.Cancelled };
1263+
this.updateDiffExpandButton();
1264+
break;
1265+
case DiffExpandStateType.Expanded:
1266+
case DiffExpandStateType.Cancelled:
1267+
for ( const revision of this.revisions ) {
1268+
await revision.handleDiffToggle( false );
1269+
}
1270+
this.diffExpandState = { type: DiffExpandStateType.Unexpanded };
1271+
this.updateDiffExpandButton();
1272+
break;
1273+
}
1274+
}
1275+
11091276
}

0 commit comments

Comments
 (0)