Show all plugins' types in legacy ui (#1429)

This commit upgrades the legacy explorer to now properly include types
from all loaded plugins, rather than just the GitHub plugin. This makes
the legacy UI much more usable for inspecting SourceCred's own
(multi-plugin) cred.

Test plan: Manual inspection of the frontend. `yarn test` passes.

Part of https://discourse.sourcecred.io/t/fixup-legacy-explorer/316
This commit is contained in:
Dandelion Mané 2019-10-28 23:51:33 -06:00 committed by GitHub
parent 3754cafb7d
commit dfc7ee8524
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 62 deletions

View File

@ -8,7 +8,6 @@ import CheckedLocalStore from "../../webutil/checkedLocalStore";
import BrowserLocalStore from "../../webutil/browserLocalStore";
import Link from "../../webutil/Link";
import {type NodeAddressT} from "../../core/graph";
import {declaration as githubDeclaration} from "../../plugins/github/declaration";
import {PagerankTable} from "./pagerankTable/Table";
import {WeightConfig} from "../weights/WeightConfig";
@ -84,25 +83,6 @@ export function createApp(
render() {
const {appState} = this.state;
const weightConfig = (
<WeightConfig
declarations={[githubDeclaration]}
nodeTypeWeights={this.state.weights.nodeTypeWeights}
edgeTypeWeights={this.state.weights.edgeTypeWeights}
onNodeWeightChange={(prefix, weight) => {
this.setState(({weights}) => {
weights.nodeTypeWeights.set(prefix, weight);
return {weights};
});
}}
onEdgeWeightChange={(prefix, weight) => {
this.setState(({weights}) => {
weights.edgeTypeWeights.set(prefix, weight);
return {weights};
});
}}
/>
);
const weightFileManager = (
<WeightsFileManager
weights={this.state.weights}
@ -113,6 +93,26 @@ export function createApp(
);
let pagerankTable;
if (appState.type === "PAGERANK_EVALUATED") {
const declarations = appState.timelineCred.plugins();
const weightConfig = (
<WeightConfig
declarations={declarations}
nodeTypeWeights={this.state.weights.nodeTypeWeights}
edgeTypeWeights={this.state.weights.edgeTypeWeights}
onNodeWeightChange={(prefix, weight) => {
this.setState(({weights}) => {
weights.nodeTypeWeights.set(prefix, weight);
return {weights};
});
}}
onEdgeWeightChange={(prefix, weight) => {
this.setState(({weights}) => {
weights.edgeTypeWeights.set(prefix, weight);
return {weights};
});
}}
/>
);
const pnd = appState.pagerankNodeDecomposition;
pagerankTable = (
<PagerankTable
@ -120,7 +120,7 @@ export function createApp(
weightConfig={weightConfig}
weightFileManager={weightFileManager}
manualWeights={this.state.weights.nodeManualWeights}
declarations={[githubDeclaration]}
declarations={declarations}
graph={appState.timelineCred.graph()}
onManualWeightsChange={(addr: NodeAddressT, weight: number) =>
this.setState(({weights}) => {
@ -159,10 +159,6 @@ export function createApp(
this.stateTransitionMachine.loadTimelineCredAndRunPagerank(
this.props.assets,
this.state.weights,
{
nodeTypes: githubDeclaration.nodeTypes.slice(),
edgeTypes: githubDeclaration.edgeTypes.slice(),
},
GithubPrefix.user
)
}

View File

@ -5,7 +5,6 @@ import deepEqual from "lodash.isequal";
import {Graph, type NodeAddressT} from "../../core/graph";
import type {Assets} from "../../webutil/assets";
import {type EdgeEvaluator} from "../../analysis/pagerank";
import type {NodeAndEdgeTypes} from "../../analysis/types";
import {defaultLoader} from "../TimelineApp";
import {
type PagerankNodeDecomposition,
@ -16,6 +15,7 @@ import {TimelineCred} from "../../analysis/timeline/timelineCred";
import type {Weights} from "../../analysis/weights";
import {weightsToEdgeEvaluator} from "../../analysis/weightsToEdgeEvaluator";
import {combineTypes} from "../../analysis/pluginDeclaration";
/*
This models the UI states of the credExplorer/App as a state machine.
@ -69,11 +69,10 @@ export function createStateTransitionMachine(
// Exported for testing purposes.
export interface StateTransitionMachineInterface {
+loadTimelineCred: (Assets) => Promise<boolean>;
+runPagerank: (Weights, NodeAndEdgeTypes, NodeAddressT) => Promise<void>;
+runPagerank: (Weights, NodeAddressT) => Promise<void>;
+loadTimelineCredAndRunPagerank: (
Assets,
Weights,
NodeAndEdgeTypes,
NodeAddressT
) => Promise<void>;
}
@ -144,11 +143,7 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
return false;
}
async runPagerank(
weights: Weights,
types: NodeAndEdgeTypes,
totalScoreNodePrefix: NodeAddressT
) {
async runPagerank(weights: Weights, totalScoreNodePrefix: NodeAddressT) {
const state = this.getState();
if (
state.type !== "READY_TO_RUN_PAGERANK" &&
@ -164,6 +159,7 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
this.setState(loadingState);
const graph = state.timelineCred.graph();
let newState: ?AppState;
const types = combineTypes(state.timelineCred.plugins());
try {
const pagerankNodeDecomposition = await this.pagerank(
graph,
@ -196,7 +192,6 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
async loadTimelineCredAndRunPagerank(
assets: Assets,
weights: Weights,
types: NodeAndEdgeTypes,
totalScoreNodePrefix: NodeAddressT
) {
const state = this.getState();
@ -205,12 +200,12 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
case "READY_TO_LOAD_GRAPH":
const loadedTimelineCred = await this.loadTimelineCred(assets);
if (loadedTimelineCred) {
await this.runPagerank(weights, types, totalScoreNodePrefix);
await this.runPagerank(weights, totalScoreNodePrefix);
}
break;
case "READY_TO_RUN_PAGERANK":
case "PAGERANK_EVALUATED":
await this.runPagerank(weights, types, totalScoreNodePrefix);
await this.runPagerank(weights, totalScoreNodePrefix);
break;
default:
throw new Error((type: empty));

View File

@ -76,9 +76,6 @@ describe("explorer/legacy/state", () => {
function pagerankNodeDecomposition() {
return new Map();
}
function defaultTypes() {
return {nodeTypes: [], edgeTypes: []};
}
function loading(state: AppState) {
return state.loading;
}
@ -150,7 +147,7 @@ describe("explorer/legacy/state", () => {
const badState = readyToLoadGraph();
const {stm} = example(badState);
await expect(
stm.runPagerank(defaultWeights(), defaultTypes(), NodeAddress.empty)
stm.runPagerank(defaultWeights(), NodeAddress.empty)
).rejects.toThrow("incorrect state");
});
it("can be run when READY_TO_RUN_PAGERANK or PAGERANK_EVALUATED", async () => {
@ -159,11 +156,7 @@ describe("explorer/legacy/state", () => {
const {stm, getState, pagerankMock} = example(g);
const pnd = pagerankNodeDecomposition();
pagerankMock.mockReturnValue(Promise.resolve(pnd));
await stm.runPagerank(
defaultWeights(),
defaultTypes(),
NodeAddress.empty
);
await stm.runPagerank(defaultWeights(), NodeAddress.empty);
const state = getState();
if (state.type !== "PAGERANK_EVALUATED") {
throw new Error("Impossible");
@ -175,13 +168,13 @@ describe("explorer/legacy/state", () => {
it("immediately sets loading status", () => {
const {getState, stm} = example(readyToRunPagerank());
expect(loading(getState())).toBe("NOT_LOADING");
stm.runPagerank(defaultWeights(), defaultTypes(), NodeAddress.empty);
stm.runPagerank(defaultWeights(), NodeAddress.empty);
expect(loading(getState())).toBe("LOADING");
});
it("calls pagerank with the totalScoreNodePrefix option", async () => {
const {pagerankMock, stm} = example(readyToRunPagerank());
const foo = NodeAddress.fromParts(["foo"]);
await stm.runPagerank(defaultWeights(), defaultTypes(), foo);
await stm.runPagerank(defaultWeights(), foo);
const args = pagerankMock.mock.calls[0];
expect(args[2].totalScoreNodePrefix).toBe(foo);
});
@ -191,11 +184,7 @@ describe("explorer/legacy/state", () => {
// $ExpectFlowError
console.error = jest.fn();
pagerankMock.mockReturnValue(Promise.reject(error));
await stm.runPagerank(
defaultWeights(),
defaultTypes(),
NodeAddress.empty
);
await stm.runPagerank(defaultWeights(), NodeAddress.empty);
const state = getState();
expect(loading(state)).toBe("FAILED");
expect(state.type).toBe("READY_TO_RUN_PAGERANK");
@ -212,13 +201,12 @@ describe("explorer/legacy/state", () => {
stm.loadTimelineCred.mockResolvedValue(true);
const assets = new Assets("/gateway/");
const prefix = NodeAddress.fromParts(["bar"]);
const types = defaultTypes();
const wt = defaultWeights();
await stm.loadTimelineCredAndRunPagerank(assets, wt, types, prefix);
await stm.loadTimelineCredAndRunPagerank(assets, wt, prefix);
expect(stm.loadTimelineCred).toHaveBeenCalledTimes(1);
expect(stm.loadTimelineCred).toHaveBeenCalledWith(assets);
expect(stm.runPagerank).toHaveBeenCalledTimes(1);
expect(stm.runPagerank).toHaveBeenCalledWith(wt, types, prefix);
expect(stm.runPagerank).toHaveBeenCalledWith(wt, prefix);
});
it("does not run pagerank if loadTimelineCred did not succeed", async () => {
const {stm} = example(readyToLoadGraph());
@ -230,7 +218,6 @@ describe("explorer/legacy/state", () => {
await stm.loadTimelineCredAndRunPagerank(
assets,
defaultWeights(),
defaultTypes(),
prefix
);
expect(stm.loadTimelineCred).toHaveBeenCalledTimes(1);
@ -242,16 +229,14 @@ describe("explorer/legacy/state", () => {
(stm: any).runPagerank = jest.fn();
const prefix = NodeAddress.fromParts(["bar"]);
const wt = defaultWeights();
const types = defaultTypes();
await stm.loadTimelineCredAndRunPagerank(
new Assets("/gateway/"),
wt,
types,
prefix
);
expect(stm.loadTimelineCred).toHaveBeenCalledTimes(0);
expect(stm.runPagerank).toHaveBeenCalledTimes(1);
expect(stm.runPagerank).toHaveBeenCalledWith(wt, types, prefix);
expect(stm.runPagerank).toHaveBeenCalledWith(wt, prefix);
});
it("when PAGERANK_EVALUATED, runs pagerank", async () => {
const {stm} = example(pagerankEvaluated());
@ -259,16 +244,14 @@ describe("explorer/legacy/state", () => {
(stm: any).runPagerank = jest.fn();
const prefix = NodeAddress.fromParts(["bar"]);
const wt = defaultWeights();
const types = defaultTypes();
await stm.loadTimelineCredAndRunPagerank(
new Assets("/gateway/"),
wt,
types,
prefix
);
expect(stm.loadTimelineCred).toHaveBeenCalledTimes(0);
expect(stm.runPagerank).toHaveBeenCalledTimes(1);
expect(stm.runPagerank).toHaveBeenCalledWith(wt, types, prefix);
expect(stm.runPagerank).toHaveBeenCalledWith(wt, prefix);
});
});
});