Skip to content
Snippets Groups Projects
Commit b32fdb6a authored by Miłosz Grocholewski's avatar Miłosz Grocholewski
Browse files

chore: resolve merge conflicts

parents b62cb338 281a064f
No related branches found
No related tags found
1 merge request!295refactor(map): change view zoomFactor (zoom step)
Pipeline #97330 passed
Showing
with 118 additions and 50 deletions
minerva-front (19.0.0~alpha.0) stable; urgency=medium
* Feature: support for matomo (#289)
* Feature: allow plugin to not have a panel (#306)
-- Piotr Gawron <piotr.gawron@uni.lu> Fri, 18 Oct 2024 13:00:00 +0200
minerva-front (18.0.2) stable; urgency=medium
* Bug fix: Terms of Service modal is not hidden by Select project modal when
login via ORCID (#305)
* Bug fix: when downloading map there was missing spinner indicating the
download is in progress (#297)
-- Piotr Gawron <piotr.gawron@uni.lu> Wed, 30 Oct 2024 13:00:00 +0200
minerva-front (18.0.1) stable; urgency=medium
* Bug fix: show cookie baner only when cookie baner link is provided (#304)
* Bug fix: when link to submap is provided add submap name (#303)
* Bug fix: some old maps could not be opened (#311)
-- Piotr Gawron <piotr.gawron@uni.lu> Thu, 24 Oct 2024 13:00:00 +0200
......
......@@ -11,6 +11,7 @@ Your plugin should utilize the `window.minerva.plugins.registerPlugin` method fo
pluginName: string;
pluginVersion: string;
pluginUrl: string;
withoutPanel: boolean | undefined;
}
```
......@@ -21,6 +22,7 @@ window.minerva.plugins.registerPlugin({
pluginName: 'Your Plugin Name',
pluginVersion: '1.8.3',
pluginUrl: 'https://example.com/plugins/plugin.js',
withoutPanel: false,
});
```
......@@ -28,17 +30,17 @@ window.minerva.plugins.registerPlugin({
The `window.minerva.plugins.registerPlugin` method returns object with `element` property which is a DOM element, allowing your plugin to append its HTML content to the DOM. Use this element to create and modify the HTML structure of your plugin.
```
```javascript
// Plugin registration
const { element } = window.minerva.plugins.registerPlugin({
pluginName: "Your Plugin Name",
pluginVersion: "1.0.0",
pluginUrl: "your-plugin-url",
pluginName: 'Your Plugin Name',
pluginVersion: '1.0.0',
pluginUrl: 'your-plugin-url',
});
// Modify plugin's HTML structure
const yourContent = document.createElement('div');
yourContent.textContent = "Your Plugin Content";
yourContent.textContent = 'Your Plugin Content';
element.appendChild(yourContent);
```
......
......@@ -3,15 +3,12 @@ import { fitBounds } from '@/services/pluginsManager/map/fitBounds';
import { getOpenMapId } from '@/services/pluginsManager/map/getOpenMapId';
import { triggerSearch } from '@/services/pluginsManager/map/triggerSearch';
import { MinervaConfiguration } from '@/services/pluginsManager/pluginsManager';
import { MapInstance } from '@/types/map';
import { getModels } from '@/services/pluginsManager/map/models/getModels';
import { openMap } from '@/services/pluginsManager/map/openMap';
import { getCenter } from '@/services/pluginsManager/map/position/getCenter';
import { setCenter } from '@/services/pluginsManager/map/position/setCenter';
import { triggerSearch } from '@/services/pluginsManager/map/triggerSearch';
import { getZoom } from '@/services/pluginsManager/map/zoom/getZoom';
import { setZoom } from '@/services/pluginsManager/map/zoom/setZoom';
import { MinervaConfiguration } from '@/services/pluginsManager/pluginsManager';
import { getDisease } from '@/services/pluginsManager/project/data/getDisease';
import { getName } from '@/services/pluginsManager/project/data/getName';
import { getOrganism } from '@/services/pluginsManager/project/data/getOrganism';
......@@ -29,6 +26,7 @@ type Plugin = {
pluginName: string;
pluginVersion: string;
pluginUrl: string;
withoutPanel: boolean | undefined;
};
type RegisterPlugin = ({ pluginName, pluginVersion, pluginUrl }: Plugin) => {
......
......@@ -9,11 +9,9 @@ import {
getReduxWrapperWithStore,
} from '@/utils/testing/getReduxWrapperWithStore';
import { act, render, screen, within } from '@testing-library/react';
import { HISTAMINE_MAP_ID, MAIN_MAP_ID } from '@/constants/mocks';
import { MapNavigation } from './MapNavigation.component';
const MAIN_MAP_ID = 5053;
const HISTAMINE_MAP_ID = 5052;
const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
......
......@@ -3,7 +3,7 @@ import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
import { Button } from '@/shared/Button';
import { getSessionValid, logout, updateUser } from '@/redux/user/user.thunks';
import { closeModal } from '@/redux/modal/modal.slice';
import { closeModal, openSelectProjectModal } from '@/redux/modal/modal.slice';
import { userSelector } from '@/redux/user/user.selectors';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { termsOfServiceValSelector } from '@/redux/configuration/configuration.selectors';
......@@ -15,13 +15,14 @@ export const ToSModal: React.FC = () => {
const termsOfService = useAppSelector(termsOfServiceValSelector);
const updateUserTosHandler = async (): Promise<void> => {
// eslint-disable-next-line no-console
console.log('update');
if (userData) {
const user = { ...userData, termsOfUseConsent: true };
await dispatch(updateUser(user));
await dispatch(getSessionValid());
dispatch(closeModal());
if (userData.orcidId && userData.orcidId !== '') {
dispatch(openSelectProjectModal());
}
}
};
......
......@@ -16,7 +16,9 @@ export const LoadPlugin = ({ plugin }: Props): JSX.Element => {
hash: plugin.hash,
pluginUrl: plugin.urls[0],
onPluginLoaded: () => {
dispatch(setCurrentDrawerPluginHash(plugin.hash));
if (!plugin.withoutPanel) {
dispatch(setCurrentDrawerPluginHash(plugin.hash));
}
},
});
......
......@@ -3,7 +3,7 @@ import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { isActiveLegendSelector } from '@/redux/legend/legend.selectors';
import { removePluginLegend, setDefaultLegendId } from '@/redux/legend/legend.slice';
import {
allActivePluginsSelector,
allActivePluginsWithPanelSelector,
isPluginActiveSelector,
isPluginLoadingSelector,
isPluginSelectedSelector,
......@@ -42,12 +42,12 @@ export const useLoadPlugin = ({
const isPluginLoading = useAppSelector(state => isPluginLoadingSelector(state, hash));
const isPluginSelected = useAppSelector(state => isPluginSelectedSelector(state, hash));
const isActivePluginLegend = useAppSelector(state => isActiveLegendSelector(state, hash));
const allActivePlugins = useAppSelector(allActivePluginsSelector);
const allActivePluginsWithPanel = useAppSelector(allActivePluginsWithPanelSelector);
const dispatch = useAppDispatch();
const setLastPluginAsCurrentActivePlugin = (): void => {
const newAllActivePlugins = allActivePlugins.filter(p => p.hash !== hash);
const newAllActivePlugins = allActivePluginsWithPanel.filter(p => p.hash !== hash);
const lastActivePlugin = newAllActivePlugins.pop();
if (lastActivePlugin) {
dispatch(setCurrentDrawerPluginHash(lastActivePlugin.hash));
......
......@@ -19,7 +19,7 @@ export const AssociatedSubmap = (): React.ReactNode => {
data-testid="associated-submap"
className="flex flex-row flex-nowrap items-center justify-between"
>
<p>Associated Submap: </p>
<p>Associated Submap: {relatedSubmap.name}</p>
<Button className="max-h-8" variantStyles="ghost" onClick={openSubmap}>
Open submap
</Button>
......
......@@ -11,6 +11,7 @@ import {
} from '@/utils/testing/getReduxWrapperWithStore';
import { render, screen } from '@testing-library/react';
import { MockStoreEnhanced } from 'redux-mock-store';
import { HISTAMINE_MAP_ID, MAIN_MAP_ID, PRKN_SUBSTRATES_MAP_ID } from '@/constants/mocks';
import { BioEntitiesAccordion } from './BioEntitiesAccordion.component';
const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
......@@ -95,10 +96,22 @@ describe('BioEntitiesAccordion - component', () => {
},
});
expect(screen.getByText('Content (10)')).toBeInTheDocument();
expect(screen.getByText('Core PD map (2)')).toBeInTheDocument();
expect(screen.getByText('Histamine signaling (5)')).toBeInTheDocument();
expect(screen.getByText('PRKN substrates (3)')).toBeInTheDocument();
const countHistamine = bioEntitiesContentFixture.filter(
content => content.bioEntity.model === HISTAMINE_MAP_ID,
).length;
const countCore = bioEntitiesContentFixture.filter(
content => content.bioEntity.model === MAIN_MAP_ID,
).length;
const countPrkn = bioEntitiesContentFixture.filter(
content => content.bioEntity.model === PRKN_SUBSTRATES_MAP_ID,
).length;
const countAll = bioEntitiesContentFixture.length;
expect(screen.getByText(`Content (${countAll})`)).toBeInTheDocument();
expect(screen.getByText(`Core PD map (${countCore})`)).toBeInTheDocument();
expect(screen.getByText(`Histamine signaling (${countHistamine})`)).toBeInTheDocument();
expect(screen.getByText(`PRKN substrates (${countPrkn})`)).toBeInTheDocument();
});
it('should fire toggleIsContentTabOpened on accordion item button click', () => {
......
......@@ -62,6 +62,11 @@ const renderComponent = (
};
describe('PinsListItem - component ', () => {
drugsFixture[0].targets[0].targetParticipants[0].link = 'https://example.com/plugin.js';
drugsFixture[0].targets[0].targetParticipants[1].link = 'https://example.com/plugin.js';
chemicalsFixture[0].targets[0].targetParticipants[0].link = 'https://example.com/plugin.js';
chemicalsFixture[0].targets[0].targetParticipants[1].link = 'https://example.com/plugin.js';
it('should display full name of pin', () => {
renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs', BIO_ENTITY, INITIAL_STORE_STATE);
......
......@@ -2,18 +2,34 @@ import { formatsHandlersSelector } from '@/redux/configuration/configuration.sel
import { Button } from '@/shared/Button';
import { useSelect } from 'downshift';
import { useSelector } from 'react-redux';
import Image from 'next/image';
import spinnerIcon from '@/assets/vectors/icons/spinner.svg';
import { useState } from 'react';
import { downloadFileFromUrl } from '@/redux/export/export.utils';
import { SUBMAP_DOWNLOAD_HANDLERS_NAMES } from './DownloadSubmap.constants';
import { useGetSubmapDownloadUrl } from './utils/useGetSubmapDownloadUrl';
export const DownloadSubmap = (): JSX.Element => {
export const DownloadSubmap = (): React.ReactNode => {
const formatsHandlers = useSelector(formatsHandlersSelector);
const formatsHandlersItems = Object.entries(formatsHandlers);
const getSubmapDownloadUrl = useGetSubmapDownloadUrl();
const { isOpen, getToggleButtonProps, getMenuProps } = useSelect({
const [isDownloading, setIsDownloading] = useState<boolean>(false);
const { isOpen, getToggleButtonProps, getMenuProps, closeMenu } = useSelect({
items: formatsHandlersItems,
});
const downloadSubmap = (handler: string) => {
return function () {
closeMenu();
setIsDownloading(true);
downloadFileFromUrl(getSubmapDownloadUrl({ handler })).finally(function () {
setIsDownloading(false);
});
};
};
return (
<div className="relative">
<Button
......@@ -22,6 +38,15 @@ export const DownloadSubmap = (): JSX.Element => {
className="mr-4"
{...getToggleButtonProps()}
>
{isDownloading && (
<Image
src={spinnerIcon}
alt="spinner icon"
height={12}
width={12}
className="mr-5 animate-spin"
/>
)}
Download
</Button>
<ul
......@@ -34,14 +59,13 @@ export const DownloadSubmap = (): JSX.Element => {
{isOpen &&
formatsHandlersItems.map(([formatId, handler]) => (
<li key={formatId}>
<a
className="flex flex-col border-t px-4 py-2 shadow-sm"
href={getSubmapDownloadUrl({ handler })}
target="_blank"
download
<Button
variantStyles="ghost"
className="flex w-full flex-col border-t px-4 py-2 shadow-sm"
onClick={downloadSubmap(handler)}
>
<span>{SUBMAP_DOWNLOAD_HANDLERS_NAMES[formatId]}</span>
</a>
{SUBMAP_DOWNLOAD_HANDLERS_NAMES[formatId]}
</Button>
</li>
))}
</ul>
......
......@@ -8,10 +8,18 @@ export default function getCenter(coords: Array<Coordinate>): Coordinate {
let maxY = -Infinity;
coords.forEach(([x, y]) => {
if (x < minX) minX = x;
if (x > maxX) maxX = x;
if (y < minY) minY = y;
if (y > maxY) maxY = y;
if (x < minX) {
minX = x;
}
if (x > maxX) {
maxX = x;
}
if (y < minY) {
minY = y;
}
if (y > maxY) {
maxY = y;
}
});
const centerX = (minX + maxX) / 2;
......
......@@ -209,8 +209,6 @@ describe('handleAliasResults - util', () => {
'entityNumber/addNumbersToEntityNumberData',
'project/getBioEntityById/fulfilled',
'entityNumber/addNumbersToEntityNumberData',
'reactions/getByIds/pending',
'reactions/getByIds/fulfilled',
'project/getMultiBioEntity/fulfilled',
'drawer/selectTab',
'drawer/openBioEntityDrawerById',
......
......@@ -17,7 +17,9 @@ export const PluginHeaderInfo = ({ plugin }: Props): JSX.Element => {
hash: plugin.hash,
pluginUrl: plugin.urls[FIRST_ARRAY_ELEMENT],
onPluginLoaded: () => {
dispatch(setCurrentDrawerPluginHash(plugin.hash));
if (!plugin.withoutPanel) {
dispatch(setCurrentDrawerPluginHash(plugin.hash));
}
},
});
......
......@@ -19,7 +19,9 @@ export const LoadPluginElement = ({ plugin }: LoadPluginButtonProps): JSX.Elemen
hash,
pluginUrl: urls[FIRST_ARRAY_ELEMENT],
onPluginLoaded: () => {
dispatch(setCurrentDrawerPluginHash(hash));
if (!plugin.withoutPanel) {
dispatch(setCurrentDrawerPluginHash(hash));
}
},
});
......
......@@ -21,7 +21,9 @@ export const PluginSingleTab = ({ plugin }: Props): JSX.Element => {
});
const onPluginTabClick = (): void => {
dispatch(setCurrentDrawerPluginHash(plugin.hash));
if (!plugin.withoutPanel) {
dispatch(setCurrentDrawerPluginHash(plugin.hash));
}
};
const onPluginUnload = (event: React.MouseEvent<HTMLDivElement>): void => {
......
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { ZERO } from '@/constants/common';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { allActivePluginsSelector } from '@/redux/plugins/plugins.selectors';
import { allActivePluginsWithPanelSelector } from '@/redux/plugins/plugins.selectors';
import { useMemo } from 'react';
import { PluginSingleTab } from './PluginSingleTab';
export const PluginsTabs = (): JSX.Element => {
const allActivePlugins = useAppSelector(allActivePluginsSelector);
const allActivePlugins = useAppSelector(allActivePluginsWithPanelSelector);
const isPluginsEmpty = allActivePlugins.length === ZERO;
const pluginsTabs = allActivePlugins.map(plugin => (
......
// eslint-disable-next-line no-magic-numbers
export const MODEL_IDS_MOCK = [5052, 5053, 5054];
export const MAIN_MAP_ID = 5053;
export const HISTAMINE_MAP_ID = 5052;
export const PRKN_SUBSTRATES_MAP_ID = 5054;
export const MODEL_IDS_MOCK = [HISTAMINE_MAP_ID, MAIN_MAP_ID, PRKN_SUBSTRATES_MAP_ID];
......@@ -34,7 +34,7 @@ export const bioEntitySchema = z.object({
.number()
.optional()
.transform(height => height ?? ZERO),
visibilityLevel: z.string(),
visibilityLevel: z.string().nullable(),
transparencyLevel: z.string().nullable().optional(),
synonyms: z.array(z.string()),
formerSymbols: z.array(z.string()).nullable().optional(),
......@@ -46,13 +46,13 @@ export const bioEntitySchema = z.object({
activity: z.boolean().optional(),
structuralState: z.optional(structuralStateSchema.nullable()),
hypothetical: z.boolean().nullable().optional(),
boundaryCondition: z.boolean().optional(),
constant: z.boolean().optional(),
boundaryCondition: z.boolean().optional().nullable(),
constant: z.boolean().optional().nullable(),
initialAmount: z.number().nullable().optional(),
initialConcentration: z.number().nullable().optional(),
charge: z.number().nullable().optional(),
substanceUnits: z.string().nullable().optional(),
onlySubstanceUnits: z.boolean().optional(),
onlySubstanceUnits: z.boolean().optional().nullable(),
modificationResidues: z.optional(z.array(modificationResiduesSchema)),
complex: z.number().nullable().optional(),
compartment: z.number().nullable().optional(),
......
......@@ -32,7 +32,7 @@ export const compartmentPathwayDetailsSchema = z.object({
formula: z.null(),
fullName: z.string().nullable(),
glyph: z.any(),
hierarchyVisibilityLevel: z.string(),
hierarchyVisibilityLevel: z.string().nullable(),
homomultimer: z.null(),
hypothetical: z.null(),
id: z.number().gt(-1),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment