diff --git a/web-app/client/src/assets/icons/check.svg b/web-app/client/src/assets/icons/check.svg index 0013b543e..2d21d1e1d 100644 --- a/web-app/client/src/assets/icons/check.svg +++ b/web-app/client/src/assets/icons/check.svg @@ -1,3 +1,3 @@ - - + + diff --git a/web-app/client/src/assets/icons/close.svg b/web-app/client/src/assets/icons/close.svg deleted file mode 100644 index c7813d278..000000000 --- a/web-app/client/src/assets/icons/close.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web-app/client/src/assets/icons/cross.svg b/web-app/client/src/assets/icons/cross.svg index b02cdcad5..1beb30039 100644 --- a/web-app/client/src/assets/icons/cross.svg +++ b/web-app/client/src/assets/icons/cross.svg @@ -1,4 +1,4 @@ - - - + + + diff --git a/web-app/client/src/assets/icons/white-cross.svg b/web-app/client/src/assets/icons/white-cross.svg deleted file mode 100644 index aa2852d66..000000000 --- a/web-app/client/src/assets/icons/white-cross.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web-app/client/src/components/Inputs/MultiSelect/customComponents.tsx b/web-app/client/src/components/Inputs/MultiSelect/customComponents.tsx index 3d833626b..5283dfec1 100644 --- a/web-app/client/src/components/Inputs/MultiSelect/customComponents.tsx +++ b/web-app/client/src/components/Inputs/MultiSelect/customComponents.tsx @@ -16,7 +16,7 @@ import { NoticeProps, } from 'react-select'; import ChevronDownIcon from '@assets/icons/arrow-down.svg?component'; -import EmptyButton from '@assets/icons/close.svg?component'; +import EmptyButton from '@assets/icons/cross.svg?component'; import { InputPropsBase } from '@components/Inputs'; import badgeStyles from '@components/Inputs/MultiSelect/OptionBadge/OptionBadge.module.scss'; import { Option as OptionType } from 'types/inputs'; diff --git a/web-app/client/src/components/MobileBanner/MobileBanner.module.scss b/web-app/client/src/components/MobileBanner/MobileBanner.module.scss index a3dbf842a..5e3d22da8 100644 --- a/web-app/client/src/components/MobileBanner/MobileBanner.module.scss +++ b/web-app/client/src/components/MobileBanner/MobileBanner.module.scss @@ -17,3 +17,7 @@ margin-left: 24px; } } + +.cross { + color: $white; +} diff --git a/web-app/client/src/components/MobileBanner/MobileBanner.tsx b/web-app/client/src/components/MobileBanner/MobileBanner.tsx index f6e8e8faf..821516408 100644 --- a/web-app/client/src/components/MobileBanner/MobileBanner.tsx +++ b/web-app/client/src/components/MobileBanner/MobileBanner.tsx @@ -1,5 +1,5 @@ import { FC, useLayoutEffect, useReducer, useRef } from 'react'; -import Cross from '@assets/icons/white-cross.svg?component'; +import Cross from '@assets/icons/cross.svg?component'; import styles from './MobileBanner.module.scss'; const isMobile = () => @@ -37,7 +37,7 @@ const MobileBanner: FC = () => { unavailable. ); diff --git a/web-app/client/src/components/ModalContainer/ModalContainer.tsx b/web-app/client/src/components/ModalContainer/ModalContainer.tsx index 110290939..899a004c4 100644 --- a/web-app/client/src/components/ModalContainer/ModalContainer.tsx +++ b/web-app/client/src/components/ModalContainer/ModalContainer.tsx @@ -1,7 +1,7 @@ import cn from 'classnames'; import { useEffect } from 'react'; import { animated, useSpring } from 'react-spring'; -import CloseIcon from '@assets/icons/close.svg?component'; +import CloseIcon from '@assets/icons/cross.svg?component'; import OutsideClickObserver from '@components/OutsideClickObserver'; import { FCWithChildren } from 'types/react'; import styles from './ModalContainer.module.scss'; diff --git a/web-app/client/src/components/ScrollableNodeTable/ScrollableNodeTable.module.scss b/web-app/client/src/components/ScrollableNodeTable/ScrollableNodeTable.module.scss index e518f00fa..c5c749f68 100644 --- a/web-app/client/src/components/ScrollableNodeTable/ScrollableNodeTable.module.scss +++ b/web-app/client/src/components/ScrollableNodeTable/ScrollableNodeTable.module.scss @@ -61,7 +61,7 @@ padding: 8px 24px; } - tr:nth-child(even) { + tr.alternate:nth-child(even) { background-color: $black-05; } } @@ -87,6 +87,7 @@ display: none; } } + .disabled .table tbody { td { color: $black-10; diff --git a/web-app/client/src/components/ScrollableNodeTable/ScrollableNodeTable.tsx b/web-app/client/src/components/ScrollableNodeTable/ScrollableNodeTable.tsx index 68c1b725a..58ad4ac1b 100644 --- a/web-app/client/src/components/ScrollableNodeTable/ScrollableNodeTable.tsx +++ b/web-app/client/src/components/ScrollableNodeTable/ScrollableNodeTable.tsx @@ -23,6 +23,7 @@ const Table: FC = ({ hiddenColumnIndices, onScroll, className, + alternateRowColors = true, }) => { const threshold = 200; @@ -94,7 +95,7 @@ const Table: FC = ({ > - + {displayHeader.map((item, columnIndex) => (
void; className?: string; + alternateRowColors?: boolean; }; diff --git a/web-app/client/src/components/ScrollableNodeTable/implementations/AFD/AFDTable.module.scss b/web-app/client/src/components/ScrollableNodeTable/implementations/AFD/AFDTable.module.scss index 8f3c578ea..76ae5d074 100644 --- a/web-app/client/src/components/ScrollableNodeTable/implementations/AFD/AFDTable.module.scss +++ b/web-app/client/src/components/ScrollableNodeTable/implementations/AFD/AFDTable.module.scss @@ -5,7 +5,7 @@ } .greenOdd { - background: $success-10 !important; // stylelint-disable-line declaration-no-important + background: $success-10; } .redEven { @@ -13,21 +13,15 @@ } .redOdd { - background: $error-10 !important; // stylelint-disable-line declaration-no-important + background: $error-10; } .checkmark { - path { - fill: $success-100; - stroke: none; - } + color: $success-100; } .cross { - path { - fill: $error-100; - stroke: none; - } + color: $error-100; } .valueText { diff --git a/web-app/client/src/components/ScrollableNodeTable/implementations/AFD/AFDTable.tsx b/web-app/client/src/components/ScrollableNodeTable/implementations/AFD/AFDTable.tsx index 852934924..ab21d49b4 100644 --- a/web-app/client/src/components/ScrollableNodeTable/implementations/AFD/AFDTable.tsx +++ b/web-app/client/src/components/ScrollableNodeTable/implementations/AFD/AFDTable.tsx @@ -1,3 +1,4 @@ +import { FC, useMemo } from 'react'; import Check from '@assets/icons/check.svg?component'; import Cross from '@assets/icons/cross.svg?component'; @@ -6,7 +7,6 @@ import Table, { ScrollDirection, TableProps, } from '@components/ScrollableNodeTable'; -import { FC, useMemo } from 'react'; import styles from './AFDTable.module.scss'; @@ -44,7 +44,7 @@ const getAFDRow: (row: AFDTableRow, position: number) => Row = ( row.isFrequent ? ( ) : ( - + ), ...row.snippetRow, ], diff --git a/web-app/client/src/components/ScrollableNodeTable/implementations/MFDTable.module.scss b/web-app/client/src/components/ScrollableNodeTable/implementations/MFDTable.module.scss index 35160cdd0..c85005bbd 100644 --- a/web-app/client/src/components/ScrollableNodeTable/implementations/MFDTable.module.scss +++ b/web-app/client/src/components/ScrollableNodeTable/implementations/MFDTable.module.scss @@ -1,41 +1,35 @@ @import "styles/common"; .greenHighlighted { - background: $success-25 !important; // stylelint-disable-line declaration-no-important + background: $success-25; } .greenEven { - background: $success-05 !important; // stylelint-disable-line declaration-no-important + background: $success-05; } .greenOdd { - background: $success-10 !important; // stylelint-disable-line declaration-no-important + background: $success-10; } .redHighlighted { - background: $error-25 !important; // stylelint-disable-line declaration-no-important + background: $error-25; } .redEven { - background: $error-05 !important; // stylelint-disable-line declaration-no-important + background: $error-05; } .redOdd { - background: $error-10 !important; // stylelint-disable-line declaration-no-important + background: $error-10; } .checkmark { - path { - fill: $success-100; - stroke: none; - } + color: $success-100; } .cross { - path { - fill: $error-100; - stroke: none; - } + color: $error-100; } .valueText { diff --git a/web-app/client/src/components/ScrollableNodeTable/implementations/MFDTable.tsx b/web-app/client/src/components/ScrollableNodeTable/implementations/MFDTable.tsx index ea266b076..fe463e765 100644 --- a/web-app/client/src/components/ScrollableNodeTable/implementations/MFDTable.tsx +++ b/web-app/client/src/components/ScrollableNodeTable/implementations/MFDTable.tsx @@ -66,7 +66,7 @@ const getMFDRow: ( highlight.withinLimit ? ( // icon ) : ( - + ), highlight.maximumDistance, // maximum distance highlight.index, // index diff --git a/web-app/client/src/components/Toast/ToastContainer.module.scss b/web-app/client/src/components/Toast/ToastContainer.module.scss index 68aa933b7..0ace458c0 100644 --- a/web-app/client/src/components/Toast/ToastContainer.module.scss +++ b/web-app/client/src/components/Toast/ToastContainer.module.scss @@ -71,3 +71,7 @@ opacity: 0.9; } } + +.cross { + color: $white; +} diff --git a/web-app/client/src/components/Toast/ToastContainer.tsx b/web-app/client/src/components/Toast/ToastContainer.tsx index 58d440c4b..5f8a85498 100644 --- a/web-app/client/src/components/Toast/ToastContainer.tsx +++ b/web-app/client/src/components/Toast/ToastContainer.tsx @@ -4,12 +4,12 @@ import { ToastContainer as TostifyToastContainer, CloseButtonProps, } from 'react-toastify'; -import Cross from '@assets/icons/white-cross.svg?component'; +import Cross from '@assets/icons/cross.svg?component'; import styles from './ToastContainer.module.scss'; const CloseButton: FC = ({ closeToast, ariaLabel }) => ( ); diff --git a/web-app/client/src/constants/descriptionCFD.tsx b/web-app/client/src/constants/descriptionCFD.tsx new file mode 100644 index 000000000..bd55f796d --- /dev/null +++ b/web-app/client/src/constants/descriptionCFD.tsx @@ -0,0 +1,23 @@ +import { FC } from 'react'; + +const DescriptionCFD: FC = () => { + return ( + <> + Conditional functional dependencies are relaxed form of functional + dependencies and are mainly used for data cleaning and error detection + problems. A single CFD is represented by two entities: +
    +
  1. a binary relationship between disjoint sets of attributes and
  2. +
  3. + conditions (also known as pattern tableau) which specify the subset of + tuples on which a relationship holds. +
  4. +
+ CFDs mining process is parameterized by confidence and support levels, + which makes CFD in terms of resources consumption more complex concept + than FD. + + ); +}; + +export default DescriptionCFD; diff --git a/web-app/client/src/constants/primitiveInfoType.tsx b/web-app/client/src/constants/primitiveInfoType.tsx index 8af7f2cee..6014bd0d7 100644 --- a/web-app/client/src/constants/primitiveInfoType.tsx +++ b/web-app/client/src/constants/primitiveInfoType.tsx @@ -1,6 +1,7 @@ import { ReactNode } from 'react'; import { MainPrimitiveType } from 'types/globalTypes'; import DescriptionAFD from './descriptionAFD'; +import DescriptionCFD from './descriptionCFD'; export type PrimitiveInfoType = { label: string; @@ -17,8 +18,7 @@ const primitiveInfo: Partial> = { }, [MainPrimitiveType.CFD]: { label: 'Conditional Functional Dependencies', - description: - 'Conditional functional dependencies are relaxed form of functional dependencies and are mainly used for data cleaning and error detection problems. A single CFD is represented by two entities: (1) a binary relationship between disjoint sets of attributes and (2) conditions (also known as pattern tableau) which specify the subset of tuples on which a relationship holds. CFDs mining process is parameterized by confidence and support levels, which makes CFD in terms of resources consumption more complex concept than FD.', + description: , link: 'https://mstrutov.github.io/Desbordante/guides/cfd-mining.html', }, [MainPrimitiveType.AR]: { diff --git a/web-app/client/src/pages/reports/approximate-dependencies.tsx b/web-app/client/src/pages/reports/approximate-dependencies.tsx index 78663526f..1faae3a69 100644 --- a/web-app/client/src/pages/reports/approximate-dependencies.tsx +++ b/web-app/client/src/pages/reports/approximate-dependencies.tsx @@ -1,3 +1,5 @@ +import React, { ReactElement, useCallback, useRef, useState } from 'react'; +import { FormProvider } from 'react-hook-form'; import EyeIcon from '@assets/icons/eye.svg?component'; import ArrowCrossed from '@assets/icons/line-arrow-right-crossed.svg?component'; import Arrow from '@assets/icons/line-arrow-right.svg?component'; @@ -10,21 +12,25 @@ import Pagination from '@components/Pagination/Pagination'; import ReportFiller from '@components/ReportFiller/ReportFiller'; import ReportsLayout from '@components/ReportsLayout'; +import { ScrollDirection } from '@components/ScrollableNodeTable'; import { AFDTable } from '@components/ScrollableNodeTable/implementations/AFD/AFDTable'; import styles from '@styles/ApproximateDependencies.module.scss'; -import React, { ReactElement, useState } from 'react'; -import { FormProvider } from 'react-hook-form'; import { PrimitiveType } from 'types/globalTypes'; import { NextPageWithLayout } from 'types/pageWithLayout'; import { data } from './AFDFakeData'; -import { Scrolling } from './onScroll'; const ReportsAFD: NextPageWithLayout = () => { - const [clusterIndex, setClusterIndex] = useState(0); + const defaultLimit = 150; + const defaultOffsetDifference = 50; + const maxLimit = data.result.clustersTotalCount; + const [clusterIndex, setClusterIndex] = useState(0); const [isOrderingShown, setIsOrderingShown] = useState(false); const [isVisibilityShown, setIsVisibilityShown] = useState(false); + const shouldIgnoreScrollEvent = useRef(false); + + const [limit, setLimit] = useState(defaultLimit); const { threshold, violatingRows, clustersTotalCount } = data.result; const { frequentness, mostFrequentValue, size, distinctRHSValues } = @@ -32,7 +38,19 @@ const ReportsAFD: NextPageWithLayout = () => { const methods = useFilters(PrimitiveType.AFD); - const onScroll = Scrolling(); + const onScroll = useCallback( + (direction: ScrollDirection) => { + if (!shouldIgnoreScrollEvent.current && direction === 'down') { + shouldIgnoreScrollEvent.current = true; + if (limit < maxLimit) { + setLimit((limit) => limit + defaultOffsetDifference); + } else { + shouldIgnoreScrollEvent.current = false; + } + } + }, + [limit, defaultOffsetDifference, maxLimit], + ); return ( <> @@ -64,10 +82,8 @@ const ReportsAFD: NextPageWithLayout = () => { )} {!clustersTotalCount && !data.result && ( } /> )} diff --git a/web-app/client/src/pages/reports/onScroll.ts b/web-app/client/src/pages/reports/onScroll.ts deleted file mode 100644 index 2d75a3463..000000000 --- a/web-app/client/src/pages/reports/onScroll.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ScrollDirection } from '@components/ScrollableNodeTable'; -import { useCallback, useEffect, useRef, useState } from 'react'; -import { data } from './AFDFakeData'; - -const defaultLimit = 150; -const defaultOffsetDifference = 50; - -export const Scrolling = () => { - const shouldIgnoreScrollEvent = useRef(false); - - const [limit, setLimit] = useState(defaultLimit); - - useEffect(() => { - shouldIgnoreScrollEvent.current = false; - }, [shouldIgnoreScrollEvent]); - - return useCallback( - (direction: ScrollDirection) => { - if (!shouldIgnoreScrollEvent.current && direction === 'down') { - shouldIgnoreScrollEvent.current = true; - if (limit < data.result.clustersTotalCount) { - setLimit((limit) => limit + defaultOffsetDifference); - } else { - shouldIgnoreScrollEvent.current = false; - } - } - }, - [limit], - ); -};