Skip to content

Commit 0d809e6

Browse files
committed
feat(file-manager): implement file manager component
* Add FileProps interface for file structure * Create UserFiles component to display user files * Implement FileManager component for file navigation * Add NavCrumb component for breadcrumb navigation * Update styles for file manager layout * Remove obsolete AdministrationUserFileTree component
1 parent c67d138 commit 0d809e6

10 files changed

Lines changed: 359 additions & 112 deletions

File tree

apps/web/@types/user-files.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
interface FileProps {
2+
path: string;
3+
name: string;
4+
children?: FileProps[];
5+
}

apps/web/actions/administration/getUserFileTree.ts

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,11 @@ import { api } from "@/lib/apis";
44

55
import { validateAuth } from "../auth/validateAuth";
66

7-
interface OrigFileProps {
8-
path: string;
9-
name: string;
10-
children?: OrigFileProps[];
11-
}
12-
13-
interface FileProps {
14-
value: string;
15-
label: string;
16-
children?: FileProps[];
17-
}
18-
19-
function transformFileObject(node: OrigFileProps) {
7+
function transformFileObject(node: FileProps) {
208
// Create the new object with the renamed keys
219
const newNode: FileProps = {
22-
value: node.path, // Rename 'path' to 'value'
23-
label: node.name, // Rename 'name' to 'label'
10+
path: node.path,
11+
name: node.name,
2412
};
2513

2614
// Check if the node has children and if it's an array
@@ -46,7 +34,7 @@ function transformFileObject(node: OrigFileProps) {
4634
return 1; // b comes first (it has children, a doesn't)
4735
} else {
4836
// Both have children OR neither has children: sort alphabetically by label
49-
return a.label.localeCompare(b.label);
37+
return a.name.localeCompare(b.name);
5038
}
5139
});
5240

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"use client";
2+
import { Alert, Text, Title } from "@mantine/core";
3+
import { IconFileOff } from "@tabler/icons-react";
4+
5+
import { FileManager } from "@/components/FileManager/FileManager";
6+
import { useUserFileTree } from "@/hooks/administration/useUserFileTree";
7+
8+
import classes from "./page.module.css";
9+
10+
interface Props {
11+
userName: string;
12+
}
13+
14+
export function UserFiles({ userName }: Props) {
15+
const { data } = useUserFileTree(userName);
16+
17+
if (
18+
!data ||
19+
data === "unauthenticated" ||
20+
data === "unauthorized" ||
21+
!data[0].path
22+
) {
23+
return (
24+
<div className={classes.noFilesContainer}>
25+
<IconFileOff size={96} />
26+
<Title>No Files Found</Title>
27+
</div>
28+
);
29+
}
30+
31+
return (
32+
<div className={classes.fileBrowserContainer}>
33+
<div className={classes.fileBrowserSideContainer}>
34+
<Title order={2}>File Browser</Title>
35+
<Text>Viewing files of {userName}</Text>
36+
<Alert
37+
className={classes.infoContainer}
38+
variant="light"
39+
color="blue"
40+
title="Folders"
41+
>
42+
<Text>
43+
You can enter <strong>folders</strong> by double-clicking on them.
44+
</Text>
45+
</Alert>
46+
<Alert
47+
className={classes.infoContainer}
48+
variant="light"
49+
color="blue"
50+
title="Files"
51+
>
52+
<Text>
53+
You can <strong>download files</strong> by double-clicking on them.
54+
</Text>
55+
</Alert>
56+
<Alert
57+
className={classes.infoContainer}
58+
variant="light"
59+
color="blue"
60+
title="Need to get back?"
61+
>
62+
<Text>
63+
You can <strong>go back</strong> by clicking on the folder you want
64+
on the top bar.
65+
</Text>
66+
</Alert>
67+
</div>
68+
<FileManager files={data} />
69+
</div>
70+
);
71+
}
Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,43 @@
11
.container {
22
display: flex;
33
flex-direction: column;
4-
height: 100%;
5-
max-height: calc(100dvh - 45px - var(--app-shell-header-offset) - calc(var(--app-shell-padding) * 3));
64
gap: var(--mantine-spacing-md);
75
justify-content: space-between;
86
}
7+
8+
9+
.fileBrowserContainer {
10+
display: flex;
11+
flex: 1;
12+
max-height: calc(100dvh - 60px);
13+
margin: calc(-1 * var(--mantine-spacing-md));
14+
}
15+
16+
.fileBrowserSideContainer {
17+
display: flex;
18+
flex-direction: column;
19+
gap: var(--mantine-spacing-md);
20+
background-color: var(--mantine-color-gray-0);
21+
height: 100%;
22+
min-width: 256px;
23+
width: 256px;
24+
max-width: 256px;
25+
padding: var(--mantine-spacing-md);
26+
}
27+
28+
.infoContainer {
29+
text-align: justify;
30+
}
31+
32+
.noFilesContainer {
33+
display: flex;
34+
flex-direction: column;
35+
justify-content: center;
36+
align-items: center;
37+
height: 100%;
38+
gap: var(--mantine-spacing-md);
39+
}
40+
41+
.noFileIcon {
42+
font-size: 96px;
43+
}
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Title } from "@mantine/core";
2-
3-
import { AdministrationUserFileTree } from "@/components/Administration/Users/FileTree";
41
import { PageLayout } from "@/components/Layout/PageLayout/PageLayout";
52

