Skip to content

Commit

Permalink
feat: choose whether to send feedback from recommend deletion popup
Browse files Browse the repository at this point in the history
  • Loading branch information
double-beep authored Jun 14, 2024
1 parent 630d4d0 commit 3033394
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 67 deletions.
60 changes: 54 additions & 6 deletions src/UserscriptTools/Post.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import { getFlagToRaise } from '../AdvancedFlagging';
import { Flags } from '../FlagTypes';
import { getSvg, PostType, FlagNames, getFormDataFromObject, addXHRListener, addProgress, FlagTypeFeedbacks } from '../shared';
import {
getSvg,
PostType,
FlagNames,
getFormDataFromObject,
addXHRListener,
addProgress,
FlagTypeFeedbacks,
BotNames,
} from '../shared';

import { CopyPastorAPI } from './CopyPastorAPI';
import { GenericBotAPI } from './GenericBotAPI';
import { MetaSmokeAPI } from './MetaSmokeAPI';
import { NattyAPI } from './NattyApi';

import { Cached, CachedFlag, Store } from './Store';
import Page from './Page';
import { Progress } from './Progress';
import Page from './Page';
import Reporter from './Reporter';

import { Checkbox } from '@userscripters/stacks-helpers';

type ReporterBoxes = Record<BotNames, Parameters<typeof Checkbox.makeStacksCheckboxes>[0][0]>;

