From 34d192ca0bf8119d76583516241ab9c71a805489 Mon Sep 17 00:00:00 2001 From: Narin Sundarabhaya Date: Fri, 27 Oct 2023 23:44:21 +0700 Subject: [PATCH 1/6] add lens and cam columns --- src/renderer/src/Sections/Results/columns.tsx | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/Sections/Results/columns.tsx b/src/renderer/src/Sections/Results/columns.tsx index 9825e83..3af4e08 100644 --- a/src/renderer/src/Sections/Results/columns.tsx +++ b/src/renderer/src/Sections/Results/columns.tsx @@ -344,7 +344,38 @@ export const duplicateImageColumns: ColumnDef[] = [ enableGrouping: false, size: 32 }, - // TODO add camera & lens + { + id: 'cameraModel', + accessorKey: 'cameraModel', + header: 'Camera Model', + enableSorting: false, + cell: (info): CommonValue => { + if (info.row.depth === 0) { + return null + } + + const row = info.row.original as unknown as DuplicateFile + if (row.fileType === 'audio') return + + return row?.metadata?.cameraModel ?? '' + } + }, + { + id: 'lensModel', + accessorKey: 'lensModel', + header: 'Lens Model', + enableSorting: false, + cell: (info): CommonValue => { + if (info.row.depth === 0) { + return null + } + + const row = info.row.original as unknown as DuplicateFile + if (row.fileType === 'audio') return + + return row?.metadata?.lensModel ?? '' + } + }, { id: 'duplicateCount', size: 24, From 12137b254b336117410268d49a3f27b5f70862a0 Mon Sep 17 00:00:00 2001 From: Narin Sundarabhaya Date: Sat, 28 Oct 2023 12:25:15 +0700 Subject: [PATCH 2/6] fix loop bug, revert to original implementation --- .../src/Sections/Directories/index.tsx | 8 +- src/renderer/src/Sections/Results/index.tsx | 3 +- .../src/hooks/useDeletedFilesTracking.ts | 78 ++++++++++--------- 3 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/renderer/src/Sections/Directories/index.tsx b/src/renderer/src/Sections/Directories/index.tsx index cbcce00..861c0fe 100644 --- a/src/renderer/src/Sections/Directories/index.tsx +++ b/src/renderer/src/Sections/Directories/index.tsx @@ -7,7 +7,7 @@ import { useMain } from '@renderer/context/MainContext' import { TableProvider, useTableContext } from '@renderer/context/TableContext' import useFetchDirectories from '@renderer/hooks/useDirectoriesList' import { createColumnHelper, getCoreRowModel, useReactTable } from '@tanstack/react-table' -import { memo, useEffect, useMemo } from 'react' +import { memo, useMemo } from 'react' import { fuzzyFilter } from '../Results/utils' import ActionsRow from './ActionsRow' import ConfigurationPanel from './ConfigurationPanel' @@ -22,11 +22,7 @@ const List = (): JSX.Element => { const { state } = useMain() const { rowSelection, setRowSelection } = useTableContext() - const { status, fetchData } = useFetchDirectories() - - useEffect(() => { - fetchData() - }, []) + const { status } = useFetchDirectories() const directories = state.directorySrcs diff --git a/src/renderer/src/Sections/Results/index.tsx b/src/renderer/src/Sections/Results/index.tsx index ba80284..40bff77 100644 --- a/src/renderer/src/Sections/Results/index.tsx +++ b/src/renderer/src/Sections/Results/index.tsx @@ -56,7 +56,6 @@ const Table = ({ id }: { id: string }): JSX.Element => { return transformScanResultsToRows(results, scan) }, [results, scan]) const [columnFilters, setColumnFilters] = useState([]) - const columns = useMemo[]>(() => { if (scan.configuration.type === 'image') { return duplicateImageColumns @@ -71,7 +70,7 @@ const Table = ({ id }: { id: string }): JSX.Element => { } return [] - }, []) + }, [scan]) const table = useReactTable({ columnResizeMode: 'onChange', diff --git a/src/renderer/src/hooks/useDeletedFilesTracking.ts b/src/renderer/src/hooks/useDeletedFilesTracking.ts index 2be4020..3708c9b 100644 --- a/src/renderer/src/hooks/useDeletedFilesTracking.ts +++ b/src/renderer/src/hooks/useDeletedFilesTracking.ts @@ -3,8 +3,7 @@ import { getDeletedFilesById } from '@renderer/actions/ipc' import { useMain } from '@renderer/context/MainContext' import { transformDeletedFiles } from '@renderer/utils/transformDeletedFiles' import { ADD_DELETED_FILES_RESULT } from '@src/constants' -import { DatabaseOperationResult } from '@src/types' -import { useQueries, useQueryClient } from '@tanstack/react-query' +import { ExtendedScan } from '@src/types' import { useEffect } from 'react' /** @@ -22,49 +21,52 @@ const useDeletedFilesTracking = ({ state: ReturnType['state'] dispatch: ReturnType['dispatch'] }): void => { - const queryClient = useQueryClient() - const scans = Object.values(state.scans) + useEffect(() => { + const intervalIds: NodeJS.Timeout[] = [] + const pollingDuration = 3 * 60 * 1000 // timeout at 3 min - const queries = useQueries({ - queries: scans.map((scan) => ({ - queryKey: ['deletedFiles', scan.trackingDeleteId], - queryFn: () => (scan.trackingDeleteId ? getDeletedFilesById(scan.trackingDeleteId) : null), - refetchInterval: 2000, // Refetch every 2 seconds - onSuccess: (deleteRes: DatabaseOperationResult): void => { - if (deleteRes.success && deleteRes.data) { - dispatch({ - type: ADD_DELETED_FILES_RESULT, - payload: { - scanId: scan.id, - deletedFiles: transformDeletedFiles(deleteRes.data) - } - }) - } - } - })) - }) + Object.keys(state.scans).forEach((id) => { + const scan = state.scans[id] + const { trackingDeleteId } = scan + const deletedFiles = + (scan as ExtendedScan & { deletedFiles: DeletedFiles[] })?.deletedFiles ?? [] + const deletedFilesIds = deletedFiles.map((file) => file.id) - useEffect(() => { - const timeoutId = setTimeout( - () => { - scans.forEach((scan) => { - queryClient.removeQueries({ - queryKey: ['deletedFiles', scan.trackingDeleteId] - }) + if (trackingDeleteId && !deletedFilesIds.includes(trackingDeleteId)) { + const intervalId = setInterval(async () => { + const deleteRes = await getDeletedFilesById(trackingDeleteId) + + if (deleteRes.success === false) { + clearInterval(intervalId) + } + + if (deleteRes.success && deleteRes.data) { + clearInterval(intervalId) + + dispatch({ + type: ADD_DELETED_FILES_RESULT, + payload: { + scanId: id, + deletedFiles: transformDeletedFiles(deleteRes.data) + } + }) + } }) - }, - 3 * 60 * 1000 - ) // Stop refetching after 3 minutes + + intervalIds.push(intervalId) + } + }) + + const timeoutId = setTimeout(() => { + intervalIds.forEach((id) => clearInterval(id)) + }, pollingDuration) return () => { clearTimeout(timeoutId) - scans.forEach((scan) => { - queryClient.removeQueries({ - queryKey: ['deletedFiles', scan.trackingDeleteId] - }) - }) + + intervalIds.forEach((id) => clearInterval(id)) } - }, [queries]) + }, [state.scans, dispatch]) } export default useDeletedFilesTracking From ab26892109c2f88271d68434763eb2cb92d967bd Mon Sep 17 00:00:00 2001 From: Narin Sundarabhaya Date: Sat, 28 Oct 2023 12:56:21 +0700 Subject: [PATCH 3/6] refactor columns selection menu now generated dynamically --- .../Sections/Results/ConfigurationPanel.tsx | 47 +------------- src/renderer/src/Sections/Results/columns.tsx | 7 +++ .../src/components/Table/ColumnSelection.tsx | 63 +++++++++++++++---- 3 files changed, 59 insertions(+), 58 deletions(-) diff --git a/src/renderer/src/Sections/Results/ConfigurationPanel.tsx b/src/renderer/src/Sections/Results/ConfigurationPanel.tsx index e1eac0a..9ab405c 100644 --- a/src/renderer/src/Sections/Results/ConfigurationPanel.tsx +++ b/src/renderer/src/Sections/Results/ConfigurationPanel.tsx @@ -59,52 +59,7 @@ export default function ConfigurationPanel({ id }: { id: string }): JSX.Element )}
- { - return includeCrates || column.key !== 'crates' - })} - /> + [] = [ { + id: 'id', accessorKey: 'id', enableGrouping: true, size: 16, @@ -49,6 +50,7 @@ export const duplicatesColumns: ColumnDef[] = [ }, { accessorKey: 'name', + header: 'Name', cell: (info) => info.getValue(), enableGrouping: false, enableSorting: true @@ -253,7 +255,9 @@ export const duplicateImageColumns: ColumnDef[] = [ ) }, { + id: 'name', accessorKey: 'name', + header: 'Name', cell: (info) => info.getValue(), enableGrouping: false, enableSorting: true @@ -390,6 +394,7 @@ export const duplicateImageColumns: ColumnDef[] = [ export const unCratedColumns: ColumnDef[] = [ { + id: 'id', accessorKey: 'id', enableGrouping: true, size: 16, @@ -411,7 +416,9 @@ export const unCratedColumns: ColumnDef[] = [ ) }, { + id: 'name', accessorKey: 'name', + header: 'Name', cell: (info) => info.getValue(), enableGrouping: false, enableSorting: true diff --git a/src/renderer/src/components/Table/ColumnSelection.tsx b/src/renderer/src/components/Table/ColumnSelection.tsx index 92744d9..6aed081 100644 --- a/src/renderer/src/components/Table/ColumnSelection.tsx +++ b/src/renderer/src/components/Table/ColumnSelection.tsx @@ -1,16 +1,55 @@ +import { + duplicateImageColumns, + duplicatesColumns, + unCratedColumns +} from '@renderer/Sections/Results/columns' +import { useMain } from '@renderer/context/MainContext' import { useTableContext } from '@renderer/context/TableContext' -import { useEffect } from 'react' - -const ColumnSelection = ({ - columns -}: { - columns: { - key: string - name: string - }[] -}): JSX.Element => { +import { useEffect, useMemo } from 'react' + +const columMap = { + duplicateAudio: duplicatesColumns, + duplicateImage: duplicateImageColumns, + uncrated: unCratedColumns +} + +const ColumnSelection = ({ id }: { id: string }): JSX.Element => { + const { state } = useMain() + const scan = state.scans[id] + const { type, scanType, includeCrates } = scan.configuration const { columnVisibility, setColumnVisibility } = useTableContext() + const columns: { key: string; name: string }[] = useMemo(() => { + if (type === 'image') { + return columMap['duplicateImage'] + .map((col) => ({ + key: col.id as string, + name: col.header as string + })) + .filter((col) => col.key && col.key !== 'id') + } + + if (scanType === 'duplicate') { + return columMap['duplicateAudio'] + .map((col) => ({ + key: col.id as string, + name: col.header as string + })) + .filter((col) => col.key && (includeCrates || col.key !== 'crates') && col.key !== 'id') + } + + if (scanType === 'not_crated') { + return columMap['uncrated'] + .map((col) => ({ + key: col.id as string, + name: col.header as string + })) + .filter((col) => col.key && col.key !== 'id') + } + + return [] + }, [type, scanType, includeCrates]) + useEffect(() => { // on mount set all to true except crates setColumnVisibility((cur) => { @@ -39,14 +78,14 @@ const ColumnSelection = ({ > {columns.map((col) => (
  • - + +
  • ))} From 39936e5e4ed48eba21ee56e5c7dea772666e3b72 Mon Sep 17 00:00:00 2001 From: Narin Sundarabhaya Date: Sat, 28 Oct 2023 14:27:12 +0700 Subject: [PATCH 4/6] add eslint action and fix missing dep and configuration --- .eslintrc.cjs | 10 +++++++++- .github/workflows/eslint.yml | 26 ++++++++++++++++++++++++++ package.json | 1 + yarn.lock | 5 +++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/eslint.yml diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 5a221d8..26aae7f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -3,10 +3,18 @@ module.exports = { 'eslint:recommended', 'plugin:react/recommended', 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', '@electron-toolkit/eslint-config-ts/recommended', '@electron-toolkit/eslint-config-prettier' ], + plugins: ['react-hooks', 'react-refresh'], rules: { - 'react-refresh/only-export-components': 'warn' + 'react-refresh/only-export-components': 'warn', + 'react-hooks/exhaustive-deps': 'warn' + }, + settings: { + react: { + version: 'detect' + } } } diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml new file mode 100644 index 0000000..b6f3b52 --- /dev/null +++ b/.github/workflows/eslint.yml @@ -0,0 +1,26 @@ +name: ESLint + +on: + push: + branches: + - main # adjust with your default branch if it's not "main" + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' # adjust with your desired Node.js version + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Run ESLint + run: yarn lint diff --git a/package.json b/package.json index 76ddf58..230283c 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "daisyui": "^3.8.2", "date-fns": "^2.30.0", "electron-updater": "^6.1.1", + "eslint-plugin-react-hooks": "^4.6.0", "exifreader": "^4.14.1", "music-metadata": "7.13.4", "ramda": "^0.29.0", diff --git a/yarn.lock b/yarn.lock index 3ec54ee..27fcf81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2738,6 +2738,11 @@ eslint-plugin-prettier@^5.0.0: prettier-linter-helpers "^1.0.0" synckit "^0.8.5" +eslint-plugin-react-hooks@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== + eslint-plugin-react-refresh@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.3.tgz#59dae8c00a119f06ea16b1d3e6891df3775947c7" From 8ad07f9f4a955095a2c2bf97ae2724b1c4d9fc3c Mon Sep 17 00:00:00 2001 From: Narin Sundarabhaya Date: Sat, 28 Oct 2023 14:28:05 +0700 Subject: [PATCH 5/6] fix eslint warning/errors --- .../src/Sections/Directories/ActionsRow.tsx | 4 +- .../Directories/ConfigurationPanel.tsx | 4 +- .../src/Sections/Directories/List.tsx | 105 +++++++++++++++++ .../src/Sections/Directories/index.tsx | 110 ++---------------- .../src/Sections/Results/ActionsRow.tsx | 4 +- .../Sections/Results/ConfigurationPanel.tsx | 4 +- .../Sections/Results/DeleteConfirmModal.tsx | 6 +- src/renderer/src/Sections/Results/columns.tsx | 4 +- src/renderer/src/Sections/Results/index.tsx | 7 +- .../src/components/DebouncedInput.tsx | 6 +- .../src/components/PreviousResults.tsx | 2 +- src/renderer/src/components/SectionTabs.tsx | 8 +- .../src/components/Table/ColumnSelection.tsx | 5 +- .../components/Table/InderminateCheckbox.tsx | 2 +- src/renderer/src/context/MainContext.tsx | 13 +-- src/renderer/src/context/TableContext.tsx | 12 +- src/renderer/src/context/hooks/useMain.ts | 14 +++ .../src/context/hooks/useTableContext.ts | 13 +++ .../src/hooks/useDeletedFilesTracking.ts | 2 +- src/renderer/src/hooks/useDirectoriesList.ts | 2 +- src/renderer/src/hooks/useIPCListener.ts | 2 +- src/renderer/src/hooks/usePolling.ts | 2 +- src/renderer/src/hooks/useScanTracking.ts | 4 +- src/renderer/src/hooks/useScansList.ts | 4 +- 24 files changed, 182 insertions(+), 157 deletions(-) create mode 100644 src/renderer/src/Sections/Directories/List.tsx create mode 100644 src/renderer/src/context/hooks/useMain.ts create mode 100644 src/renderer/src/context/hooks/useTableContext.ts diff --git a/src/renderer/src/Sections/Directories/ActionsRow.tsx b/src/renderer/src/Sections/Directories/ActionsRow.tsx index 8660282..8e3c746 100644 --- a/src/renderer/src/Sections/Directories/ActionsRow.tsx +++ b/src/renderer/src/Sections/Directories/ActionsRow.tsx @@ -1,8 +1,8 @@ import { insertScan, openFilesDirectoryDialog, removeDirectories } from '@renderer/actions/ipc' import ErrorMessage from '@renderer/components/ErrorMessage' import PreviousResults from '@renderer/components/PreviousResults' -import { useMain } from '@renderer/context/MainContext' -import { useTableContext } from '@renderer/context/TableContext' +import useMain from '@renderer/context/hooks/useMain' +import useTableContext from '@renderer/context/hooks/useTableContext' import { transformScan } from '@renderer/utils/transformScan' import { ADD_NEW_SCAN, REMOVE_DIRECTORIES, UPDATE_ACTIVE_TAB } from '@src/constants' import { useQueryClient } from '@tanstack/react-query' diff --git a/src/renderer/src/Sections/Directories/ConfigurationPanel.tsx b/src/renderer/src/Sections/Directories/ConfigurationPanel.tsx index 7ce3f13..f4d774a 100644 --- a/src/renderer/src/Sections/Directories/ConfigurationPanel.tsx +++ b/src/renderer/src/Sections/Directories/ConfigurationPanel.tsx @@ -1,4 +1,4 @@ -import { useMain } from '@renderer/context/MainContext' +import useMain from '@renderer/context/hooks/useMain' import { useEffect } from 'react' const classNames = { @@ -74,7 +74,7 @@ export default function ConfigurationPanel(): JSX.Element { } }) } - }, [type, scanConfiguration.scanType, dispatch]) + }, [type, scanConfiguration.scanType, dispatch, scanType, includeCrates]) return (
    diff --git a/src/renderer/src/Sections/Directories/List.tsx b/src/renderer/src/Sections/Directories/List.tsx new file mode 100644 index 0000000..e10152e --- /dev/null +++ b/src/renderer/src/Sections/Directories/List.tsx @@ -0,0 +1,105 @@ +import { FilesDirectory } from '@prisma/client' +import Loader from '@renderer/components/Loader' +import Body from '@renderer/components/Table/Body' +import TableHeader from '@renderer/components/Table/Header' +import IndeterminateCheckbox from '@renderer/components/Table/InderminateCheckbox' +import useMain from '@renderer/context/hooks/useMain' +import useTableContext from '@renderer/context/hooks/useTableContext' +import useFetchDirectories from '@renderer/hooks/useDirectoriesList' +import { createColumnHelper, getCoreRowModel, useReactTable } from '@tanstack/react-table' +import { useMemo } from 'react' +import { fuzzyFilter } from '../Results/utils' + +const classNames = { + table: 'table table-xs padding-sm w-full' +} +const columnHelper = createColumnHelper() + +const List = (): JSX.Element => { + const { state } = useMain() + const { rowSelection, setRowSelection } = useTableContext() + + const { status } = useFetchDirectories() + + const directories = state.directorySrcs + + const columns = useMemo( + () => [ + columnHelper.display({ + id: 'select', + size: 16, + header: ({ table }) => ( + + ), + cell: ({ row }) => ( +
    + +
    + ) + }), + columnHelper.accessor('id', { + id: 'id' + }), + columnHelper.accessor('path', { + id: 'path', + cell: (info) => info.getValue(), + header: () => Path + }) + ], + [] + ) + + const table = useReactTable({ + data: directories ?? [], + columns, + getCoreRowModel: getCoreRowModel(), + state: { + columnVisibility: { + id: false + }, + rowSelection + }, + filterFns: { + fuzzy: fuzzyFilter + }, + enableRowSelection: true, + onRowSelectionChange: setRowSelection + }) + + const renderList = (): JSX.Element => { + if (status === 'pending') { + return ( +
    + +
    + ) + } + + return ( + + headerGroups={table.getHeaderGroups()} /> + + table={table} + noResultsMessage="No directories selected. Use the buttons below to add/remove directories to scan." + /> +
    + ) + } + + return
    {renderList()}
    +} + +export default List diff --git a/src/renderer/src/Sections/Directories/index.tsx b/src/renderer/src/Sections/Directories/index.tsx index 861c0fe..7e9fd25 100644 --- a/src/renderer/src/Sections/Directories/index.tsx +++ b/src/renderer/src/Sections/Directories/index.tsx @@ -1,111 +1,13 @@ -import { FilesDirectory } from '@prisma/client' -import Loader from '@renderer/components/Loader' -import Body from '@renderer/components/Table/Body' -import TableHeader from '@renderer/components/Table/Header' -import IndeterminateCheckbox from '@renderer/components/Table/InderminateCheckbox' -import { useMain } from '@renderer/context/MainContext' -import { TableProvider, useTableContext } from '@renderer/context/TableContext' -import useFetchDirectories from '@renderer/hooks/useDirectoriesList' -import { createColumnHelper, getCoreRowModel, useReactTable } from '@tanstack/react-table' -import { memo, useMemo } from 'react' -import { fuzzyFilter } from '../Results/utils' +import { TableProvider } from '@renderer/context/TableContext' import ActionsRow from './ActionsRow' import ConfigurationPanel from './ConfigurationPanel' +import List from './List' const classNames = { - container: 'h-full w-full grid grid-rows-max-1fr-max', - table: 'table table-xs padding-sm w-full' + container: 'h-full w-full grid grid-rows-max-1fr-max' } -const columnHelper = createColumnHelper() -const List = (): JSX.Element => { - const { state } = useMain() - const { rowSelection, setRowSelection } = useTableContext() - - const { status } = useFetchDirectories() - - const directories = state.directorySrcs - - const columns = useMemo( - () => [ - columnHelper.display({ - id: 'select', - size: 16, - header: ({ table }) => ( - - ), - cell: ({ row }) => ( -
    - -
    - ) - }), - columnHelper.accessor('id', { - id: 'id' - }), - columnHelper.accessor('path', { - id: 'path', - cell: (info) => info.getValue(), - header: () => Path - }) - ], - [] - ) - - const table = useReactTable({ - data: directories ?? [], - columns, - getCoreRowModel: getCoreRowModel(), - state: { - columnVisibility: { - id: false - }, - rowSelection - }, - filterFns: { - fuzzy: fuzzyFilter - }, - enableRowSelection: true, - onRowSelectionChange: setRowSelection - }) - - const renderList = (): JSX.Element => { - if (status === 'pending') { - return ( -
    - -
    - ) - } - - return ( - - headerGroups={table.getHeaderGroups()} /> - - table={table} - noResultsMessage="No directories selected. Use the buttons below to add/remove directories to scan." - /> -
    - ) - } - - return
    {renderList()}
    -} - -export default memo(function Directories(): JSX.Element { +function Directories(): JSX.Element { return (
    @@ -115,4 +17,6 @@ export default memo(function Directories(): JSX.Element {
    ) -}) +} + +export default Directories diff --git a/src/renderer/src/Sections/Results/ActionsRow.tsx b/src/renderer/src/Sections/Results/ActionsRow.tsx index f878eb9..6218683 100644 --- a/src/renderer/src/Sections/Results/ActionsRow.tsx +++ b/src/renderer/src/Sections/Results/ActionsRow.tsx @@ -1,6 +1,6 @@ import ErrorMessage from '@renderer/components/ErrorMessage' -import { useMain } from '@renderer/context/MainContext' -import { useTableContext } from '@renderer/context/TableContext' +import useMain from '@renderer/context/hooks/useMain' +import useTableContext from '@renderer/context/hooks/useTableContext' import { useMemo } from 'react' const classNames = { diff --git a/src/renderer/src/Sections/Results/ConfigurationPanel.tsx b/src/renderer/src/Sections/Results/ConfigurationPanel.tsx index 9ab405c..d8fc3ab 100644 --- a/src/renderer/src/Sections/Results/ConfigurationPanel.tsx +++ b/src/renderer/src/Sections/Results/ConfigurationPanel.tsx @@ -1,7 +1,7 @@ import DebouncedInput from '@renderer/components/DebouncedInput' import ColumnSelection from '@renderer/components/Table/ColumnSelection' -import { useMain } from '@renderer/context/MainContext' -import { useTableContext } from '@renderer/context/TableContext' +import useMain from '@renderer/context/hooks/useMain' +import useTableContext from '@renderer/context/hooks/useTableContext' import { values } from 'ramda' import { useMemo } from 'react' import ErrorIcon from '../../assets/error.svg?react' diff --git a/src/renderer/src/Sections/Results/DeleteConfirmModal.tsx b/src/renderer/src/Sections/Results/DeleteConfirmModal.tsx index d419cbf..6a6225b 100644 --- a/src/renderer/src/Sections/Results/DeleteConfirmModal.tsx +++ b/src/renderer/src/Sections/Results/DeleteConfirmModal.tsx @@ -1,5 +1,5 @@ import { deleteFiles } from '@renderer/actions/ipc' -import { useMain } from '@renderer/context/MainContext' +import useMain from '@renderer/context/hooks/useMain' import { ADD_TRACKING_DELETE_ID } from '@src/constants' import { DuplicateData, NotCratedData, ResultsData } from '@src/types' import { memo } from 'react' @@ -13,7 +13,7 @@ type Props = { selected: Record } -export default memo(function deleteWarningModal({ +const DeleteModal = memo(function DeleteWarningModal({ data, id, selected, @@ -79,3 +79,5 @@ export default memo(function deleteWarningModal({ ) }) + +export default DeleteModal diff --git a/src/renderer/src/Sections/Results/columns.tsx b/src/renderer/src/Sections/Results/columns.tsx index ca555ec..6d59161 100644 --- a/src/renderer/src/Sections/Results/columns.tsx +++ b/src/renderer/src/Sections/Results/columns.tsx @@ -164,7 +164,7 @@ export const duplicatesColumns: ColumnDef[] = [ header: 'Crates', accessorFn: (row): number => { if ((row as DuplicateData)?.files?.length === 0) { - // @ts-ignore + // @ts-ignore row type is incorrect return (row.crates || []).length } @@ -175,7 +175,7 @@ export const duplicatesColumns: ColumnDef[] = [ cell: (info): JSX.Element | number | string => { if (info.row.depth === 0) { const count = info.row.subRows.reduce((acc, row) => { - // @ts-ignore + // @ts-ignore row type is incorrect return acc + row.original?.crates?.length ?? 0 }, 0) diff --git a/src/renderer/src/Sections/Results/index.tsx b/src/renderer/src/Sections/Results/index.tsx index 40bff77..57d0487 100644 --- a/src/renderer/src/Sections/Results/index.tsx +++ b/src/renderer/src/Sections/Results/index.tsx @@ -1,7 +1,8 @@ import Loader from '@renderer/components/Loader' import Body from '@renderer/components/Table/Body' -import { useMain } from '@renderer/context/MainContext' -import { TableProvider, useTableContext } from '@renderer/context/TableContext' +import { TableProvider } from '@renderer/context/TableContext' +import useMain from '@renderer/context/hooks/useMain' +import useTableContext from '@renderer/context/hooks/useTableContext' import { ResultsData, ScanResults } from '@src/types' import { RankingInfo } from '@tanstack/match-sorter-utils' import { @@ -50,7 +51,7 @@ const Table = ({ id }: { id: string }): JSX.Element => { setRowSelection } = useTableContext() const scan = state.scans[id] - const results: ScanResults = scan.results ?? { files: {} } + const results: ScanResults = useMemo(() => scan.results ?? { files: {} }, [scan]) const [sorted, setSorting] = useState([]) const data: ResultsData[] = useMemo(() => { return transformScanResultsToRows(results, scan) diff --git a/src/renderer/src/components/DebouncedInput.tsx b/src/renderer/src/components/DebouncedInput.tsx index 094b413..219eb31 100644 --- a/src/renderer/src/components/DebouncedInput.tsx +++ b/src/renderer/src/components/DebouncedInput.tsx @@ -1,6 +1,6 @@ import { InputHTMLAttributes, memo, useEffect, useState } from 'react' -export default memo(function DebouncedInput({ +const Input = memo(function DebouncedInput({ value: initialValue, onChange, debounce = 500, @@ -24,7 +24,7 @@ export default memo(function DebouncedInput({ }, debounce) return (): void => clearTimeout(timeout) - }, [value]) + }, [debounce, onChange, value]) return ( ) }) + +export default Input diff --git a/src/renderer/src/components/PreviousResults.tsx b/src/renderer/src/components/PreviousResults.tsx index d52b400..b3d64f0 100644 --- a/src/renderer/src/components/PreviousResults.tsx +++ b/src/renderer/src/components/PreviousResults.tsx @@ -1,4 +1,4 @@ -import { useMain } from '@renderer/context/MainContext' +import useMain from '@renderer/context/hooks/useMain' import useScansList from '@renderer/hooks/useScansList' import { UPDATE_ACTIVE_TAB } from '@src/constants' import { format } from 'date-fns' diff --git a/src/renderer/src/components/SectionTabs.tsx b/src/renderer/src/components/SectionTabs.tsx index b714ae4..76cb598 100644 --- a/src/renderer/src/components/SectionTabs.tsx +++ b/src/renderer/src/components/SectionTabs.tsx @@ -1,5 +1,5 @@ import Directories from '@renderer/Sections/Directories' -import { useMain } from '@renderer/context/MainContext' +import useMain from '@renderer/context/hooks/useMain' import { REMOVE_SCAN, UPDATE_ACTIVE_TAB } from '@src/constants' import { keys } from 'ramda' import { Suspense, lazy, memo, useMemo } from 'react' @@ -15,7 +15,7 @@ const classNames = { contentContainer: 'bg-base-300 h-full w-full rounded-t-none rounded-b overflow-hidden p-4' } -function SectionTabs(): JSX.Element { +const Tabs = memo(function SectionTabs(): JSX.Element { const { state, dispatch } = useMain() const handleTabClick = (tabId: string): void => { @@ -101,6 +101,6 @@ function SectionTabs(): JSX.Element {
    ) -} +}) -export default memo(SectionTabs) +export default Tabs diff --git a/src/renderer/src/components/Table/ColumnSelection.tsx b/src/renderer/src/components/Table/ColumnSelection.tsx index 6aed081..772aa05 100644 --- a/src/renderer/src/components/Table/ColumnSelection.tsx +++ b/src/renderer/src/components/Table/ColumnSelection.tsx @@ -3,8 +3,8 @@ import { duplicatesColumns, unCratedColumns } from '@renderer/Sections/Results/columns' -import { useMain } from '@renderer/context/MainContext' -import { useTableContext } from '@renderer/context/TableContext' +import useMain from '@renderer/context/hooks/useMain' +import useTableContext from '@renderer/context/hooks/useTableContext' import { useEffect, useMemo } from 'react' const columMap = { @@ -58,6 +58,7 @@ const ColumnSelection = ({ id }: { id: string }): JSX.Element => { {} ) }) + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) const handleCheckboxChange = (columnName: string): void => { diff --git a/src/renderer/src/components/Table/InderminateCheckbox.tsx b/src/renderer/src/components/Table/InderminateCheckbox.tsx index c99453f..1450c44 100644 --- a/src/renderer/src/components/Table/InderminateCheckbox.tsx +++ b/src/renderer/src/components/Table/InderminateCheckbox.tsx @@ -11,7 +11,7 @@ export default function IndeterminateCheckbox({ if (typeof indeterminate === 'boolean') { ref.current.indeterminate = !rest.checked && indeterminate } - }, [ref, indeterminate]) + }, [ref, indeterminate, rest.checked]) return (
    diff --git a/src/renderer/src/context/MainContext.tsx b/src/renderer/src/context/MainContext.tsx index 76245fa..e2b1bd1 100644 --- a/src/renderer/src/context/MainContext.tsx +++ b/src/renderer/src/context/MainContext.tsx @@ -5,10 +5,10 @@ import { useIpcListener } from '@renderer/hooks/useIPCListener' import useScanTracking from '@renderer/hooks/useScanTracking' import { NEW_FILES_DIRECTORY } from '@src/constants' import { DatabaseOperationResult } from '@src/types' -import React, { ReactNode, createContext, useContext, useReducer } from 'react' +import React, { ReactNode, createContext, useReducer } from 'react' import { directoryReducer, initialState } from '../actions/reducer' -const MainContext = createContext(null) +export const MainContext = createContext(null) interface MainProviderProps { children: ReactNode @@ -40,12 +40,3 @@ export const MainProvider: React.FC = ({ children }) => { return {children} } - -// Custom hook to use the directory state and dispatch -export const useMain = (): MainContextProps => { - const context = useContext(MainContext) - if (!context) { - throw new Error('useDirectory must be used within a DirectoryProvider') - } - return context -} diff --git a/src/renderer/src/context/TableContext.tsx b/src/renderer/src/context/TableContext.tsx index 409bf37..c1e55d1 100644 --- a/src/renderer/src/context/TableContext.tsx +++ b/src/renderer/src/context/TableContext.tsx @@ -1,8 +1,8 @@ import { TableContextProps } from '@src/types' import { ExpandedState, VisibilityState } from '@tanstack/react-table' -import React, { ReactNode, createContext, useContext, useState } from 'react' +import React, { ReactNode, createContext, useState } from 'react' -const TableContext = createContext(undefined) +export const TableContext = createContext(undefined) interface TableProviderProps { children: ReactNode @@ -31,11 +31,3 @@ export const TableProvider: React.FC = ({ children }) => { ) } - -export const useTableContext = (): TableContextProps => { - const context = useContext(TableContext) - if (!context) { - throw new Error('useTableContext must be used within a TableProvider') - } - return context -} diff --git a/src/renderer/src/context/hooks/useMain.ts b/src/renderer/src/context/hooks/useMain.ts new file mode 100644 index 0000000..f06b9f6 --- /dev/null +++ b/src/renderer/src/context/hooks/useMain.ts @@ -0,0 +1,14 @@ +import { MainContextProps } from '@renderer/actions/types' +import { useContext } from 'react' +import { MainContext } from '../MainContext' + +// Custom hook to use the directory state and dispatch +const useMain = (): MainContextProps => { + const context = useContext(MainContext) + if (!context) { + throw new Error('useDirectory must be used within a DirectoryProvider') + } + return context +} + +export default useMain diff --git a/src/renderer/src/context/hooks/useTableContext.ts b/src/renderer/src/context/hooks/useTableContext.ts new file mode 100644 index 0000000..13d22c7 --- /dev/null +++ b/src/renderer/src/context/hooks/useTableContext.ts @@ -0,0 +1,13 @@ +import { TableContextProps } from '@src/types' +import { useContext } from 'react' +import { TableContext } from '../TableContext' + +const useTableContext = (): TableContextProps => { + const context = useContext(TableContext) + if (!context) { + throw new Error('useTableContext must be used within a TableProvider') + } + return context +} + +export default useTableContext diff --git a/src/renderer/src/hooks/useDeletedFilesTracking.ts b/src/renderer/src/hooks/useDeletedFilesTracking.ts index 3708c9b..98f1c14 100644 --- a/src/renderer/src/hooks/useDeletedFilesTracking.ts +++ b/src/renderer/src/hooks/useDeletedFilesTracking.ts @@ -1,6 +1,6 @@ import { DeletedFiles } from '@prisma/client' import { getDeletedFilesById } from '@renderer/actions/ipc' -import { useMain } from '@renderer/context/MainContext' +import useMain from '@renderer/context/hooks/useMain' import { transformDeletedFiles } from '@renderer/utils/transformDeletedFiles' import { ADD_DELETED_FILES_RESULT } from '@src/constants' import { ExtendedScan } from '@src/types' diff --git a/src/renderer/src/hooks/useDirectoriesList.ts b/src/renderer/src/hooks/useDirectoriesList.ts index ac64f4d..42d5b77 100644 --- a/src/renderer/src/hooks/useDirectoriesList.ts +++ b/src/renderer/src/hooks/useDirectoriesList.ts @@ -1,6 +1,6 @@ import { FilesDirectory } from '@prisma/client' import { getFilesDirectories } from '@renderer/actions/ipc' -import { useMain } from '@renderer/context/MainContext' +import useMain from '@renderer/context/hooks/useMain' import { GET_FILES_DIRECTORIES } from '@src/constants' import { DatabaseOperationResult } from '@src/types' import { useQuery } from '@tanstack/react-query' diff --git a/src/renderer/src/hooks/useIPCListener.ts b/src/renderer/src/hooks/useIPCListener.ts index c8be3c7..f2d5130 100644 --- a/src/renderer/src/hooks/useIPCListener.ts +++ b/src/renderer/src/hooks/useIPCListener.ts @@ -7,5 +7,5 @@ export const useIpcListener = (channel: string, callback: IPCListenerCallBack return () => { removeListener() } - }, [channel]) + }, [callback, channel]) } diff --git a/src/renderer/src/hooks/usePolling.ts b/src/renderer/src/hooks/usePolling.ts index a865e82..5cd6bbc 100644 --- a/src/renderer/src/hooks/usePolling.ts +++ b/src/renderer/src/hooks/usePolling.ts @@ -38,5 +38,5 @@ export const usePolling = ( clearInterval(intervalId.current) } } - }, [callback, interval]) + }, [callback, dispatch, interval]) } diff --git a/src/renderer/src/hooks/useScanTracking.ts b/src/renderer/src/hooks/useScanTracking.ts index ffbeb48..dbc2ea8 100644 --- a/src/renderer/src/hooks/useScanTracking.ts +++ b/src/renderer/src/hooks/useScanTracking.ts @@ -1,5 +1,5 @@ import { fetchScanStatusById } from '@renderer/actions/ipc' -import { useMain } from '@renderer/context/MainContext' +import useMain from '@renderer/context/hooks/useMain' import { transformScan } from '@renderer/utils/transformScan' import { UPDATE_SCAN_STATUS } from '@src/constants' import { useEffect } from 'react' @@ -112,7 +112,7 @@ const useScanTracking = ({ clearTimeout(timeoutId) intervalIds.forEach((id) => clearInterval(id)) } - }, [state.scans]) + }, [dispatch, state.scans]) } export default useScanTracking diff --git a/src/renderer/src/hooks/useScansList.ts b/src/renderer/src/hooks/useScansList.ts index ea38b2a..54b2c26 100644 --- a/src/renderer/src/hooks/useScansList.ts +++ b/src/renderer/src/hooks/useScansList.ts @@ -1,6 +1,6 @@ import { Scan } from '@prisma/client' import { getScansList } from '@renderer/actions/ipc' -import { useMain } from '@renderer/context/MainContext' +import useMain from '@renderer/context/hooks/useMain' import { DatabaseOperationResult } from '@src/types' import { useQuery } from '@tanstack/react-query' import { useEffect } from 'react' @@ -31,5 +31,5 @@ export default function useScansList(): void { } }) } - }, [data]) + }, [data, dispatch]) } From 4089ac2b1a9d6db0041f6d5785de424e95a90bf6 Mon Sep 17 00:00:00 2001 From: Narin Sundarabhaya Date: Sat, 28 Oct 2023 14:33:04 +0700 Subject: [PATCH 6/6] fix node version --- .github/workflows/eslint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index b6f3b52..895050f 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -3,7 +3,7 @@ name: ESLint on: push: branches: - - main # adjust with your default branch if it's not "main" + - main pull_request: jobs: @@ -17,7 +17,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v2 with: - node-version: '14' # adjust with your desired Node.js version + node-version: 18 - name: Install dependencies run: yarn install --frozen-lockfile