Skip to content
Snippets Groups Projects
Commit 9de97e5c authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge remote-tracking branch 'origin/main' into 131-min-194-display-user-grouped-overlays

parents 2465d9a6 9a8a69b2
No related branches found
No related tags found
1 merge request!380Resolve "[MIN-194] Display user grouped overlays"
...@@ -14,6 +14,13 @@ minerva-front (19.0.0~alpha.0) stable; urgency=medium ...@@ -14,6 +14,13 @@ minerva-front (19.0.0~alpha.0) stable; urgency=medium
-- Piotr Gawron <piotr.gawron@uni.lu> Fri, 18 Oct 2024 13:00:00 +0200 -- Piotr Gawron <piotr.gawron@uni.lu> Fri, 18 Oct 2024 13:00:00 +0200
minerva-front (18.1.1) stable; urgency=medium
* Bug fix: styling of notes reset only for a href (#334)
* Bug fix: disable searching for chemicals in projects without disease (#347)
* Bug fix: public overlays were not sorted (#349)
-- Piotr Gawron <piotr.gawron@uni.lu> Tue, 04 Feb 2025 16:00:00 +0200
minerva-front (18.1.0) stable; urgency=medium minerva-front (18.1.0) stable; urgency=medium
* Small improvement: support for links that should be opened immediately * Small improvement: support for links that should be opened immediately
(#342) (#342)
...@@ -22,7 +29,6 @@ minerva-front (18.1.0) stable; urgency=medium ...@@ -22,7 +29,6 @@ minerva-front (18.1.0) stable; urgency=medium
* Bug fix: submap download did not download selected map (#337) * Bug fix: submap download did not download selected map (#337)
* Bug fix: styling of notes contains original styling for links (#344) * Bug fix: styling of notes contains original styling for links (#344)
-- Piotr Gawron <piotr.gawron@uni.lu> Thu, 30 Jan 2025 15:00:00 +0200 -- Piotr Gawron <piotr.gawron@uni.lu> Thu, 30 Jan 2025 15:00:00 +0200
minerva-front (18.0.7) stable; urgency=medium minerva-front (18.0.7) stable; urgency=medium
......
...@@ -14,6 +14,8 @@ import { ...@@ -14,6 +14,8 @@ import {
MODEL_ELEMENT_LINKING_TO_SUBMAP, MODEL_ELEMENT_LINKING_TO_SUBMAP,
MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK,
} from '@/redux/modelElements/modelElements.mock'; } from '@/redux/modelElements/modelElements.mock';
import { projectFixture } from '@/models/fixtures/projectFixture';
import { PROJECT_STATE_INITIAL_MOCK } from '@/redux/project/project.mock';
import { BioEntityDrawer } from './BioEntityDrawer.component'; import { BioEntityDrawer } from './BioEntityDrawer.component';
const renderComponent = ( const renderComponent = (
...@@ -261,6 +263,13 @@ describe('BioEntityDrawer - component', () => { ...@@ -261,6 +263,13 @@ describe('BioEntityDrawer - component', () => {
it('should fetch chemicals on chemicals for target click', () => { it('should fetch chemicals on chemicals for target click', () => {
const { store } = renderComponent({ const { store } = renderComponent({
...INITIAL_STORE_STATE_MOCK,
project: {
data: projectFixture,
loading: 'succeeded',
error: { message: '', name: '' },
projectId: projectFixture.projectId,
},
modelElements: { modelElements: {
data: { data: {
0: { 0: {
...@@ -311,6 +320,10 @@ describe('BioEntityDrawer - component', () => { ...@@ -311,6 +320,10 @@ describe('BioEntityDrawer - component', () => {
chemicals: {}, chemicals: {},
}, },
}, },
project: {
...PROJECT_STATE_INITIAL_MOCK,
data: projectFixture,
},
}); });
const button = screen.getByText('Drugs for target', { exact: false }); const button = screen.getByText('Drugs for target', { exact: false });
......
...@@ -18,6 +18,8 @@ import { ...@@ -18,6 +18,8 @@ import {
currentDrawerModelElementRelatedSubmapSelector, currentDrawerModelElementRelatedSubmapSelector,
currentDrawerModelElementSelector, currentDrawerModelElementSelector,
} from '@/redux/modelElements/modelElements.selector'; } from '@/redux/modelElements/modelElements.selector';
import { projectDataSelector } from '@/redux/project/project.selectors';
import { showToast } from '@/utils/showToast';
import { CollapsibleSection } from '../ExportDrawer/CollapsibleSection'; import { CollapsibleSection } from '../ExportDrawer/CollapsibleSection';
import { AssociatedSubmap } from './AssociatedSubmap'; import { AssociatedSubmap } from './AssociatedSubmap';
import { ChemicalsList } from './ChemicalsList'; import { ChemicalsList } from './ChemicalsList';
...@@ -32,8 +34,18 @@ export const BioEntityDrawer = (): React.ReactNode => { ...@@ -32,8 +34,18 @@ export const BioEntityDrawer = (): React.ReactNode => {
const commentsData = useAppSelector(currentDrawerElementCommentsSelector); const commentsData = useAppSelector(currentDrawerElementCommentsSelector);
const relatedSubmap = useAppSelector(currentDrawerModelElementRelatedSubmapSelector); const relatedSubmap = useAppSelector(currentDrawerModelElementRelatedSubmapSelector);
const currentTargetId = modelElement?.id ? `${TARGET_PREFIX}:${modelElement.id}` : ''; const currentTargetId = modelElement?.id ? `${TARGET_PREFIX}:${modelElement.id}` : '';
const project = useAppSelector(projectDataSelector);
const fetchChemicalsForTarget = (): void => { const fetchChemicalsForTarget = (): void => {
dispatch(getChemicalsForBioEntityDrawerTarget(currentTargetId)); if (project === undefined || project.disease === null || project.disease === undefined) {
showToast({
type: 'info',
message: `Project disease not defined. Only projects with defined disease have chemical search available`,
});
} else {
dispatch(getChemicalsForBioEntityDrawerTarget(currentTargetId));
}
}; };
const compartmentName = useAppSelector(state => const compartmentName = useAppSelector(state =>
compartmentNameByIdSelector(state, modelElement?.compartment), compartmentNameByIdSelector(state, modelElement?.compartment),
...@@ -74,7 +86,7 @@ export const BioEntityDrawer = (): React.ReactNode => { ...@@ -74,7 +86,7 @@ export const BioEntityDrawer = (): React.ReactNode => {
</div> </div>
)} )}
{modelElement.notes && ( {modelElement.notes && (
<span className="visited:text-purple-600 text-blue-600 underline hover:text-blue-800"> <span className="[&_a]:text-blue-600 [&_a]:underline [&_a]:hover:text-blue-800">
<hr className="border-b border-b-divide" /> <hr className="border-b border-b-divide" />
<div <div
className="mt-2 text-sm font-normal" className="mt-2 text-sm font-normal"
......
...@@ -67,7 +67,7 @@ export const UserOverlaysGroup = ({ ...@@ -67,7 +67,7 @@ export const UserOverlaysGroup = ({
sideMenu={ sideMenu={
groupId && ( groupId && (
<button onClick={openEditGroup} type="button" className="mr-2"> <button onClick={openEditGroup} type="button" className="mr-2">
<Icon name="edit-image" /> <Icon name="pencil" />
</button> </button>
) )
} }
......
import { z } from 'zod';
export const disease = z.object({
id: z.number().int().positive(),
link: z.string().nullable(),
type: z.string(),
resource: z.string(),
annotatorClassName: z.string(),
});
// eslint-disable-next-line import/no-extraneous-dependencies // eslint-disable-next-line import/no-extraneous-dependencies
import { createFixture, Generator } from 'zod-fixture'; import { createFixture, Generator } from 'zod-fixture';
import { disease } from '@/models/disease';
import { ZOD_SEED } from '@/constants'; import { ZOD_SEED } from '@/constants';
import { ZodNullable } from 'zod'; import { ZodNullable } from 'zod';
import { referenceSchema } from '@/models/referenceSchema';
export const diseaseGenerator = Generator({ export const diseaseGenerator = Generator({
schema: ZodNullable, schema: ZodNullable,
...@@ -11,7 +11,7 @@ export const diseaseGenerator = Generator({ ...@@ -11,7 +11,7 @@ export const diseaseGenerator = Generator({
return context.path.at(-1) === 'disease'; return context.path.at(-1) === 'disease';
}, },
output: () => output: () =>
createFixture(disease, { createFixture(referenceSchema, {
seed: ZOD_SEED, seed: ZOD_SEED,
array: { min: 2, max: 2 }, array: { min: 2, max: 2 },
}), }),
......
import { z } from 'zod'; import { z } from 'zod';
import { licenseSchema } from '@/models/licenseSchema'; import { licenseSchema } from '@/models/licenseSchema';
import { disease } from './disease'; import { referenceSchema } from '@/models/referenceSchema';
import { organism } from './organism'; import { organism } from './organism';
import { overviewImageView } from './overviewImageView'; import { overviewImageView } from './overviewImageView';
export const projectSchema = z.object({ export const projectSchema = z.object({
id: z.number().int().nonnegative(), id: z.number().int().nonnegative(),
version: z.string(), version: z.string(),
disease: disease.nullable(), disease: referenceSchema.nullable(),
diseaseName: z.string().nullable(), diseaseName: z.string().nullable(),
organism: organism.nullable(), organism: organism.nullable(),
organismName: z.string().nullable(), organismName: z.string().nullable(),
......
...@@ -44,7 +44,9 @@ export const getAllPublicOverlaysByProjectId = createAsyncThunk<MapOverlay[], st ...@@ -44,7 +44,9 @@ export const getAllPublicOverlaysByProjectId = createAsyncThunk<MapOverlay[], st
pageableSchema(mapOverlaySchema), pageableSchema(mapOverlaySchema),
); );
return isDataValid ? response.data.content : []; return isDataValid
? response.data.content.sort((overlayA, overlayB) => overlayA.order - overlayB.order)
: [];
} catch (error) { } catch (error) {
return Promise.reject(getError({ error, prefix: OVERLAYS_FETCHING_ERROR_PREFIX })); return Promise.reject(getError({ error, prefix: OVERLAYS_FETCHING_ERROR_PREFIX }));
} }
......
...@@ -2,23 +2,32 @@ import { twMerge } from 'tailwind-merge'; ...@@ -2,23 +2,32 @@ import { twMerge } from 'tailwind-merge';
import { Icon } from '../Icon'; import { Icon } from '../Icon';
type ToastArgs = { type ToastArgs = {
type: 'success' | 'error'; type: 'success' | 'error' | 'info';
message: string; message: string;
onDismiss: () => void; onDismiss: () => void;
}; };
const textColors = {
error: 'text-red-500',
success: 'text-green-500',
info: 'text-blue-500',
};
const bgColors = {
error: 'before:bg-red-500',
success: 'before:bg-green-500',
info: 'before:bg-blue-500',
};
export const Toast = ({ type, message, onDismiss }: ToastArgs): React.ReactNode => ( export const Toast = ({ type, message, onDismiss }: ToastArgs): React.ReactNode => (
<div <div
className={twMerge( className={twMerge(
'flex h-[76px] w-[700px] items-center rounded-l rounded-r-lg bg-white p-4 drop-shadow before:absolute before:inset-y-0 before:left-0 before:block before:w-1 before:rounded-l-lg before:content-[""]', 'flex h-[76px] w-[700px] items-center rounded-l rounded-r-lg bg-white p-4 drop-shadow before:absolute before:inset-y-0 before:left-0 before:block before:w-1 before:rounded-l-lg before:content-[""]',
type === 'error' ? 'before:bg-red-500' : 'before:bg-green-500', bgColors[type],
)} )}
> >
<p <p
className={twMerge( className={twMerge('h-full overflow-y-auto text-base font-bold', textColors[type])}
'h-full overflow-y-auto text-base font-bold',
type === 'error' ? 'text-red-500' : 'text-green-500',
)}
dangerouslySetInnerHTML={{ __html: message }} dangerouslySetInnerHTML={{ __html: message }}
/> />
......
...@@ -4,7 +4,7 @@ import { Toast } from '@/shared/Toast'; ...@@ -4,7 +4,7 @@ import { Toast } from '@/shared/Toast';
const DEFAULT_DURATION_MS = 5000; const DEFAULT_DURATION_MS = 5000;
type ShowToastArgs = { type ShowToastArgs = {
type: 'success' | 'error'; type: 'success' | 'error' | 'info';
message: string; message: string;
duration?: number; duration?: number;
}; };
......
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