From cd717eada42230e5c087c2fc4a31a0f7bf39a6d7 Mon Sep 17 00:00:00 2001 From: Mikhail Petrov Date: Wed, 4 Jun 2025 17:16:21 +0300 Subject: [PATCH 1/4] web: Put api version in call function so that users understands which version of api is used in which function Signed-off-by: Mikhail Petrov --- .env | 2 +- README.md | 2 +- src/App.jsx | 18 +++++++++--------- src/Components/ContainerItem/ContainerItem.jsx | 4 ++-- src/Components/EACLPanel/EACLPanel.jsx | 2 +- src/Components/TreeView/TreeView.jsx | 8 ++++---- src/Getobject.jsx | 4 ++-- src/Profile.jsx | 4 ++-- src/api.js | 2 +- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.env b/.env index 2d6d54d..06b726a 100644 --- a/.env +++ b/.env @@ -2,7 +2,7 @@ VITE_WC_PROJECT_ID=8e39af16af0819871be6f2da61a3a038 VITE_URL=https://panel.fs.neo.org/ -VITE_RESTGW=https://rest.fs.neo.org/v1 +VITE_RESTGW=https://rest.fs.neo.org # Mainnet NeoFS contract VITE_NETWORK=mainnet diff --git a/README.md b/README.md index 7b38183..481ab23 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ You can easily run the node locally in a docker container using [@nspcc-dev/neof You need to update the parameters in the `.env` file to make it work: ```env -VITE_RESTGW=http://localhost:8090/v1 +VITE_RESTGW=http://localhost:8090 ``` # Make instructions diff --git a/src/App.jsx b/src/App.jsx index 7adb63e..f72367f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -52,7 +52,7 @@ export const App = () => { }); const [params] = useState({ - rest_gw: import.meta.env.VITE_RESTGW ? import.meta.env.VITE_RESTGW : 'https://rest.t5.fs.neo.org/v1', + rest_gw: import.meta.env.VITE_RESTGW ? import.meta.env.VITE_RESTGW : 'https://rest.t5.fs.neo.org', }); const [objectLinkLifetime, setObjectLinkLifetime] = useState(new Date().toLocaleDateString("sv")); @@ -210,7 +210,7 @@ export const App = () => { onPopup('success', 'Wallet connected'); onModal(); - api('GET', '/network-info').then((e) => { + api('GET', '/v1/network-info').then((e) => { if (!e.message) { setNetworkInfo(e); } @@ -347,7 +347,7 @@ export const App = () => { }] } - api('POST', '/auth', body, { + api('POST', '/v1/auth', body, { "X-Bearer-Owner-Id": walletData.account.address, "X-Bearer-Lifetime": params.objectId ? formatDateToHours(objectLinkLifetime) : 2, "X-Bearer-For-All-Users": true, @@ -389,7 +389,7 @@ export const App = () => { } if (type === 'object') { - api('GET', '/auth/bearer?walletConnect=true', {}, { + api('GET', '/v1/auth/bearer?walletConnect=true', {}, { "Authorization": `Bearer ${msg}`, "X-Bearer-Signature": response.data + response.salt, "X-Bearer-Signature-Key": response.publicKey, @@ -412,7 +412,7 @@ export const App = () => { if (containerForm.containerName.length >= 3) { setError({ active: false, type: [], text: '' }); setLoadingForm(true); - api('PUT', '/containers?walletConnect=true&name-scope-global=true', { + api('PUT', '/v1/containers?walletConnect=true&name-scope-global=true', { "containerName": containerForm.containerName, "placementPolicy": containerForm.placementPolicy, "basicAcl": containerForm.basicAcl, @@ -440,7 +440,7 @@ export const App = () => { setError({ active: true, type: [], text: e.message }); } else { if (containerForm.eACLParams.length > 0) { - api('PUT', `/containers/${e.containerId}/eacl?walletConnect=true`, { + api('PUT', `/v1/containers/${e.containerId}/eacl?walletConnect=true`, { "records": containerForm.eACLParams.filter((item) => delete item.isOpen), }, { "Authorization": `Bearer ${walletData.tokens.container.SETEACL.token}`, @@ -492,7 +492,7 @@ export const App = () => { const onDeleteContainer = (containerName) => { setLoadingForm(true); setError({ active: false, type: [], text: '' }); - api('DELETE', `/containers/${containerName}?walletConnect=true`, {}, { + api('DELETE', `/v1/containers/${containerName}?walletConnect=true`, {}, { "Authorization": `Bearer ${walletData.tokens.container.DELETE.token}`, "X-Bearer-Owner-Id": walletData.account.address, "X-Bearer-Signature": walletData.tokens.container.DELETE.signature, @@ -535,7 +535,7 @@ export const App = () => { const attributesHeaders = {}; attributes.map((attribute) => attributesHeaders[attribute.key] = attribute.value); - api('POST', `/objects/${containerId}`, objectForm.file, { + api('POST', `/v1/objects/${containerId}`, objectForm.file, { 'Content-Type': objectForm.file.type, "Authorization": `Bearer ${walletData.tokens.object.bearer}`, 'X-Attributes': JSON.stringify({ @@ -572,7 +572,7 @@ export const App = () => { const onDeleteObject = (containerId, objectId) => { setError({ active: false, type: [], text: '' }); setLoadingForm(true); - api('DELETE', `/objects/${containerId}/${objectId}`, {}, { + api('DELETE', `/v1/objects/${containerId}/${objectId}`, {}, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((e) => { setLoadingForm(false); diff --git a/src/Components/ContainerItem/ContainerItem.jsx b/src/Components/ContainerItem/ContainerItem.jsx index c183150..61210cb 100644 --- a/src/Components/ContainerItem/ContainerItem.jsx +++ b/src/Components/ContainerItem/ContainerItem.jsx @@ -89,7 +89,7 @@ export default function ContainerItem({ const onGetObjects = (containerId, pageTemp = pagination.page) => { setPagination({ ...pagination, page: pageTemp}); setLoadingObjects(true); - api('POST', `/objects/${containerId}/search?limit=${ObjectsPerPage}&offset=${pageTemp * ObjectsPerPage}`, { + api('POST', `/v1/objects/${containerId}/search?limit=${ObjectsPerPage}&offset=${pageTemp * ObjectsPerPage}`, { filters: filters.every((item) => item.key !== '' && item.value !== '') ? filters : [], }, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, @@ -106,7 +106,7 @@ export default function ContainerItem({ const onGetEACL = (containerId) => { setLoadingEACL(true); - api('GET', `/containers/${containerId}/eacl`, {}, { + api('GET', `/v1/containers/${containerId}/eacl`, {}, { "X-Bearer-Owner-Id": walletData.account.address, }).then((e) => { setLoadingEACL(false); diff --git a/src/Components/EACLPanel/EACLPanel.jsx b/src/Components/EACLPanel/EACLPanel.jsx index 01f4eca..f024d62 100644 --- a/src/Components/EACLPanel/EACLPanel.jsx +++ b/src/Components/EACLPanel/EACLPanel.jsx @@ -36,7 +36,7 @@ export default function EACLPanel({ if (eACLParams.every((eACLItem) => eACLItem.operation !== '' && eACLItem.action !== '' && eACLItem.targets[0].role !== '' && eACLItem.filters.every((filterItem) => filterItem.headerType !== '' && filterItem.matchType !== '' && filterItem.key !== '' && filterItem.value !== ''))) { setError({ active: false, type: [], text: '' }); setLoadingForm(true); - api('PUT', `/containers/${containerId}/eacl?walletConnect=true`, { + api('PUT', `/v1/containers/${containerId}/eacl?walletConnect=true`, { "records": eACLParams.filter((item) => delete item.isOpen), }, { "Authorization": `Bearer ${walletData.tokens.container.SETEACL.token}`, diff --git a/src/Components/TreeView/TreeView.jsx b/src/Components/TreeView/TreeView.jsx index a7b5843..2f839c6 100644 --- a/src/Components/TreeView/TreeView.jsx +++ b/src/Components/TreeView/TreeView.jsx @@ -88,7 +88,7 @@ const File = ({ const handleToggle = e => { setIsOpen(!isOpen); if (!isOpen) { - api('HEAD', `/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + api('HEAD', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((e) => { setObjectDate(e); @@ -166,7 +166,7 @@ const File = ({ className="manage_icon" onClick={() => { onModal('loading'); - api('GET', `/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + api('GET', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((data) => { if (data.message) { @@ -201,7 +201,7 @@ const File = ({ className="manage_icon" onClick={() => { onModal('loading'); - api('GET', `/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + api('GET', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((data) => { if (data.message) { @@ -234,7 +234,7 @@ const File = ({ className="manage_icon" onClick={() => { onModal('loading'); - api('HEAD', `/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + api('HEAD', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((e) => { onModal('shareObjectLink', { diff --git a/src/Getobject.jsx b/src/Getobject.jsx index 269bc8a..230749c 100644 --- a/src/Getobject.jsx +++ b/src/Getobject.jsx @@ -26,7 +26,7 @@ const Getobject = ({ if (token) { payload["Authorization"] = `Bearer ${token}`; } - api('HEAD', `/objects/${containerId}/by_id/${objectId}`, {}, payload).then((e) => { + api('HEAD', `/v1/objects/${containerId}/by_id/${objectId}`, {}, payload).then((e) => { if (e.message) { onModal('failed', e.message); } else { @@ -42,7 +42,7 @@ const Getobject = ({ if (params.token) { payload["Authorization"] = `Bearer ${params.token}`; } - api('GET', `/objects/${params.containerId}/by_id/${params.objectId}`, {}, payload).then((data) => { + api('GET', `/v1/objects/${params.containerId}/by_id/${params.objectId}`, {}, payload).then((data) => { if (data.message) { onModal('failed', data.message); } else { diff --git a/src/Profile.jsx b/src/Profile.jsx index 34b4d5d..a7e0130 100644 --- a/src/Profile.jsx +++ b/src/Profile.jsx @@ -70,7 +70,7 @@ const Profile = ({ const onNeoFSBalance = async () => { setIsLoadingNeoFSBalance(true); - api('GET', `/accounting/balance/${walletData.account.address}`).then((e) => { + api('GET', `/v1/accounting/balance/${walletData.account.address}`).then((e) => { if (e.message) { onPopup('failed', e.message); } else { @@ -135,7 +135,7 @@ const Profile = ({ const onGetContainers = () => { setIsLoadingContainers(true); - api('GET', `/containers?ownerId=${walletData.account.address}`).then((e) => { + api('GET', `/v1/containers?ownerId=${walletData.account.address}`).then((e) => { if (e.message) { onPopup('failed', e.message); } else { diff --git a/src/api.js b/src/api.js index ad0cdc2..a8344da 100644 --- a/src/api.js +++ b/src/api.js @@ -1,4 +1,4 @@ -const rest_gw = import.meta.env.VITE_RESTGW ? import.meta.env.VITE_RESTGW : 'https://rest.t5.fs.neo.org/v1'; +const rest_gw = import.meta.env.VITE_RESTGW ? import.meta.env.VITE_RESTGW : 'https://rest.t5.fs.neo.org'; async function serverRequest(method, url, params, headers) { const json = { From 05fdf3d101faea3e5ef7c119bbfb52604aaef598 Mon Sep 17 00:00:00 2001 From: Mikhail Petrov Date: Fri, 20 Jun 2025 19:00:18 +0300 Subject: [PATCH 2/4] web: Implement searchv2 in objects pagination Signed-off-by: Mikhail Petrov --- public/img/icons/list_view.svg | 1 + public/img/icons/tree_view.svg | 1 + src/App.jsx | 1 + .../ContainerItem/ContainerItem.jsx | 94 +++++++++++++------ src/Components/TreeView/TreeView.jsx | 14 +-- src/Functions/handle.js | 58 ++++++------ 6 files changed, 102 insertions(+), 67 deletions(-) create mode 100644 public/img/icons/list_view.svg create mode 100644 public/img/icons/tree_view.svg diff --git a/public/img/icons/list_view.svg b/public/img/icons/list_view.svg new file mode 100644 index 0000000..4f05c40 --- /dev/null +++ b/public/img/icons/list_view.svg @@ -0,0 +1 @@ + diff --git a/public/img/icons/tree_view.svg b/public/img/icons/tree_view.svg new file mode 100644 index 0000000..5a530e0 --- /dev/null +++ b/public/img/icons/tree_view.svg @@ -0,0 +1 @@ + diff --git a/src/App.jsx b/src/App.jsx index f72367f..0fa2a3e 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1485,6 +1485,7 @@ export const App = () => { Attributes + Attributes are key value pairs (string:string) that are attached to the metadata of objects. You can specify anything as an attribute.

