From 6624defbe69df3a3296357dd175027f9d29748c7 Mon Sep 17 00:00:00 2001 From: "Juan B. Rodriguez" Date: Sun, 22 Dec 2024 13:49:02 -0500 Subject: [PATCH] feat: restore select all targets button (scatter) (#109) * feat: initial toggle all ui + logic (wip) * feat: implement select all feature --- ui/src/flows/scatter/select/targets.tsx | 15 +++++++++++++-- ui/src/flows/scatter/select/toggle.tsx | 19 +++++++++++++++++++ ui/src/shared/panel/panel.tsx | 11 ++++++++--- ui/src/state/scatter.tsx | 23 +++++++++++++++++++++++ 4 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 ui/src/flows/scatter/select/toggle.tsx diff --git a/ui/src/flows/scatter/select/targets.tsx b/ui/src/flows/scatter/select/targets.tsx index 00bc8846..6fbd2019 100644 --- a/ui/src/flows/scatter/select/targets.tsx +++ b/ui/src/flows/scatter/select/targets.tsx @@ -6,24 +6,35 @@ import { useScatterSource, useScatterTargets, useScatterActions, + useScatterAllTargetsChecked, } from '~/state/scatter'; import { Checkbox } from '~/shared/checkbox/checkbox'; import { Disk } from '~/shared/disk/disk'; import { Disk as IDisk } from '~/types'; +import { Toggle } from './toggle'; export const Targets: React.FunctionComponent = () => { const disks = useUnraidDisks(); const source = useScatterSource(); const targets = useScatterTargets(); - const { toggleTarget } = useScatterActions(); + const allChecked = useScatterAllTargetsChecked(); + const { toggleTarget, toggleAll } = useScatterActions(); const visible = source !== ''; const elegible = disks.filter((disk) => disk.name !== source); const onCheck = (disk: IDisk) => () => toggleTarget(disk.name); + const onToggleAll = () => toggleAll(disks.map((d) => d.name)); return ( - + + ) : undefined + } + > {visible && elegible.map((disk) => (
diff --git a/ui/src/flows/scatter/select/toggle.tsx b/ui/src/flows/scatter/select/toggle.tsx new file mode 100644 index 00000000..361c2e0d --- /dev/null +++ b/ui/src/flows/scatter/select/toggle.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Checkbox } from '~/shared/checkbox/checkbox'; + +interface ToggleProps { + allChecked: boolean; + onCheck: () => void; +} + +export const Toggle: React.FunctionComponent = ({ + allChecked, + onCheck, +}) => { + return ( +
+ + Select All +
+ ); +}; diff --git a/ui/src/shared/panel/panel.tsx b/ui/src/shared/panel/panel.tsx index 30a050ab..bc2b4235 100644 --- a/ui/src/shared/panel/panel.tsx +++ b/ui/src/shared/panel/panel.tsx @@ -6,12 +6,14 @@ interface PanelProps { title?: string; children: React.ReactNode; scrollToTop?: boolean; + subtitle?: React.ReactNode; } export const Panel: React.FunctionComponent = ({ title = '', children, scrollToTop = false, + subtitle = null, }) => { const ref = React.useRef(null); @@ -25,9 +27,12 @@ export const Panel: React.FunctionComponent = ({
{title.length > 0 ? (
-

- {title} -

+
+

+ {title} +

+ {subtitle} +

) : null} diff --git a/ui/src/state/scatter.tsx b/ui/src/state/scatter.tsx index db0f2440..7a97b7fe 100644 --- a/ui/src/state/scatter.tsx +++ b/ui/src/state/scatter.tsx @@ -12,11 +12,13 @@ interface ScatterStore { targets: Targets; tree: Nodes; binDisk: string; + allTargetsChecked: boolean; actions: { setSource: (source: string) => Promise; loadBranch: (node: Node) => Promise; toggleSelected: (node: Node) => void; toggleTarget: (name: string) => void; + toggleAll: (names: string[]) => void; setBinDisk: (binDisk: string) => void; }; } @@ -45,6 +47,7 @@ export const useScatterStore = create()( tree: { root: decorateNode(rootNode as Node) }, logs: [], binDisk: '', + allTargetsChecked: false, actions: { setSource: async (source: string) => { const loader = decorateNode({ ...loaderNode } as Node); @@ -171,6 +174,24 @@ export const useScatterStore = create()( } delete state.targets[name]; + state.allTargetsChecked = false; + }); + }, + toggleAll: (names: string[]) => { + set((state) => { + state.allTargetsChecked = !state.allTargetsChecked; + + for (let i = 0; i < names.length; i++) { + if (names[i] === state.source) { + continue; + } + + if (state.allTargetsChecked) { + state.targets[names[i]] = true; + } else { + delete state.targets[names[i]]; + } + } }); }, setBinDisk: (binDisk: string) => { @@ -195,3 +216,5 @@ export const useScatterTargets = () => useScatterStore((state) => state.targets); export const useScatterBinDisk = () => useScatterStore((state) => state.binDisk); +export const useScatterAllTargetsChecked = () => + useScatterStore((state) => state.allTargetsChecked);