diff options
Diffstat (limited to 'source/features/clean-conversation-filters.tsx')
-rw-r--r-- | source/features/clean-conversation-filters.tsx | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/source/features/clean-conversation-filters.tsx b/source/features/clean-conversation-filters.tsx new file mode 100644 index 00000000..35de266a --- /dev/null +++ b/source/features/clean-conversation-filters.tsx @@ -0,0 +1,84 @@ +import cache from 'webext-storage-cache'; +import select from 'select-dom'; +import elementReady from 'element-ready'; +import * as pageDetect from 'github-url-detection'; + +import features from '.'; +import * as api from '../github-helpers/api'; +import {getRepositoryInfo, getRepoURL, getRepoGQL} from '../github-helpers'; + +const hasAnyProjects = cache.function(async (): Promise<boolean> => { + const {repository, organization} = await api.v4(` + repository(${getRepoGQL()}) { + projects { totalCount } + } + organization(login: "${getRepositoryInfo().owner!}") { + projects { totalCount } + } + `, { + allowErrors: true + }); + + return Boolean(repository.projects.totalCount) && Boolean(organization?.projects?.totalCount); +}, { + maxAge: 3, + staleWhileRevalidate: 20, + cacheKey: () => `has-projects:${getRepoURL()}` +}); + +function getCount(element: HTMLElement): number { + return Number(element.textContent!.trim()); +} + +async function hideMilestones(): Promise<void> { + const milestones = select('[data-selected-links^="repo_milestones"] .Counter')!; + if (getCount(milestones) === 0) { + select('[data-hotkey="m"]')!.parentElement!.remove(); + } +} + +async function hasProjects(): Promise<boolean> { + const activeProjectsCounter = select('[data-hotkey="g b"] .Counter'); + if (activeProjectsCounter && getCount(activeProjectsCounter) > 0) { + return true; + } + + const isOrganization = select.exists('[rel=author][data-hovercard-type="organization"]'); + if (!activeProjectsCounter && !isOrganization) { + // No tab = Projects disabled in repo + // No organization = no Projects in organization + return false; + } + + return hasAnyProjects(); +} + +async function hideProjects(): Promise<void> { + if (!await hasProjects()) { + select('[data-hotkey="p"]')!.parentElement!.remove(); + } +} + +async function init(): Promise<void | false> { + if (!await elementReady('#js-issues-toolbar')) { + // Repo has no issues, so no toolbar is shown + return false; + } + + await Promise.all([ + hideMilestones(), + hideProjects() + ]); +} + +void features.add({ + id: __filebasename, + description: 'Hides `Projects` and `Milestones` filters in conversation lists if they are empty.', + screenshot: 'https://user-images.githubusercontent.com/37769974/59083449-0ef88f80-8915-11e9-8296-68af1ddcf191.png' +}, { + include: [ + pageDetect.isRepoConversationList + ], + waitForDomReady: false, + init +}); |