Skip to content

Commit

Permalink
Use the trigger field from track api payload to pass messages to geno…
Browse files Browse the repository at this point in the history
…me browser (#1019)
  • Loading branch information
azangru authored Sep 5, 2023
1 parent 95fbdcc commit 0945e69
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 53 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"coverage": "jest --coverage"
},
"dependencies": {
"@ensembl/ensembl-genome-browser": "0.6.6",
"@ensembl/ensembl-genome-browser": "0.6.7",
"@react-spring/web": "9.7.3",
"@reduxjs/toolkit": "1.9.5",
"@sentry/browser": "7.66.0",
Expand Down
43 changes: 36 additions & 7 deletions src/content/app/genome-browser/hooks/useGenomeBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,35 @@ import { GenomeBrowserContext } from 'src/content/app/genome-browser/contexts/Ge

import { useAppSelector } from 'src/store';
import { getBrowserActiveGenomeId } from 'src/content/app/genome-browser/state/browser-general/browserGeneralSelectors';
import { useGenomeTracksQuery } from 'src/content/app/genome-browser/state/api/genomeBrowserApiSlice';

import type { ChrLocation } from 'src/content/app/genome-browser/state/browser-general/browserGeneralSlice';
import type { GenomeTrackCategory } from 'src/content/app/genome-browser/state/types/tracks';

const useGenomeBrowser = () => {
const activeGenomeId = useAppSelector(getBrowserActiveGenomeId);
const useMandatoryGenomeBrowserContext = () => {
const genomeBrowserContext = useContext(GenomeBrowserContext);

if (!genomeBrowserContext) {
throw new Error(
'useGenomeBrowser must be used with GenomeBrowserContext Provider'
);
}

return genomeBrowserContext;
};

const useGenomeBrowser = () => {
const genomeBrowserContext = useMandatoryGenomeBrowserContext();
const activeGenomeId = useAppSelector(getBrowserActiveGenomeId);

const { currentData: trackCategories } = useGenomeTracksQuery(
activeGenomeId ?? '',
{
skip: !activeGenomeId
}
);

const trackIdToPathMap = getTrackIdToTrackPathMap(trackCategories ?? []);

const {
genomeBrowser,
genomeBrowserService,
Expand Down Expand Up @@ -130,10 +146,11 @@ const useGenomeBrowser = () => {
return;
}
const { trackId, isEnabled } = params;
const trackPath = trackIdToPathMap[trackId] ?? ['track', trackId];

genomeBrowserCommands.toggleTrack({
genomeBrowser,
trackId,
trackPath,
isEnabled
});
};
Expand All @@ -147,11 +164,14 @@ const useGenomeBrowser = () => {
if (!genomeBrowser) {
return;
}
const { trackId, setting, isEnabled } = params;
const trackPath = trackIdToPathMap[trackId] ?? ['track', trackId];

genomeBrowserCommands.toggleTrackSetting({
genomeBrowser,
trackId: params.trackId,
setting: params.setting,
isEnabled: params.isEnabled
trackPath,
setting,
isEnabled
});
};

Expand Down Expand Up @@ -183,4 +203,13 @@ const useGenomeBrowser = () => {
};
};

const getTrackIdToTrackPathMap = (trackCategories: GenomeTrackCategory[]) => {
const tracks = trackCategories.flatMap(({ track_list }) => track_list);

return tracks.reduce((accumulator, track) => {
accumulator[track.track_id] = track.trigger;
return accumulator;
}, {} as Record<string, string[]>);
};

export default useGenomeBrowser;
10 changes: 7 additions & 3 deletions src/content/app/genome-browser/hooks/useGenomeBrowserTracks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,17 @@ const prepareTrackSettings = ({

trackCategories.forEach((category) => {
category.track_list.forEach((track) => {
const { track_id } = track;
const { track_id, on_by_default } = track;
const trackType = getTrackType(track_id);

if (trackType === TrackType.GENE) {
defaultTrackSettings[track_id] = buildDefaultGeneTrack(track_id);
const trackSettings = buildDefaultGeneTrack(track_id);
trackSettings.settings.isVisible = on_by_default;
defaultTrackSettings[track_id] = trackSettings;
} else {
defaultTrackSettings[track_id] = buildDefaultRegularTrack(track_id);
const trackSettings = buildDefaultRegularTrack(track_id);
trackSettings.settings.isVisible = on_by_default;
defaultTrackSettings[track_id] = trackSettings;
}
});
});
Expand Down
5 changes: 3 additions & 2 deletions src/content/app/genome-browser/hooks/useGenomicTracks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,11 @@ const prepareTrackIdsList = (
): TrackIdsList => {
const trackIdsList = trackGroups
.flatMap(({ track_list }) => track_list)
.map(({ track_id }) => {
.map(({ track_id, on_by_default }) => {
const track = trackSettings[track_id];
const isVisibleTrack =
(track?.settings as { isVisible?: boolean })?.isVisible ?? true;
(track?.settings as { isVisible?: boolean })?.isVisible ??
on_by_default;
return {
trackId: track_id,
isEnabled: isVisibleTrack
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,26 +59,26 @@ export const setBrowserLocation = (payload: {

export const toggleTrack = (payload: {
genomeBrowser: EnsemblGenomeBrowser;
trackId: string;
trackPath: string[];
isEnabled: boolean;
}) => {
const { genomeBrowser, trackId, isEnabled } = payload;
genomeBrowser.switch(['track', trackId], isEnabled);
const { genomeBrowser, trackPath, isEnabled } = payload;
genomeBrowser.switch(trackPath, isEnabled);
};

// NOTE: this method can only handle boolean flags
export const toggleTrackSetting = (payload: {
genomeBrowser: EnsemblGenomeBrowser;
trackId: string;
trackPath: string[];
setting: string;
isEnabled: boolean;
}) => {
const { genomeBrowser, trackId, setting, isEnabled } = payload;
const { genomeBrowser, trackPath, setting, isEnabled } = payload;

if (trackId === 'focus-variant') {
if (trackPath.includes('focus-variant')) {
toggleFocusVariantTrackSetting(payload);
} else {
genomeBrowser.switch(['track', trackId, setting], isEnabled);
genomeBrowser.switch([...trackPath, setting], isEnabled);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,29 +104,6 @@ export const defaultTrackSettingsForGenome: TrackSettingsForGenome = {
settingsForIndividualTracks: {}
};

export const saveTrackSettingsForGenome = createAsyncThunk(
'genome-browser-track-settings/save-track-settings-for-genome',
async (genomeId: string, thunkAPI) => {
const state = thunkAPI.getState() as RootState;
const trackSettingsForGenome = getAllTrackSettingsForGenome(
state,
genomeId
);
if (!trackSettingsForGenome) {
return; // shouldn't happen
}

const trackSettingsArray = Object.values(
trackSettingsForGenome.settingsForIndividualTracks
);

await trackSettingsStorageService.updateTrackSettingsForGenome(
genomeId,
trackSettingsArray
);
}
);

export const updateTrackSettingsAndSave = createAsyncThunk(
'genome-browser-track-settings/update-track-settings-and-save',
async (
Expand Down
28 changes: 26 additions & 2 deletions src/content/app/genome-browser/state/types/tracks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,36 @@

import { TrackSet } from 'src/content/app/genome-browser/components/track-panel/trackPanelConfig';

/**
* NOTE ON THE TRIGGER FIELD ON THE GenomicTrack TYPE
*
* Tracks are stored in genome browser's memory in a tree-like structure,
* and a trigger is an array that represents the path to a given track node.
* Sadly, the client needs to be aware of this implementation detail,
* because it needs to use this trigger to toggle a track, or its settings
* (which are represented as tree nodes inside the track node) on and off.
*
* The contents of a trigger array for a given track are vaguely predictable,
* but not certain. For some tracks, the trigger to toggle the track on/off
* will be ["track", track_id]. For other tracks, it will be ["track", expansion_node, track_id].
* Since there is no way for the client to know which is which, it has
* to rely on track api to tell it.
*
* The content of trigger arrays for track settings is predictable,
* and consist of the contents of the track trigger followed by
* the name of the setting. Thus, triggers for settings can be generated
* on the client.
*/

export type GenomicTrack = {
colour: string; // NOTE: the backend will want to get rid of this field
label: string;
track_id: string;
trigger: string[]; // <-- see the note about triggers above
label: string;
colour: string; // NOTE: the backend will want to get rid of this field
additional_info: string;
description: string;
on_by_default: boolean;
display_order: number;
sources: Array<{
name: string;
url: string | null;
Expand Down
5 changes: 4 additions & 1 deletion tests/fixtures/genomes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,13 @@ export const createGenomeCategories = (): GenomeTrackCategory[] => [

const createTrack = (): GenomicTrack => {
return {
track_id: 'gene-pc-fwd',
trigger: ['track', 'gene-pc-fwd'],
additional_info: faker.lorem.words(),
colour: 'DARK_GREY',
label: faker.lorem.words(),
track_id: 'gene-pc-fwd',
on_by_default: true,
display_order: 1,
description: faker.lorem.sentence(),
sources: [
{
Expand Down

0 comments on commit 0945e69

Please sign in to comment.