diff --git a/client/src/javascript/components/sidebar/LocationFilters.tsx b/client/src/javascript/components/sidebar/LocationFilters.tsx index 859b8a4f6..ef4b1f8ce 100644 --- a/client/src/javascript/components/sidebar/LocationFilters.tsx +++ b/client/src/javascript/components/sidebar/LocationFilters.tsx @@ -16,25 +16,37 @@ const LocationFilters: FC = observer(() => { } const buildLocationFilterTree = (location: LocationTreeNode): ReactNode => { - if (location.children.length === 1 && TorrentFilterStore.taxonomy.locationCounts[location.fullPath] === TorrentFilterStore.taxonomy.locationCounts[location.children[0].fullPath]) { + if ( + location.children.length === 1 && + TorrentFilterStore.taxonomy.locationCounts[location.fullPath] === + TorrentFilterStore.taxonomy.locationCounts[location.children[0].fullPath] + ) { const onlyChild = location.children[0]; - const separator = onlyChild.fullPath.includes('/') ? '/' : '\\' - return buildLocationFilterTree({...onlyChild, directoryName: location.directoryName + separator + onlyChild.directoryName}); + const separator = onlyChild.fullPath.includes('/') ? '/' : '\\'; + return buildLocationFilterTree({ + ...onlyChild, + directoryName: location.directoryName + separator + onlyChild.directoryName, + }); } const children = location.children.map(buildLocationFilterTree); return ( - TorrentFilterStore.setLocationFilters(filter, event)} + + TorrentFilterStore.setLocationFilters(filter, event) + } count={TorrentFilterStore.taxonomy.locationCounts[location.fullPath] || 0} key={location.fullPath} - isActive={(location.fullPath === '' && !TorrentFilterStore.locationFilter.length) || TorrentFilterStore.locationFilter.includes(location.fullPath)} + isActive={ + (location.fullPath === '' && !TorrentFilterStore.locationFilter.length) || + TorrentFilterStore.locationFilter.includes(location.fullPath) + } name={location.directoryName} slug={location.fullPath} size={TorrentFilterStore.taxonomy.locationSizes[location.fullPath]} > - {children.length && children || undefined} + {(children.length && children) || undefined} ); }; diff --git a/client/src/javascript/components/sidebar/SidebarFilter.tsx b/client/src/javascript/components/sidebar/SidebarFilter.tsx index 413117f65..7c64e4023 100644 --- a/client/src/javascript/components/sidebar/SidebarFilter.tsx +++ b/client/src/javascript/components/sidebar/SidebarFilter.tsx @@ -36,12 +36,14 @@ const SidebarFilter: FC = ({ }); const expanderClassNames = classnames('sidebar-filter__expander', { 'is-active': isActive, - 'expanded': expanded, - }) + expanded: expanded, + }); - const flexCss = children ? { - display: 'flex', - }: {}; + const flexCss = children + ? { + display: 'flex', + } + : {}; const focusCss = { ':focus': { outline: 'none', @@ -69,28 +71,28 @@ const SidebarFilter: FC = ({ const target = event.target as HTMLSpanElement; const overflowed = target.scrollWidth > target.clientWidth; target.title = overflowed ? target.textContent || '' : ''; - } + }; const unsetTitle = (event: MouseEvent) => { const target = event.target as HTMLSpanElement; target.title = ''; - } + }; return (
  • - {children && - - } + {children && ( + + )}
    - {children && expanded && -
      - {children} -
    } + {children && expanded &&
      {children}
    }
  • ); }; diff --git a/client/src/javascript/stores/TorrentFilterStore.ts b/client/src/javascript/stores/TorrentFilterStore.ts index 30b804640..d207fa618 100644 --- a/client/src/javascript/stores/TorrentFilterStore.ts +++ b/client/src/javascript/stores/TorrentFilterStore.ts @@ -1,9 +1,9 @@ -import {computed, makeAutoObservable} from 'mobx'; -import jsonpatch, {Operation} from 'fast-json-patch'; -import {KeyboardEvent, MouseEvent, TouchEvent} from 'react'; +import { computed, makeAutoObservable } from 'mobx'; +import jsonpatch, { Operation } from 'fast-json-patch'; +import { KeyboardEvent, MouseEvent, TouchEvent } from 'react'; -import type {Taxonomy} from '@shared/types/Taxonomy'; -import torrentStatusMap, {TorrentStatus} from '@shared/constants/torrentStatusMap'; +import type { Taxonomy } from '@shared/types/Taxonomy'; +import torrentStatusMap, { TorrentStatus } from '@shared/constants/torrentStatusMap'; class TorrentFilterStore { locationFilter: Array = []; @@ -26,7 +26,13 @@ class TorrentFilterStore { }; @computed get isFilterActive() { - return this.locationFilter.length || this.searchFilter !== '' || this.statusFilter.length || this.tagFilter.length || this.trackerFilter.length; + return ( + this.locationFilter.length || + this.searchFilter !== '' || + this.statusFilter.length || + this.tagFilter.length || + this.trackerFilter.length + ); } constructor() { diff --git a/server/services/taxonomyService.ts b/server/services/taxonomyService.ts index ce61a99d7..76925ff50 100644 --- a/server/services/taxonomyService.ts +++ b/server/services/taxonomyService.ts @@ -1,14 +1,14 @@ -import jsonpatch, {Operation} from 'fast-json-patch'; +import jsonpatch, { Operation } from 'fast-json-patch'; import BaseService from './BaseService'; import torrentStatusMap from '../../shared/constants/torrentStatusMap'; -import type {Taxonomy, LocationTreeNode} from '../../shared/types/Taxonomy'; -import type {TorrentStatus} from '../../shared/constants/torrentStatusMap'; -import type {TorrentProperties, TorrentList} from '../../shared/types/Torrent'; +import type { Taxonomy, LocationTreeNode } from '../../shared/types/Taxonomy'; +import type { TorrentStatus } from '../../shared/constants/torrentStatusMap'; +import type { TorrentProperties, TorrentList } from '../../shared/types/Torrent'; interface TaxonomyServiceEvents { - TAXONOMY_DIFF_CHANGE: (payload: {id: number; diff: Operation[]}) => void; + TAXONOMY_DIFF_CHANGE: (payload: { id: number; diff: Operation[] }) => void; } class TaxonomyService extends BaseService { @@ -16,10 +16,10 @@ class TaxonomyService extends BaseService { locationCounts: { '': 0 }, locationSizes: {}, locationTree: [], - statusCounts: {'': 0}, - tagCounts: {'': 0, untagged: 0}, + statusCounts: { '': 0 }, + tagCounts: { '': 0, untagged: 0 }, tagSizes: {}, - trackerCounts: {'': 0}, + trackerCounts: { '': 0 }, trackerSizes: {}, }; @@ -33,7 +33,7 @@ class TaxonomyService extends BaseService { return; } - const {clientGatewayService} = this.services; + const { clientGatewayService } = this.services; clientGatewayService.on('PROCESS_TORRENT_LIST_START', this.handleProcessTorrentListStart); clientGatewayService.on('PROCESS_TORRENT_LIST_END', this.handleProcessTorrentListEnd); @@ -46,7 +46,7 @@ class TaxonomyService extends BaseService { return; } - const {clientGatewayService} = this.services; + const { clientGatewayService } = this.services; clientGatewayService.removeListener('PROCESS_TORRENT_LIST_START', this.handleProcessTorrentListStart); clientGatewayService.removeListener('PROCESS_TORRENT_LIST_END', this.handleProcessTorrentListEnd); @@ -64,27 +64,27 @@ class TaxonomyService extends BaseService { handleProcessTorrentListStart = () => { this.lastTaxonomy = { - locationCounts: {...this.taxonomy.locationCounts}, - locationSizes: {...this.taxonomy.locationCounts}, + locationCounts: { ...this.taxonomy.locationCounts }, + locationSizes: { ...this.taxonomy.locationCounts }, locationTree: [...this.taxonomy.locationTree], - statusCounts: {...this.taxonomy.statusCounts}, - tagCounts: {...this.taxonomy.tagCounts}, - tagSizes: {...this.taxonomy.tagSizes}, - trackerCounts: {...this.taxonomy.trackerCounts}, - trackerSizes: {...this.taxonomy.trackerSizes}, + statusCounts: { ...this.taxonomy.statusCounts }, + tagCounts: { ...this.taxonomy.tagCounts }, + tagSizes: { ...this.taxonomy.tagSizes }, + trackerCounts: { ...this.taxonomy.trackerCounts }, + trackerSizes: { ...this.taxonomy.trackerSizes }, }; torrentStatusMap.forEach((status) => { this.taxonomy.statusCounts[status] = 0; }); - this.taxonomy.locationCounts = {'': 0}; + this.taxonomy.locationCounts = { '': 0 }; this.taxonomy.locationSizes = {}; - this.taxonomy.locationTree = [] + this.taxonomy.locationTree = []; this.taxonomy.statusCounts[''] = 0; - this.taxonomy.tagCounts = {'': 0, untagged: 0}; + this.taxonomy.tagCounts = { '': 0, untagged: 0 }; this.taxonomy.tagSizes = {}; - this.taxonomy.trackerCounts = {'': 0}; + this.taxonomy.trackerCounts = { '': 0 }; this.taxonomy.trackerSizes = {}; }; @@ -99,39 +99,43 @@ class TaxonomyService extends BaseService { } // Order slashes before similar paths with different symbols, eg. /files/PC/ should come before /files/PC-98/ for treeing - return a.replace(/[^\\/\w]/g, "~").localeCompare(b.replace(/[^\\/\w]/g, "~")); + return a.replace(/[^\\/\w]/g, '~').localeCompare(b.replace(/[^\\/\w]/g, '~')); }); const separator = sortedLocations.length < 2 || sortedLocations[1].includes('/') ? '/' : '\\'; let previousLocation: LocationTreeNode; this.taxonomy.locationTree = sortedLocations.reduce((tree, filter) => { const directory = filter.split(separator).slice(-1)[0]; - const parentPath = filter.substring(0, filter.lastIndexOf(separator + directory)) + const parentPath = filter.substring(0, filter.lastIndexOf(separator + directory)); const location: LocationTreeNode = { directoryName: directory, fullPath: filter, children: [] }; - while (previousLocation) { // Move up the tree to a matching parent + while (previousLocation) { + // Move up the tree to a matching parent if (!previousLocation.parent || previousLocation.fullPath === parentPath) { break; } previousLocation = previousLocation.parent; } - if (previousLocation && previousLocation.fullPath === parentPath && parentPath !== '') { // Child + if (previousLocation && previousLocation.fullPath === parentPath && parentPath !== '') { + // Child location.parent = previousLocation; previousLocation.children.push(location); - } else if (previousLocation && previousLocation.parent && previousLocation.parent.fullPath === parentPath) { // Sibling + } else if (previousLocation && previousLocation.parent && previousLocation.parent.fullPath === parentPath) { + // Sibling location.parent = previousLocation.parent; previousLocation.parent.children.push(location); - } else { // Root + } else { + // Root tree.push(location); } previousLocation = location; return tree; }, [] as LocationTreeNode[]); - } + }; cleanLocationTree = (location: LocationTreeNode) => { location.parent = undefined; location.children.forEach(this.cleanLocationTree); - } + }; handleProcessTorrentListEnd = ({ torrents }: { torrents: TorrentList }) => { const { length } = Object.keys(torrents); @@ -163,7 +167,10 @@ class TaxonomyService extends BaseService { this.incrementTrackerSizes(torrentProperties.trackerURIs, torrentProperties.sizeBytes); }; - incrementLocationCountsAndSizes(directory: TorrentProperties['directory'], sizeBytes: TorrentProperties['sizeBytes']) { + incrementLocationCountsAndSizes( + directory: TorrentProperties['directory'], + sizeBytes: TorrentProperties['sizeBytes'], + ) { const separator = directory.includes('/') ? '/' : '\\'; const parts = directory.startsWith(separator) ? directory.split(separator).slice(1) : directory.split(separator); let heirarchy = ''; diff --git a/shared/types/Taxonomy.ts b/shared/types/Taxonomy.ts index 765eb1e40..a3abe5314 100644 --- a/shared/types/Taxonomy.ts +++ b/shared/types/Taxonomy.ts @@ -3,7 +3,7 @@ export interface LocationTreeNode { fullPath: string; children: LocationTreeNode[]; parent?: LocationTreeNode; -}; +} export interface Taxonomy { locationCounts: Record;