Skip to content

Commit 7fbb08e

Browse files
committed
feat: Add skipping local inventory in Network Search
1 parent fc1bbd3 commit 7fbb08e

File tree

4 files changed

+109
-17
lines changed

4 files changed

+109
-17
lines changed

jccm/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "jccm",
33
"productName": "Juniper Cloud Connection Manager",
44
"description": "Juniper Cloud Connection Manager",
5-
"version": "1.2.8",
5+
"version": "1.2.9",
66
"main": ".webpack/main",
77
"scripts": {
88
"start": "pkill -9 node; nodemon --watch ./src --ext js,json --ignore ./src/Frontend/ --exec 'electron-forge start'",

jccm/src/Frontend/Layout/InventorySearch/InventorySearch.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ const InventorySearchCard = ({ isOpen, onClose }) => {
381381
width: '100%',
382382
height: '100%',
383383
marginLeft: '10px',
384-
overflow: 'hidden',
384+
overflow: 'visible',
385385
}}
386386
>
387387
{/* Search Control */}

jccm/src/Frontend/Layout/InventorySearch/InventorySearchControl.js

+104-12
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
Popover,
1818
PopoverSurface,
1919
PopoverTrigger,
20+
Switch,
2021
tokens,
2122
} from '@fluentui/react-components';
2223

@@ -43,13 +44,15 @@ import { getDeviceFacts } from '../Devices';
4344

