Skip to content

Commit

Permalink
analysis section, Earwig quick-link
Browse files Browse the repository at this point in the history
  • Loading branch information
ChlodAlejandro committed Jul 12, 2022
1 parent 6db4dc3 commit ca726f0
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 62 deletions.
7 changes: 6 additions & 1 deletion i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,10 @@
"deputy.session.page.caseInfo.revision.none": "Revision out of scope",
"deputy.session.page.caseInfo.revision.help": "The requested revision was out of scope for the current Deputy case page. It was likely made by a user who is not a subject of the case page, or has already been removed or assessed by another user. Tools will still be available, but you will not be able to mark this revision as \"assessed\".",
"deputy.session.page.caseInfo.assessed": "Assessed?",
"deputy.session.page.caseInfo.next": "Navigate to next unassessed revision"
"deputy.session.page.caseInfo.next": "Navigate to next unassessed revision",

"deputy.session.page.analysis": "Analysis",
"deputy.session.page.earwigLatest": "Earwig's Copyvio Detector (latest)",
"deputy.session.page.earwigRevision": "Earwig's Copyvio Detector (revision)",
"deputy.session.page.earwigUnsupported": "Earwig's Copyvio Detector does not support this wiki."
}
18 changes: 18 additions & 0 deletions src/css/deputy.css
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,14 @@ body.mediawiki.rtl .dp-cs-row-head > :not(:first-child):not(:last-child) {
}

.dp-pt-section + .dp-pt-section {
/* TODO: Recheck RTL compatibility */
margin-left: 16px;
padding-left: 16px;
border-left: 1px solid gray;
}

.dp-pt-section:last-child {
/* TODO: Recheck RTL compatibility */
margin-right: 8px;
}

Expand All @@ -310,6 +315,10 @@ body.mediawiki.rtl .dp-cs-row-head > :not(:first-child):not(:last-child) {
text-transform: uppercase;
}

.dp-pt-section-content .oo-ui-buttonElement:last-child {
margin-right: 0;
}

