From c15e97b4d4c063de053f62559b47af2478b00dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Tue, 16 Jul 2019 19:31:11 +0100 Subject: [PATCH] change the world: track projects not repos This commit swaps usage over to the new implementation of `cli/load` (the one that wraps `api/load`) and makes changes throughout the project to accomodate that we now track instances by Project rather than by RepoId. Test plan: Unit tests updated; run `yarn test --full`. Also, for safety: actually load a project (by whole org, why not) and verify that the frontend still works. --- config/env.js | 6 +- config/webpack.config.web.js | 44 +++------- scripts/build_static_site.sh | 21 +++-- .../example-github/github/view.json.gz | Bin 3279 -> 0 bytes .../data/sourcecred/example-github/graph.json | 1 - .../cred.json | 2 +- .../graph.json | 1 + .../project.json | 1 + .../repositoryRegistry.json | 1 - sharness/test_build_static_site.t | 76 +++++++----------- sharness/test_cli_scores.t | 14 ++-- src/cli/help.js | 2 +- src/cli/scores.js | 51 +++++------- src/cli/sourcecred.js | 2 +- src/cli/sourcecred.test.js | 2 +- src/explorer/TimelineApp.js | 18 ++--- src/explorer/TimelineExplorer.js | 10 +-- src/explorer/legacy/App.js | 19 +++-- src/explorer/legacy/App.test.js | 16 ++-- src/explorer/legacy/state.js | 27 +++---- src/explorer/legacy/state.test.js | 16 ++-- src/homepage/ProjectPage.js | 7 +- src/homepage/PrototypesPage.js | 12 +-- src/homepage/TimelinePage.js | 7 +- .../createRouteDataFromEnvironment.js | 9 +-- src/homepage/homepageExplorer.js | 7 +- src/homepage/homepageTimeline.js | 5 +- src/homepage/routeData.js | 22 ++--- src/homepage/routeData.test.js | 5 +- src/homepage/server.js | 2 +- src/plugins/github/analysisAdapter.test.js | 3 +- 31 files changed, 176 insertions(+), 233 deletions(-) delete mode 100644 sharness/__snapshots__/example-github-load/data/sourcecred/example-github/github/view.json.gz delete mode 100644 sharness/__snapshots__/example-github-load/data/sourcecred/example-github/graph.json rename sharness/__snapshots__/example-github-load/{data/sourcecred/example-github => projects/c291cmNlY3JlZC9leGFtcGxlLWdpdGh1Yg}/cred.json (78%) create mode 100644 sharness/__snapshots__/example-github-load/projects/c291cmNlY3JlZC9leGFtcGxlLWdpdGh1Yg/graph.json create mode 100644 sharness/__snapshots__/example-github-load/projects/c291cmNlY3JlZC9leGFtcGxlLWdpdGh1Yg/project.json delete mode 100644 sharness/__snapshots__/example-github-load/repositoryRegistry.json diff --git a/config/env.js b/config/env.js index c703f86..ddf5524 100644 --- a/config/env.js +++ b/config/env.js @@ -134,9 +134,7 @@ function getGitState() /*: GitState */ { const SOURCECRED_GIT_STATE = stringify(getGitState()); process.env.SOURCECRED_GIT_STATE = SOURCECRED_GIT_STATE; -function getClientEnvironment( - repoRegistryContents /*: RepoIdRegistry | null */ -) { +function getClientEnvironment(projectIds /*: $ReadOnlyArray | null*/) { const raw = {}; // Useful for determining whether we’re running in production mode. // Most importantly, it switches React into the correct mode. @@ -144,7 +142,7 @@ function getClientEnvironment( // Used by `src/core/version.js`. raw.SOURCECRED_GIT_STATE = SOURCECRED_GIT_STATE; // Optional. Used by `src/homepage/routeData.js` - raw.REPO_REGISTRY = stringify(repoRegistryContents); + raw.PROJECT_IDS = stringify(projectIds); // Stringify all values so we can feed into Webpack's DefinePlugin. const stringified = {"process.env": {}}; diff --git a/config/webpack.config.web.js b/config/webpack.config.web.js index 9317f90..00b9a75 100644 --- a/config/webpack.config.web.js +++ b/config/webpack.config.web.js @@ -7,7 +7,6 @@ import type { } from "express"; import type {RepoIdRegistry} from "../src/core/repoIdRegistry"; */ -const fs = require("fs"); const os = require("os"); const path = require("path"); const webpack = require("webpack"); @@ -18,45 +17,22 @@ const StaticSiteGeneratorPlugin = require("static-site-generator-webpack-plugin" const ModuleScopePlugin = require("react-dev-utils/ModuleScopePlugin"); const paths = require("./paths"); const getClientEnvironment = require("./env"); +const _getProjectIds = require("../src/core/_getProjectIds"); // Source maps are resource heavy and can cause out of memory issue for large source files. const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false"; -function loadRepoRegistry() /*: RepoIdRegistry */ { +function loadProjectIds() /*: Promise<$ReadOnlyArray> */ { const env = process.env.SOURCECRED_DIRECTORY; // TODO(#945): de-duplicate finding the directory with src/cli/common.js const defaultDirectory = path.join(os.tmpdir(), "sourcecred"); const scDirectory = env != null ? env : defaultDirectory; - // TODO(@dandelion): Remove hacks around compat usage here - // TODO(@dandelion): Import rather than hardcode the registry file name - const registryFile = path.join(scDirectory, "repositoryRegistry.json"); - - let jsonString; - try { - jsonString = fs.readFileSync(registryFile).toString(); - } catch (e) { - if (e.code === "ENOENT") { - jsonString = JSON.stringify([ - {version: "0.2.0", type: "REPO_ID_REGISTRY"}, - [], - ]); - } else { - throw e; - } - } - const json = JSON.parse(jsonString); - const compat = json[0]; - if (compat.version !== "0.2.0" || compat.type !== "REPO_ID_REGISTRY") { - throw new Error("Compat mismatch"); - } - return json[1]; + return _getProjectIds(scDirectory); } -const repoRegistry = loadRepoRegistry(); -// Get environment variables to inject into our app. -const env = getClientEnvironment(repoRegistry); - -function makeConfig(mode /*: "production" | "development" */) /*: mixed */ { +async function makeConfig( + mode /*: "production" | "development" */ +) /*: Promise */ { return { // Don't attempt to continue if there are any errors. bail: true, @@ -211,7 +187,7 @@ function makeConfig(mode /*: "production" | "development" */) /*: mixed */ { }, ], }, - plugins: plugins(mode), + plugins: await plugins(mode), // Some libraries import Node modules but don't use them in the browser. // Tell Webpack to provide empty mocks for them so importing them works. node: { @@ -225,12 +201,14 @@ function makeConfig(mode /*: "production" | "development" */) /*: mixed */ { }; } -function plugins(mode /*: "development" | "production" */) { +async function plugins(mode /*: "development" | "production" */) { + const projectIds = await loadProjectIds(); + const env = getClientEnvironment(projectIds); const basePlugins = [ new StaticSiteGeneratorPlugin({ entry: "ssr", paths: require("../src/homepage/routeData") - .makeRouteData(repoRegistry) + .makeRouteData(projectIds) .map(({path}) => path), locals: {}, }), diff --git a/scripts/build_static_site.sh b/scripts/build_static_site.sh index 8edc8c3..1ccdb4b 100755 --- a/scripts/build_static_site.sh +++ b/scripts/build_static_site.sh @@ -3,8 +3,8 @@ set -eu usage() { printf 'usage: build_static_site.sh --target TARGET\n' + printf ' [--project PROJECT [...]]\n' printf ' [--weights WEIGHTS_FILE]\n' - printf ' [--repo OWNER/NAME [...]]\n' printf ' [--cname DOMAIN]\n' printf ' [--no-backend]\n' printf ' [-h|--help]\n' @@ -13,12 +13,11 @@ usage() { printf '\n' printf '%s\n' '--target TARGET' printf '\t%s\n' 'an empty directory into which to build the site' + printf '%s\n' '--project PROJECT' + printf '\t%s\n' 'a project spec; see help for cli/load.js for details' printf '%s\n' '--weights WEIGHTS_FILE' printf '\t%s\n' 'path to a json file which contains a weights configuration.' printf '\t%s\n' 'This will be used instead of the default weights and persisted.' - printf '%s\n' '--repo OWNER/NAME' - printf '\t%s\n' 'a GitHub repository (e.g., torvalds/linux) for which' - printf '\t%s\n' 'to include example data' printf '%s\n' '--cname DOMAIN' printf '\t%s\n' 'configure DNS for a GitHub Pages site to point to' printf '\t%s\n' 'the provided custom domain' @@ -55,6 +54,7 @@ parse_args() { cname= weights= repos=( ) + projects=( ) while [ $# -gt 0 ]; do case "$1" in --target) @@ -73,10 +73,10 @@ parse_args() { if [ $# -eq 0 ]; then die 'missing value for --weights'; fi weights="$1" ;; - --repo) + --project) shift - if [ $# -eq 0 ]; then die 'missing value for --repo'; fi - repos+=( "$1" ) + if [ $# -eq 0 ]; then die 'missing value for --project'; fi + projects+=( "$1" ) ;; --cname) shift @@ -140,15 +140,14 @@ build() { yarn -s backend --output-path "${SOURCECRED_BIN}" fi - if [ "${#repos[@]}" -ne 0 ]; then + if [ "${#projects[@]}" -ne 0 ]; then local weightsStr="" if [ -n "${weights}" ]; then weightsStr="--weights ${weights}" fi - for repo in "${repos[@]}"; do - printf >&2 'info: loading repository: %s\n' "${repo}" + for project in "${projects[@]}"; do NODE_PATH="./node_modules${NODE_PATH:+:${NODE_PATH}}" \ - node "${SOURCECRED_BIN:-./bin}/sourcecred.js" load "${repo}" $weightsStr + node "${SOURCECRED_BIN:-./bin}/sourcecred.js" load "${project}" $weightsStr done fi diff --git a/sharness/__snapshots__/example-github-load/data/sourcecred/example-github/github/view.json.gz b/sharness/__snapshots__/example-github-load/data/sourcecred/example-github/github/view.json.gz deleted file mode 100644 index f9f5c531e12946d0f57911ef78abd70a1f7b5ffc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3279 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 && - grep -qF -- "missing value for --repo" err && +test_expect_success "should fail with missing project value" ' + test_must_fail run --target putative_output --project 2>err && + grep -qF -- "missing value for --project" err && printf "redacted\n" | test_cmp - important_dir/.wallet.dat ' @@ -98,8 +98,8 @@ test_expect_success "should fail with multiple cname values" ' ' # -# Now, actually generate output in two cases: one with repositories, and -# one with no repositories. We can only do this if we have a token. +# Now, actually generate output in two cases: one with projects, and +# one with no projects. We can only do this if we have a token. if [ -n "${SOURCECRED_GITHUB_TOKEN:-}" ]; then test_set_prereq HAVE_GITHUB_TOKEN @@ -114,7 +114,6 @@ run_build() { description="$1"; shift output_dir="build_output/output_${prereq_name}" api_dir="${output_dir}/api/v1/data" - data_dir="${api_dir}/data" unsafe_arg= for arg in "${output_dir}" "$@"; do unusual_chars="$(printf '%s' "$arg" | sed -e 's#[A-Za-z0-9:/_.-]##g')" @@ -133,7 +132,7 @@ run_build() { run '"${flags}"' >out 2>err && test_must_fail grep -vF \ -e "Removing contents of build directory: " \ - -e "info: loading repository" \ + -e "info: loading project" \ -e "DeprecationWarning: Tapable.plugin is deprecated." \ err && test_path_is_dir "${output_dir}" && @@ -193,63 +192,50 @@ test_pages() { ' } -run_build TWO_REPOS \ - "should build the site with two repositories and a CNAME" \ +run_build TWO_PROJECTS \ + "should build the site with two projects and a CNAME" \ --no-backend \ --cname sourcecred.example.com \ - --repo sourcecred/example-git \ - --repo sourcecred/example-github \ + --project sourcecred/example-git \ + --project sourcecred/example-github \ ; -test_pages TWO_REPOS +test_pages TWO_PROJECTS -test_expect_success TWO_REPOS \ - "TWO_REPOS: should have a registry with two repositories" ' - registry_file="${api_dir}/repositoryRegistry.json" && - test_path_is_file "${registry_file}" && - grep -oF "\"name\":" "${registry_file}" | wc -l >actual_count && - printf "2\n" | test_cmp - actual_count +test_expect_success TWO_PROJECTS \ + "TWO_PROJECTS: should have project ids loaded into env" ' + grep -F "PROJECT_IDS" out && + grep -xF "PROJECT_IDS: [\"sourcecred/example-git\",\"sourcecred/example-github\"]" out ' -test_expect_success TWO_REPOS \ - "TWO_REPOS: should have a repo registry loaded into env" ' - grep -F "REPO_REGISTRY" out && - grep -xF "REPO_REGISTRY: [{\"repoId\":{\"name\":\"example-git\",\"owner\":\"sourcecred\"}},{\"repoId\":{\"name\":\"example-github\",\"owner\":\"sourcecred\"}}]" out -' - -test_expect_success TWO_REPOS \ - "TWO_REPOS: should have data for the two repositories" ' - for repo in sourcecred/example-git sourcecred/example-github; do - for file in github/view.json.gz; do - test -s "${data_dir}/${repo}/${file}" || return - done +test_expect_success TWO_PROJECTS \ + "TWO_PROJECTS: should have data for the two projects" ' + # encoded ids for sourcecred/example-git and sourcecred/example-github + for id in c291cmNlY3JlZC9leGFtcGxlLWdpdA c291cmNlY3JlZC9leGFtcGxlLWdpdGh1Yg; do + test -s "${api_dir}/projects/${id}/cred.json" && + test -s "${api_dir}/projects/${id}/graph.json" || + return done ' -test_expect_success TWO_REPOS "TWO_REPOS: should have a correct CNAME record" ' +test_expect_success TWO_PROJECTS "TWO_PROJECTS: should have a correct CNAME record" ' test_path_is_file "${output_dir}/CNAME" && printf "sourcecred.example.com" | test_cmp - "${output_dir}/CNAME" ' -test_pages NO_REPOS +test_pages NO_PROJECTS -test_expect_success NO_REPOS \ - "NO_REPOS: should not have a repository registry" ' - registry_file="${api_dir}/repositoryRegistry.json" && - test_must_fail test -e "${registry_file}" -' - -test_expect_success NO_REPOS \ - "NO_REPOS: should have empty repo registry loaded into env" ' - grep -F "REPO_REGISTRY" out && - grep -xF "REPO_REGISTRY: []" out +test_expect_success NO_PROJECTS \ + "NO_REPOS: should have empty list of project ids loaded into env" ' + grep -F "PROJECT_IDS" out && + grep -xF "PROJECT_IDS: []" out ' test_expect_success NO_REPOS \ "NO_REPOS: should not have repository data" ' - for repo in sourcecred/example-git sourcecred/example-github; do - for file in git/graph.json github/view.json.gz; do - test_must_fail test -f "${data_dir}/${repo}/${file}" || return + for id in c291cmNlY3JlZC9leGFtcGxlLWdpdA== c291cmNlY3JlZC9leGFtcGxlLWdpdGh1Yg==; do + for file in graph.json cred.json; do + test_must_fail test -f "${api_dir}/projects/${id}/${file}" || return done done ' diff --git a/sharness/test_cli_scores.t b/sharness/test_cli_scores.t index d1bef51..b402d92 100755 --- a/sharness/test_cli_scores.t +++ b/sharness/test_cli_scores.t @@ -54,28 +54,28 @@ run_without_validation() ( test_expect_success SETUP "should print help message when called without args" ' test_must_fail run_without_validation scores && - grep -q "no repository ID provided" err && + grep -q "no project ID provided" err && grep -q "sourcecred help scores" err ' test_expect_success SETUP "help should print usage info" ' run help scores && - grep -q "usage: sourcecred scores REPO_ID" out + grep -q "usage: sourcecred scores PROJECT_ID" out ' test_expect_success SETUP "--help should print usage info" ' run scores --help && - grep -q "usage: sourcecred scores REPO_ID" out + grep -q "usage: sourcecred scores PROJECT_ID" out ' -test_expect_success SETUP "should fail for multiple repos" ' +test_expect_success SETUP "should fail for multiple projects" ' test_must_fail run_without_validation scores sourcecred/sourcecred torvalds/linux && - grep -q "fatal: multiple repository IDs provided" err + grep -q "fatal: multiple project IDs provided" err ' -test_expect_success SETUP "should fail for unloaded repo" ' +test_expect_success SETUP "should fail for unloaded project" ' test_must_fail run_without_validation scores torvalds/linux && - grep -q "fatal: repository ID torvalds/linux not loaded" err + grep -q "fatal: project torvalds/linux not loaded" err ' if [ -n "${UPDATE_SNAPSHOT}" ]; then diff --git a/src/cli/help.js b/src/cli/help.js index 835b151..bc6e815 100644 --- a/src/cli/help.js +++ b/src/cli/help.js @@ -4,7 +4,7 @@ import type {Command} from "./command"; import dedent from "../util/dedent"; -import {help as loadHelp} from "./deprecated_load"; +import {help as loadHelp} from "./load"; import {help as analyzeHelp} from "./analyze"; import {help as pagerankHelp} from "./pagerank"; import {help as scoresHelp} from "./scores"; diff --git a/src/cli/scores.js b/src/cli/scores.js index 1455611..ec6b518 100644 --- a/src/cli/scores.js +++ b/src/cli/scores.js @@ -4,8 +4,6 @@ import {toCompat, type Compatible} from "../util/compat"; import path from "path"; import fs from "fs-extra"; -import * as RepoIdRegistry from "../core/repoIdRegistry"; -import {repoIdToString, stringToRepoId, type RepoId} from "../core/repoId"; import dedent from "../util/dedent"; import type {Command} from "./command"; import * as Common from "./common"; @@ -18,25 +16,25 @@ import { import {DEFAULT_CRED_CONFIG} from "../plugins/defaultCredConfig"; import {userNodeType} from "../plugins/github/declaration"; import * as GN from "../plugins/github/nodes"; +import {directoryForProjectId} from "../core/project_io"; const COMPAT_INFO = {type: "sourcecred/cli/scores", version: "0.1.0"}; function usage(print: (string) => void): void { print( dedent`\ - usage: sourcecred scores REPO_ID [--help] + usage: sourcecred scores PROJECT_ID [--help] - Print the SourceCred user scores for a given REPO_ID. - Data must already be loaded for the given REPO_ID, using - 'sourcecred load REPO_ID' + Print the SourceCred user scores for a given PROJECT_ID. + Data must already be loaded for the given PROJECT_ID, using + 'sourcecred load PROJECT_ID' - REPO_ID refers to a GitHub repository in the form OWNER/NAME: for - example, torvalds/linux. The REPO_ID may be a "combined" repo as - created by the --output flag to sourcecred load. + PROJECT_ID refers to a project, as loaded by the \`load\` command. + Run \`sourcecred load --help\` for details. Arguments: - REPO_ID - Already-loaded repository for which to load data. + PROJECT_ID + Already-loaded project for which to load data. --help Show this help message and exit, as 'sourcecred help scores'. @@ -70,7 +68,7 @@ export type ScoreOutput = Compatible<{| |}>; export const scores: Command = async (args, std) => { - let repoId: RepoId | null = null; + let projectId: string | null = null; for (let i = 0; i < args.length; i++) { switch (args[i]) { case "--help": { @@ -78,33 +76,28 @@ export const scores: Command = async (args, std) => { return 0; } default: { - if (repoId != null) return die(std, "multiple repository IDs provided"); - // Should be a repository. - repoId = stringToRepoId(args[i]); + if (projectId != null) return die(std, "multiple project IDs provided"); + projectId = args[i]; break; } } } - if (repoId == null) { - return die(std, "no repository ID provided"); + if (projectId == null) { + return die(std, "no project ID provided"); } - const directory = Common.sourcecredDirectory(); - const registry = RepoIdRegistry.getRegistry(directory); - if (RepoIdRegistry.getEntry(registry, repoId) == null) { - const repoIdStr = repoIdToString(repoId); - std.err(`fatal: repository ID ${repoIdStr} not loaded`); - std.err(`Try running \`sourcecred load ${repoIdStr}\` first.`); + const projectDirectory = directoryForProjectId( + projectId, + Common.sourcecredDirectory() + ); + const credFile = path.join(projectDirectory, "cred.json"); + if (!fs.existsSync(credFile)) { + std.err(`fatal: project ${projectId} not loaded`); + std.err(`Try running \`sourcecred load ${projectId}\` first.`); return 1; } - const credFile = path.join( - Common.sourcecredDirectory(), - "data", - repoIdToString(repoId), - "cred.json" - ); const credBlob = await fs.readFile(credFile); const credJSON = JSON.parse(credBlob.toString()); const timelineCred = TimelineCred.fromJSON(credJSON, DEFAULT_CRED_CONFIG); diff --git a/src/cli/sourcecred.js b/src/cli/sourcecred.js index 04f4c1c..9e4dca1 100644 --- a/src/cli/sourcecred.js +++ b/src/cli/sourcecred.js @@ -6,7 +6,7 @@ import type {Command} from "./command"; import {VERSION_SHORT} from "../core/version"; import help from "./help"; -import load from "./deprecated_load"; +import load from "./load"; import analyze from "./analyze"; import pagerank from "./pagerank"; import scores from "./scores"; diff --git a/src/cli/sourcecred.test.js b/src/cli/sourcecred.test.js index be71741..144c2d0 100644 --- a/src/cli/sourcecred.test.js +++ b/src/cli/sourcecred.test.js @@ -12,7 +12,7 @@ function mockCommand(name) { } jest.mock("./help", () => mockCommand("help")); -jest.mock("./deprecated_load", () => mockCommand("load")); +jest.mock("./load", () => mockCommand("load")); jest.mock("./analyze", () => mockCommand("analyze")); jest.mock("./pagerank", () => mockCommand("pagerank")); jest.mock("./clear", () => mockCommand("clear")); diff --git a/src/explorer/TimelineApp.js b/src/explorer/TimelineApp.js index 0464743..777c74b 100644 --- a/src/explorer/TimelineApp.js +++ b/src/explorer/TimelineApp.js @@ -2,19 +2,19 @@ import React from "react"; import type {Assets} from "../webutil/assets"; -import type {RepoId} from "../core/repoId"; import {TimelineExplorer} from "./TimelineExplorer"; import {TimelineCred} from "../analysis/timeline/timelineCred"; import {declaration as githubDeclaration} from "../plugins/github/declaration"; import {DEFAULT_CRED_CONFIG} from "../plugins/defaultCredConfig"; +import {encodeProjectId, type ProjectId} from "../core/project"; export type Props = {| +assets: Assets, - +repoId: RepoId, + +projectId: string, +loader: Loader, |}; -export type Loader = (assets: Assets, repoId: RepoId) => Promise; +export type Loader = (assets: Assets, projectId: string) => Promise; export type LoadResult = Loading | LoadSuccess | LoadError; export type Loading = {|+type: "LOADING"|}; @@ -37,7 +37,7 @@ export class TimelineApp extends React.Component { async load() { const loadResult = await this.props.loader( this.props.assets, - this.props.repoId + this.props.projectId ); this.setState({loadResult}); } @@ -68,7 +68,7 @@ export class TimelineApp extends React.Component { return ( ); @@ -81,12 +81,12 @@ export class TimelineApp extends React.Component { export async function defaultLoader( assets: Assets, - repoId: RepoId + projectId: ProjectId ): Promise { async function fetchCred(): Promise { - const url = assets.resolve( - `api/v1/data/data/${repoId.owner}/${repoId.name}/cred.json` - ); + console.error(">>>DEFAULTLOADER"); + const encodedId = encodeProjectId(projectId); + const url = assets.resolve(`api/v1/data/projects/${encodedId}/cred.json`); const response = await fetch(url); if (!response.ok) { return Promise.reject(response); diff --git a/src/explorer/TimelineExplorer.js b/src/explorer/TimelineExplorer.js index 3faaea7..87bb050 100644 --- a/src/explorer/TimelineExplorer.js +++ b/src/explorer/TimelineExplorer.js @@ -2,7 +2,6 @@ import React from "react"; import deepEqual from "lodash.isequal"; -import {type RepoId} from "../core/repoId"; import {type PluginDeclaration} from "../analysis/pluginDeclaration"; import {type Weights, copy as weightsCopy} from "../analysis/weights"; import { @@ -14,7 +13,7 @@ import {WeightConfig} from "./weights/WeightConfig"; import {WeightsFileManager} from "./weights/WeightsFileManager"; export type Props = { - repoId: RepoId, + projectId: string, initialTimelineCred: TimelineCred, // TODO: Get this info from the TimelineCred declarations: $ReadOnlyArray, @@ -35,7 +34,7 @@ export type State = { * It basically wraps a TimelineCredView with some additional features and options: * - allows changing the weights and re-calculating cred with new weights * - allows saving/loading weights - * - displays the RepoId + * - displays the string */ export class TimelineExplorer extends React.Component { constructor(props: Props) { @@ -110,13 +109,12 @@ export class TimelineExplorer extends React.Component { re-compute cred ); - const {owner, name} = this.props.repoId; return (
- cred for {owner}/{name} - (legacy) + cred for {this.props.projectId} + (legacy)