diff --git a/src/APIInterface.mjs b/src/APIInterface.mjs
index 4e7b86ef..29c2e7f6 100644
--- a/src/APIInterface.mjs
+++ b/src/APIInterface.mjs
@@ -1,42 +1,46 @@
-
// Interface for handling function called from the tubemap frontend
// Abstract class expecting different implmentations of the following functions
-// Substituting different subclasses should allow the functions to give the same result
+// Substituting different subclasses should allow the functions to give the same result
export class APIInterface {
- // Takes in and process a tube map view(viewTarget) from the tubemap container
- // Expects a object to be returned with the necessary information to draw a tubemap from vg
- // object should contain keys: graph, gam, region, coloredNodes
- async getChunkedData(viewTarget) {
- throw new Error("getChunkedData function not implemented");
- }
+ // Takes in and process a tube map view(viewTarget) from the tubemap container.
+ // Expects a object to be returned with the necessary information to draw a tubemap from vg
+ // object should contain keys: graph, gam, region, coloredNodes.
+ // cancelSignal is an AbortSignal that can be used to cancel the request.
+ async getChunkedData(viewTarget, cancelSignal) {
+ throw new Error("getChunkedData function not implemented");
+ }
- // Returns files used to determine what options are available in the track picker
- // Returns object with keys: files, bedFiles
- async getFilenames() {
- throw new Error("getFilenames function not implemented");
- }
+ // Returns files used to determine what options are available in the track picker.
+ // Returns object with keys: files, bedFiles.
+ // cancelSignal is an AbortSignal that can be used to cancel the request.
+ async getFilenames(cancelSignal) {
+ throw new Error("getFilenames function not implemented");
+ }
- // Takes in a bedfile path or a url pointing to a raw bed file
- // Returns object with key: bedRegions
- // bedRegions contains information extrapolated from each line of the bedfile
- async getBedRegions(bedFile) {
- throw new Error("getBedRegions function not implemented");
- }
+ // Takes in a bedfile path or a url pointing to a raw bed file.
+ // Returns object with key: bedRegions.
+ // bedRegions contains information extrapolated from each line of the bedfile.
+ // cancelSignal is an AbortSignal that can be used to cancel the request.
+ async getBedRegions(bedFile, cancelSignal) {
+ throw new Error("getBedRegions function not implemented");
+ }
- // Takes in a graphFile path
- // Returns object with key: pathNames
- // Returns pathnames available in a graphfile
- async getPathNames(graphFile) {
- throw new Error("getPathNames function not implemented");
- }
+ // Takes in a graphFile path.
+ // Returns object with key: pathNames.
+ // Returns pathnames available in a graphfile.
+ // cancelSignal is an AbortSignal that can be used to cancel the request.
+ async getPathNames(graphFile, cancelSignal) {
+ throw new Error("getPathNames function not implemented");
+ }
- // Expects a bed file(or url) and a chunk name
- // Attempts to download tracks associated with the chunk name from the bed file if it is a URL
- // Returns object with key: tracks
- // Returns tracks found from local directories as a tracks object
- async getChunkTracks(bedFile, chunk) {
- throw new Error("getChunkTracks function not implemented");
- }
+ // Expects a bed file(or url) and a chunk name.
+ // Attempts to download tracks associated with the chunk name from the bed file if it is a URL.
+ // Returns object with key: tracks.
+ // Returns tracks found from local directories as a tracks object.
+ // cancelSignal is an AbortSignal that can be used to cancel the request.
+ async getChunkTracks(bedFile, chunk, cancelSignal) {
+ throw new Error("getChunkTracks function not implemented");
+ }
}
-export default APIInterface;
\ No newline at end of file
+export default APIInterface;
diff --git a/src/App.css b/src/App.css
index ae8188bd..aad9f671 100644
--- a/src/App.css
+++ b/src/App.css
@@ -126,7 +126,6 @@ input[type="file"] {
border-color: #b61515;
}
-
.btn-secondary {
background-color: #868e96;
border-color: #868e96;
@@ -218,7 +217,7 @@ input[type="file"] {
/* Close Popup */
-.closePopup{
+.closePopup {
align-items: center;
scale: 0.7;
border-radius: 50%;
diff --git a/src/App.js b/src/App.js
index d46f0dc5..2ebe9404 100644
--- a/src/App.js
+++ b/src/App.js
@@ -19,12 +19,11 @@ import ServerAPI from "./ServerAPI.mjs";
const EXAMPLE_TRACKS = [
// Fake tracks for the generated examples.
// TODO: Move over there.
- {"files": [{"type": "graph", "name": "fakeGraph"}]},
- {"files": [{"type": "read", "name": "fakeReads"}]}
+ { files: [{ type: "graph", name: "fakeGraph" }] },
+ { files: [{ type: "read", name: "fakeReads" }] },
];
function getColorSchemesFromTracks(tracks) {
-
let schemes = [];
for (const key in tracks) {
@@ -33,13 +32,13 @@ function getColorSchemesFromTracks(tracks) {
if (tracks[key].trackColorSettings !== undefined) {
schemes[key] = tracks[key].trackColorSettings;
} else if (tracks[key].trackType === "read") {
- schemes[key] = {...config.defaultReadColorPalette};
+ schemes[key] = { ...config.defaultReadColorPalette };
} else {
- schemes[key] = {...config.defaultHaplotypeColorPalette};
+ schemes[key] = { ...config.defaultHaplotypeColorPalette };
}
}
}
-
+
return schemes;
}
@@ -49,7 +48,7 @@ class App extends Component {
this.APIInterface = new ServerAPI(props.apiUrl);
- console.log('App component starting up with API URL: ' + props.apiUrl)
+ console.log("App component starting up with API URL: " + props.apiUrl);
// Set defaultViewTarget to either URL params (if present) or the first example
this.defaultViewTarget =
@@ -100,23 +99,21 @@ class App extends Component {
!isEqual(this.state.viewTarget, newViewTarget) ||
this.state.dataOrigin !== dataOriginTypes.API
) {
-
- console.log("Adopting view target: ", newViewTarget)
+ console.log("Adopting view target: ", newViewTarget);
this.setState((state) => {
// Make sure we have color schemes.
let newColorSchemes = getColorSchemesFromTracks(newViewTarget.tracks);
-
- console.log("Adopting color schemes: ", newColorSchemes)
+ console.log("Adopting color schemes: ", newColorSchemes);
return {
viewTarget: newViewTarget,
dataOrigin: dataOriginTypes.API,
visOptions: {
...state.visOptions,
- colorSchemes: newColorSchemes,
- }
+ colorSchemes: newColorSchemes,
+ },
};
});
}
@@ -150,21 +147,21 @@ class App extends Component {
// index is the index in the tracks array of the track to operate on. For now,
// haplotypes and paths are lumped together as track 0 here, with up to two
// tracks of reads afterward; eventually this will follow the indexing of the real
- // tracks array.
+ // tracks array.
//
// value is the value to set. For "mainPalette" and "auxPalette" this is the name
// of a color palette, such as "reds".
setColorSetting = (key, index, value) => {
this.setState((state) => {
- let newcolors = [...state.visOptions.colorSchemes]
+ let newcolors = [...state.visOptions.colorSchemes];
if (newcolors[index] === undefined) {
// Handle the set call from example data maybe coming before we set up any nonempty real tracks.
// TODO: Come up with a better way to do this.
- newcolors[index] = {...config.defaultReadColorPalette};
+ newcolors[index] = { ...config.defaultReadColorPalette };
}
- newcolors[index] = {...newcolors[index], [key]: value};
- console.log('Set index ' + index + ' key ' + key + ' to ' + value);
- console.log('New colors: ', newcolors);
+ newcolors[index] = { ...newcolors[index], [key]: value };
+ console.log("Set index " + index + " key " + key + " to " + value);
+ console.log("New colors: ", newcolors);
return {
visOptions: {
...state.visOptions,
@@ -175,7 +172,7 @@ class App extends Component {
};
setDataOrigin = (dataOrigin) => {
- this.setState({dataOrigin});
+ this.setState({ dataOrigin });
};
render() {
@@ -200,14 +197,18 @@ class App extends Component {
/>
-
+
);
}
diff --git a/src/App.test.js b/src/App.test.js
index c17ded16..8ec0a41c 100644
--- a/src/App.test.js
+++ b/src/App.test.js
@@ -8,7 +8,6 @@ import App from "./App";
import { fetchAndParse } from "./fetchAndParse";
-
// We want to be able to replace the `fetchAndParse` that *other* files see,
// and we want to use *different* implementations for different tests in this
// file. We can mock it with Jest, but Jest will move this call before the
@@ -17,12 +16,12 @@ import { fetchAndParse } from "./fetchAndParse";
// Register the given replacement function to be called instead of fetchAndParse.
function setFetchAndParseMock(replacement) {
- globalThis["__App.test.js_fetchAndParse_mock"] = replacement
+ globalThis["__App.test.js_fetchAndParse_mock"] = replacement;
}
// Remove any replacement function and go back to the real fetchAndParse.
function clearFetchAndParseMock() {
- globalThis["__App.test.js_fetchAndParse_mock"] = undefined
+ globalThis["__App.test.js_fetchAndParse_mock"] = undefined;
}
jest.mock("./fetchAndParse", () => {
@@ -31,14 +30,15 @@ jest.mock("./fetchAndParse", () => {
// Ge tthe real fetchAndParse
const { fetchAndParse } = jest.requireActual("./fetchAndParse");
// Grab the replacement or the real one if no replacement is set
- let functionToUse = globalThis["__App.test.js_fetchAndParse_mock"] ?? fetchAndParse;
+ let functionToUse =
+ globalThis["__App.test.js_fetchAndParse_mock"] ?? fetchAndParse;
// Give it any arguments we got and return its return value.
return functionToUse.apply(this, arguments);
- };
+ }
// When someone asks for this module, hand them these contents instead.
return {
__esModule: true,
- fetchAndParse: fetchAndParseDispatcher
+ fetchAndParse: fetchAndParseDispatcher,
};
});
diff --git a/src/ServerAPI.mjs b/src/ServerAPI.mjs
index cf7467ef..199aeede 100644
--- a/src/ServerAPI.mjs
+++ b/src/ServerAPI.mjs
@@ -1,72 +1,75 @@
import { fetchAndParse } from "./fetchAndParse.js";
import { APIInterface } from "./APIInterface.mjs";
+/**
+ * API implementation that uses vg running on the server to manipulate files.
+ */
export class ServerAPI extends APIInterface {
- constructor(apiUrl) {
- super();
- this.apiUrl = apiUrl;
- }
+ constructor(apiUrl) {
+ super();
+ this.apiUrl = apiUrl;
+ }
- // Each function takes a cancelSignal to cancel the fetch request if we will unmount component
+ // Each function takes a cancelSignal to cancel the fetch request if we will unmount component
- async getChunkedData(viewTarget, cancelSignal) {
- const json = await fetchAndParse(`${this.apiUrl}/getChunkedData`, {
- signal: cancelSignal,
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(viewTarget),
- });
- return json;
- }
+ async getChunkedData(viewTarget, cancelSignal) {
+ const json = await fetchAndParse(`${this.apiUrl}/getChunkedData`, {
+ signal: cancelSignal,
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(viewTarget),
+ });
+ return json;
+ }
- async getFilenames(cancelSignal) {
- const json = await fetchAndParse(`${this.apiUrl}/getFilenames`, {
- signal: cancelSignal,
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- },
- });
- return json;
- }
+ async getFilenames(cancelSignal) {
+ const json = await fetchAndParse(`${this.apiUrl}/getFilenames`, {
+ signal: cancelSignal,
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ return json;
+ }
- async getBedRegions(bedFile, cancelSignal) {
- const json = await fetchAndParse(`${this.apiUrl}/getBedRegions`, {
- signal: cancelSignal,
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ bedFile }),
- });
- return json;
- }
+ async getBedRegions(bedFile, cancelSignal) {
+ const json = await fetchAndParse(`${this.apiUrl}/getBedRegions`, {
+ signal: cancelSignal,
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ bedFile }),
+ });
+ return json;
+ }
- async getPathNames(graphFile, cancelSignal) {
- const json = await fetchAndParse(`${this.apiUrl}/getPathNames`, {
- signal: cancelSignal,
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ graphFile }),
- });
- return json
- }
+ async getPathNames(graphFile, cancelSignal) {
+ const json = await fetchAndParse(`${this.apiUrl}/getPathNames`, {
+ signal: cancelSignal,
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ graphFile }),
+ });
+ return json;
+ }
- async getChunkTracks(bedFile, chunk, cancelSignal) {
- const json = await fetchAndParse(`${this.apiUrl}/getChunkTracks`, {
- signal: cancelSignal,
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ bedFile: bedFile, chunk: chunk }),
- });
- return json;
- }
+ async getChunkTracks(bedFile, chunk, cancelSignal) {
+ const json = await fetchAndParse(`${this.apiUrl}/getChunkTracks`, {
+ signal: cancelSignal,
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ bedFile: bedFile, chunk: chunk }),
+ });
+ return json;
+ }
}
-export default ServerAPI;
\ No newline at end of file
+export default ServerAPI;
diff --git a/src/common.mjs b/src/common.mjs
index 233a9260..4b429d1c 100644
--- a/src/common.mjs
+++ b/src/common.mjs
@@ -4,12 +4,12 @@
// client, we CANNOT import config.json. It would require syntax on Node which
// is not allowed by the transpiler.
// So we get the cinfig a fancy way instead. But you *must* import config-client.js or config-server.,js before this file!
-import {config} from "./config-global.mjs";
+import { config } from "./config-global.mjs";
// function to remove commas from coordinate input
const removeCommas = (input) => {
let parts = input.split(":");
- if (parts.length < 2){
+ if (parts.length < 2) {
return input;
}
// get coordinate - numerical range after last colon
@@ -49,7 +49,7 @@ export function parseRegion(region) {
let start_end = region_col[region_col.length - 1].split("-");
let pos_dist = region_col[region_col.length - 1].split("+");
- let contig = region_col.slice(0, -1).join(':');
+ let contig = region_col.slice(0, -1).join(":");
if (start_end.length === 2) {
let start = Number(start_end[0]);
@@ -58,11 +58,10 @@ export function parseRegion(region) {
} else if (pos_dist.length === 2) {
let start = Number(pos_dist[0]);
let distance = Number(pos_dist[1]);
- return {contig, start, distance };
+ return { contig, start, distance };
} else {
throw new Error("Coordinates must be in the form 'X:Y-Z' or 'X:Y+Z'.");
}
-
}
/// Return a version of region that is {contig, start, end} even if region is {contig, start, distance}
@@ -72,7 +71,7 @@ export function convertRegionToRangeRegion(region) {
return {
contig: region.contig,
start: region.start,
- end: region.start + region.distance
+ end: region.start + region.distance,
};
} else {
// Should already have an end.
@@ -82,15 +81,15 @@ export function convertRegionToRangeRegion(region) {
// Take a { contig, start, end} region and turn it into a
// string compatible with parseRegion() or with vg.
-export function stringifyRangeRegion({contig, start, end}) {
- return contig.concat(':', start, '-', end);
+export function stringifyRangeRegion({ contig, start, end }) {
+ return contig.concat(":", start, "-", end);
}
// Take a {contig, start, end} or {contig, start, distance} region and turn it into a string compatible with parseRegion
export function stringifyRegion(region) {
if (region.distance !== undefined) {
// It is a distance-based region
- return region.contig.concat(':', region.start, '+', region.distance);
+ return region.contig.concat(":", region.start, "+", region.distance);
} else {
// It is a range region
return stringifyRangeRegion(region);
@@ -99,22 +98,22 @@ export function stringifyRegion(region) {
/* This function accepts a track type input and returns the default color scheme for that track type if the
track type is valid */
-export function defaultTrackColors(trackType){
- if (trackType === "graph"){
+export function defaultTrackColors(trackType) {
+ if (trackType === "graph") {
return config.defaultGraphColorPalette;
- } else if (trackType === "read"){
+ } else if (trackType === "read") {
return config.defaultReadColorPalette;
- } else if (trackType === "haplotype"){
+ } else if (trackType === "haplotype") {
return config.defaultHaplotypeColorPalette;
} else {
- throw new Error("Invalid track type: " + trackType);
+ throw new Error("Invalid track type: " + trackType);
}
}
/* Function to determine if any of the tracks are reads, where the tracks parameter is an object of track types */
-export function readsExist(tracks){
- for (let key in tracks){
- if (tracks[key].trackType === "read"){
+export function readsExist(tracks) {
+ for (let key in tracks) {
+ if (tracks[key].trackType === "read") {
return true;
}
}
@@ -129,8 +128,8 @@ export function isValidURL(string) {
let url;
try {
- url = new URL(string)
- } catch(error) {
+ url = new URL(string);
+ } catch (error) {
return false;
}
@@ -140,4 +139,3 @@ export function isValidURL(string) {
export function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
-
diff --git a/src/components/BedFileDropdown.demo.js b/src/components/BedFileDropdown.demo.js
index d69a23b6..1af4731c 100644
--- a/src/components/BedFileDropdown.demo.js
+++ b/src/components/BedFileDropdown.demo.js
@@ -1,28 +1,32 @@
-import Demo, {props as P} from 'react-demo'
+import Demo, { props as P } from "react-demo";
// See https://github.com/rpominov/react-demo for how to make a demo
import BedFileDropdown from "./BedFileDropdown";
// We want to two-way-bind the demo region prop so we use advanced mode and pass the render function.
-export default (
- {
- (props, update) => {
+export default (
+
+ {(props, update) => {
// We need to render the component under test using the props in props, and
// call update when the component wants to adjust the props.
- return {
- // Bind new value back up to value.
- // Remember: we get a fake event object with a "target" that has an "id" and a "value"
- update({value: fakeEvent.target.value})
- }}/>
- }
- }
-)
-
+ return (
+ {
+ // Bind new value back up to value.
+ // Remember: we get a fake event object with a "target" that has an "id" and a "value"
+ update({ value: fakeEvent.target.value });
+ }}
+ />
+ );
+ }}
+
+);
diff --git a/src/components/BedFileDropdown.js b/src/components/BedFileDropdown.js
index 02ab703f..d480dd40 100644
--- a/src/components/BedFileDropdown.js
+++ b/src/components/BedFileDropdown.js
@@ -1,19 +1,19 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
//import Select from "react-select";
-import CreatableSelect from 'react-select/creatable';
+import CreatableSelect from "react-select/creatable";
/**
* A searchable selection dropdown component.
* Expects a two-way-binding where "value" is the selected value (out of the
* array in "options"), and calling "onChange" with an event-like object
* updates the value.
- *
+ *
* The onChange argument is meant to look enough like a DOM change event on a
* "real"