From c5e418f2a70653be8c4f8c1decb04a082f9db6f1 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Wed, 23 Aug 2023 10:05:01 +0800 Subject: [PATCH] feat: use meta.json to request smarter & fix wrong initialization timings of features (#717) * feat: a `hasMeta` function with cache support to check if the meta file exists * feat: now features that rely on OD data only run when meta.json exists * refactor: encapsulate the meta related code with the MetaStore class * feat: use meta.updatedAt to decide lastDataAvailableMonth * fix: features initialize unexpectedly in the new UI now they run expectedly in the both old and new UI --- package.json | 2 +- src/api/common.ts | 78 +++++++++++++++++++ src/feature-manager.ts | 2 +- src/helpers/generate-data-by-month.ts | 24 ++++-- src/helpers/get-developer-info.ts | 9 +++ src/helpers/get-repo-info.ts | 28 +++++++ src/helpers/is-perceptor.ts | 5 +- src/helpers/is-public-repo.ts | 17 ---- .../index.tsx | 19 +++-- .../view.tsx | 12 +-- .../features/developer-networks/index.tsx | 7 +- .../ContentScripts/features/oss-gpt/index.tsx | 3 +- .../features/perceptor-layout/index.tsx | 3 +- .../features/perceptor-tab/index.tsx | 4 +- .../repo-activity-openrank-trends/index.tsx | 19 ++++- .../repo-activity-openrank-trends/view.tsx | 17 ++-- .../repo-activity-racing-bar/index.tsx | 7 +- .../features/repo-fork-tooltip/index.tsx | 14 +++- .../features/repo-fork-tooltip/view.tsx | 6 +- .../features/repo-header-labels/index.tsx | 19 ++++- .../features/repo-header-labels/view.tsx | 9 ++- .../features/repo-issue-tooltip/index.tsx | 18 +++-- .../features/repo-issue-tooltip/view.tsx | 18 +++-- .../features/repo-networks/index.tsx | 7 +- .../features/repo-pr-tooltip/index.tsx | 18 +++-- .../features/repo-pr-tooltip/view.tsx | 39 ++++++---- .../features/repo-star-tooltip/index.tsx | 14 +++- .../features/repo-star-tooltip/view.tsx | 6 +- yarn.lock | 8 +- 29 files changed, 318 insertions(+), 114 deletions(-) delete mode 100644 src/helpers/is-public-repo.ts diff --git a/package.json b/package.json index 7d8e223e..eb046b57 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "dom-loaded": "^3.0.0", "echarts": "^5.3.0", "element-ready": "^6.2.1", - "github-url-detection": "^6.1.0", + "github-url-detection": "^8.1.0", "jquery": "^3.6.0", "lodash-es": "^4.17.21", "office-ui-fabric-react": "^7.183.0", diff --git a/src/api/common.ts b/src/api/common.ts index 73468fe2..8c9bf118 100644 --- a/src/api/common.ts +++ b/src/api/common.ts @@ -22,3 +22,81 @@ export const getMetricByName = async ( } } }; + +/** + * Common interface for both repo meta and user meta + * e.g. https://oss.x-lab.info/open_digger/github/X-lab2017/open-digger/meta.json (repo meta file) + * e.g. https://oss.x-lab.info/open_digger/github/tyn1998/meta.json (user meta file) + * @param name repo name or user name + */ +export interface CommonMeta { + type: 'user' | 'repo'; + updatedAt: number; // time stamp + labels: unknown[]; // TODO: define the type +} + +export interface RepoMeta extends CommonMeta {} + +export interface UserMeta extends CommonMeta { + repos: unknown[]; +} + +class MetaStore { + private static instance: MetaStore; + private responseCache: Map>; + private constructor() { + this.responseCache = new Map>(); + } + + public static getInstance(): MetaStore { + if (!MetaStore.instance) { + MetaStore.instance = new MetaStore(); + } + return MetaStore.instance; + } + + /** + * Fetch the meta file and cache the response + * @param name repo name or user name + */ + private fetchMeta(name: string) { + const url = `${OSS_XLAB_ENDPOINT}/open_digger/github/${name}/meta.json`; + const promise = fetch(url); + this.responseCache.set(name, promise); + } + + /** + * Check if the meta file exists + * @param name repo name or user name + * @returns true if the meta file exists, false otherwise + */ + public async has(name: string) { + if (!this.responseCache.has(name)) { + this.fetchMeta(name); + } + const response = await this.responseCache.get(name)!; + if (!response.ok) { + return false; + } else { + return true; + } + } + + /** + * Get the parsed meta file if it exists + * @param name repo name or user name + * @returns the parsed meta file if it exists, undefined otherwise + */ + public async get(name: string): Promise { + if (await this.has(name)) { + const meta: CommonMeta = await this.responseCache + .get(name)! + // clone the response to avoid the response being used up + // https://stackoverflow.com/a/54115314/10369621 + .then((res) => res.clone().json()); + return meta; + } + } +} + +export const metaStore = MetaStore.getInstance(); diff --git a/src/feature-manager.ts b/src/feature-manager.ts index aec669b5..bb043bfb 100644 --- a/src/feature-manager.ts +++ b/src/feature-manager.ts @@ -125,7 +125,7 @@ const getFeatureID = (url: string): FeatureId => { /** Register a new feature */ const add = async ( id: FeatureId, - ...loaders: FeatureLoader[] + ...loaders: FeatureLoader[] // support multiple loaders for one feature, but currently only one is used ): Promise => { /* Feature filtering and running */ const options = await globalReady; diff --git a/src/helpers/generate-data-by-month.ts b/src/helpers/generate-data-by-month.ts index 8ff922d8..a5909be9 100644 --- a/src/helpers/generate-data-by-month.ts +++ b/src/helpers/generate-data-by-month.ts @@ -1,4 +1,11 @@ -const generateDataByMonth = (originalData: any) => { +/** + * Months with value of 0 are not listed in data file for size optimization + * purpose, this function inserts those missing zeros. + * @param originalData + * @param updatedAt meta file last updated time + * @returns + */ +const generateDataByMonth = (originalData: any, updatedAt?: number) => { if (originalData === null) { return []; } @@ -19,15 +26,16 @@ const generateDataByMonth = (originalData: any) => { else if (dateA > dateB) return 1; else return 0; }); + + // get the last month that has data + const lastDataAvailableMonth = updatedAt ? new Date(updatedAt) : new Date(); + lastDataAvailableMonth.setDate(0); + const oldestMonth = orderedMonths[0]; - const now = new Date(); - if (now.getDate() === 1) { - // data for last month is not ready in the first day of the month (#595) - now.setDate(0); // a way to let month - 1 - } - now.setDate(0); // see issue #632 const newestMonth = - now.getFullYear() + '-' + (now.getMonth() + 1).toString().padStart(2, '0'); + lastDataAvailableMonth.getFullYear() + + '-' + + (lastDataAvailableMonth.getMonth() + 1).toString().padStart(2, '0'); // insert no-event months (assigned to 0) and generate final data const arrayData: [string, number][] = []; const start = new Date(oldestMonth); diff --git a/src/helpers/get-developer-info.ts b/src/helpers/get-developer-info.ts index 13a0fef1..04c4173c 100644 --- a/src/helpers/get-developer-info.ts +++ b/src/helpers/get-developer-info.ts @@ -1,5 +1,14 @@ +import { metaStore } from '../api/common'; + import $ from 'jquery'; +import * as pageDetect from 'github-url-detection'; export function getDeveloperName() { return $('.p-nickname.vcard-username.d-block').text().trim().split(' ')[0]; } + +export async function isDeveloperWithMeta() { + return ( + pageDetect.isUserProfile() && (await metaStore.has(getDeveloperName())) + ); +} diff --git a/src/helpers/get-repo-info.ts b/src/helpers/get-repo-info.ts index fd6b620a..08b0bfe2 100644 --- a/src/helpers/get-repo-info.ts +++ b/src/helpers/get-repo-info.ts @@ -1,5 +1,33 @@ +import { metaStore } from '../api/common'; + +import $ from 'jquery'; import * as pageDetect from 'github-url-detection'; +import elementReady from 'element-ready'; export function getRepoName() { return pageDetect.utils.getRepositoryInfo(window.location)!.nameWithOwner; } + +export function hasRepoContainerHeader() { + const headerElement = $('#repository-container-header'); + return headerElement && !headerElement.attr('hidden'); +} + +export async function isRepoRoot() { + return pageDetect.isRepoRoot(); +} + +/** + * check if the repository is public + */ +export async function isPublicRepo() { + const selector = 'meta[name="octolytics-dimension-repository_public"]'; + await elementReady(selector); + // + const isPublic = $(selector).attr('content') === 'true'; + return pageDetect.isRepo() && isPublic; +} + +export async function isPublicRepoWithMeta() { + return (await isPublicRepo()) && (await metaStore.has(getRepoName())); +} diff --git a/src/helpers/is-perceptor.ts b/src/helpers/is-perceptor.ts index c9b6e4bd..3cad003f 100644 --- a/src/helpers/is-perceptor.ts +++ b/src/helpers/is-perceptor.ts @@ -1,4 +1,5 @@ -const isPerceptor = (): boolean => - window.location.search.includes('?redirect=perceptor'); +const isPerceptor = (): boolean => { + return window.location.search.includes('?redirect=perceptor'); +}; export default isPerceptor; diff --git a/src/helpers/is-public-repo.ts b/src/helpers/is-public-repo.ts deleted file mode 100644 index 0124d0d7..00000000 --- a/src/helpers/is-public-repo.ts +++ /dev/null @@ -1,17 +0,0 @@ -import $ from 'jquery'; -import * as pageDetect from 'github-url-detection'; -import elementReady from 'element-ready'; - -// check if the repository is public -export default async function isPublicRepo() { - // another selector that also works - // const repoLabel = $('strong[itemprop="name"]').siblings('span.Label.Label--secondary').text(); - await elementReady('#repository-container-header'); - const repoLabel = $('#repository-container-header') - .find('span.Label.Label--secondary:first') - .text(); - return ( - pageDetect.isRepo() && - (repoLabel === 'Public' || repoLabel === 'Public template') - ); -} diff --git a/src/pages/ContentScripts/features/developer-activity-openrank-trends/index.tsx b/src/pages/ContentScripts/features/developer-activity-openrank-trends/index.tsx index bb2b0522..1400e998 100644 --- a/src/pages/ContentScripts/features/developer-activity-openrank-trends/index.tsx +++ b/src/pages/ContentScripts/features/developer-activity-openrank-trends/index.tsx @@ -1,25 +1,33 @@ import React from 'react'; import { render, Container } from 'react-dom'; import $ from 'jquery'; -import * as pageDetect from 'github-url-detection'; import features from '../../../../feature-manager'; -import { getDeveloperName } from '../../../../helpers/get-developer-info'; +import { + getDeveloperName, + isDeveloperWithMeta, +} from '../../../../helpers/get-developer-info'; import { getActivity, getOpenrank } from '../../../../api/developer'; +import { UserMeta, metaStore } from '../../../../api/common'; import View from './view'; const featureId = features.getFeatureID(import.meta.url); let developerName: string; let activity: any; let openrank: any; +let meta: UserMeta; const getData = async () => { activity = await getActivity(developerName); openrank = await getOpenrank(developerName); + meta = (await metaStore.get(developerName)) as UserMeta; }; const renderTo = (container: Container) => { - render(, container); + render( + , + container + ); }; const init = async (): Promise => { @@ -45,10 +53,9 @@ const restore = async () => { } renderTo($(`#${featureId}`)[0]); }; - features.add(featureId, { - include: [pageDetect.isUserProfile], - awaitDomReady: true, + asLongAs: [isDeveloperWithMeta], + awaitDomReady: false, init, restore, }); diff --git a/src/pages/ContentScripts/features/developer-activity-openrank-trends/view.tsx b/src/pages/ContentScripts/features/developer-activity-openrank-trends/view.tsx index 6f8a30e9..a1950dab 100644 --- a/src/pages/ContentScripts/features/developer-activity-openrank-trends/view.tsx +++ b/src/pages/ContentScripts/features/developer-activity-openrank-trends/view.tsx @@ -8,22 +8,24 @@ import optionsStorage, { defaults, } from '../../../../options-storage'; import Bars from '../../../../components/Bars'; +import { UserMeta } from '../../../../api/common'; const githubTheme = getGithubTheme(); -const generateBarsData = (activity: any, openrank: any) => { +const generateBarsData = (activity: any, openrank: any, updatedAt: number) => { return { - data1: generateDataByMonth(activity), - data2: generateDataByMonth(openrank), + data1: generateDataByMonth(activity, updatedAt), + data2: generateDataByMonth(openrank, updatedAt), }; }; interface Props { activity: any; openrank: any; + meta: UserMeta; } -const View = ({ activity, openrank }: Props): JSX.Element | null => { +const View = ({ activity, openrank, meta }: Props): JSX.Element | null => { const [options, setOptions] = useState(defaults); useEffect(() => { @@ -34,7 +36,7 @@ const View = ({ activity, openrank }: Props): JSX.Element | null => { if (!activity || !openrank) return null; - let barsData: any = generateBarsData(activity, openrank); + let barsData: any = generateBarsData(activity, openrank, meta.updatedAt); return (
diff --git a/src/pages/ContentScripts/features/developer-networks/index.tsx b/src/pages/ContentScripts/features/developer-networks/index.tsx index 827fa3de..9b0435d9 100644 --- a/src/pages/ContentScripts/features/developer-networks/index.tsx +++ b/src/pages/ContentScripts/features/developer-networks/index.tsx @@ -5,7 +5,10 @@ import * as pageDetect from 'github-url-detection'; import elementReady from 'element-ready'; import features from '../../../../feature-manager'; -import { getDeveloperName } from '../../../../helpers/get-developer-info'; +import { + getDeveloperName, + isDeveloperWithMeta, +} from '../../../../helpers/get-developer-info'; import { getDeveloperNetwork, getRepoNetwork } from '../../../../api/developer'; import View from './view'; @@ -58,7 +61,7 @@ const restore = async () => { }; features.add(featureId, { - asLongAs: [pageDetect.isUserProfile], + asLongAs: [isDeveloperWithMeta], awaitDomReady: false, init, restore, diff --git a/src/pages/ContentScripts/features/oss-gpt/index.tsx b/src/pages/ContentScripts/features/oss-gpt/index.tsx index 214f92fa..d9e73f8e 100644 --- a/src/pages/ContentScripts/features/oss-gpt/index.tsx +++ b/src/pages/ContentScripts/features/oss-gpt/index.tsx @@ -4,8 +4,7 @@ import $ from 'jquery'; import features from '../../../../feature-manager'; import getGithubTheme from '../../../../helpers/get-github-theme'; -import isPublicRepo from '../../../../helpers/is-public-repo'; -import { getRepoName } from '../../../../helpers/get-repo-info'; +import { getRepoName, isPublicRepo } from '../../../../helpers/get-repo-info'; import View from './view'; interface DocsMetaItem { diff --git a/src/pages/ContentScripts/features/perceptor-layout/index.tsx b/src/pages/ContentScripts/features/perceptor-layout/index.tsx index fec4cd77..fbcce059 100644 --- a/src/pages/ContentScripts/features/perceptor-layout/index.tsx +++ b/src/pages/ContentScripts/features/perceptor-layout/index.tsx @@ -5,6 +5,7 @@ import { render, Container } from 'react-dom'; import features from '../../../../feature-manager'; import isPerceptor from '../../../../helpers/is-perceptor'; +import { isPublicRepoWithMeta } from '../../../../helpers/get-repo-info'; import View from './view'; const featureId = features.getFeatureID(import.meta.url); @@ -33,7 +34,7 @@ const init = async (): Promise => { }; features.add(featureId, { - asLongAs: [isPerceptor], + asLongAs: [isPerceptor, isPublicRepoWithMeta], awaitDomReady: false, init, }); diff --git a/src/pages/ContentScripts/features/perceptor-tab/index.tsx b/src/pages/ContentScripts/features/perceptor-tab/index.tsx index 497bc49a..6ea6d1c4 100644 --- a/src/pages/ContentScripts/features/perceptor-tab/index.tsx +++ b/src/pages/ContentScripts/features/perceptor-tab/index.tsx @@ -4,7 +4,7 @@ import elementReady from 'element-ready'; import iconSvgPath from './icon-svg-path'; import features from '../../../../feature-manager'; import isPerceptor from '../../../../helpers/is-perceptor'; -import isPublicRepo from '../../../../helpers/is-public-repo'; +import { isPublicRepoWithMeta } from '../../../../helpers/get-repo-info'; import sleep from '../../../../helpers/sleep'; const featureId = features.getFeatureID(import.meta.url); @@ -95,7 +95,7 @@ const init = async (): Promise => { }; features.add(featureId, { - asLongAs: [isPublicRepo], + asLongAs: [isPublicRepoWithMeta], awaitDomReady: false, init, }); diff --git a/src/pages/ContentScripts/features/repo-activity-openrank-trends/index.tsx b/src/pages/ContentScripts/features/repo-activity-openrank-trends/index.tsx index a1bf60c0..e53592a4 100644 --- a/src/pages/ContentScripts/features/repo-activity-openrank-trends/index.tsx +++ b/src/pages/ContentScripts/features/repo-activity-openrank-trends/index.tsx @@ -1,26 +1,37 @@ import React from 'react'; import { render, Container } from 'react-dom'; import $ from 'jquery'; -import * as pageDetect from 'github-url-detection'; import features from '../../../../feature-manager'; -import { getRepoName } from '../../../../helpers/get-repo-info'; +import { + getRepoName, + isPublicRepoWithMeta, + isRepoRoot, +} from '../../../../helpers/get-repo-info'; import { getActivity, getOpenrank } from '../../../../api/repo'; +import { RepoMeta, metaStore } from '../../../../api/common'; import View from './view'; const featureId = features.getFeatureID(import.meta.url); let repoName: string; let activity: any; let openrank: any; +let meta: RepoMeta; const getData = async () => { activity = await getActivity(repoName); openrank = await getOpenrank(repoName); + meta = (await metaStore.get(repoName)) as RepoMeta; }; const renderTo = (container: Container) => { render( - , + , container ); }; @@ -55,7 +66,7 @@ const restore = async () => { }; features.add(featureId, { - include: [pageDetect.isRepoHome], + asLongAs: [isPublicRepoWithMeta, isRepoRoot], awaitDomReady: true, init, restore, diff --git a/src/pages/ContentScripts/features/repo-activity-openrank-trends/view.tsx b/src/pages/ContentScripts/features/repo-activity-openrank-trends/view.tsx index f0572fe4..4c9a2151 100644 --- a/src/pages/ContentScripts/features/repo-activity-openrank-trends/view.tsx +++ b/src/pages/ContentScripts/features/repo-activity-openrank-trends/view.tsx @@ -8,13 +8,14 @@ import optionsStorage, { defaults, } from '../../../../options-storage'; import Bars from '../../../../components/Bars'; +import { RepoMeta } from '../../../../api/common'; const githubTheme = getGithubTheme(); -const generateBarsData = (activity: any, openrank: any) => { +const generateBarsData = (activity: any, openrank: any, updatedAt: number) => { return { - data1: generateDataByMonth(activity), - data2: generateDataByMonth(openrank), + data1: generateDataByMonth(activity, updatedAt), + data2: generateDataByMonth(openrank, updatedAt), }; }; @@ -22,9 +23,15 @@ interface Props { repoName: string; activity: any; openrank: any; + meta: RepoMeta; } -const View = ({ repoName, activity, openrank }: Props): JSX.Element | null => { +const View = ({ + repoName, + activity, + openrank, + meta, +}: Props): JSX.Element | null => { const [options, setOptions] = useState(defaults); useEffect(() => { @@ -35,7 +42,7 @@ const View = ({ repoName, activity, openrank }: Props): JSX.Element | null => { if (!activity || !openrank) return null; - let barsData: any = generateBarsData(activity, openrank); + let barsData: any = generateBarsData(activity, openrank, meta.updatedAt); const onClick = (params: any) => { const { seriesIndex, data } = params; diff --git a/src/pages/ContentScripts/features/repo-activity-racing-bar/index.tsx b/src/pages/ContentScripts/features/repo-activity-racing-bar/index.tsx index 76bf23f5..e9b2fd7e 100644 --- a/src/pages/ContentScripts/features/repo-activity-racing-bar/index.tsx +++ b/src/pages/ContentScripts/features/repo-activity-racing-bar/index.tsx @@ -4,7 +4,10 @@ import $ from 'jquery'; import features from '../../../../feature-manager'; import isPerceptor from '../../../../helpers/is-perceptor'; -import { getRepoName } from '../../../../helpers/get-repo-info'; +import { + getRepoName, + isPublicRepoWithMeta, +} from '../../../../helpers/get-repo-info'; import { getActivityDetails } from '../../../../api/repo'; import View from './view'; import DataNotFound from '../repo-networks/DataNotFound'; @@ -52,7 +55,7 @@ const restore = async () => { }; features.add(featureId, { - asLongAs: [isPerceptor], + asLongAs: [isPerceptor, isPublicRepoWithMeta], awaitDomReady: false, init, restore, diff --git a/src/pages/ContentScripts/features/repo-fork-tooltip/index.tsx b/src/pages/ContentScripts/features/repo-fork-tooltip/index.tsx index 5a6f144f..46d61f50 100644 --- a/src/pages/ContentScripts/features/repo-fork-tooltip/index.tsx +++ b/src/pages/ContentScripts/features/repo-fork-tooltip/index.tsx @@ -4,23 +4,29 @@ import elementReady from 'element-ready'; import $ from 'jquery'; import features from '../../../../feature-manager'; -import isPublicRepo from '../../../../helpers/is-public-repo'; import getGithubTheme from '../../../../helpers/get-github-theme'; -import { getRepoName } from '../../../../helpers/get-repo-info'; +import { + getRepoName, + hasRepoContainerHeader, + isPublicRepoWithMeta, +} from '../../../../helpers/get-repo-info'; import { getForks } from '../../../../api/repo'; +import { RepoMeta, metaStore } from '../../../../api/common'; import View from './view'; const githubTheme = getGithubTheme(); const featureId = features.getFeatureID(import.meta.url); let repoName: string; let forks: any; +let meta: RepoMeta; const getData = async () => { forks = await getForks(repoName); + meta = (await metaStore.get(repoName)) as RepoMeta; }; const renderTo = (container: Container) => { - render(, container); + render(, container); }; const init = async (): Promise => { @@ -60,7 +66,7 @@ const restore = async () => { }; features.add(featureId, { - asLongAs: [isPublicRepo], + asLongAs: [isPublicRepoWithMeta, hasRepoContainerHeader], awaitDomReady: false, init, restore, diff --git a/src/pages/ContentScripts/features/repo-fork-tooltip/view.tsx b/src/pages/ContentScripts/features/repo-fork-tooltip/view.tsx index ea304626..81f57b84 100644 --- a/src/pages/ContentScripts/features/repo-fork-tooltip/view.tsx +++ b/src/pages/ContentScripts/features/repo-fork-tooltip/view.tsx @@ -9,14 +9,16 @@ import optionsStorage, { import generateDataByMonth from '../../../../helpers/generate-data-by-month'; import ReactTooltip from 'react-tooltip'; import ForkChart from './ForkChart'; +import { RepoMeta } from '../../../../api/common'; const githubTheme = getGithubTheme(); interface Props { forks: any; + meta: RepoMeta; } -const View = ({ forks }: Props): JSX.Element | null => { +const View = ({ forks, meta }: Props): JSX.Element | null => { const [options, setOptions] = useState(defaults); useEffect(() => { @@ -36,7 +38,7 @@ const View = ({ forks }: Props): JSX.Element | null => { theme={githubTheme as 'light' | 'dark'} width={270} height={130} - data={generateDataByMonth(forks)} + data={generateDataByMonth(forks, meta.updatedAt)} /> ); diff --git a/src/pages/ContentScripts/features/repo-header-labels/index.tsx b/src/pages/ContentScripts/features/repo-header-labels/index.tsx index e9e78709..f4ba45be 100644 --- a/src/pages/ContentScripts/features/repo-header-labels/index.tsx +++ b/src/pages/ContentScripts/features/repo-header-labels/index.tsx @@ -4,9 +4,13 @@ import elementReady from 'element-ready'; import $ from 'jquery'; import features from '../../../../feature-manager'; -import isPublicRepo from '../../../../helpers/is-public-repo'; -import { getRepoName } from '../../../../helpers/get-repo-info'; +import { + getRepoName, + hasRepoContainerHeader, + isPublicRepoWithMeta, +} from '../../../../helpers/get-repo-info'; import { getActivity, getOpenrank, getParticipant } from '../../../../api/repo'; +import { RepoMeta, metaStore } from '../../../../api/common'; import View from './view'; const featureId = features.getFeatureID(import.meta.url); @@ -14,16 +18,23 @@ let repoName: string; let activity: any; let openrank: any; let participant: any; +let meta: RepoMeta; const getData = async () => { activity = await getActivity(repoName); openrank = await getOpenrank(repoName); participant = await getParticipant(repoName); + meta = (await metaStore.get(repoName)) as RepoMeta; }; const renderTo = (container: Container) => { render( - , + , container ); }; @@ -55,7 +66,7 @@ const restore = async () => { }; features.add(featureId, { - asLongAs: [isPublicRepo], + asLongAs: [isPublicRepoWithMeta, hasRepoContainerHeader], awaitDomReady: false, init, restore, diff --git a/src/pages/ContentScripts/features/repo-header-labels/view.tsx b/src/pages/ContentScripts/features/repo-header-labels/view.tsx index 13633c18..8b94e105 100644 --- a/src/pages/ContentScripts/features/repo-header-labels/view.tsx +++ b/src/pages/ContentScripts/features/repo-header-labels/view.tsx @@ -14,6 +14,7 @@ import generateDataByMonth from '../../../../helpers/generate-data-by-month'; import ActivityChart from './ActivityChart'; import OpenRankChart from './OpenRankChart'; import ParticipantChart from './ParticipantChart'; +import { RepoMeta } from '../../../../api/common'; const githubTheme = getGithubTheme(); @@ -21,12 +22,14 @@ interface Props { activity: any; openrank: any; participant: any; + meta: RepoMeta; } const View = ({ activity, openrank, participant, + meta, }: Props): JSX.Element | null => { const [options, setOptions] = useState(defaults); @@ -42,9 +45,9 @@ const View = ({ if (isNull(activity) || isNull(openrank) || isNull(participant)) return null; - const activityData = generateDataByMonth(activity); - const openrankData = generateDataByMonth(openrank); - const participantData = generateDataByMonth(participant); + const activityData = generateDataByMonth(activity, meta.updatedAt); + const openrankData = generateDataByMonth(openrank, meta.updatedAt); + const participantData = generateDataByMonth(participant, meta.updatedAt); return (
diff --git a/src/pages/ContentScripts/features/repo-issue-tooltip/index.tsx b/src/pages/ContentScripts/features/repo-issue-tooltip/index.tsx index 651c14e3..ee2e6996 100644 --- a/src/pages/ContentScripts/features/repo-issue-tooltip/index.tsx +++ b/src/pages/ContentScripts/features/repo-issue-tooltip/index.tsx @@ -4,15 +4,18 @@ import elementReady from 'element-ready'; import $ from 'jquery'; import features from '../../../../feature-manager'; -import isPublicRepo from '../../../../helpers/is-public-repo'; import getGithubTheme from '../../../../helpers/get-github-theme'; -import { getRepoName } from '../../../../helpers/get-repo-info'; +import { + getRepoName, + isPublicRepoWithMeta, +} from '../../../../helpers/get-repo-info'; import { getIssuesOpened, getIssuesClosed, getIssueComments, } from '../../../../api/repo'; import View, { IssueDetail } from './view'; +import { RepoMeta, metaStore } from '../../../../api/common'; const githubTheme = getGithubTheme(); const featureId = features.getFeatureID(import.meta.url); @@ -22,15 +25,20 @@ let issueDetail: IssueDetail = { issuesClosed: null, issueComments: null, }; +let meta: RepoMeta; const getData = async () => { issueDetail.issuesOpened = await getIssuesOpened(repoName); issueDetail.issuesClosed = await getIssuesClosed(repoName); issueDetail.issueComments = await getIssueComments(repoName); + meta = (await metaStore.get(repoName)) as RepoMeta; }; const renderTo = (container: Container) => { - render(, container); + render( + , + container + ); }; const init = async (): Promise => { @@ -53,7 +61,7 @@ const init = async (): Promise => { const container = document.createElement('div'); container.id = featureId; renderTo(container); - (await elementReady('#repository-container-header'))?.append(container); + (await elementReady('nav.js-repo-nav'))?.append(container); }; const restore = async () => { @@ -70,7 +78,7 @@ const restore = async () => { }; features.add(featureId, { - asLongAs: [isPublicRepo], + asLongAs: [isPublicRepoWithMeta], awaitDomReady: false, init, restore, diff --git a/src/pages/ContentScripts/features/repo-issue-tooltip/view.tsx b/src/pages/ContentScripts/features/repo-issue-tooltip/view.tsx index 45975d78..e8ac54e8 100644 --- a/src/pages/ContentScripts/features/repo-issue-tooltip/view.tsx +++ b/src/pages/ContentScripts/features/repo-issue-tooltip/view.tsx @@ -10,6 +10,7 @@ import optionsStorage, { import generateDataByMonth from '../../../../helpers/generate-data-by-month'; import ReactTooltip from 'react-tooltip'; import IssueChart from './IssueChart'; +import { RepoMeta } from '../../../../api/common'; const githubTheme = getGithubTheme(); @@ -22,17 +23,22 @@ export interface IssueDetail { interface Props { currentRepo: string; issueDetail: IssueDetail; + meta: RepoMeta; } -const generateData = (issueDetail: IssueDetail): any => { +const generateData = (issueDetail: IssueDetail, updatedAt: number): any => { return { - issuesOpened: generateDataByMonth(issueDetail.issuesOpened), - issuesClosed: generateDataByMonth(issueDetail.issuesClosed), - issueComments: generateDataByMonth(issueDetail.issueComments), + issuesOpened: generateDataByMonth(issueDetail.issuesOpened, updatedAt), + issuesClosed: generateDataByMonth(issueDetail.issuesClosed, updatedAt), + issueComments: generateDataByMonth(issueDetail.issueComments, updatedAt), }; }; -const View = ({ currentRepo, issueDetail }: Props): JSX.Element | null => { +const View = ({ + currentRepo, + issueDetail, + meta, +}: Props): JSX.Element | null => { const [options, setOptions] = useState(defaults); useEffect(() => { @@ -71,7 +77,7 @@ const View = ({ currentRepo, issueDetail }: Props): JSX.Element | null => { theme={githubTheme as 'light' | 'dark'} width={300} height={200} - data={generateData(issueDetail)} + data={generateData(issueDetail, meta.updatedAt)} onClick={onClick} /> diff --git a/src/pages/ContentScripts/features/repo-networks/index.tsx b/src/pages/ContentScripts/features/repo-networks/index.tsx index 83e801c1..5eca87b3 100644 --- a/src/pages/ContentScripts/features/repo-networks/index.tsx +++ b/src/pages/ContentScripts/features/repo-networks/index.tsx @@ -4,7 +4,10 @@ import $ from 'jquery'; import features from '../../../../feature-manager'; import isPerceptor from '../../../../helpers/is-perceptor'; -import { getRepoName } from '../../../../helpers/get-repo-info'; +import { + getRepoName, + isPublicRepoWithMeta, +} from '../../../../helpers/get-repo-info'; import { getRepoNetwork, getDeveloperNetwork } from '../../../../api/repo'; import View from './view'; import DataNotFound from './DataNotFound'; @@ -55,7 +58,7 @@ const restore = async () => { }; features.add(featureId, { - asLongAs: [isPerceptor], + asLongAs: [isPerceptor, isPublicRepoWithMeta], awaitDomReady: false, init, restore, diff --git a/src/pages/ContentScripts/features/repo-pr-tooltip/index.tsx b/src/pages/ContentScripts/features/repo-pr-tooltip/index.tsx index 00ddbbdc..376d9b86 100644 --- a/src/pages/ContentScripts/features/repo-pr-tooltip/index.tsx +++ b/src/pages/ContentScripts/features/repo-pr-tooltip/index.tsx @@ -4,9 +4,11 @@ import elementReady from 'element-ready'; import $ from 'jquery'; import features from '../../../../feature-manager'; -import isPublicRepo from '../../../../helpers/is-public-repo'; import getGithubTheme from '../../../../helpers/get-github-theme'; -import { getRepoName } from '../../../../helpers/get-repo-info'; +import { + getRepoName, + isPublicRepoWithMeta, +} from '../../../../helpers/get-repo-info'; import { getPROpened, getPRMerged, @@ -15,6 +17,7 @@ import { getMergedCodeDeletion, } from '../../../../api/repo'; import View, { PRDetail } from './view'; +import { RepoMeta, metaStore } from '../../../../api/common'; const githubTheme = getGithubTheme(); const featureId = features.getFeatureID(import.meta.url); @@ -26,6 +29,7 @@ let PRDetail: PRDetail = { mergedCodeAddition: null, mergedCodeDeletion: null, }; +let meta: RepoMeta; const getData = async () => { PRDetail.PROpened = await getPROpened(repoName); @@ -33,10 +37,14 @@ const getData = async () => { PRDetail.PRReviews = await getPRReviews(repoName); PRDetail.mergedCodeAddition = await getMergedCodeAddition(repoName); PRDetail.mergedCodeDeletion = await getMergedCodeDeletion(repoName); + meta = (await metaStore.get(repoName)) as RepoMeta; }; const renderTo = (container: Container) => { - render(, container); + render( + , + container + ); }; const init = async (): Promise => { @@ -59,7 +67,7 @@ const init = async (): Promise => { const container = document.createElement('div'); container.id = featureId; renderTo(container); - (await elementReady('#repository-container-header'))?.append(container); + (await elementReady('nav.js-repo-nav'))?.append(container); }; const restore = async () => { @@ -76,7 +84,7 @@ const restore = async () => { }; features.add(featureId, { - asLongAs: [isPublicRepo], + asLongAs: [isPublicRepoWithMeta], awaitDomReady: false, init, restore, diff --git a/src/pages/ContentScripts/features/repo-pr-tooltip/view.tsx b/src/pages/ContentScripts/features/repo-pr-tooltip/view.tsx index 39e3382e..7c6fa870 100644 --- a/src/pages/ContentScripts/features/repo-pr-tooltip/view.tsx +++ b/src/pages/ContentScripts/features/repo-pr-tooltip/view.tsx @@ -11,6 +11,7 @@ import generateDataByMonth from '../../../../helpers/generate-data-by-month'; import ReactTooltip from 'react-tooltip'; import PRChart from './PRChart'; import MergedLinesChart from './MergedLinesChart'; +import { RepoMeta } from '../../../../api/common'; const githubTheme = getGithubTheme(); @@ -25,30 +26,38 @@ export interface PRDetail { interface Props { currentRepo: string; PRDetail: PRDetail; + meta: RepoMeta; } -const generatePRChartData = (PRDetail: PRDetail): any => { +const generatePRChartData = (PRDetail: PRDetail, updatedAt: number): any => { return { - PROpened: generateDataByMonth(PRDetail.PROpened), - PRMerged: generateDataByMonth(PRDetail.PRMerged), - PRReviews: generateDataByMonth(PRDetail.PRReviews), + PROpened: generateDataByMonth(PRDetail.PROpened, updatedAt), + PRMerged: generateDataByMonth(PRDetail.PRMerged, updatedAt), + PRReviews: generateDataByMonth(PRDetail.PRReviews, updatedAt), }; }; -const generateMergedLinesChartData = (PRDetail: PRDetail): any => { +const generateMergedLinesChartData = ( + PRDetail: PRDetail, + updatedAt: number +): any => { return { - mergedCodeAddition: generateDataByMonth(PRDetail.mergedCodeAddition), - mergedCodeDeletion: generateDataByMonth(PRDetail.mergedCodeDeletion).map( - (item) => { - const dataItem = item; - dataItem[1] = -item[1]; - return dataItem; - } + mergedCodeAddition: generateDataByMonth( + PRDetail.mergedCodeAddition, + updatedAt ), + mergedCodeDeletion: generateDataByMonth( + PRDetail.mergedCodeDeletion, + updatedAt + ).map((item) => { + const dataItem = item; + dataItem[1] = -item[1]; + return dataItem; + }), }; }; -const View = ({ currentRepo, PRDetail }: Props): JSX.Element | null => { +const View = ({ currentRepo, PRDetail, meta }: Props): JSX.Element | null => { const [options, setOptions] = useState(defaults); useEffect(() => { @@ -87,7 +96,7 @@ const View = ({ currentRepo, PRDetail }: Props): JSX.Element | null => { theme={githubTheme as 'light' | 'dark'} width={330} height={200} - data={generatePRChartData(PRDetail)} + data={generatePRChartData(PRDetail, meta.updatedAt)} onClick={onClick} />
@@ -97,7 +106,7 @@ const View = ({ currentRepo, PRDetail }: Props): JSX.Element | null => { theme={githubTheme as 'light' | 'dark'} width={330} height={200} - data={generateMergedLinesChartData(PRDetail)} + data={generateMergedLinesChartData(PRDetail, meta.updatedAt)} /> ); diff --git a/src/pages/ContentScripts/features/repo-star-tooltip/index.tsx b/src/pages/ContentScripts/features/repo-star-tooltip/index.tsx index a9fa2e3d..e94f424d 100644 --- a/src/pages/ContentScripts/features/repo-star-tooltip/index.tsx +++ b/src/pages/ContentScripts/features/repo-star-tooltip/index.tsx @@ -5,22 +5,28 @@ import $ from 'jquery'; import features from '../../../../feature-manager'; import getGithubTheme from '../../../../helpers/get-github-theme'; -import isPublicRepo from '../../../../helpers/is-public-repo'; -import { getRepoName } from '../../../../helpers/get-repo-info'; +import { + getRepoName, + hasRepoContainerHeader, + isPublicRepoWithMeta, +} from '../../../../helpers/get-repo-info'; import { getStars } from '../../../../api/repo'; import View from './view'; +import { RepoMeta, metaStore } from '../../../../api/common'; const githubTheme = getGithubTheme(); const featureId = features.getFeatureID(import.meta.url); let repoName: string; let stars: any; +let meta: RepoMeta; const getData = async () => { stars = await getStars(repoName); + meta = (await metaStore.get(repoName)) as RepoMeta; }; const renderTo = (container: Container) => { - render(, container); + render(, container); }; const init = async (): Promise => { @@ -62,7 +68,7 @@ const restore = async () => { }; features.add(featureId, { - asLongAs: [isPublicRepo], + asLongAs: [isPublicRepoWithMeta, hasRepoContainerHeader], awaitDomReady: false, init, restore, diff --git a/src/pages/ContentScripts/features/repo-star-tooltip/view.tsx b/src/pages/ContentScripts/features/repo-star-tooltip/view.tsx index 1c766a06..dfc4cb82 100644 --- a/src/pages/ContentScripts/features/repo-star-tooltip/view.tsx +++ b/src/pages/ContentScripts/features/repo-star-tooltip/view.tsx @@ -9,14 +9,16 @@ import optionsStorage, { import generateDataByMonth from '../../../../helpers/generate-data-by-month'; import ReactTooltip from 'react-tooltip'; import StarChart from './StarChart'; +import { RepoMeta } from '../../../../api/common'; const githubTheme = getGithubTheme(); interface Props { stars: any; + meta: RepoMeta; } -const View = ({ stars: stars }: Props): JSX.Element | null => { +const View = ({ stars, meta }: Props): JSX.Element | null => { const [options, setOptions] = useState(defaults); useEffect(() => { @@ -36,7 +38,7 @@ const View = ({ stars: stars }: Props): JSX.Element | null => { theme={githubTheme as 'light' | 'dark'} width={270} height={130} - data={generateDataByMonth(stars)} + data={generateDataByMonth(stars, meta.updatedAt)} /> ); diff --git a/yarn.lock b/yarn.lock index 2cba1086..32710910 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3204,10 +3204,10 @@ get-stream@^6.0.0, get-stream@^6.0.1: resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -github-url-detection@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/github-url-detection/-/github-url-detection-6.1.0.tgz#b5a478fa7cb36f673d3da52cd5b3075fb3a43b3a" - integrity sha512-Z2z3WmR38cbHegKHN3jiyo2wDBEPRlEn/8HHK05iidiHtNF8KltmjKiaNzB3QdGU+OxF2QhgwT1q4rLT15Z08w== +github-url-detection@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/github-url-detection/-/github-url-detection-8.1.0.tgz#f415564f39c8b92ca2e823c22d1386bd0ac3fdf8" + integrity sha512-GvKgbLdIP6++wzBMCeJFJhoysFoUunE52m2B1K3ltfVfL3LO4TGQ/lv4utWoVCmVP85dVk+ZWkYA7IB3+fPt7A== glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2"