Skip to content

Commit

Permalink
feat: new progress design
Browse files Browse the repository at this point in the history
  • Loading branch information
double-beep authored Jun 7, 2024
1 parent c86b609 commit dcd0106
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 200 deletions.
20 changes: 6 additions & 14 deletions src/UserscriptTools/CopyPastorAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,9 @@ export class CopyPastorAPI extends Reporter {
});
}

public override sendFeedback(feedback: string): Promise<string> {
public override sendFeedback(feedback: string): Promise<void> {
const chatId = new ChatApi().getChatUserId();

if (!this.copypastorId) {
return Promise.resolve('');
}

const success = this.getSentMessage(true, feedback);
const failure = this.getSentMessage(false, feedback);

const payload = {
post_id: this.copypastorId,
feedback_type: feedback,
Expand All @@ -125,13 +118,12 @@ export class CopyPastorAPI extends Reporter {
.map(item => item.join('='))
.join('&');

return new Promise<string>((resolve, reject) => {
return new Promise<void>((resolve, reject) => {
const url = `${CopyPastorAPI.server}/feedback/create`;

if (Store.dryRun) {
console.log('Feedback to Guttenberg via', url, data);

reject('Didn\'t send feedback: debug mode');
resolve();
}

GM_xmlhttpRequest({
Expand All @@ -143,10 +135,10 @@ export class CopyPastorAPI extends Reporter {
data,
onload: ({ status }) => {
status === 200
? resolve(success)
: reject(failure);
? resolve()
: reject();
},
onerror: () => reject(failure)
onerror: () => reject()
});
});
}
Expand Down
29 changes: 17 additions & 12 deletions src/UserscriptTools/GenericBotAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import { Store } from './Store';

export class GenericBotAPI extends Reporter {
private readonly key = 'Cm45BSrt51FR3ju';
private readonly success = 'Post tracked with Generic Bot';
private readonly failure = 'Server refused to track the post';

constructor(
id: number,
Expand All @@ -15,12 +13,10 @@ export class GenericBotAPI extends Reporter {
super('Generic Bot', id);
}

public override sendFeedback(trackPost: string): Promise<string> {
public override sendFeedback(trackPost: string): Promise<void> {
const flaggerName = encodeURIComponent(username || '');

if (!trackPost || !Page.isStackOverflow || !flaggerName) {
return Promise.resolve('');
}
if (!trackPost) return Promise.resolve();

const answer = document.querySelector(`#answer-${this.id} .js-post-body`);
const answerBody = answer?.innerHTML.trim() ?? '';
Expand All @@ -41,10 +37,10 @@ export class GenericBotAPI extends Reporter {
if (Store.dryRun) {
console.log('Track post via', url, payload);

return Promise.resolve('');
return Promise.resolve();
}

return new Promise<string>((resolve, reject) => {
return new Promise<void>((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
url,
Expand All @@ -55,12 +51,12 @@ export class GenericBotAPI extends Reporter {
onload: ({ status, response }) => {
if (status !== 200) {
console.error('Failed to send track request.', response);
reject(this.failure);
reject();
}

resolve(this.success);
resolve();
},
onerror: () => reject(this.failure)
onerror: () => reject()
});
});
}
Expand All @@ -71,7 +67,16 @@ export class GenericBotAPI extends Reporter {
}

public override canSendFeedback(feedback: AllFeedbacks): boolean {
return feedback === 'track' && !this.deleted && Page.isStackOverflow;
return feedback === 'track'
&& !this.deleted // can't track deleted posts
&& Page.isStackOverflow // only SO posts can be tracked
&& Boolean(username); // in case username isn't found for some reason
}

public override getProgressMessage(feedback: string): string {
return feedback
? 'Tracking post with Generic Bot'
: '';
}

// Ask Floern what this does
Expand Down
58 changes: 34 additions & 24 deletions src/UserscriptTools/MetaSmokeAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { Modals, Input, Buttons } from '@userscripters/stacks-helpers';
import { displayToaster, page } from '../AdvancedFlagging';
import Reporter from './Reporter';
import { WebsocketUtils } from './WebsocketUtils';
import WebsocketUtils from './WebsocketUtils';

interface MetaSmokeApiItem {
id: number;
Expand Down Expand Up @@ -161,8 +161,7 @@ export class MetaSmokeAPI extends Reporter {

if (Store.dryRun) {
console.log('Report post via', url, data);

throw new Error('Didn\'t report post: in debug mode');
return;
}

const reportRequest = await fetch(
Expand Down Expand Up @@ -197,34 +196,42 @@ export class MetaSmokeAPI extends Reporter {
}

public override canSendFeedback(feedback: AllFeedbacks): boolean {
return Boolean(this.smokeyId) || ( // the post has been reported OR:
feedback === 'tpu-' // the feedback is tpu-
&& !this.deleted // AND the post is not deleted
&& !MetaSmokeAPI.isDisabled // AND SD info is stored in cache
&& Boolean(MetaSmokeAPI.accessToken) // AND user has authenticated with SM
);
const { isDisabled, accessToken } = MetaSmokeAPI;

return !isDisabled // user must have MS enabled
&& Boolean(accessToken) // and must have authenticated with MS
&& (
Boolean(this.smokeyId) || ( // the post has been reported OR:
feedback === 'tpu-' // the feedback is tpu-
&& !this.deleted // AND the post is not deleted
)
);
}

public override async sendFeedback(feedback: string): Promise<string> {
if (MetaSmokeAPI.isDisabled) return '';

public override async sendFeedback(feedback: string): Promise<void> {
const { appKey, accessToken } = MetaSmokeAPI;

// not reported, feedback is tpu AND the post isn't deleted => report it!
if (!this.smokeyId && feedback === 'tpu-' && !this.deleted) {
// see: https://chat.stackexchange.com/transcript/message/65076878
const wsUtils = new WebsocketUtils(this.wsUrl, this.id, this.wsAuth);
await this.reportRedFlag();
const wsUtils = new WebsocketUtils(this.wsUrl, this.id, this.progress, this.wsAuth);

const reportProgress = this.progress?.addSubItem('Sending report...');
try {
await this.reportRedFlag();
reportProgress?.completed();
} catch (error) {
wsUtils.closeWebsocket();
reportProgress?.failed();

throw error;
}

await wsUtils.waitForReport(event => this.reportReceived(event));

// https://chat.stackexchange.com/transcript/message/65097399
// wait 3 seconds so that SD can start watching for post deletion
await new Promise(resolve => setTimeout(resolve, 3 * 1000));

return this.reportMessage;
} else if (!accessToken || !this.smokeyId) {
// user hasn't authenticated or the post hasn't been reported => don't send feedback
return '';
}

// otherwise, send feedback
Expand All @@ -237,8 +244,7 @@ export class MetaSmokeAPI extends Reporter {

if (Store.dryRun) {
console.log('Feedback to Smokey via', url, data);

throw new Error('Didn\'t send feedback: debug mode');
return;
}

const feedbackRequest = await fetch(
Expand All @@ -253,10 +259,8 @@ export class MetaSmokeAPI extends Reporter {
if (!feedbackRequest.ok) {
console.error(`Failed to send feedback for ${this.smokeyId} to Smokey`, feedbackResponse);

throw new Error(this.getSentMessage(false, feedback));
throw new Error();
}

return this.getSentMessage(true, feedback);
}

public override getIcon(): HTMLDivElement {
Expand All @@ -267,6 +271,12 @@ export class MetaSmokeAPI extends Reporter {
);
}

public override getProgressMessage(feedback: string): string {
return this.wasReported() || feedback !== 'tpu-'
? super.getProgressMessage(feedback)
: 'Reporting post to Smokey';
}

private static getMetasmokeTokenPopup(): HTMLElement {
const codeInput = Input.makeStacksInput(
'advanced-flagging-metasmoke-token-input',
Expand Down
113 changes: 36 additions & 77 deletions src/UserscriptTools/NattyApi.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { ChatApi } from './ChatApi';
import { AllFeedbacks } from '../shared';
import { page } from '../AdvancedFlagging';

import WebsocketUtils from './WebsocketUtils';
import Reporter from './Reporter';
import Page from './Page';
import { WebsocketUtils } from './WebsocketUtils';
import { Spinner } from '@userscripters/stacks-helpers';
import Post from './Post';

const dayMillis = 1000 * 60 * 60 * 24;
const nattyFeedbackUrl = 'https://logs.sobotics.org/napi-1.1/api/stored/';
Expand Down Expand Up @@ -77,112 +76,72 @@ export class NattyAPI extends Reporter {
}

public override canSendFeedback(feedback: AllFeedbacks): boolean {
// a post can't be reported if it's been deleted!
return this.wasReported() || (this.canBeReported() && feedback === 'tp');
return Page.isStackOverflow // only SO is supported
&& (
this.wasReported() || (
this.canBeReported()
&& feedback === 'tp'
&& !this.deleted // deleted posts can't be reported
)
);
}

public override async sendFeedback(feedback: string): Promise<string> {
public override async sendFeedback(feedback: string): Promise<void> {
if (this.wasReported()) {
await this.chat.sendMessage(`${this.feedbackMessage} ${feedback}`);

return this.getSentMessage(true, feedback);
} else if (feedback === 'tp') {
return this.report();
await this.report();
}
}

public override getIcon(): HTMLDivElement {
return this.createBotIcon(
this.wasReported()
? `//sentinel.erwaysoftware.com/posts/aid/${this.id}`
: ''
);
}

return '';
public override getProgressMessage(feedback: string): string {
return this.wasReported() || feedback !== 'tp'
? super.getProgressMessage(feedback)
: 'Reporting post to Natty';
}

private async report(): Promise<string> {
if (!this.canBeReported()) return '';

const submit = document.querySelector('form .js-modal-submit');

const popover = document.createElement('div');
popover.classList.add('s-popover');
popover.id = 'advanced-flagging-progress-popover';

const arrow = document.createElement('div');
arrow.classList.add('s-popover--arrow');

if (Page.isLqpReviewPage && submit) {
// attach a popover to the "Delete" button indicating
// that post is being reported to Natty
Stacks.attachPopover(submit, popover, {
placement: 'bottom-start',
autoShow: true
});
}

// Handle cases where the post may not be reported to Natty on time:
// - when a mod flags a post as NAA/VLQ it is deleted immediately.
// - when a reviewer sends the last Recommend deletion/Delete review,
// the post is also deleted immediately
if (StackExchange.options.user.isModerator || Page.isLqpReviewPage) {
this.addItem('Connecting to chat websocket...');
// init websocket
const url = await this.chat.getFinalUrl();
const wsUtils = new WebsocketUtils(url, this.id);
const wsUtils = new WebsocketUtils(url, this.id, this.progress);

this.addItem('Reporting post to Natty...');
await this.chat.sendMessage(this.reportMessage);
const reportProgress = this.progress?.addSubItem('Sending report...');
try {
await this.chat.sendMessage(this.reportMessage);
reportProgress?.completed();
} catch (error) {
wsUtils.closeWebsocket();
reportProgress?.failed();

throw error;
}

// wait until the report is received
this.addItem('Waiting for Natty to receive the report...');
await wsUtils.waitForReport(event => this.chat.reportReceived(event));
} else {
await this.chat.sendMessage(this.reportMessage);
}

this.addItem('Completing review task...');
return nattyReportedMessage;
}

public override getIcon(): HTMLDivElement {
return this.createBotIcon(
this.wasReported()
? `//sentinel.erwaysoftware.com/posts/aid/${this.id}`
: ''
);
}

private getDaysBetween(questionDate: Date, answerDate: Date): number {
// get the number of days between the creation of the question and the answer
return (answerDate.valueOf() - questionDate.valueOf()) / dayMillis;
}

private addItem(text: string): void {
if (!Page.isLqpReviewPage) return;

const wrapper = document.createElement('div');
wrapper.classList.add('d-flex', 'gs8');

const action = document.createElement('div');
action.classList.add('flex--item');
action.textContent = text;

StackExchange.helpers.removeSpinner();

const spinner = Spinner.makeSpinner({
size: 'sm',
classes: [ 'flex--item' ]
});

wrapper.append(spinner, action);

const done = document.createElement('div');
done.classList.add('flex--item', 'fc-green-500', 'fw-bold');
done.textContent = 'done!';

const popover = document.querySelector('#advanced-flagging-progress-popover');

// previous process has been finished
const tick = Post.getActionIcons()[0];
tick.style.display = 'block';

popover?.lastElementChild?.prepend(tick);
popover?.lastElementChild?.append(done);
// info about current process
popover?.append(wrapper);
}
}
Loading

0 comments on commit dcd0106

Please sign in to comment.