If you set the FileName attribute, you can also see the file name in the object list. The FilePath attribute allows you to present the list of objects as a tree in the panel interface.
= 3 ? { overflow: 'scroll', maxHeight: 180 } : {}}> {attributes.map((attribute, index) => ( diff --git a/src/Components/ContainerItem/ContainerItem.jsx b/src/Components/ContainerItem/ContainerItem.jsx index 61210cb..49ad025 100644 --- a/src/Components/ContainerItem/ContainerItem.jsx +++ b/src/Components/ContainerItem/ContainerItem.jsx @@ -29,8 +29,8 @@ export default function ContainerItem({ const ObjectsPerPage = 40; const [isOpen, setIsOpen] = useState(false); const [pagination, setPagination] = useState({ - page: 0, - objects: 0, + history: [], + cursor: '', }); const [filters, setFilters] = useState([{ key: '', @@ -42,10 +42,11 @@ export default function ContainerItem({ const [isLoadingEACL, setLoadingEACL] = useState(false); const [eACLParams, setEACLParams] = useState([]); const [activePanel, setActivePanel] = useState(''); + const [isTreeViewObjects, setTreeViewObjects] = useState(false); useEffect(() => { if (isLoadContainers === containerItem.containerId) { - onGetObjects(isLoadContainers); + onGetObjects(isLoadContainers, '', { history: [], cursor: '' }); setLoadContainers(false); onModal(); } @@ -54,7 +55,7 @@ export default function ContainerItem({ useEffect(() => { if (walletData.tokens.object && walletData.tokens.object.containerId === containerItem.containerId) { setActivePanel('objects'); - onGetObjects(containerItem.containerId); + onGetObjects(containerItem.containerId, '', { history: [], cursor: '' }); onModal(); setWalletData({ ...walletData, @@ -86,11 +87,17 @@ export default function ContainerItem({ } }, [walletData]); // eslint-disable-line react-hooks/exhaustive-deps - const onGetObjects = (containerId, pageTemp = pagination.page) => { - setPagination({ ...pagination, page: pageTemp}); + const onGetObjects = (containerId, cursor = '', paginationTemp = pagination, isTreeViewObjectsTemp = isTreeViewObjects) => { setLoadingObjects(true); - api('POST', `/v1/objects/${containerId}/search?limit=${ObjectsPerPage}&offset=${pageTemp * ObjectsPerPage}`, { - filters: filters.every((item) => item.key !== '' && item.value !== '') ? filters : [], + let filtersApplied = filters.filter(item => item.key !== '' && item.value !== ''); + if (isTreeViewObjectsTemp) { + const hasFilePath = filtersApplied.some(item => item.key === 'FilePath'); + filtersApplied = hasFilePath ? filtersApplied : [{ key: "FilePath", match: "MatchCommonPrefix", value: "" }, ...filtersApplied]; + } + + api('POST', `/v2/objects/${containerId}/search?limit=${ObjectsPerPage}${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ''}`, { + attributes: [...new Set(filtersApplied.map(item => item.key))], + filters: filtersApplied, }, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((e) => { @@ -98,8 +105,14 @@ export default function ContainerItem({ if (e.message) { onPopup('failed', e.message); } else { - setPagination({ objects: e.objects ? e.objects.length : 0, page: pageTemp}); - setObjects(e.objects ? formatForTreeView(e.objects) : []); + const pos = paginationTemp.history.indexOf(e.cursor); + if (pos !== -1) { + paginationTemp.history.splice(pos, 1); + } else if (paginationTemp.cursor !== '') { + paginationTemp.history.push(paginationTemp.cursor); + } + setPagination({ history: paginationTemp.history, cursor: e.cursor }); + setObjects(e.objects && e.objects.length > 0 ? formatForTreeView(e.objects) : []); } }); }; @@ -282,7 +295,7 @@ export default function ContainerItem({ } else if (activePanel === 'objects') { setActivePanel(''); } else { - onGetObjects(containerItem.containerId, 0); + onGetObjects(containerItem.containerId, '', { history: [], cursor: '' }); setActivePanel('objects'); } }} @@ -299,17 +312,40 @@ export default function ContainerItem({ Objects
{activePanel === 'objects' && ( - +
+ + +
)} {activePanel === 'objects' && ( @@ -430,7 +466,7 @@ export default function ContainerItem({ color="primary" size="small" style={{ marginTop: 8 }} - onClick={() => onGetObjects(containerItem.containerId, 0)} + onClick={() => onGetObjects(containerItem.containerId, '', { history: [], cursor: '' })} disabled={isLoadingObjects || filters.some((item) => item.key === '' || item.value === '')} > Search @@ -449,18 +485,18 @@ export default function ContainerItem({ containerItem={containerItem} objects={objects} /> - {!(pagination.page === 0 && pagination.objects === 0) && ( + {objects.length !== 0 && (
onGetObjects(containerItem.containerId, pagination.page - 1)} - style={pagination.page === 0 ? { pointerEvents: 'none', borderColor: '#e9e9e9' } : {}} + onClick={() => onGetObjects(containerItem.containerId, pagination.history.length > 1 ? pagination.history[pagination.history.length - 2] : '')} + style={pagination.history.length === 0 ? { pointerEvents: 'none', borderColor: '#e9e9e9', color: '#9f9f9f' } : {}} >{`<`}
-
{pagination.page + 1}
+
{pagination.history.length + 1}
onGetObjects(containerItem.containerId, pagination.page + 1)} - style={pagination.objects < ObjectsPerPage ? { pointerEvents: 'none', borderColor: '#e9e9e9' } : {}} + onClick={() => onGetObjects(containerItem.containerId, pagination.cursor)} + style={pagination.cursor === '' ? { pointerEvents: 'none', borderColor: '#e9e9e9', color: '#9f9f9f' } : {}} >{`>`}
)} diff --git a/src/Components/TreeView/TreeView.jsx b/src/Components/TreeView/TreeView.jsx index 2f839c6..a06851d 100644 --- a/src/Components/TreeView/TreeView.jsx +++ b/src/Components/TreeView/TreeView.jsx @@ -88,7 +88,7 @@ const File = ({ const handleToggle = e => { setIsOpen(!isOpen); if (!isOpen) { - api('HEAD', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + api('HEAD', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.objectId}`, {}, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((e) => { setObjectDate(e); @@ -129,7 +129,7 @@ const File = ({ Information {`Object id: `} - {objectItem.address.objectId} + {objectItem.objectId} {`Owner id: `} @@ -166,7 +166,7 @@ const File = ({ className="manage_icon" onClick={() => { onModal('loading'); - api('GET', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + api('GET', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.objectId}`, {}, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((data) => { if (data.message) { @@ -201,7 +201,7 @@ const File = ({ className="manage_icon" onClick={() => { onModal('loading'); - api('GET', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + api('GET', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.objectId}`, {}, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((data) => { if (data.message) { @@ -234,13 +234,13 @@ const File = ({ className="manage_icon" onClick={() => { onModal('loading'); - api('HEAD', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.address.objectId}`, {}, { + api('HEAD', `/v1/objects/${containerItem.containerId}/by_id/${objectItem.objectId}`, {}, { "Authorization": `Bearer ${walletData.tokens.object.bearer}`, }).then((e) => { onModal('shareObjectLink', { type: e === 200 ? 'public' : 'private', containerId: containerItem.containerId, - objectId: objectItem.address.objectId, + objectId: objectItem.objectId, }); }); }} @@ -253,7 +253,7 @@ const File = ({ src="/img/icons/manage/delete.png" className="manage_icon" onClick={(e) => { - onModal('deleteObject', { containerId: containerItem.containerId, objectId: objectItem.address.objectId }); + onModal('deleteObject', { containerId: containerItem.containerId, objectId: objectItem.objectId }); e.stopPropagation(); }} width={40} diff --git a/src/Functions/handle.js b/src/Functions/handle.js index c711f72..e338f09 100644 --- a/src/Functions/handle.js +++ b/src/Functions/handle.js @@ -1,40 +1,36 @@ export function formatForTreeView(objects) { - const getTreeView = objectsList => ( - objectsList.reduce((root, item) => { - const parts = item.filePath ? item.filePath.split('/') : ['']; - const lastPart = parts[parts.length - 1]; - if (parts.length === 1 && lastPart === '') { - let childrenTemp = []; - if (root['/']) { - childrenTemp = root['/']; + for (let i = 0; i < objects.length; i++) { + objects[i].fileName = objects[i].attributes.FileName ? objects[i].attributes.FileName : ''; + objects[i].filePath = objects[i].attributes.FilePath ? objects[i].attributes.FilePath : ''; + } + + const getTreeView = (objectsList) => { + return objectsList.reduce((root, item) => { + const path = item.filePath || ''; + const parts = path.split('/').filter(Boolean); + let current = root; + + for (const part of parts) { + if (!current[part]) { + current[part] = {}; } - root = { ...root, '/': [...childrenTemp, item] }; - } - parts.filter((n) => n !== '').reduce((acc, part) => { - let children = []; - if (part === lastPart) { - let childrenTemp = []; - if (acc[part]) { - childrenTemp = acc[part]['/']; - } - children = [...childrenTemp, item]; - } else if (acc[part]) { - let childrenTemp = []; - childrenTemp = acc[part]['/']; - children = [...childrenTemp]; + if (!current[part]['/']) { + current[part]['/'] = []; } - return (acc[part] && (acc[part] = { ...acc[part], '/': children })) || (acc[part] = { '/': children }); - }, root); + current = current[part]; + } + + if (!current['/']) { + current['/'] = []; + } + current['/'].push(item); + return root; - }, Object.create(null)) - ); + }, {}); + }; for (let i = 0; i < objects.length; i++) { - if (!objects[i].filePath) { - objects[i].filePath = ''; - } - const path = objects[i].filePath.replace(/\/+/g, '/').replace(/\\\\/g, '\\').split('/'); if (path[path.length - 1] === '') { objects[i].filePath = ''; @@ -44,7 +40,7 @@ export function formatForTreeView(objects) { } if (!objects[i].name) { - objects[i].name = objects[i].address.objectId; + objects[i].name = objects[i].attributes.FileName ? objects[i].attributes.FileName : objects[i].objectId; } objects[i].fullName = `${objects[i].filePath ? `${objects[i].filePath.trim()}/` : ''}${objects[i].name.trim()}`; From bb4c9f7bc93b488342b88ccdeea5b456f8b81d88 Mon Sep 17 00:00:00 2001 From: Mikhail Petrov Date: Fri, 20 Jun 2025 19:00:28 +0300 Subject: [PATCH 3/4] .github: Update ubuntu version 20 -> 22 in npm tests Signed-off-by: Mikhail Petrov --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ad5df63..1668b3c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ on: jobs: tests: name: npm tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: matrix: node-version: [18.x] From b94c6082378af3d533fa10f34fff650708832daa Mon Sep 17 00:00:00 2001 From: Mikhail Petrov Date: Fri, 20 Jun 2025 19:00:52 +0300 Subject: [PATCH 4/4] test: Adapt TreeView objects test for new response structure closes #234 Signed-off-by: Mikhail Petrov --- src/Components/TreeView/TreeView.test.jsx | 42 ++++---- src/Functions/handle.test.jsx | 119 +++++++++++----------- 2 files changed, 76 insertions(+), 85 deletions(-) diff --git a/src/Components/TreeView/TreeView.test.jsx b/src/Components/TreeView/TreeView.test.jsx index fa5de75..2034855 100644 --- a/src/Components/TreeView/TreeView.test.jsx +++ b/src/Components/TreeView/TreeView.test.jsx @@ -32,15 +32,14 @@ function getAllFileNames(obj) { describe('testTreeView', () => { it('DOM display correct TreeView #1', () => { const objects = [{ - "address": { "containerId": "123", "objectId": "456" }, - "name": "cat.jpg", - "filePath": "/root/id", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/id" }, + "objectId": "123", }, { - "address": { "containerId": "123", "objectId": "456" }, - "name": "cat.jpg", + "attributes": { "FileName": "cat.jpg" }, + "objectId": "456", }, { - "address": { "containerId": "789", "objectId": "012" }, - "name": "cat.jpg", + "attributes": { "FileName": "cat.jpg" }, + "objectId": "789", }]; const objectsTreeView = formatForTreeView(objects); const { container, queryAllByText } = render(); @@ -61,12 +60,11 @@ describe('testTreeView', () => { describe('testTreeView', () => { it('DOM display correct TreeView #2', () => { const objects = [{ - "address": { "containerId": "123", "objectId": "456" }, - "name": "cat.jpg", - "filePath": "my/folder/children//photos//photo2", + "attributes": { "FileName": "cat.jpg", "FilePath": "my/folder/children//photos//photo2" }, + "objectId": "123", }, { - "address": { "containerId": "789", "objectId": "012" }, - "filePath": "345/ё\\ferkln/kmper/\\\\v////4345fk/-~s\\%20q\]%r", + "attributes": { "FileName": "", "FilePath": "345/ё\\ferkln/kmper/\\\\v////4345fk/-~s\\%20q\]%r" }, + "objectId": "456", }]; const objectsTreeView = formatForTreeView(objects); const { container, queryAllByText } = render(); @@ -87,21 +85,17 @@ describe('testTreeView', () => { describe('testTreeView', () => { it('DOM display correct TreeView #3', () => { const objects = [{ - "address": { "containerId": "123", "objectId": "456" }, - "name": "cat.jpg", - "filePath": "/root", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root" }, + "objectId": "123", }, { - "address": { "containerId": "789", "objectId": "012" }, - "name": "cat.jpg", - "filePath": "/root/", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/" }, + "objectId": "456", }, { - "address": { "containerId": "345", "objectId": "678" }, - "name": "cat.jpg", - "filePath": "/root/usr", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/usr" }, + "objectId": "789", }, { - "address": { "containerId": "901", "objectId": "234" }, - "name": "cat.jpg", - "filePath": "/root/obj.txt", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/obj.txt" }, + "objectId": "012", }]; const objectsTreeView = formatForTreeView(objects); const { container, queryAllByText } = render(); diff --git a/src/Functions/handle.test.jsx b/src/Functions/handle.test.jsx index 457873c..9e3bb85 100644 --- a/src/Functions/handle.test.jsx +++ b/src/Functions/handle.test.jsx @@ -4,42 +4,50 @@ import { formatForTreeView } from './handle'; describe('testTreeView', () => { it('display correct TreeView #1', () => { const objects = [{ - "address": { "containerId": "123", "objectId": "456" }, - "name": "cat.jpg", - "filePath": "/root/id", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/id" }, + "objectId": "123", }, { - "address": { "containerId": "123", "objectId": "456" }, - "name": "cat.jpg", + "attributes": { "FileName": "cat.jpg" }, + "objectId": "456", }, { - "address": { "containerId": "789", "objectId": "012" }, - "name": "cat.jpg", + "attributes": { "FileName": "cat.jpg" }, + "objectId": "789", }, { - "address": { "containerId": "123", "objectId": "456" } + "attributes": { "FileName": "01cat.jpg" }, + "objectId": "012", }]; const tree = { "/": [{ - "address": { "containerId": "123", "objectId": "456" }, + "attributes": { "FileName": "01cat.jpg" }, + "fileName": "01cat.jpg", "filePath": "", - "fullName": "456", - "name": "456", + "fullName": "01cat.jpg", + "name": "01cat.jpg", + "objectId": "012", }, { - "address": { "containerId": "123", "objectId": "456" }, + "attributes": { "FileName": "cat.jpg" }, + "fileName": "cat.jpg", "filePath": "", "fullName": "cat.jpg", "name": "cat.jpg", + "objectId": "456", }, { - "address": { "containerId": "789", "objectId": "012" }, + "attributes": { "FileName": "cat.jpg" }, + "fileName": "cat.jpg", "filePath": "", "fullName": "cat.jpg", "name": "cat.jpg", + "objectId": "789", }], "root": { "/": [{ - "address": { "containerId": "123", "objectId": "456" }, + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/id" }, + "fileName": "cat.jpg", "filePath": "/root", "fullName": "/root/id", "name": "id", + "objectId": "123", }] } }; @@ -48,12 +56,11 @@ describe('testTreeView', () => { it('display correct TreeView #2', () => { const objects = [{ - "address": { "containerId": "123", "objectId": "456" }, - "name": "cat.jpg", - "filePath": "my/folder/children//photos//photo2", + "attributes": { "FileName": "cat.jpg", "FilePath": "my/folder/children//photos//photo2" }, + "objectId": "123", }, { - "address": { "containerId": "789", "objectId": "012" }, - "filePath": "345/ё\\ferkln/kmper/\\\\v////4345fk/-~s\\%20q\]%r", + "attributes": { "FileName": "", "FilePath": "345/ё\\ferkln/kmper/\\\\v////4345fk/-~s\\%20q\]%r" }, + "objectId": "456", }]; const tree = { @@ -67,13 +74,12 @@ describe('testTreeView', () => { "/": [], "4345fk": { "/": [{ - "address": { - "containerId": "789", - "objectId": "012" - }, + "attributes": { "FileName": "", "FilePath": "345/ё\\ferkln/kmper/\\\\v////4345fk/-~s\\%20q\]%r" }, + "fileName": "", "filePath": "345/ё\\ferkln/kmper/\\v/4345fk", "fullName": "345/ё\\ferkln/kmper/\\v/4345fk/-~s\\%20q]%r", - "name": "-~s\\%20q]%r" + "name": "-~s\\%20q]%r", + "objectId": "456", }] } } @@ -88,13 +94,12 @@ describe('testTreeView', () => { "/": [], "photos": { "/": [{ - "address": { - "containerId": "123", - "objectId": "456" - }, + "attributes": { "FileName": "cat.jpg", "FilePath": "my/folder/children//photos//photo2" }, + "fileName": "cat.jpg", "filePath": "my/folder/children/photos", "fullName": "my/folder/children/photos/photo2", - "name": "photo2" + "name": "photo2", + "objectId": "123", }] } } @@ -106,61 +111,53 @@ describe('testTreeView', () => { it('display correct TreeView #3', () => { const objects = [{ - "address": { "containerId": "123", "objectId": "456" }, - "name": "cat.jpg", - "filePath": "/root", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root" }, + "objectId": "123", }, { - "address": { "containerId": "789", "objectId": "012" }, - "name": "cat.jpg", - "filePath": "/root/", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/" }, + "objectId": "456", }, { - "address": { "containerId": "345", "objectId": "678" }, - "name": "cat.jpg", - "filePath": "/root/usr", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/usr" }, + "objectId": "789", }, { - "address": { "containerId": "901", "objectId": "234" }, - "name": "cat.jpg", - "filePath": "/root/obj.txt", + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/obj.txt" }, + "objectId": "012", }]; const tree = { "/": [{ - "address": { - "containerId": "789", - "objectId": "012" - }, + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/" }, + "fileName": "cat.jpg", "filePath": "", "fullName": "cat.jpg", - "name": "cat.jpg" + "name": "cat.jpg", + "objectId": "456", }, { - "address": { - "containerId": "123", - "objectId": "456" - }, + "attributes": { "FileName": "cat.jpg", "FilePath": "/root" }, + "fileName": "cat.jpg", "filePath": "", "fullName": "root", - "name": "root" + "name": "root", + "objectId": "123", } ], "root": { "/": [{ - "address": { - "containerId": "901", - "objectId": "234" - }, + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/obj.txt" }, + "fileName": "cat.jpg", "filePath": "/root", "fullName": "/root/obj.txt", - "name": "obj.txt" + "name": "obj.txt", + "objectId": "012", }, { - "address": { - "containerId": "345", - "objectId": "678" - }, + "attributes": { "FileName": "cat.jpg", "FilePath": "/root/usr" }, + "fileName": "cat.jpg", "filePath": "/root", "fullName": "/root/usr", - "name": "usr" + "name": "usr", + "objectId": "789", } ] }