Skip to content
Snippets Groups Projects
Commit 60c77c63 authored by mateusz-winiarczyk's avatar mateusz-winiarczyk
Browse files

Merge branch 'MIN-153-select-type' into 'development'

feat(export): MIN-153 select type

See merge request !89
parents 5a7c99ce 5b324319
No related branches found
No related tags found
2 merge requests!223reset the pin numbers before search results are fetch (so the results will be...,!89feat(export): MIN-153 select type
Pipeline #83921 passed
Showing
with 563 additions and 43 deletions
...@@ -85,4 +85,25 @@ describe('CheckboxFilter - component', () => { ...@@ -85,4 +85,25 @@ describe('CheckboxFilter - component', () => {
expect(onCheckedChange).toHaveBeenCalledWith([]); expect(onCheckedChange).toHaveBeenCalledWith([]);
}); });
it('should render search input when isSearchEnabled is true', () => {
render(<CheckboxFilter options={options} />);
const searchInput = screen.getByLabelText('search-input');
expect(searchInput).toBeInTheDocument();
});
it('should not render search input when isSearchEnabled is false', () => {
render(<CheckboxFilter options={options} isSearchEnabled={false} />);
const searchInput = screen.queryByLabelText('search-input');
expect(searchInput).not.toBeInTheDocument();
});
it('should not filter options based on search input when isSearchEnabled is false', () => {
render(<CheckboxFilter options={options} isSearchEnabled={false} />);
const searchInput = screen.queryByLabelText('search-input');
expect(searchInput).not.toBeInTheDocument();
options.forEach(option => {
const checkboxLabel = screen.getByText(option.label);
expect(checkboxLabel).toBeInTheDocument();
});
});
}); });
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import Image from 'next/image'; import Image from 'next/image';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import lensIcon from '@/assets/vectors/icons/lens.svg'; import lensIcon from '@/assets/vectors/icons/lens.svg';
import { twMerge } from 'tailwind-merge';
type CheckboxItem = { id: string; label: string }; type CheckboxItem = { id: string; label: string };
...@@ -9,12 +10,14 @@ type CheckboxFilterProps = { ...@@ -9,12 +10,14 @@ type CheckboxFilterProps = {
options: CheckboxItem[]; options: CheckboxItem[];
onFilterChange?: (filteredItems: CheckboxItem[]) => void; onFilterChange?: (filteredItems: CheckboxItem[]) => void;
onCheckedChange?: (filteredItems: CheckboxItem[]) => void; onCheckedChange?: (filteredItems: CheckboxItem[]) => void;
isSearchEnabled?: boolean;
}; };
export const CheckboxFilter = ({ export const CheckboxFilter = ({
options, options,
onFilterChange, onFilterChange,
onCheckedChange, onCheckedChange,
isSearchEnabled = true,
}: CheckboxFilterProps): React.ReactNode => { }: CheckboxFilterProps): React.ReactNode => {
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [filteredOptions, setFilteredOptions] = useState<CheckboxItem[]>(options); const [filteredOptions, setFilteredOptions] = useState<CheckboxItem[]>(options);
...@@ -50,29 +53,37 @@ export const CheckboxFilter = ({ ...@@ -50,29 +53,37 @@ export const CheckboxFilter = ({
return ( return (
<div className="relative" data-testid="checkbox-filter"> <div className="relative" data-testid="checkbox-filter">
<div className="relative" data-testid="search"> {isSearchEnabled && (
<input <div className="relative" data-testid="search">
name="search-input" <input
aria-label="search-input" name="search-input"
value={searchTerm} aria-label="search-input"
onChange={handleSearchTermChange} value={searchTerm}
placeholder="Search..." onChange={handleSearchTermChange}
className="h-9 w-full rounded-[64px] border border-transparent bg-cultured px-4 py-2.5 text-xs font-medium text-font-400 outline-none hover:border-greyscale-600 focus:border-greyscale-600" placeholder="Search..."
/> className="h-9 w-full rounded-[64px] border border-transparent bg-cultured px-4 py-2.5 text-xs font-medium text-font-400 outline-none hover:border-greyscale-600 focus:border-greyscale-600"
/>
<Image <Image
src={lensIcon} src={lensIcon}
alt="lens icon" alt="lens icon"
height={16} height={16}
width={16} width={16}
className="absolute right-4 top-2.5" className="absolute right-4 top-2.5"
/> />
</div> </div>
<div className="my-6 max-h-[250px] overflow-y-auto py-2.5 pr-2.5 "> )}
<div
className={twMerge(
'mb-6 max-h-[300px] overflow-y-auto py-2.5 pr-2.5',
isSearchEnabled && 'mt-6',
)}
>
{filteredOptions.length === 0 ? ( {filteredOptions.length === 0 ? (
<p className="w-full text-sm text-font-400">No matching elements found.</p> <p className="w-full text-sm text-font-400">No matching elements found.</p>
) : ( ) : (
<ul className="columns-2 gap-8 "> <ul className="columns-2 gap-8">
{filteredOptions.map(option => ( {filteredOptions.map(option => (
<li key={option.id} className="mb-5 flex items-center gap-x-2"> <li key={option.id} className="mb-5 flex items-center gap-x-2">
<input <input
......
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { CollapsibleSection } from './CollapsibleSection.component';
describe('CollapsibleSection - component', () => {
it('should render with title and content', () => {
render(
<CollapsibleSection title="Section">
<div>Content</div>
</CollapsibleSection>,
);
expect(screen.getByText('Section')).toBeInTheDocument();
expect(screen.getByText('Content')).toBeInTheDocument();
});
it('should collapse and expands on button click', () => {
render(
<CollapsibleSection title="Test Section">
<div>Test Content</div>
</CollapsibleSection>,
);
const button = screen.getByText('Test Section');
const content = screen.getByText('Test Content');
expect(content).not.toBeVisible();
// Expand
fireEvent.click(button);
expect(content).toBeVisible();
// Collapse
fireEvent.click(button);
expect(content).not.toBeVisible();
});
});
import {
Accordion,
AccordionItem,
AccordionItemButton,
AccordionItemHeading,
AccordionItemPanel,
} from '@/shared/Accordion';
type CollapsibleSectionProps = {
title: string;
children: React.ReactNode;
};
export const CollapsibleSection = ({
title,
children,
}: CollapsibleSectionProps): React.ReactNode => (
<Accordion allowZeroExpanded>
<AccordionItem>
<AccordionItemHeading>
<AccordionItemButton>{title}</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel>{children}</AccordionItemPanel>
</AccordionItem>
</Accordion>
);
export { CollapsibleSection } from './CollapsibleSection.component';
import { render, screen, waitFor } from '@testing-library/react';
import {
InitialStoreState,
getReduxWrapperWithStore,
} from '@/utils/testing/getReduxWrapperWithStore';
import { StoreType } from '@/redux/store';
import { statisticsFixture } from '@/models/fixtures/statisticsFixture';
import { act } from 'react-dom/test-utils';
import { Annotations } from './Annotations.component';
const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
return (
render(
<Wrapper>
<Annotations />
</Wrapper>,
),
{
store,
}
);
};
describe('Annotations - component', () => {
it('should display annotations checkboxes when fetching data is successful', async () => {
renderComponent({
statistics: {
data: {
...statisticsFixture,
elementAnnotations: {
compartment: 1,
pathway: 0,
},
},
loading: 'succeeded',
error: {
message: '',
name: '',
},
},
});
expect(screen.queryByTestId('checkbox-filter')).not.toBeVisible();
const navigationButton = screen.getByTestId('accordion-item-button');
act(() => {
navigationButton.click();
});
expect(screen.getByText('Select annotations')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByTestId('checkbox-filter')).toBeInTheDocument();
expect(screen.getByLabelText('compartment')).toBeInTheDocument();
expect(screen.getByLabelText('search-input')).toBeInTheDocument();
});
});
it('should not display annotations checkboxes when fetching data fails', async () => {
renderComponent({
statistics: {
data: undefined,
loading: 'failed',
error: {
message: '',
name: '',
},
},
});
expect(screen.getByText('Select annotations')).toBeInTheDocument();
const navigationButton = screen.getByTestId('accordion-item-button');
act(() => {
navigationButton.click();
});
expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
});
it('should not display annotations checkboxes when fetched data is empty object', async () => {
renderComponent({
statistics: {
data: {
...statisticsFixture,
elementAnnotations: {},
},
loading: 'failed',
error: {
message: '',
name: '',
},
},
});
expect(screen.getByText('Select annotations')).toBeInTheDocument();
const navigationButton = screen.getByTestId('accordion-item-button');
act(() => {
navigationButton.click();
});
expect(screen.queryByTestId('checkbox-filter')).not.toBeInTheDocument();
});
it('should display loading message when fetching data is pending', async () => {
renderComponent({
statistics: {
data: undefined,
loading: 'pending',
error: {
message: '',
name: '',
},
},
});
expect(screen.getByText('Select annotations')).toBeInTheDocument();
const navigationButton = screen.getByTestId('accordion-item-button');
act(() => {
navigationButton.click();
});
expect(screen.getByText('Loading...')).toBeInTheDocument();
});
});
/* eslint-disable no-magic-numbers */
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import {
elementAnnotationsSelector,
loadingStatisticsSelector,
} from '@/redux/statistics/statistics.selectors';
import { CheckboxFilter } from '../../CheckboxFilter';
import { CollapsibleSection } from '../../CollapsibleSection';
export const Annotations = (): React.ReactNode => {
const loadingStatistics = useAppSelector(loadingStatisticsSelector);
const elementAnnotations = useAppSelector(elementAnnotationsSelector);
const isPending = loadingStatistics === 'pending';
const mappedElementAnnotations = elementAnnotations
? Object.keys(elementAnnotations)?.map(el => ({ id: el, label: el }))
: [];
return (
<CollapsibleSection title="Select annotations">
{isPending && <p>Loading...</p>}
{!isPending && mappedElementAnnotations && mappedElementAnnotations.length > 0 && (
<CheckboxFilter options={mappedElementAnnotations} />
)}
</CollapsibleSection>
);
};
export { Annotations } from './Annotations.component';
import { Types } from './Types';
import { Annotations } from '../Annotations'; import { Annotations } from '../Annotations';
export const Elements = (): React.ReactNode => { export const Elements = (): React.ReactNode => {
return ( return (
<div data-testid="elements-tab"> <div data-testid="elements-tab">
<Types />
<Annotations /> <Annotations />
</div> </div>
); );
......
import { render, screen } from '@testing-library/react';
import {
InitialStoreState,
getReduxWrapperWithStore,
} from '@/utils/testing/getReduxWrapperWithStore';
import { StoreType } from '@/redux/store';
import { Types } from './Types.component';
const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
return (
render(
<Wrapper>
<Types />
</Wrapper>,
),
{
store,
}
);
};
describe('Types Component', () => {
test('renders without crashing', () => {
renderComponent();
expect(screen.getByText('Select types')).toBeInTheDocument();
});
});
import { elementTypesSelector } from '@/redux/configuration/configuration.selectors';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { getCheckboxElements } from './Types.utils';
import { CheckboxFilter } from '../../CheckboxFilter';
import { CollapsibleSection } from '../../CollapsibleSection';
export const Types = (): React.ReactNode => {
const elementTypes = useAppSelector(elementTypesSelector);
const checkboxElements = getCheckboxElements(elementTypes);
return (
<CollapsibleSection title="Select types">
{checkboxElements && <CheckboxFilter options={checkboxElements} isSearchEnabled={false} />}
</CollapsibleSection>
);
};
import { getCheckboxElements } from './Types.utils';
describe('getCheckboxElements', () => {
it('should return an empty array when elementTypes is undefined', () => {
const result = getCheckboxElements(undefined);
expect(result).toEqual([]);
});
it('should map elementTypes to MappedElementTypes and exclude duplicates based on name and parentClass', () => {
const elementTypes = [
{ className: 'class1', name: 'type1', parentClass: 'parent1' },
{ className: 'class2', name: 'type2', parentClass: 'parent2' },
{ className: 'class1', name: 'type1', parentClass: 'parent1' },
{ className: 'class3', name: 'type3', parentClass: 'parent3' },
{ className: 'class2', name: 'type2', parentClass: 'parent2' },
];
const result = getCheckboxElements(elementTypes);
expect(result).toEqual([
{ id: 'type1', label: 'type1' },
{ id: 'type2', label: 'type2' },
{ id: 'type3', label: 'type3' },
]);
});
it('should handle an empty array of elementTypes', () => {
const result = getCheckboxElements([]);
expect(result).toEqual([]);
});
it('should return an empty array when elementTypes is undefined', () => {
const result = getCheckboxElements(undefined);
expect(result).toEqual([]);
});
});
type ElementTypes =
| {
className: string;
name: string;
parentClass: string;
}[]
| undefined;
type MappedElementTypes = { id: string; label: string }[];
type PresenceMap = { [key: string]: boolean };
export const getCheckboxElements = (elementTypes: ElementTypes): MappedElementTypes => {
if (!elementTypes) return [];
const excludedTypes: PresenceMap = {};
elementTypes?.forEach(type => {
excludedTypes[type.parentClass] = true;
});
const mappedElementTypes: MappedElementTypes = [];
const processedNames: PresenceMap = {};
elementTypes.forEach(elementType => {
if (excludedTypes[elementType.className] || processedNames[elementType.name]) return;
processedNames[elementType.name] = true;
mappedElementTypes.push({
id: elementType.name,
label: elementType.name,
});
});
return mappedElementTypes;
};
export { Types } from './Types.component';
import { z } from 'zod';
export const elementTypeSchema = z.object({
className: z.string(),
name: z.string(),
parentClass: z.string(),
});
export const optionSchema = z.object({
idObject: z.number(),
type: z.string(),
valueType: z.string(),
commonName: z.string(),
isServerSide: z.boolean(),
group: z.string(),
value: z.string().optional(),
});
export const imageFormatSchema = z.object({
name: z.string(),
handler: z.string(),
extension: z.string(),
});
export const modelFormatSchema = z.object({
name: z.string(),
handler: z.string(),
extension: z.string(),
});
export const overlayTypeSchema = z.object({ name: z.string() });
export const reactionTypeSchema = z.object({
className: z.string(),
name: z.string(),
parentClass: z.string(),
});
export const miriamTypesSchema = z.record(
z.string(),
z.object({
commonName: z.string(),
homepage: z.string().nullable(),
registryIdentifier: z.string().nullable(),
uris: z.array(z.string()),
}),
);
export const bioEntityFieldSchema = z.object({ commonName: z.string(), name: z.string() });
export const annotatorSchema = z.object({
className: z.string(),
name: z.string(),
description: z.string(),
url: z.string(),
elementClassNames: z.array(z.string()),
parameters: z.array(
z.object({
field: z.string().nullable().optional(),
annotation_type: z.string().nullable().optional(),
order: z.number(),
type: z.string(),
}),
),
});
export const privilegeTypeSchema = z.record(
z.string(),
z.object({
commonName: z.string(),
objectType: z.string().nullable(),
valueType: z.string(),
}),
);
export const mapTypeSchema = z.object({ name: z.string(), id: z.string() });
export const mapCanvasTypeSchema = z.object({ name: z.string(), id: z.string() });
export const unitTypeSchema = z.object({ name: z.string(), id: z.string() });
export const modificationStateTypeSchema = z.record(
z.string(),
z.object({ commonName: z.string(), abbreviation: z.string() }),
);
export const configurationSchema = z.object({
elementTypes: z.array(elementTypeSchema),
options: z.array(optionSchema),
imageFormats: z.array(imageFormatSchema),
modelFormats: z.array(modelFormatSchema),
overlayTypes: z.array(overlayTypeSchema),
reactionTypes: z.array(reactionTypeSchema),
miriamTypes: miriamTypesSchema,
bioEntityFields: z.array(bioEntityFieldSchema),
version: z.string(),
buildDate: z.string(),
gitHash: z.string(),
annotators: z.array(annotatorSchema),
privilegeTypes: privilegeTypeSchema,
mapTypes: z.array(mapTypeSchema),
mapCanvasTypes: z.array(mapCanvasTypeSchema),
unitTypes: z.array(unitTypeSchema),
modificationStateTypes: modificationStateTypeSchema,
});
...@@ -32,6 +32,7 @@ export const apiPath = { ...@@ -32,6 +32,7 @@ export const apiPath = {
getSessionValid: (): string => `users/isSessionValid`, getSessionValid: (): string => `users/isSessionValid`,
postLogin: (): string => `doLogin`, postLogin: (): string => `doLogin`,
getConfigurationOptions: (): string => 'configuration/options/', getConfigurationOptions: (): string => 'configuration/options/',
getConfiguration: (): string => 'configuration/',
getOverlayBioEntity: ({ overlayId, modelId }: { overlayId: number; modelId: number }): string => getOverlayBioEntity: ({ overlayId, modelId }: { overlayId: number; modelId: number }): string =>
`projects/${PROJECT_ID}/overlays/${overlayId}/models/${modelId}/bioEntities/`, `projects/${PROJECT_ID}/overlays/${overlayId}/models/${modelId}/bioEntities/`,
getStatisticsById: (projectId: string): string => `projects/${projectId}/statistics/`, getStatisticsById: (projectId: string): string => `projects/${projectId}/statistics/`,
......
...@@ -2,6 +2,7 @@ import { DEFAULT_ERROR } from '@/constants/errors'; ...@@ -2,6 +2,7 @@ import { DEFAULT_ERROR } from '@/constants/errors';
import { Loading } from '@/types/loadingState'; import { Loading } from '@/types/loadingState';
import { ConfigurationOption } from '@/types/models'; import { ConfigurationOption } from '@/types/models';
import { createEntityAdapter } from '@reduxjs/toolkit'; import { createEntityAdapter } from '@reduxjs/toolkit';
import { ConfigurationMainState } from './configuration.types';
export const configurationAdapter = createEntityAdapter<ConfigurationOption>({ export const configurationAdapter = createEntityAdapter<ConfigurationOption>({
selectId: option => option.type, selectId: option => option.type,
...@@ -12,7 +13,14 @@ const REQUEST_INITIAL_STATUS: { loading: Loading; error: Error } = { ...@@ -12,7 +13,14 @@ const REQUEST_INITIAL_STATUS: { loading: Loading; error: Error } = {
error: DEFAULT_ERROR, error: DEFAULT_ERROR,
}; };
export const CONFIGURATION_INITIAL_STATE = const MAIN_CONFIGURATION_INITIAL_STATE: ConfigurationMainState = {
configurationAdapter.getInitialState(REQUEST_INITIAL_STATUS); data: undefined,
...REQUEST_INITIAL_STATUS,
};
export const CONFIGURATION_INITIAL_STATE = {
options: configurationAdapter.getInitialState(REQUEST_INITIAL_STATUS),
main: MAIN_CONFIGURATION_INITIAL_STATE,
};
export type ConfigurationState = typeof CONFIGURATION_INITIAL_STATE; export type ConfigurationState = typeof CONFIGURATION_INITIAL_STATE;
...@@ -7,21 +7,35 @@ import { ...@@ -7,21 +7,35 @@ import {
import { ConfigurationState } from './configuration.adapter'; import { ConfigurationState } from './configuration.adapter';
export const CONFIGURATION_INITIAL_STORE_MOCK: ConfigurationState = { export const CONFIGURATION_INITIAL_STORE_MOCK: ConfigurationState = {
ids: [], options: {
entities: {}, ids: [],
loading: 'idle', entities: {},
error: DEFAULT_ERROR, loading: 'idle',
error: DEFAULT_ERROR,
},
main: {
data: undefined,
loading: 'idle',
error: DEFAULT_ERROR,
},
}; };
/** IMPORTANT MOCK IDS MUST MATCH KEYS IN ENTITIES */ /** IMPORTANT MOCK IDS MUST MATCH KEYS IN ENTITIES */
export const CONFIGURATION_INITIAL_STORE_MOCKS: ConfigurationState = { export const CONFIGURATION_INITIAL_STORE_MOCKS: ConfigurationState = {
ids: CONFIGURATION_OPTIONS_TYPES_MOCK, options: {
entities: { ids: CONFIGURATION_OPTIONS_TYPES_MOCK,
[CONFIGURATION_OPTIONS_TYPES_MOCK[0]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[0], entities: {
[CONFIGURATION_OPTIONS_TYPES_MOCK[1]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[1], [CONFIGURATION_OPTIONS_TYPES_MOCK[0]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[0],
[CONFIGURATION_OPTIONS_TYPES_MOCK[2]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[2], [CONFIGURATION_OPTIONS_TYPES_MOCK[1]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[1],
[CONFIGURATION_OPTIONS_TYPES_MOCK[3]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[3], [CONFIGURATION_OPTIONS_TYPES_MOCK[2]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[2],
[CONFIGURATION_OPTIONS_TYPES_MOCK[3]]: CONFIGURATION_OPTIONS_COLOURS_MOCK[3],
},
loading: 'idle',
error: DEFAULT_ERROR,
},
main: {
data: undefined,
loading: 'idle',
error: DEFAULT_ERROR,
}, },
loading: 'idle',
error: DEFAULT_ERROR,
}; };
import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
import { getConfigurationOptions } from './configuration.thunks'; import { getConfiguration, getConfigurationOptions } from './configuration.thunks';
import { ConfigurationState, configurationAdapter } from './configuration.adapter'; import { ConfigurationState, configurationAdapter } from './configuration.adapter';
export const getConfigurationOptionsReducer = ( export const getConfigurationOptionsReducer = (
builder: ActionReducerMapBuilder<ConfigurationState>, builder: ActionReducerMapBuilder<ConfigurationState>,
): void => { ): void => {
builder.addCase(getConfigurationOptions.pending, state => { builder.addCase(getConfigurationOptions.pending, state => {
state.loading = 'pending'; state.options.loading = 'pending';
}); });
builder.addCase(getConfigurationOptions.fulfilled, (state, action) => { builder.addCase(getConfigurationOptions.fulfilled, (state, action) => {
if (action.payload) { if (action.payload) {
state.loading = 'succeeded'; state.options.loading = 'succeeded';
configurationAdapter.addMany(state, action.payload); configurationAdapter.addMany(state.options, action.payload);
} }
}); });
builder.addCase(getConfigurationOptions.rejected, state => { builder.addCase(getConfigurationOptions.rejected, state => {
state.loading = 'failed'; state.options.loading = 'failed';
// TODO to discuss manage state of failure
});
};
export const getConfigurationReducer = (
builder: ActionReducerMapBuilder<ConfigurationState>,
): void => {
builder.addCase(getConfiguration.pending, state => {
state.main.loading = 'pending';
});
builder.addCase(getConfiguration.fulfilled, (state, action) => {
state.main.loading = 'succeeded';
state.main.data = action.payload;
});
builder.addCase(getConfiguration.rejected, state => {
state.main.loading = 'failed';
// TODO to discuss manage state of failure // TODO to discuss manage state of failure
}); });
}; };
...@@ -10,30 +10,41 @@ import { ...@@ -10,30 +10,41 @@ import {
} from './configuration.constants'; } from './configuration.constants';
const configurationSelector = createSelector(rootSelector, state => state.configuration); const configurationSelector = createSelector(rootSelector, state => state.configuration);
const configurationOptionsSelector = createSelector(configurationSelector, state => state.options);
const configurationAdapterSelectors = configurationAdapter.getSelectors(); const configurationAdapterSelectors = configurationAdapter.getSelectors();
export const minColorValSelector = createSelector( export const minColorValSelector = createSelector(
configurationSelector, configurationOptionsSelector,
state => configurationAdapterSelectors.selectById(state, MIN_COLOR_VAL_NAME_ID)?.value, state => configurationAdapterSelectors.selectById(state, MIN_COLOR_VAL_NAME_ID)?.value,
); );
export const maxColorValSelector = createSelector( export const maxColorValSelector = createSelector(
configurationSelector, configurationOptionsSelector,
state => configurationAdapterSelectors.selectById(state, MAX_COLOR_VAL_NAME_ID)?.value, state => configurationAdapterSelectors.selectById(state, MAX_COLOR_VAL_NAME_ID)?.value,
); );
export const neutralColorValSelector = createSelector( export const neutralColorValSelector = createSelector(
configurationSelector, configurationOptionsSelector,
state => configurationAdapterSelectors.selectById(state, NEUTRAL_COLOR_VAL_NAME_ID)?.value, state => configurationAdapterSelectors.selectById(state, NEUTRAL_COLOR_VAL_NAME_ID)?.value,
); );
export const overlayOpacitySelector = createSelector( export const overlayOpacitySelector = createSelector(
configurationSelector, configurationOptionsSelector,
state => configurationAdapterSelectors.selectById(state, OVERLAY_OPACITY_NAME_ID)?.value, state => configurationAdapterSelectors.selectById(state, OVERLAY_OPACITY_NAME_ID)?.value,
); );
export const simpleColorValSelector = createSelector( export const simpleColorValSelector = createSelector(
configurationSelector, configurationOptionsSelector,
state => configurationAdapterSelectors.selectById(state, SIMPLE_COLOR_VAL_NAME_ID)?.value, state => configurationAdapterSelectors.selectById(state, SIMPLE_COLOR_VAL_NAME_ID)?.value,
); );
export const configurationMainSelector = createSelector(
configurationSelector,
state => state.main.data,
);
export const elementTypesSelector = createSelector(
configurationMainSelector,
state => state?.elementTypes,
);
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