Skip to content

Commit

Permalink
refactor(web): asset file tree and add unit tests (#1133)
Browse files Browse the repository at this point in the history
* refactor: move unzip file list to a folder

* test: add unit tests
  • Loading branch information
nourbalaha authored Apr 24, 2024
1 parent b2b6878 commit 7d4cb49
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Key } from "rc-table/lib/interface";
import { expect, test } from "vitest";

import { AssetFile } from "@reearth-cms/components/molecules/Asset/types";

import { generateAssetTreeData } from "./generateAssetTreeData";

test("returns empty array if filePaths property is not provided", () => {
const result = generateAssetTreeData({ name: "", path: "/" }, [], "http://example.com");
expect(result).toEqual([]);
});

test("returns correct file tree data", () => {
const file: AssetFile = {
name: "root",
path: "/",
filePaths: [
"/folder1/file1.txt",
"/folder1/folder2/file2.txt",
"/folder3/file3.txt",
"/folder3/file4.txt",
],
};
const selectedKeys: Key[] = [];
const assetBaseUrl = "http://example.com";
const result = generateAssetTreeData(file, selectedKeys, assetBaseUrl);

// /folder1/
expect(result[0].key).toEqual("0-0");
expect(result[0].name).toEqual("folder1");
expect(result[0].path).toEqual("/folder1/");
expect(result[0].children.length).toEqual(2);

// /folder1/file1.txt
expect(result[0].children[0].key).toEqual("0-1");
expect(result[0].children[0].name).toEqual("file1.txt");
expect(result[0].children[0].path).toEqual("/folder1/file1.txt");
expect(result[0].children[0].children.length).toEqual(0);

// /folder1/folder2/
expect(result[0].children[1].key).toEqual("1-1");
expect(result[0].children[1].name).toEqual("folder2");
expect(result[0].children[1].path).toEqual("/folder1/folder2/");
expect(result[0].children[1].children.length).toEqual(1);

// /folder1/folder2/file2.txt
expect(result[0].children[1].children[0].key).toEqual("1-2");
expect(result[0].children[1].children[0].name).toEqual("file2.txt");
expect(result[0].children[1].children[0].path).toEqual("/folder1/folder2/file2.txt");
expect(result[0].children[1].children[0].children.length).toEqual(0);

// /folder3/
expect(result[1].key).toEqual("2-0");
expect(result[1].name).toEqual("folder3");
expect(result[1].path).toEqual("/folder3/");
expect(result[1].children.length).toEqual(2);

// /folder3/file3.txt
expect(result[1].children[0].key).toEqual("2-1");
expect(result[1].children[0].name).toEqual("file3.txt");
expect(result[1].children[0].path).toEqual("/folder3/file3.txt");
expect(result[1].children[0].children.length).toEqual(0);

// /folder3/file4.txt
expect(result[1].children[1].key).toEqual("3-1");
expect(result[1].children[1].name).toEqual("file4.txt");
expect(result[1].children[1].path).toEqual("/folder3/file4.txt");
expect(result[1].children[1].children.length).toEqual(0);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import styled from "@emotion/styled";
import { Key } from "rc-table/lib/interface";

import Icon from "@reearth-cms/components/atoms/Icon";
import { AssetFile } from "@reearth-cms/components/molecules/Asset/types";

import { FileNode } from "./types";

export const generateAssetTreeData = (
file: AssetFile,
selectedKeys: Key[],
assetBaseUrl: string,
): FileNode[] => {
if (!file.filePaths) return [];

const root: FileNode = {
key: "0",
name: file.name,
path: "/",
children: [],
};

file.filePaths.forEach((filepath, i) => {
const parts = filepath.split("/");
let currentNode = root;

parts.slice(1).forEach((part, j) => {
const existingNode = currentNode.children?.find((node: FileNode) => node.name === part);
if (!existingNode) {
const key = `${i}-${j}`;
const path = `${currentNode.path}${part}${/\.[^.]+$/.test(part) ? "" : "/"}`;
const newNode: FileNode = {
key: key,
title: (
<>
{part}
<CopyIcon
selected={selectedKeys[0] === key}
icon="copy"
onClick={() => {
navigator.clipboard.writeText(assetBaseUrl + path);
}}
/>
</>
),
name: part,
path: path,
children: [],
};

currentNode.children?.push(newNode);
currentNode = newNode;
} else {
currentNode = existingNode;
}
});
});

return root.children;
};

const CopyIcon = styled(Icon)<{ selected?: boolean }>`
margin-left: 16px;
visibility: ${({ selected }) => (selected ? "visible" : "hidden")};
&:active {
color: #096dd9;
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,20 @@ import { useCallback, useEffect, useState } from "react";

import Icon from "@reearth-cms/components/atoms/Icon";
import Spin from "@reearth-cms/components/atoms/Spin";
import Tree, { DataNode, TreeProps } from "@reearth-cms/components/atoms/Tree";
import Tree, { TreeProps } from "@reearth-cms/components/atoms/Tree";
import { ArchiveExtractionStatus, AssetFile } from "@reearth-cms/components/molecules/Asset/types";
import { useT } from "@reearth-cms/i18n";

import { generateAssetTreeData } from "./generateAssetTreeData";
import { FileNode } from "./types";

type Props = {
file: AssetFile;
assetBaseUrl: string;
archiveExtractionStatus: ArchiveExtractionStatus;
setAssetUrl: (url: string) => void;
};

type FileNode = DataNode & {
name: string;
path: string;
children: FileNode[];
};

const UnzipFileList: React.FC<Props> = ({
file,
assetBaseUrl,
Expand All @@ -33,61 +30,10 @@ const UnzipFileList: React.FC<Props> = ({
const [selectedKeys, setSelectedKeys] = useState<FileNode["key"][]>([]);
const [treeData, setTreeData] = useState<FileNode[]>([]);

const getTreeData = useCallback(
(file?: AssetFile): FileNode[] => {
if (!file?.filePaths) return [];

const root: FileNode = {
key: "0",
name: file.name,
path: "/",
children: [],
};

file.filePaths.forEach((filepath, i) => {
const parts = filepath.split("/");
let currentNode = root;

parts.slice(1).forEach((part, j) => {
const existingNode = currentNode.children?.find((node: FileNode) => node.name === part);
if (!existingNode) {
const key = `${i}-${j}`;
const path = `${currentNode.path}${part}${/\.[^.]+$/.test(part) ? "" : "/"}`;
const newNode: FileNode = {
key: key,
title: (
<>
{part}
<CopyIcon
selected={selectedKeys[0] === key}
icon="copy"
onClick={() => {
navigator.clipboard.writeText(assetBaseUrl + path);
}}
/>
</>
),
name: part,
path: path,
children: [],
};

currentNode.children?.push(newNode);
currentNode = newNode;
} else {
currentNode = existingNode;
}
});
});

return root.children;
},
[assetBaseUrl, selectedKeys],
);

useEffect(() => {
setTreeData(getTreeData(file));
}, [file, getTreeData]);
const data = generateAssetTreeData(file, selectedKeys, assetBaseUrl);
setTreeData(data);
}, [assetBaseUrl, file, selectedKeys]);

const previewFile = useCallback(
(path: string) => {
Expand Down Expand Up @@ -163,14 +109,6 @@ const ExtractionFailedIcon = styled(Icon)`
margin-bottom: 28px;
`;

const CopyIcon = styled(Icon)<{ selected?: boolean }>`
margin-left: 16px;
visibility: ${({ selected }) => (selected ? "visible" : "hidden")};
&:active {
color: #096dd9;
}
`;

const ExtractionFailedText = styled.p`
margin-bottom: 0;
font-family: Roboto;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { DataNode } from "@reearth-cms/components/atoms/Tree";

export type FileNode = DataNode & {
name: string;
path: string;
children: FileNode[];
};

0 comments on commit 7d4cb49

Please sign in to comment.