diff --git a/react-ui/src/components/devices/api/pnd.fetch.ts b/react-ui/src/components/devices/api/pnd.fetch.ts deleted file mode 100644 index fd49de636e53fccf73bddc19741d71ab0472c71d..0000000000000000000000000000000000000000 --- a/react-ui/src/components/devices/api/pnd.fetch.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { PndServiceGetPndListApiArg, api } from "@api/api" -import { createAsyncThunk } from "@reduxjs/toolkit" -import { setPnds } from "../reducer/device.reducer" - -// TODO rethink this. This should be in the shared part bc its getting invoked in the procteded layout -export const fetchPnds = createAsyncThunk('device/fetchPnds', (_, thunkApi) => { - const payload: PndServiceGetPndListApiArg = { - timestamp: new Date().getTime().toString(), - } - - const subscription = thunkApi.dispatch(api.endpoints.pndServiceGetPndList.initiate(payload)) - subscription.unwrap().then((response) => { - thunkApi.dispatch(setPnds(response.pnd)) - }) -}) \ No newline at end of file diff --git a/react-ui/src/components/devices/view/device.view.table.tsx b/react-ui/src/components/devices/view/device.view.table.tsx index 9b731fef5ae0ff067e14455f15bedbbd066aa82f..337148f92837e4ebd627a04cd059016b314f3794 100755 --- a/react-ui/src/components/devices/view/device.view.table.tsx +++ b/react-ui/src/components/devices/view/device.view.table.tsx @@ -1,4 +1,6 @@ +import { insertMarkTags } from "@helper/text"; import { useAppSelector } from "@hooks"; +import DOMPurify from 'dompurify'; import { MutableRefObject, useCallback } from "react"; import { OverlayTrigger, Table, Tooltip } from "react-bootstrap"; import { useTranslation } from "react-i18next"; @@ -15,25 +17,30 @@ export const DeviceViewTable = (searchRef: MutableRefObject<HTMLInputElement>) = } const getDeviceTable = useCallback(() => { - return devices.filter((device) => { - if (!searchRef.current?.value) { - return true; - } + const search = searchRef.current?.value; + let filtered = devices - const searchInput = searchRef.current!.value; - const user = pnds.find(pnd => pnd.id === device.pid); + // filter if something is in search + if (search) { + filtered = devices.filter((device) => { + const user = pnds.find(pnd => pnd.id === device.pid); + + return device.id?.includes(search) || + device.name?.includes(search) || + user?.name?.includes(search); + }) + } - return device.id.includes(searchInput) || device.name.includes(searchInput) || user?.name.includes(searchInput); - }).map((device, index) => { + return filtered.map((device, index) => { const user = pnds.find(pnd => pnd.id === device.pid); return ( <tr key={index} onClick={() => trClickHandler(device)} className={selectedDevice?.device.id === device.id ? 'active' : ''}> - <td>{device.name}</td> + <td key={0} dangerouslySetInnerHTML={{ __html: search ? insertMarkTags(device.name!, search) : DOMPurify.sanitize(device.name) }}></td> <OverlayTrigger overlay={<Tooltip id={device.id}>{device.id}</Tooltip>}> - <td>{cropUUID(device.id)}</td> + <td dangerouslySetInnerHTML={{ __html: search ? insertMarkTags(cropUUID(device.id!), search) : DOMPurify.sanitize(cropUUID(device.id!)) }}></td> </OverlayTrigger> - <td>{user?.name || ''}</td> + <td key={1} dangerouslySetInnerHTML={{ __html: search ? insertMarkTags(user?.name || '', search) : DOMPurify.sanitize(user?.name || '') }}></td> <td></td> </tr> ) @@ -41,6 +48,7 @@ export const DeviceViewTable = (searchRef: MutableRefObject<HTMLInputElement>) = }, [devices, searchRef, pnds, selectedDevice, trClickHandler]); + return ( <Table striped responsive className="device-table"> <thead> diff --git a/react-ui/src/shared/components/json_viewer/view/json_viewer.view.tsx b/react-ui/src/shared/components/json_viewer/view/json_viewer.view.tsx index b8358c686994263e5c731504806da2c139b3f648..33e52a39788fe1120c18972c14181a6abaf8067b 100755 --- a/react-ui/src/shared/components/json_viewer/view/json_viewer.view.tsx +++ b/react-ui/src/shared/components/json_viewer/view/json_viewer.view.tsx @@ -1,5 +1,6 @@ import { faAlignRight, faPenToSquare, faTrashCan } from "@fortawesome/free-solid-svg-icons" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" +import { insertMarkTags } from "@helper/text" import DOMPurify from 'dompurify' import React, { Suspense, useMemo, useRef } from "react" import { Form, Table } from "react-bootstrap" @@ -30,13 +31,6 @@ export const JsonViewer = ({ json }: JsonViewerProbs) => { ) }, [breadcrumbs]) - const insertMarkTags = (text: string, search: string): string => { - const start = text.indexOf(search) - const end = start + search.length - - return DOMPurify.sanitize(text.substring(0, start)) + "<span class='highlight'>" + DOMPurify.sanitize(search) + "</span>" + DOMPurify.sanitize(text.substring(end, text.length)) - } - const renderInner = (innerJson: JSON, nested: number = 0, parentKey: string = "", path: string = "/network-instance/0/"): JSX.Element => { path += parentKey + (parentKey === "" ? "" : "/") diff --git a/react-ui/src/shared/helper/text.ts b/react-ui/src/shared/helper/text.ts new file mode 100644 index 0000000000000000000000000000000000000000..6aee13790561eefcfe347fb2e42a79c5ef84cfec --- /dev/null +++ b/react-ui/src/shared/helper/text.ts @@ -0,0 +1,12 @@ + +import DOMPurify from 'dompurify' + +export const insertMarkTags = (text: string, search: string): string => { + const start = text.indexOf(search) + if (start === -1) { + return DOMPurify.sanitize(text) + } + const end = start + search.length + + return DOMPurify.sanitize(text.substring(0, start)) + "<span class='highlight'>" + DOMPurify.sanitize(search) + "</span>" + DOMPurify.sanitize(text.substring(end, text.length)) +} \ No newline at end of file diff --git a/react-ui/src/shared/layouts/protected.layout/protected.layout.tsx b/react-ui/src/shared/layouts/protected.layout/protected.layout.tsx index 17b6209a5ac3fb3620fb07cd5e44ad46424d92a6..b017cf56f1987964e8221b53a11af3bc00436f0e 100755 --- a/react-ui/src/shared/layouts/protected.layout/protected.layout.tsx +++ b/react-ui/src/shared/layouts/protected.layout/protected.layout.tsx @@ -1,12 +1,11 @@ -import { fetchUser } from '@api/user.fetch'; import logo from '@assets/logo.svg'; -import { fetchPnds } from '@component/devices/api/pnd.fetch'; import { faCircleUser, faRightFromBracket } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useAppDispatch, useAppSelector } from '@hooks'; import { useAuth } from "@provider/auth.provider"; import { MenuProvider } from '@provider/menu/menu.provider'; import { DEVICE_URL, LOGIN_URL } from '@routes'; +import { fetchPnds, fetchUser } from '@shared/routine/user.routine'; import React, { useEffect } from "react"; import { Dropdown } from "react-bootstrap"; import { useTranslation } from "react-i18next"; diff --git a/react-ui/src/shared/api/user.fetch.ts b/react-ui/src/shared/routine/user.routine.ts similarity index 63% rename from react-ui/src/shared/api/user.fetch.ts rename to react-ui/src/shared/routine/user.routine.ts index 08806783b867714aae8f7804081dc302c184f238..368ccf41246176c533b2394a581124200668f527 100644 --- a/react-ui/src/shared/api/user.fetch.ts +++ b/react-ui/src/shared/routine/user.routine.ts @@ -1,7 +1,8 @@ +import { api, PndServiceGetPndListApiArg, UserServiceGetUsersApiArg } from "@api/api" +import { setPnds } from "@component/devices/reducer/device.reducer" import { createAsyncThunk } from "@reduxjs/toolkit" import { setUser } from "@shared/reducer/user.reducer" import { RootState } from "src/stores" -import { api, UserServiceGetUsersApiArg } from "./api" export const fetchUser = createAsyncThunk('user/fetchUser', (_, thunkAPI) => { const payload: UserServiceGetUsersApiArg = {} @@ -23,3 +24,14 @@ export const fetchUser = createAsyncThunk('user/fetchUser', (_, thunkAPI) => { thunkAPI.dispatch(setUser(matchedUser)) }) }) + +export const fetchPnds = createAsyncThunk('device/fetchPnds', (_, thunkApi) => { + const payload: PndServiceGetPndListApiArg = { + timestamp: new Date().getTime().toString(), + } + + const subscription = thunkApi.dispatch(api.endpoints.pndServiceGetPndList.initiate(payload)) + subscription.unwrap().then((response) => { + thunkApi.dispatch(setPnds(response.pnd)) + }) +}) \ No newline at end of file