Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • minerva/frontend
1 result
Show changes
Showing
with 356 additions and 15 deletions
import { GeneVariant } from '@/types/models';
export const GENE_VARIANTS_MOCK: GeneVariant[] = [
{
position: 162394349,
originalDna: 'G',
modifiedDna: 'A',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.162394349G>A:p.T240M',
variantIdentifier: 'rs137853054',
},
{
position: 161771219,
originalDna: 'G',
modifiedDna: 'A',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.161771219G>A:p.P437L',
variantIdentifier: 'rs149953814',
},
{
position: 162206852,
originalDna: 'G',
modifiedDna: 'A',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.162206852G>A:p.R275W',
variantIdentifier: 'rs34424986',
},
{
position: 162394349,
originalDna: 'G',
modifiedDna: 'C',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.162394349G>C:p.T240R',
variantIdentifier: 'rs137853054',
},
{
position: 161771171,
originalDna: 'C',
modifiedDna: 'T',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.161771171C>T:p.W453*',
variantIdentifier: 'rs137853056',
},
{
position: 162683694,
originalDna: 'G',
modifiedDna: 'A',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.162683694G>A:p.A92V',
variantIdentifier: 'rs566229879',
},
{
position: 162206914,
originalDna: 'T',
modifiedDna: 'C',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.162206914T>C:p.N254S',
variantIdentifier: 'rs139600787',
},
{
position: 162394349,
originalDna: 'G',
modifiedDna: 'C',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.162394349G>C:p.T240R',
variantIdentifier: 'rs137853054',
},
{
position: 162206825,
originalDna: 'C',
modifiedDna: 'G',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.162206825C>G:p.G284R',
variantIdentifier: 'rs751037529',
},
{
position: 162394338,
originalDna: 'C',
modifiedDna: 'T',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.162394338C>T:p.V244I',
variantIdentifier: 'rs771259513',
},
{
position: 161781201,
originalDna: 'G',
modifiedDna: 'A',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.161781201G>A:p.R402C',
variantIdentifier: 'rs55830907',
},
{
position: 162622239,
originalDna: 'G',
modifiedDna: 'C',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.162622239G>C:p.P153R',
variantIdentifier: 'rs55654276',
},
{
position: 161807855,
originalDna: 'C',
modifiedDna: 'G',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.161807855C>G:p.V380L',
variantIdentifier: 'rs1801582',
},
{
position: 161771237,
originalDna: 'C',
modifiedDna: 'A',
contig: 'chr6',
allelFrequency: 0.8,
aminoAcidChange: 'PRKN:NC_000006.11:g.161771237C>A:p.C431F',
variantIdentifier: 'rs397514694',
},
];
......@@ -5,7 +5,7 @@ export const PLUGINS_MOCK: MinervaPlugin[] = [
hash: '5e3fcb59588cc311ef9839feea6382eb',
name: 'Disease-variant associations',
version: '1.0.0',
isPublic: true,
isPublic: false,
isDefault: false,
urls: ['https://minerva-service.lcsb.uni.lu/plugins/disease-associations/plugin.js'],
},
......@@ -13,7 +13,7 @@ export const PLUGINS_MOCK: MinervaPlugin[] = [
hash: '20df86476c311824bbfe73d1034af89e',
name: 'GSEA',
version: '0.9.2',
isPublic: true,
isPublic: false,
isDefault: false,
urls: ['https://minerva-service.lcsb.uni.lu/plugins/gsea/plugin.js'],
},
......
import { z } from 'zod';
import { colorSchema } from './colorSchema';
import { geneVariant } from './geneVariant';
export const overlayRightBioEntitySchema = z.object({
id: z.number(),
......@@ -11,4 +12,5 @@ export const overlayRightBioEntitySchema = z.object({
value: z.number().nullable(),
color: colorSchema.nullable(),
description: z.string().nullable(),
geneVariants: z.array(geneVariant).optional().nullable(),
});
import { z } from 'zod';
import { publicationSchema } from './publicationsSchema';
export const publicationsResponseSchema = z.object({
data: z.array(publicationSchema),
totalSize: z.number(),
filteredSize: z.number(),
length: z.number(),
page: z.number(),
});
import { z } from 'zod';
import { targetElementSchema } from './targetElementSchema';
import { articleSchema } from './articleSchema';
export const publicationSchema = z.object({
elements: z.array(targetElementSchema),
publication: z.object({
article: articleSchema,
}),
});
import { PROJECT_ID } from '@/constants';
import { Point } from '@/types/map';
import { PerfectSearchParams } from '@/types/search';
import { GetPublicationsParams, PublicationsQueryParams } from './publications/publications.types';
const getPublicationsURLSearchParams = (
providedParams: PublicationsQueryParams,
): URLSearchParams => {
const params = new URLSearchParams();
const validProvidedParamsArray = Object.entries(providedParams).filter(([, value]) =>
Boolean(value),
);
validProvidedParamsArray.forEach(([key, value]) => {
params.append(key, value.toString());
});
return params;
};
export const apiPath = {
getBioEntityContentsStringWithQuery: ({
......@@ -63,6 +80,10 @@ export const apiPath = {
getSourceFile: (): string => `/projects/${PROJECT_ID}:downloadSource`,
getMesh: (meshId: string): string => `mesh/${meshId}`,
getTaxonomy: (taxonomyId: string): string => `taxonomy/${taxonomyId}`,
getPublications: ({ params, modelId = '*' }: GetPublicationsParams): string =>
`/projects/${PROJECT_ID}/models/${modelId}/publications/?${getPublicationsURLSearchParams(
params,
)}`,
registerPluign: (): string => `plugins/`,
getPlugin: (pluginId: string): string => `plugins/${pluginId}/`,
getAllPlugins: (): string => `/plugins/`,
......
......@@ -51,6 +51,12 @@ export const setOverviewImageIdReducer = (
};
};
export const openPublicationsModalReducer = (state: ModalState): void => {
state.isOpen = true;
state.modalName = 'publications';
state.modalTitle = 'Publications';
};
export const openEditOverlayModalReducer = (
state: ModalState,
action: OpenEditOverlayModalAction,
......
......@@ -7,6 +7,7 @@ import {
openOverviewImagesModalByIdReducer,
openMolArtModalByIdReducer,
setOverviewImageIdReducer,
openPublicationsModalReducer,
openEditOverlayModalReducer,
} from './modal.reducers';
......@@ -20,6 +21,7 @@ const modalSlice = createSlice({
openMolArtModalById: openMolArtModalByIdReducer,
setOverviewImageId: setOverviewImageIdReducer,
openLoginModal: openLoginModalReducer,
openPublicationsModal: openPublicationsModalReducer,
openEditOverlayModal: openEditOverlayModalReducer,
},
});
......@@ -31,6 +33,7 @@ export const {
setOverviewImageId,
openMolArtModalById,
openLoginModal,
openPublicationsModal,
openEditOverlayModal,
} = modalSlice.actions;
......
......@@ -17,6 +17,17 @@ export const modelsIdsSelector = createSelector(modelsDataSelector, models =>
models.map(model => model.idObject),
);
export const modelsNameMapSelector = createSelector(modelsDataSelector, models =>
models.reduce(
(acc, model) => ({ ...acc, [model.idObject]: model.name }),
{} as Record<number, string>,
),
);
export const modelsIdsAndNamesSelector = createSelector(modelsDataSelector, models =>
models.map(({ idObject, name }) => ({ id: idObject, name })),
);
export const currentModelIdSelector = createSelector(
currentModelSelector,
model => model?.idObject || MODEL_ID_DEFAULT,
......
import { OverlayBioEntityRender } from '@/types/OLrendering';
import { createSelector } from '@reduxjs/toolkit';
import { currentSearchedBioEntityId } from '../drawer/drawer.selectors';
import { currentModelIdSelector } from '../models/models.selectors';
import { overlaysDataSelector, overlaysIdsAndOrderSelector } from '../overlays/overlays.selectors';
import { rootSelector } from '../root/root.selectors';
......@@ -66,3 +67,20 @@ export const getOverlayOrderSelector = createSelector(
return calculateOvarlaysOrder(activeOverlaysIdsAndOrder);
},
);
export const overlaysOpenedIdsSelector = createSelector(
rootSelector,
state => state.overlayBioEntity.overlaysId,
);
export const overlaysOpenedSelector = createSelector(
overlaysDataSelector,
overlaysOpenedIdsSelector,
(data, ids) => data.filter(entity => ids.includes(entity.idObject)),
);
export const overlaysBioEntityForCurrentBioEntityAndCurrentModelSelector = createSelector(
overlayBioEntitiesForCurrentModelSelector,
currentSearchedBioEntityId,
(data, currentBioEntityId) => data.filter(entity => entity.id === currentBioEntityId),
);
......@@ -32,6 +32,7 @@ export const parseOverlayBioEntityToOlRenderingFormat = (
value: entity.right.value,
overlayId,
color: entity.right.color,
geneVariants: entity.right.geneVariants,
});
}
......
......@@ -10,4 +10,8 @@ export const PLUGINS_INITIAL_STATE: PluginsState = {
data: {},
pluginsId: [],
},
drawer: {
isOpen: false,
currentPluginHash: undefined,
},
};
import { DEFAULT_ERROR } from '@/constants/errors';
import { ActivePlugins, PluginsList, PluginsState } from './plugins.types';
import { ActivePlugins, PluginsDrawer, PluginsList, PluginsState } from './plugins.types';
export const PLUGINS_INITIAL_STATE_ACTIVE_PLUGINS_MOCK: ActivePlugins = {
data: {},
......@@ -12,7 +12,13 @@ export const PLUGINS_INITIAL_STATE_LIST_MOCK: PluginsList = {
error: DEFAULT_ERROR,
};
export const PLUGINS_INITIAL_STATE_DRAWER_MOCK: PluginsDrawer = {
isOpen: false,
currentPluginHash: undefined,
};
export const PLUGINS_INITIAL_STATE_MOCK: PluginsState = {
list: PLUGINS_INITIAL_STATE_LIST_MOCK,
activePlugins: PLUGINS_INITIAL_STATE_ACTIVE_PLUGINS_MOCK,
drawer: PLUGINS_INITIAL_STATE_DRAWER_MOCK,
};
import type { ActionReducerMapBuilder } from '@reduxjs/toolkit';
import type { PluginsState, RemovePluginAction } from './plugins.types';
import { registerPlugin, getAllPlugins } from './plugins.thunks';
import { getAllPlugins, registerPlugin } from './plugins.thunks';
import type {
PluginsState,
RemovePluginAction,
SetCurrentDrawerPluginHashAction,
} from './plugins.types';
export const removePluginReducer = (state: PluginsState, action: RemovePluginAction): void => {
const { pluginId } = action.payload;
......@@ -38,3 +42,18 @@ export const getAllPluginsReducer = (builder: ActionReducerMapBuilder<PluginsSta
// TODO to discuss manage state of failure
});
};
export const openPluginsDrawerReducer = (state: PluginsState): void => {
state.drawer.isOpen = true;
};
export const closePluginsDrawerReducer = (state: PluginsState): void => {
state.drawer.isOpen = false;
};
export const setCurrentDrawerPluginHashReducer = (
state: PluginsState,
action: SetCurrentDrawerPluginHashAction,
): void => {
state.drawer.currentPluginHash = action.payload;
};
import { createSelector } from '@reduxjs/toolkit';
import { MinervaPlugin } from '@/types/models';
import { createSelector } from '@reduxjs/toolkit';
import { rootSelector } from '../root/root.selectors';
export const pluginsSelector = createSelector(rootSelector, state => state.plugins);
......@@ -12,6 +12,10 @@ export const pluginsListDataSelector = createSelector(pluginsListSelector, plugi
return pluginsList.data;
});
export const pluginsDrawerSelector = createSelector(pluginsSelector, plugins => {
return plugins.drawer;
});
export const publicPluginsListSelector = createSelector(
pluginsListDataSelector,
pluginsListData => {
......@@ -65,3 +69,30 @@ export const isPluginLoadingSelector = createSelector(
({ data, pluginsId }, pluginId) =>
pluginsId.includes(pluginId) && data[pluginId] && !Object.keys(data[pluginId]).length,
);
export const currentDrawerPluginHashSelector = createSelector(
pluginsDrawerSelector,
drawer => drawer.currentPluginHash,
);
export const selectedDrawerPluginSelector = createSelector(
allActivePluginsSelector,
currentDrawerPluginHashSelector,
(allActivePlugins, currentDrawerPluginHash) =>
allActivePlugins.find(plugin => plugin.hash === currentDrawerPluginHash),
);
export const isPluginSelectedSelector = createSelector(
[selectedDrawerPluginSelector, (_, pluginHash: string): string => pluginHash],
(selectedPlugin, pluginHash) => selectedPlugin?.hash === pluginHash,
);
export const publicPluginsListWithoutActiveSelector = createSelector(
publicPluginsListSelector,
allActivePluginsSelector,
(publicPlugins, allActivePlugins) => {
const activePluginsHashes = allActivePlugins.map(p => p.hash);
return (publicPlugins || []).filter(plugin => !activePluginsHashes.includes(plugin.hash));
},
);
import { createSlice } from '@reduxjs/toolkit';
import {
closePluginsDrawerReducer,
getAllPluginsReducer,
openPluginsDrawerReducer,
registerPluginReducer,
removePluginReducer,
getAllPluginsReducer,
setCurrentDrawerPluginHashReducer,
} from './plugins.reducers';
import { PLUGINS_INITIAL_STATE } from './plugins.constants';
......@@ -12,6 +15,9 @@ const pluginsSlice = createSlice({
initialState: PLUGINS_INITIAL_STATE,
reducers: {
removePlugin: removePluginReducer,
openPluginsDrawer: openPluginsDrawerReducer,
closePluginsDrawer: closePluginsDrawerReducer,
setCurrentDrawerPluginHash: setCurrentDrawerPluginHashReducer,
},
extraReducers: builder => {
registerPluginReducer(builder);
......@@ -19,5 +25,6 @@ const pluginsSlice = createSlice({
},
});
export const { removePlugin } = pluginsSlice.actions;
export const { removePlugin, openPluginsDrawer, closePluginsDrawer, setCurrentDrawerPluginHash } =
pluginsSlice.actions;
export default pluginsSlice.reducer;
/* eslint-disable no-magic-numbers */
import axios from 'axios';
import { createAsyncThunk } from '@reduxjs/toolkit';
import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
import { pluginSchema } from '@/models/pluginSchema';
import type { MinervaPlugin } from '@/types/models';
import { axiosInstance } from '@/services/api/utils/axiosInstance';
import { z } from 'zod';
import type { MinervaPlugin } from '@/types/models';
import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
import { createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
import { apiPath } from '../apiPath';
type RegisterPlugin = {
......@@ -90,8 +89,10 @@ export const getAllPlugins = createAsyncThunk(
async (): Promise<MinervaPlugin[]> => {
const response = await axiosInstance.get<MinervaPlugin[]>(apiPath.getAllPlugins());
const isDataValid = validateDataUsingZodSchema(response.data, z.array(pluginSchema));
const isPluginDataValid = (pluginData: MinervaPlugin): boolean =>
validateDataUsingZodSchema(pluginData, pluginSchema);
const validPlugins = response.data.filter(isPluginDataValid);
return isDataValid ? response.data : [];
return validPlugins;
},
);
......@@ -14,7 +14,16 @@ export type ActivePlugins = {
};
};
export type PluginsDrawer = {
isOpen: boolean;
currentPluginHash?: string;
};
export type PluginsState = {
list: PluginsList;
activePlugins: ActivePlugins;
drawer: PluginsDrawer;
};
export type SetCurrentDrawerPluginHashPayload = string;
export type SetCurrentDrawerPluginHashAction = PayloadAction<SetCurrentDrawerPluginHashPayload>;
import { PublicationsState } from './publications.types';
export const PUBLICATIONS_INITIAL_STATE_MOCK: PublicationsState = {
loading: 'idle',
data: undefined,
error: { name: '', message: '' },
sortColumn: '',
sortOrder: 'asc',
searchValue: '',
selectedModelId: undefined,
};
import { ActionReducerMapBuilder, PayloadAction } from '@reduxjs/toolkit';
import { PublicationsState, SortColumn, SortOrder } from './publications.types';
import { getPublications } from './publications.thunks';
export const getPublicationsReducer = (
builder: ActionReducerMapBuilder<PublicationsState>,
): void => {
builder.addCase(getPublications.pending, state => {
state.loading = 'pending';
});
builder.addCase(getPublications.fulfilled, (state, action) => {
state.data = action.payload || undefined;
state.loading = 'succeeded';
});
builder.addCase(getPublications.rejected, state => {
state.loading = 'failed';
// TODO to discuss manage state of failure
});
};
export const setSortOrderAndColumnReducer = (
state: PublicationsState,
action: PayloadAction<{ sortOrder: SortOrder; sortColumn: SortColumn }>,
): void => {
state.sortColumn = action.payload.sortColumn;
state.sortOrder = action.payload.sortOrder;
};
export const setSelectedModelIdReducer = (
state: PublicationsState,
action: PayloadAction<string | undefined>,
): void => {
state.selectedModelId = action.payload;
};
export const setSearchValueReducer = (
state: PublicationsState,
action: PayloadAction<string>,
): void => {
state.searchValue = action.payload;
};