.dp-pt-caseInfo {
font-weight: bold;
font-size: 1.3rem;
Expand All @@ -323,3 +332,12 @@ body.mediawiki.rtl .dp-cs-row-head > :not(:first-child):not(:last-child) {
.dp-pageToolbar .dp-cs-row-status {
width: 5.4em;
}

.dp-pt-analysis .oo-ui-menuSelectWidget {
min-width: 300px;
}

.dp-pt-analysis .oo-ui-menuOptionWidget {
padding-top: 8px;
padding-bottom: 8px;
}
116 changes: 116 additions & 0 deletions src/ui/page/DeputyPageAnalysisMenu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { DeputyUIElement } from '../DeputyUIElement';
import unwrapWidget from '../../util/unwrapWidget';
import DeputyPageToolbar from './DeputyPageToolbar';
import EarwigCopyvioDetector from '../../wiki/EarwigCopyvioDetector';
import { PromiseOrNot } from '../../types';

interface DeputyPageAnalysisMenuOption {
label: string;
icon?: string;
condition?: () => boolean;
action: () => PromiseOrNot<void>;
}

/**
* Renders the MenuLayout responsible for displaying analysis options.
*/
export default class DeputyPageAnalysisMenu implements DeputyUIElement {

toolbar: DeputyPageToolbar;
baseWidget: any;
menuSelectWidget: any;

/**
*
* @param toolbar
* @param baseWidget
*/
constructor( toolbar: DeputyPageToolbar, baseWidget: any ) {
this.toolbar = toolbar;
this.baseWidget = baseWidget;
}

/**
* Options to present for this menu.
*/
readonly options: DeputyPageAnalysisMenuOption[] = [
{
icon: 'eye',
label: "Earwig's Copyvio Detector (latest)",
action: async () => {
const url = await EarwigCopyvioDetector.getUrl( this.toolbar.row.title );
window.open( url, '_blank', 'noopener' );

if ( url == null ) {
mw.notify(
mw.message( 'deputy.session.page.earwigUnsupported' ).text(),
{
type: 'error'
}
);
} else {
window.open( url, '_blank', 'noopener' );
}
}
},
{
icon: 'eye',
label: "Earwig's Copyvio Detector (revision)",
condition: () => this.toolbar.revision != null,
action: async () => {
const url = await EarwigCopyvioDetector.getUrl( this.toolbar.revision );

if ( url == null ) {
mw.notify(
mw.message( 'deputy.session.page.earwigUnsupported' ).text(),
{
type: 'error'
}
);
} else {
window.open( url, '_blank', 'noopener' );
}
}
}
];

/**
* @inheritDoc
*/
render(): HTMLElement {
const menuSelectWidget = new OO.ui.MenuSelectWidget( {
autoHide: false,
hideWhenOutOfView: false,
verticalPosition: 'above',
horizontalPosition: 'start',
widget: this.baseWidget,
$floatableContainer: this.baseWidget.$element,
items: this.options.map( ( option, i ) => new OO.ui.MenuOptionWidget( {
data: i,
disabled: option.condition ? !( option.condition() ) : false,
icon: option.icon,
label: option.label
} ) )
} );

menuSelectWidget.on( 'select', () => {
const selected = menuSelectWidget.findSelectedItem();
if ( selected ) {
this.options[ selected.getData() ].action();
// Clear selections.
menuSelectWidget.selectItem();
this.baseWidget.setValue( false );
}
} );

// Disables clipping (allows the menu to be wider than the button)
menuSelectWidget.toggleClipping( false );

this.baseWidget.on( 'change', ( toggled: boolean ) => {
menuSelectWidget.toggle( toggled );
} );

return unwrapWidget( menuSelectWidget );
}

}
156 changes: 95 additions & 61 deletions src/ui/page/DeputyPageToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import generateId from '../../util/generateId';
import DiffPage from '../../wiki/DiffPage';
import swapElements from '../../util/swapElements';
import normalizeTitle from '../../util/normalizeTitle';
import DeputyPageAnalysisMenu from './DeputyPageAnalysisMenu';
import EarwigCopyvioDetector from '../../wiki/EarwigCopyvioDetector';

export interface DeputyPageToolbarOptions extends Omit<DeputyPageStatusResponseMessage, 'type'> {
/**
Expand Down Expand Up @@ -61,6 +63,16 @@ export default class DeputyPageToolbar implements DeputyUIElement {
if ( options.revisionStatus != null ) {
this.revision = mw.config.get( 'wgRevisionId' );
}

this.runAsyncJobs();
}

/**
* Runs asynchronous preparation jobs. Makes loading more seamless later in execution,
* as this will run functions that cache data in the background.
*/
async runAsyncJobs(): Promise<void> {
await EarwigCopyvioDetector.getSupported();
}

/**
Expand Down Expand Up @@ -110,67 +122,6 @@ export default class DeputyPageToolbar implements DeputyUIElement {
</div>;
}

/**
* Renders the next revision button. Used to navigate to the next unassessed revision
* for a row.
*
* @return The OOUI ButtonWidget element.
*/
renderNextRevisionButton(): JSX.Element {
this.nextRevisionButton = new OO.ui.ButtonWidget( {
invisibleLabel: true,
label: mw.message( 'deputy.session.page.diff.next' ).text(),
title: mw.message( 'deputy.session.page.diff.next' ).text(),
icon: this.revision == null ? 'play' : 'next'
} );

this.nextRevisionButton.on( 'click', async () => {
this.setDisabled( true );

if ( this.options.nextRevision ) {
// No need to worry about swapping elements here, since `loadNewDiff`
// will fire the `wikipage.diff` MW hook. This means this element will
// be rebuilt from scratch anyway.
try {
const nextRevisionData = await window.deputy.comms.sendAndWait( {
type: 'pageNextRevisionRequest',
caseId: this.options.caseId,
page: this.row.title.getPrefixedText(),
after: this.revision
} );

if ( nextRevisionData == null ) {
OO.ui.alert(
mw.message( 'deputy.session.page.incommunicable' ).text()
);
this.setDisabled( false );
} else if ( nextRevisionData.revid != null ) {
await DiffPage.loadNewDiff( nextRevisionData.revid );
} else {
this.setDisabled( false );
this.nextRevisionButton.setDisabled( true );
}
} catch ( e ) {
console.error( e );
this.setDisabled( false );
}
} else if ( this.options.nextRevision !== false ) {
// Sets disabled to false if the value is null.
this.setDisabled( false );
}
} );

if ( this.options.nextRevision == null ) {
this.nextRevisionButton.setDisabled( true );
}

return <div class="dp-pt-section">
<div class="dp-pt-section-content">
{ unwrapWidget( this.nextRevisionButton ) }
</div>
</div>;
}

/**
* Renders the "revision" section on the toolbar.
*
Expand Down Expand Up @@ -279,6 +230,88 @@ export default class DeputyPageToolbar implements DeputyUIElement {
</div>;
}

/**
* Renders the next revision button. Used to navigate to the next unassessed revision
* for a row.
*
* @return The OOUI ButtonWidget element.
*/
renderNextRevisionButton(): JSX.Element {
this.nextRevisionButton = new OO.ui.ButtonWidget( {
invisibleLabel: true,
label: mw.message( 'deputy.session.page.diff.next' ).text(),
title: mw.message( 'deputy.session.page.diff.next' ).text(),
icon: this.revision == null ? 'play' : 'next'
} );

this.nextRevisionButton.on( 'click', async () => {
this.setDisabled( true );

if ( this.options.nextRevision ) {
// No need to worry about swapping elements here, since `loadNewDiff`
// will fire the `wikipage.diff` MW hook. This means this element will
// be rebuilt from scratch anyway.
try {
const nextRevisionData = await window.deputy.comms.sendAndWait( {
type: 'pageNextRevisionRequest',
caseId: this.options.caseId,
page: this.row.title.getPrefixedText(),
after: this.revision
} );

if ( nextRevisionData == null ) {
OO.ui.alert(
mw.message( 'deputy.session.page.incommunicable' ).text()
);
this.setDisabled( false );
} else if ( nextRevisionData.revid != null ) {
await DiffPage.loadNewDiff( nextRevisionData.revid );
} else {
this.setDisabled( false );
this.nextRevisionButton.setDisabled( true );
}
} catch ( e ) {
console.error( e );
this.setDisabled( false );
}
} else if ( this.options.nextRevision !== false ) {
// Sets disabled to false if the value is null.
this.setDisabled( false );
}
} );

if ( this.options.nextRevision == null ) {
this.nextRevisionButton.setDisabled( true );
}

return <div class="dp-pt-section">
<div class="dp-pt-section-content">
{ unwrapWidget( this.nextRevisionButton ) }
</div>
</div>;
}

/**
* Renders an "Analysis" OOUI PopupButtonWidget, which contains links to
* analysis tools and other page information.
*
* @return The section HTML
*/
renderAnalysisSection(): JSX.Element {
const popupButton = new OO.ui.ToggleButtonWidget( {
label: mw.message( 'deputy.session.page.analysis' ).text(),
framed: false,
indicator: 'up'
} );

return <div class="dp-pt-section">
<div class="dp-pt-section-content dp-pt-analysis">
{ new DeputyPageAnalysisMenu( this, popupButton ).render() }
{ unwrapWidget( popupButton ) }
</div>
</div>;
}

/**
* @inheritDoc
*/
Expand All @@ -288,6 +321,7 @@ export default class DeputyPageToolbar implements DeputyUIElement {
{ this.renderCaseInfo() }
{ this.renderRevisionInfo() }
{ this.nextRevisionSection = this.renderNextRevisionButton() as HTMLElement }
{ this.renderAnalysisSection() }
</div> as HTMLElement;
}

Expand Down
Loading

0 comments on commit ca726f0

Please sign in to comment.