import './rgh-feature-descriptions.css';
import React from 'dom-chef';
import {AlertIcon, CopyIcon, InfoIcon} from '@primer/octicons-react';
import features from '../feature-manager.js';
import {featuresMeta} from '../../readme.md';
import optionsStorage, {getNewFeatureName, isFeatureDisabled} from '../options-storage.js';
import observe from '../helpers/selector-observer.js';
import {brokenFeatures} from '../helpers/hotfix.js';
import {createRghIssueLink} from '../helpers/rgh-issue-link.js';
import openOptions from '../helpers/open-options.js';
import createBanner from '../github-helpers/banner.js';
import {isFeaturePrivate} from '../helpers/feature-utils.js';
function addDescription(infoBanner: HTMLElement, id: string, meta: FeatureMeta | undefined): void {
const isCss = location.pathname.endsWith('.css');
const description = meta?.description // Regular feature?
?? (
isFeaturePrivate(id)
? 'This feature applies only to "Refined GitHub" repositories and cannot be disabled.'
: (
isCss
? 'This feature is CSS-only and cannot be disabled.'
: undefined // The heck!?
)
);
const conversationsUrl = new URL('https://github.com/refined-github/refined-github/issues');
conversationsUrl.searchParams.set('q', `sort:updated-desc is:open "${id}"`);
const newIssueUrl = new URL('https://github.com/refined-github/refined-github/issues/new');
newIssueUrl.searchParams.set('template', '1_bug_report.yml');
newIssueUrl.searchParams.set('title', `\`${id}\`: `);
infoBanner.before(
// Block and width classes required to avoid margin collapse
{id}
{ /* eslint-disable-next-line react/no-danger */ }
{description &&
}
{meta?.screenshot && (
)}
,
);
}
async function getDisabledReason(id: string): Promise {
const classes = ['mb-3'];
// Skip dev check present in `getLocalHotfixes`, we want to see this even when developing
const hotfixes = await brokenFeatures.get() ?? [];
const hotfixed = hotfixes.find(([feature]) => feature === id);
if (hotfixed) {
const [_name, issue, unaffectedVersion] = hotfixed;
if (unaffectedVersion) {
return createBanner({
text: <>This feature was disabled until version {unaffectedVersion} due to {createRghIssueLink(issue)}.>,
classes,
icon: ,
});
}
return createBanner({
text: <>This feature is disabled due to {createRghIssueLink(issue)}.>,
classes: [...classes, 'flash-warn'],
icon: ,
});
}
if (isFeatureDisabled(await optionsStorage.getAll(), id)) {
return createBanner({
text: <>This feature is disabled on GitHub.com .>,
classes: [...classes, 'flash-warn'],
icon: ,
});
}
return undefined;
}
async function addDisabledBanner(infoBanner: HTMLElement, id: string): Promise {
const reason = await getDisabledReason(id);
if (reason) {
infoBanner.before(reason);
}
}
async function add(infoBanner: HTMLElement): Promise {
const [, filename] = /source\/features\/([^.]+)/.exec(location.pathname) ?? [];
// Enable link even on past commits
const currentFeatureName = getNewFeatureName(filename);
const meta = featuresMeta.find(feature => feature.id === currentFeatureName);
// This ID exists whether the feature is documented or not
const id = meta?.id ?? filename;
addDescription(infoBanner, id, meta);
await addDisabledBanner(infoBanner, id);
}
function init(signal: AbortSignal): void {
observe('#repos-sticky-header', add, {signal});
}
// eslint-disable-next-line unicorn/better-regex -- No "\/"
const featureUrlRegex = /^([/]refined-github){2}[/]blob[/][^/]+[/]source[/]features[/][^.]+[.](tsx|css)$/;
void features.add(import.meta.url, {
include: [
() => featureUrlRegex.test(location.pathname),
],
init,
});
/*
Test URLs:
- Regular feature: https://github.com/refined-github/refined-github/blob/main/source/features/sync-pr-commit-title.tsx
- CSS counterpart: https://github.com/refined-github/refined-github/blob/main/source/features/sync-pr-commit-title.css
- RGH feature: https://github.com/refined-github/refined-github/blob/main/source/features/rgh-feature-descriptions.css
- CSS-only feature: https://github.com/refined-github/refined-github/blob/main/source/features/center-reactions-popup.css
*/