3+
import { UserFiles } from "./UserFiles";
4+
5+
import classes from "./page.module.css";
6+
67
interface Props {
78
params: Promise<{ userName: string }>;
89
}
@@ -11,9 +12,8 @@ export default async function Page({ params }: Props) {
1112
const userName = (await params).userName;
1213

1314
return (
14-
<PageLayout>
15-
<Title order={2}>Administration: Files for {userName}</Title>
16-
<AdministrationUserFileTree userName={userName} />
15+
<PageLayout className={classes.container}>
16+
<UserFiles userName={userName} />
1717
</PageLayout>
1818
);
1919
}

apps/web/components/Administration/Users/FileTree.tsx

Lines changed: 0 additions & 87 deletions
This file was deleted.

apps/web/components/Administration/Users/UserList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export function AdministrationUserList() {
109109
<UpdateUser user={props.row.original} refetch={refetch} />
110110
<BanUser user={props.row.original} refetch={refetch} />
111111
<Link
112-
href={`/administration/users/${props.row.original.userName}`}
112+
href={`/dashboard/administration/users/${props.row.original.userName}`}
113113
>
114114
<ActionIcon
115115
color="cyan"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
.container {
2+
display: flex;
3+
height: 100%;
4+
}
5+
6+
.sideContainer {
7+
background-color: var(--mantine-color-gray-0);
8+
height: 100%;
9+
min-width: 256px;
10+
width: 256px;
11+
max-width: 256px;
12+
padding: var(--mantine-spacing-md);
13+
}
14+
15+
.mainContainer {
16+
display: flex;
17+
flex-direction: column;
18+
flex: 1;
19+
}
20+
21+
.navContainer {
22+
background-color: var(--mantine-color-gray-0);
23+
display: flex;
24+
min-height: 60px;
25+
height: 60px;
26+
max-height: 60px;
27+
width: 100%;
28+
padding: 0 var(--mantine-spacing-xs);
29+
align-items: center;
30+
}
31+
32+
.navText, .breadcrumbText {
33+
font-size: 20px;
34+
}
35+
36+
.breadcrumb {
37+
background-color: transparent;
38+
padding: 0 var(--mantine-spacing-xs);
39+
border-radius: var(--mantine-radius-md);
40+
text-transform: uppercase;
41+
42+
&:hover {
43+
background-color: #00000010;
44+
}
45+
}
46+
47+
.breadcrumbsContainer {
48+
background-color: var(--mantine-color-gray-3);
49+
display: flex;
50+
min-height: 45px;
51+
height: 45px;
52+
max-height: 45px;
53+
gap: var(--mantine-spacing-xs);
54+
width: 100%;
55+
padding: 0 var(--mantine-spacing-xs);
56+
align-items: center;
57+
border-radius: var(--mantine-radius-md);
58+
}
59+
60+
.contentContainer {
61+
display: flex;
62+
flex-wrap: wrap;
63+
flex: 1;
64+
padding: var(--mantine-spacing-lg);
65+
gap: var(--mantine-spacing-md);
66+
overflow-y: scroll;
67+
}
68+
69+
.fileContainer {
70+
display: flex;
71+
flex-direction: column;
72+
padding: var(--mantine-spacing-sm);
73+
min-height: 168px;
74+
height: 168px;
75+
max-height: 168px;
76+
min-width: 168px;
77+
width: 168px;
78+
max-width: 168px;
79+
transition: background-color 0.2s, box-shadow 0.2s, border-radius 0.2s;
80+
border-radius: var(--mantine-radius-md);
81+
82+
&:hover {
83+
background-color: var(--mantine-color-indigo-0);
84+
color: var(--mantine-color-dark-7);
85+
box-shadow: var(--mantine-shadow-xs);
86+
cursor: pointer;
87+
}
88+
}
89+
90+
.fileIconContainer {
91+
flex: 1;
92+
display: flex;
93+
justify-content: center;
94+
align-items: center;
95+
font-size: 64px;
96+
}
97+
98+
.fileName {
99+
display: block;
100+
white-space: nowrap;
101+
overflow: hidden;
102+
text-overflow: ellipsis;
103+
width: 100%;
104+
text-align: center;
105+
}

0 commit comments

Comments
 (0)