4445
export const InventorySearchControl = ({ subnets, startCallback, endCallback, onAddFact, onAddUndiscoveredList }) => {
4546
const { notify } = useNotify(); // Correctly use the hook here
46-
const { settings } = useStore();
47+
const { settings, inventory } = useStore();
4748

4849
const [isStart, setIsStart] = useState(false);
4950
const [searchRate, setSearchRate] = useState(10);
5051
const [hostSeq, setHostSeq] = useState(0);
5152
const [hostStatusCount, setHostStatusCount] = useState({});
5253
const [sshClientErrorCount, setSshClientErrorCount] = useState({});
54+
const [isSkipLocalInventory, setIsSkipLocalInventory] = useState(false);
55+
5356
const isStartRef = useRef(null);
5457
const hostSeqRef = useRef(null);
5558
const hostStatusCountRef = useRef(null);
@@ -103,6 +106,14 @@ export const InventorySearchControl = ({ subnets, startCallback, endCallback, on
103106
}
104107
};
105108

109+
const isDeviceInInventory = (device, inventory) => {
110+
const isInInventory = inventory.some(
111+
(invDevice) => invDevice.address === device.address && invDevice.port === device.port
112+
);
113+
// console.log(`${device.address}:${device.port} isDeviceInInventory: ${isInInventory}`);
114+
return isInInventory;
115+
};
116+
106117
const fetchDeviceFacts = async (device) => {
107118
const maxRetries = 2;
108119
const retryInterval = 1000; // 1 seconds in milliseconds
@@ -196,8 +207,26 @@ export const InventorySearchControl = ({ subnets, startCallback, endCallback, on
196207
setSshClientErrorCount({});
197208

198209
for (const device of getHostListMultiple(subnets)) {
210+
if (isSkipLocalInventory && isDeviceInInventory(device, inventory)) {
211+
// console.log(`>>>${device.address}:${device.port} isSkipLocalInventory: `, isSkipLocalInventory);
212+
213+
const status = 'Skipped';
214+
const message = 'Device is already in the local inventory.';
215+
216+
updateCount({ status, message });
217+
218+
await onAddUndiscoveredList({
219+
device: `${device.address}:${device.port}`,
220+
status,
221+
message,
222+
});
223+
224+
setHostSeq((seq) => seq + 1);
225+
continue;
226+
}
227+
199228
promises.push(fetchDeviceFacts(device)); // Add the promise to the array
200-
setHostSeq(n++);
229+
setHostSeq((seq) => seq + 1);
201230

202231
const expectedNextStart = startTime + n * interval;
203232
const currentTime = Date.now();
@@ -207,6 +236,8 @@ export const InventorySearchControl = ({ subnets, startCallback, endCallback, on
207236
await delay(dynamicDelay); // Adjust delay dynamically
208237
}
209238

239+
n++; // Increment `n` ONLY for processed devices
240+
210241
if (isStartRef.current === false) return;
211242
}
212243

@@ -272,6 +303,11 @@ export const InventorySearchControl = ({ subnets, startCallback, endCallback, on
272303
const rotateColorIndex = Math.floor(((searchRate - minRate) / (maxRate - minRate)) * (rotateColors.length - 1));
273304
const rotateColor = rotateColors[rotateColorIndex];
274305

306+
const onChangeIsSkipLocalInventory = async (event) => {
307+
const checked = event.currentTarget.checked;
308+
setIsSkipLocalInventory(checked === true);
309+
};
310+
275311
return (
276312
<div
277313
style={{
@@ -289,21 +325,77 @@ export const InventorySearchControl = ({ subnets, startCallback, endCallback, on
289325
justifyContent: 'space-between',
290326
width: '100%',
291327
// height: '24px',
292-
overflow: 'visible',
328+
// overflow: 'visible',
293329
gap: '10px',
330+
position: 'relative', // Enable relative positioning for the parent container
294331
}}
295332
>
333+
{/* Overlay for the "Skip local inventory" switch */}
334+
<div
335+
style={{
336+
position: 'absolute',
337+
top: '-40px', // Adjust as needed to position above the search button
338+
left: '-25px',
339+
width: '100%',
340+
display: 'flex',
341+
justifyContent: 'flex-start', // Align to the left
342+
alignItems: 'center',
343+
zIndex: 10, // Ensure it appears above other elements
344+
pointerEvents: 'auto', // Allow interactions
345+
overflow: 'visible',
346+
}}
347+
>
348+
<Tooltip
349+
content={
350+
<Text size={100} align='center'>
351+
Skips addresses in local inventory for faster searches. Merge new inventory instead of
352+
replacing it.
353+
</Text>
354+
}
355+
positioning='after'
356+
>
357+
<div
358+
style={{
359+
display: 'flex',
360+
flexDirection: 'row',
361+
alignItems: 'center',
362+
gap: '5px',
363+
}}
364+
>
365+
<div
366+
style={{
367+
transform: 'scale(0.4)',
368+
transformOrigin: 'right',
369+
}}
370+
>
371+
<Switch checked={isSkipLocalInventory} onChange={onChangeIsSkipLocalInventory} />
372+
</div>
373+
<Text size={100}>{isSkipLocalInventory ? 'Skip' : `Do not skip`} local inventory</Text>
374+
</div>
375+
</Tooltip>
376+
</div>
377+
296378
{!isStart ? (
297-
<Button
298-
disabled={subnets?.length === 0}
299-
icon={<SearchPlayIcon />}
300-
shape='circular'
301-
appearance='subtle'
302-
size='small'
303-
onClick={onClickSearchStart}
379+
<div
380+
style={{
381+
display: 'flex',
382+
flexDirection: 'row',
383+
alignContent: 'center',
384+
justifyContent: 'flex-start',
385+
gap: '5px',
386+
}}
304387
>
305-
Search
306-
</Button>
388+
<Button
389+
disabled={subnets?.length === 0}
390+
icon={<SearchPlayIcon />}
391+
shape='circular'
392+
appearance='subtle'
393+
size='small'
394+
onClick={onClickSearchStart}
395+
>
396+
Search
397+
</Button>
398+
</div>
307399
) : (
308400
<Button
309401
disabled={subnets?.length === 0}

jccm/src/Frontend/Layout/InventorySearch/InventorySearchResult.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import {
2020
ArrowCircleRightRegular,
2121
PlayCircleHintRegular,
2222
PlayCircleHintFilled,
23-
ErrorCircleSettingsRegular,
24-
ErrorCircleSettingsFilled,
23+
ErrorCircleRegular,
24+
ErrorCircleFilled,
2525
bundleIcon,
2626
} from '@fluentui/react-icons';
2727

@@ -31,7 +31,7 @@ import { RWTable } from './RWTable';
3131
import { useNotify } from '../../Common/NotificationContext';
3232

3333
const ExportButtonIcon = bundleIcon(PlayCircleHintFilled, PlayCircleHintRegular);
34-
const LogExportButtonIcon = bundleIcon(ErrorCircleSettingsFilled, ErrorCircleSettingsRegular);
34+
const LogExportButtonIcon = bundleIcon(ErrorCircleFilled, ErrorCircleRegular);
3535

3636
export const InventorySearchResult = ({ columns, items, rowHeight, disabled, undiscoveredList }) => {
3737
const { notify } = useNotify(); // Correctly use the hook here

0 commit comments

Comments
 (0)