interface StackExchangeFlagResponse {
FlagType: number;
Message: string;
Expand Down Expand Up @@ -321,11 +334,12 @@ export default class Post {
return (Object.values(this.reporters) as Reporter[])
// keep only the bots the user has opted to send feedback to
.filter(reporter => {
const { name } = reporter;
const { name, sanitisedName } = reporter;

const sanitised = name.replace(/\s/g, '').toLowerCase();
const input = this.element.querySelector<HTMLInputElement>(
`[id*="-send-feedback-to-${sanitised}-"]`
// in review, the checkbox, is not a child of this.element
const element = Page.isLqpReviewPage ? document : this.element;
const input = element.querySelector<HTMLInputElement>(
`[id*="-send-feedback-to-${sanitisedName.toLowerCase()}-"]`
);

// this may be undefined
Expand Down Expand Up @@ -402,6 +416,40 @@ export default class Post {
return (new Date().valueOf() - this.date.valueOf()) < dayMillis && this.score <= 0;
}

// returns [bot name, checkbox config]
public getFeedbackBoxes(): ReporterBoxes {
type ReportersEntries = [
['Smokey', MetaSmokeAPI],
['Natty', NattyAPI],
['Guttenberg', CopyPastorAPI],
['Generic Bot', GenericBotAPI]
];

const newEntries = (Object.entries(this.reporters) as ReportersEntries)
// exclude bots that we can't send feedback to
.filter(([, instance]) => instance.showOnPopover())
.map(([, instance]) => {
const botName = instance.sanitisedName.toLowerCase();

// need the postId in the id to make it unique
const botNameId = `advanced-flagging-send-feedback-to-${botName}-${this.id}`;
const defaultNoCheck = Store.config[instance.cacheKey];

const checkbox = {
id: botNameId,
labelConfig: {
text: `Feedback to ${instance.getIcon().outerHTML}`,
classes: [ 'fs-body1' ],
},
selected: !defaultNoCheck,
};

return [instance.name, checkbox];
});

return Object.fromEntries(newEntries) as ReporterBoxes;
}

private static getIcon(svg: SVGElement, classname: string): HTMLElement {
const wrapper = document.createElement('div');
wrapper.classList.add('flex--item');
Expand Down
8 changes: 8 additions & 0 deletions src/UserscriptTools/Reporter.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { ProgressItemActions } from './Progress';
import { attachPopover, FlagTypeFeedbacks, AllFeedbacks } from '../shared';
import Page from './Page';
import { Configuration } from './Store';

type Sanitised = 'Smokey' | 'Natty' | 'GenericBot' | 'Guttenberg';

export default class Reporter {
public readonly name: keyof FlagTypeFeedbacks;
public readonly id: number;
public readonly sanitisedName: Sanitised;
public readonly cacheKey: keyof Configuration;

public progress: ProgressItemActions | null = null;

constructor(name: keyof FlagTypeFeedbacks, id: number) {
this.name = name;
this.sanitisedName = this.name.replace(/\s/g, '') as Sanitised;
this.cacheKey = `defaultNo${this.sanitisedName}`;

this.id = id;
}

Expand Down
15 changes: 6 additions & 9 deletions src/modals/config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { Cached, Configuration, Store } from '../UserscriptTools/Store';
import { MetaSmokeAPI } from '../UserscriptTools/MetaSmokeAPI';

import {
displayStacksToast,
attachPopover,
getCachedConfigBotKey
} from '../shared';
import { displayStacksToast, attachPopover } from '../shared';

import { Buttons, Modals, Checkbox } from '@userscripters/stacks-helpers';
import Reporter from '../UserscriptTools/Reporter';

type GeneralItems = Exclude<keyof Configuration, 'EnabledFlags'>;

Expand Down Expand Up @@ -171,19 +168,19 @@ function getGeneralConfigItems(): HTMLElement {
},
{
text: 'Don\'t send feedback to Smokey by default',
configValue: getCachedConfigBotKey('Smokey')
configValue: new Reporter('Smokey', 0).cacheKey
},
{
text: 'Don\'t send feedback to Natty by default',
configValue: getCachedConfigBotKey('Natty')
configValue: new Reporter('Natty', 0).cacheKey
},
{
text: 'Don\'t send feedback to Guttenberg by default',
configValue: getCachedConfigBotKey('Guttenberg')
configValue: new Reporter('Guttenberg', 0).cacheKey
},
{
text: 'Don\'t send feedback to Generic Bot by default',
configValue: getCachedConfigBotKey('Generic Bot')
configValue: new Reporter('Generic Bot', 0).cacheKey
},
{
text: 'Enable dry-run mode',
Expand Down
46 changes: 7 additions & 39 deletions src/popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@ import {
getHumanFromDisplayName,

getFullFlag,
getCachedConfigBotKey,
FlagNames,
delay
} from './shared';
import { getFlagToRaise } from './AdvancedFlagging';
import Post from './UserscriptTools/Post';

import { MetaSmokeAPI } from './UserscriptTools/MetaSmokeAPI';
import { NattyAPI } from './UserscriptTools/NattyApi';
import { GenericBotAPI } from './UserscriptTools/GenericBotAPI';
import { CopyPastorAPI } from './UserscriptTools/CopyPastorAPI';

import { Menu, Spinner } from '@userscripters/stacks-helpers';
import { isSpecialFlag } from './Configuration';
import { Store, Cached, Configuration, CachedFlag } from './UserscriptTools/Store';
Expand All @@ -30,12 +24,9 @@ noneSpan.classList.add('o50');
noneSpan.innerText = '(none)';

export class Popover {
private readonly post: Post;
public readonly popover: HTMLUListElement;

constructor(post: Post) {
this.post = post;

constructor(private readonly post: Post) {
this.popover = this.makeMenu();
}

Expand Down Expand Up @@ -187,39 +178,16 @@ export class Popover {

// Section #3: Send feedback to X
private getSendFeedbackToRow(): Menu.StacksMenuOptions['navItems'] {
// oof!
type ReportersEntries = [
['Smokey', MetaSmokeAPI],
['Natty', NattyAPI],
['Guttenberg', CopyPastorAPI],
['Generic Bot', GenericBotAPI]
];

return (Object.entries(this.post.reporters) as ReportersEntries)
// exclude bots that we can't send feedback to
.filter(([, instance]) => instance.showOnPopover())
.map(([, instance]) => {
const cacheKey = getCachedConfigBotKey(instance.name);
const sanitised = instance.name.replace(/\s/g, '').toLowerCase();

// need the postId in the id to make it unique
const botNameId = `advanced-flagging-send-feedback-to-${sanitised}-${this.post.id}`;
const defaultNoCheck = Store.config[cacheKey];

return Object
.entries(this.post.getFeedbackBoxes())
.map(([name, checkbox]) => {
return {
checkbox: {
id: botNameId,
labelConfig: {
text: `Feedback to ${instance.getIcon().outerHTML}`,
classes: [ 'fs-body1' ]
},
selected: !defaultNoCheck,
},
checkbox,
checkboxOptions: {
classes: ['px6']
classes: [ 'px6' ]
},
popover: {
html: `Send feedback to ${instance.name}`,
html: `Send feedback to ${name}`,
position: 'right-start'
}
};
Expand Down
38 changes: 36 additions & 2 deletions src/review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { CopyPastorAPI } from './UserscriptTools/CopyPastorAPI';
import { Cached, Store } from './UserscriptTools/Store';

import Page from './UserscriptTools/Page';
import { Checkbox } from '@userscripters/stacks-helpers';
import { Checkbox, Label } from '@userscripters/stacks-helpers';

interface ReviewQueueResponse {
postId: number;
Expand Down Expand Up @@ -109,7 +109,41 @@ export function setupReview(): void {
]
);
checkbox.classList.add('flex--item');
submit.parentElement?.append(checkbox);

const label = Label.makeStacksLabel(
'noid',
{
text: 'Send feedback to:',
classes: [ 'mt2', 'fw-normal' ]
}
);

// feedback boxes
const post = new Page(true).posts[0];
const boxes = Object
.entries(post.getFeedbackBoxes())
.filter(([name]) => {
// exclude feedback to Smokey if post wasn't reported
// (only spam posts are reported, not non-answers)
return name !== 'Smokey' || post.reporters.Smokey?.wasReported();
})
.map(([, box]) => {
// remove 'fs-body1' class, add 'mb4' instead
box.labelConfig.classes = [ 'mb4' ];

const newText = box.labelConfig.text.replace('Feedback to ', '');
box.labelConfig.text = newText;

return box;
});
const [, ...checkboxes] = Checkbox.makeStacksCheckboxes(
boxes,
{ horizontal: true }
);

// add flex--item to each box, so it is properly aligned
checkboxes.forEach(box => box.classList.add('flex--item'));
submit.parentElement?.append(checkbox, label, ...checkboxes);

submit.addEventListener('click', async event => {
// find the "Not an answer" flag type
Expand Down
12 changes: 1 addition & 11 deletions src/shared.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CachedFlag, Configuration, Store } from './UserscriptTools/Store';
import { CachedFlag, Store } from './UserscriptTools/Store';
import { Flags } from './FlagTypes';
import Page from './UserscriptTools/Page';
import { Progress } from './UserscriptTools/Progress';
Expand Down Expand Up @@ -105,16 +105,6 @@ export function getFormDataFromObject<T extends Record<string, string>>(
}, new FormData());
}

export const getCachedConfigBotKey = (
botName: BotNames
): keyof Configuration => {
type Sanitised = 'Smokey' | 'Natty' | 'GenericBot' | 'Guttenberg';

const sanitised = botName.replace(/\s/g, '') as Sanitised;

return `defaultNo${sanitised}`;
};

export async function delay(milliseconds: number): Promise<void> {
return new Promise<void>(resolve => setTimeout(resolve, milliseconds));
}
Expand Down

0 comments on commit 3033394

Please sign in to comment.