Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: See which rules are affecting a particular SERP entry #522

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
15 changes: 15 additions & 0 deletions src/_locales/en/messages.json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export default exportAsMessages({
// The text of an OK button.
okButton: "OK",

// The text that represents the user's own personal blocklist.
personalBlocklist: "Personal Blocklist",

// The text that means one site has been blocked.
content_singleSiteBlocked: "uBlacklist has blocked 1 site",

Expand Down Expand Up @@ -89,6 +92,18 @@ export default exportAsMessages({
// The text of the button to activate this extension.
popup_activateButton: "Activate",

// The title of the disclosure widget that contains the matching rules information.
popup_matchingRules: "Matching Rules",

// The label for the textarea that shows rules blocking the entry.
popup_blockingRulesLabel: "Rules blocking this entry",

// The label for the textarea that shows rules unblocking the entry.
popup_unblockingRulesLabel: "Rules unblocking this entry",

// The label for the textarea that shows rules highlighting the entry.
popup_highlightingRulesLabel: "Rules highlighting this entry",

// The title of the general section.
options_generalTitle: "General",

Expand Down
5 changes: 5 additions & 0 deletions src/_locales/pt_BR/messages.json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default exportAsMessages({
"Não autorizado. Por favor, desligue a sincronização e ligue novamente.",
cancelButton: "Cancelar",
okButton: "OK",
personalBlocklist: "Lista de Bloqueio Pessoal",
content_singleSiteBlocked: "uBlacklist bloqueou 1 site",
content_multipleSitesBlocked: "uBlacklist bloqueou $1 sites",
content_showBlockedSitesLink: "Mostrar",
Expand All @@ -31,6 +32,10 @@ export default exportAsMessages({
popup_active: "uBlacklist está ativo",
popup_inactive: "uBlacklist está inativo",
popup_activateButton: "Ativar",
popup_matchingRules: "Regras em efeito",
popup_blockingRulesLabel: "Regras bloqueando este resultado",
popup_unblockingRulesLabel: "Regras desbloqueando este resultado",
popup_highlightingRulesLabel: "Regras destacando este resultado",
options_generalTitle: "Geral",
options_blacklistLabel:
"Sites bloqueados de aparecer nos resultados de busca do Google",
Expand Down
5 changes: 5 additions & 0 deletions src/common/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type MessageName =
| "unauthorizedError"
| "cancelButton"
| "okButton"
| "personalBlocklist"
| "content_singleSiteBlocked"
| "content_multipleSitesBlocked"
| "content_showBlockedSitesLink"
Expand All @@ -27,6 +28,10 @@ export type MessageName =
| "popup_active"
| "popup_inactive"
| "popup_activateButton"
| "popup_matchingRules"
| "popup_blockingRulesLabel"
| "popup_unblockingRulesLabel"
| "popup_highlightingRulesLabel"
| "options_generalTitle"
| "options_blacklistLabel"
| "options_blacklistHelper"
Expand Down
93 changes: 91 additions & 2 deletions src/scripts/block-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ import type { InteractiveRuleset } from "./interactive-ruleset.ts";
import { translate } from "./locales.ts";
import { PathDepth } from "./path-depth.ts";
import type { LinkProps } from "./ruleset/ruleset.ts";
import type { DialogTheme } from "./types.ts";
import { makeAltURL, svgToDataURL } from "./utilities.ts";
import type { DialogTheme, MatchingRulesText } from "./types.ts";
import { getMatchingRulesText, makeAltURL, svgToDataURL } from "./utilities.ts";

type BlockDialogContentProps = {
blockWholeSite: boolean;
Expand Down Expand Up @@ -59,6 +59,8 @@ const BlockDialogContent: React.FC<BlockDialogContentProps> = ({
unblock: false,
host: "",
detailsOpen: false,
matchingRulesOpen: false,
matchingRulesText: null as MatchingRulesText | null,
pathDepth: null as PathDepth | null,
depth: "",
rulesToAdd: "",
Expand All @@ -76,6 +78,8 @@ const BlockDialogContent: React.FC<BlockDialogContentProps> = ({
blockWholeSite ? tldts.getDomain(url.host) ?? url.host : url.host,
);
state.detailsOpen = false;
state.matchingRulesOpen = false;
state.matchingRulesText = null;
state.pathDepth = enablePathDepth ? new PathDepth(url) : null;
state.depth = "0";
state.rulesToAdd = patch.rulesToAdd;
Expand All @@ -86,6 +90,8 @@ const BlockDialogContent: React.FC<BlockDialogContentProps> = ({
state.unblock = false;
state.host = entryProps.url;
state.detailsOpen = false;
state.matchingRulesOpen = false;
state.matchingRulesText = null;
state.pathDepth = null;
state.depth = "";
state.rulesToAdd = "";
Expand Down Expand Up @@ -269,6 +275,89 @@ const BlockDialogContent: React.FC<BlockDialogContentProps> = ({
</Row>
</DetailsBody>
</Details>
<Details
open={state.matchingRulesOpen}
onToggle={(e) => {
const { open } = e.currentTarget;
const matchingRulesText = open
? getMatchingRulesText(ruleset, entryProps)
: null;
setState((s) => ({
...s,
matchingRulesOpen: open,
matchingRulesText,
}));
}}
>
<DetailsSummary className={FOCUS_START_CLASS}>
{translate("popup_matchingRules")}
</DetailsSummary>
<DetailsBody>
<Row>
<RowItem expanded>
<LabelWrapper fullWidth>
<ControlLabel for="blocking-rules-text">
{translate("popup_blockingRulesLabel")}
</ControlLabel>
</LabelWrapper>
{state.matchingRulesOpen && (
<TextArea
breakAll
id="blocking-rules-text"
readOnly
monospace
nowrap
rows={4}
resizable
value={state.matchingRulesText?.blockRules}
/>
)}
</RowItem>
</Row>
<Row>
<RowItem expanded>
<LabelWrapper fullWidth>
<ControlLabel for="unblocking-rules-text">
{translate("popup_unblockingRulesLabel")}
</ControlLabel>
</LabelWrapper>
{state.matchingRulesOpen && (
<TextArea
breakAll
id="unblocking-rules-text"
readOnly
monospace
nowrap
rows={4}
resizable
value={state.matchingRulesText?.unblockRules}
/>
)}
</RowItem>
</Row>
<Row>
<RowItem expanded>
<LabelWrapper fullWidth>
<ControlLabel for="highlight-rules-text">
{translate("popup_highlightingRulesLabel")}
</ControlLabel>
</LabelWrapper>
{state.matchingRulesOpen && (
<TextArea
breakAll
id="highlight-rules-text"
readOnly
monospace
nowrap
rows={4}
resizable
value={state.matchingRulesText?.highlightRules}
/>
)}
</RowItem>
</Row>
</DetailsBody>
</Details>
</RowItem>
</Row>
</DialogBody>
Expand Down
13 changes: 12 additions & 1 deletion src/scripts/components/details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,18 @@ export type DetailsProps = JSX.IntrinsicElements["details"];

export const Details = React.forwardRef<HTMLDetailsElement, DetailsProps>(
function Details(props, ref) {
return <details {...props} ref={ref} />;
const className = useClassName(
() => ({
"&:not(:first-of-type)": {
marginTop: "0.5em",
},
"&:is(details[open] + &)": {
marginTop: "1em",
},
}),
[],
);
return <details {...applyClassName(props, className)} ref={ref} />;
},
);

Expand Down
18 changes: 16 additions & 2 deletions src/scripts/components/textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,22 @@ import { useClassName } from "./utilities.ts";

export type TextAreaProps = JSX.IntrinsicElements["textarea"] & {
breakAll?: boolean;
resizable?: boolean;
monospace?: boolean;
nowrap?: boolean;
};

export const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(
function TextArea({ breakAll = false, ...props }, ref) {
function TextArea(
{
breakAll = false,
resizable = false,
monospace = false,
nowrap = false,
...props
},
ref,
) {
const className = useClassName(
(theme) => ({
background: "transparent",
Expand All @@ -22,8 +34,10 @@ export const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(
? `calc(1.5em * ${props.rows} + 1em + 2px)`
: "auto",
lineHeight: "1.5",
fontFamily: monospace ? "monospace" : "inherit",
textWrap: nowrap ? "nowrap" : "wrap",
padding: "0.5em 0.625em",
resize: "none",
resize: resizable ? "vertical" : "none",
width: "100%",
wordBreak: breakAll ? "break-all" : "normal",
"&:disabled": {
Expand Down
7 changes: 4 additions & 3 deletions src/scripts/content-script.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,10 @@ class ContentScript {
fromPlainRuleset(options.ruleset || null, options.blacklist),
Object.values(options.subscriptions)
.filter((subscription) => subscription.enabled ?? true)
.map(({ ruleset, blacklist }) =>
fromPlainRuleset(ruleset || null, blacklist),
),
.map(({ ruleset, blacklist, name }) => ({
name,
ruleset: fromPlainRuleset(ruleset || null, blacklist),
})),
),
skipBlockDialog: options.skipBlockDialog,
hideControls: options.hideControl,
Expand Down
5 changes: 4 additions & 1 deletion src/scripts/interactive-ruleset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ function createInteractiveRuleset(
): InteractiveRuleset {
return new InteractiveRuleset(
new Ruleset(user),
subscriptions.map((subscription) => new Ruleset(subscription)),
subscriptions.map((subscription, index) => ({
name: String(index),
ruleset: new Ruleset(subscription),
})),
);
}

Expand Down
Loading