added breadcrumbs
This commit is contained in:
77
app/components/FilesEditor/BreadCrumbs/index.tsx
Normal file
77
app/components/FilesEditor/BreadCrumbs/index.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import ServerIcon from "@/components/Icons/Server";
|
||||||
|
import FolderIcon from "@/components/Icons/Folder";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
serverId: string;
|
||||||
|
path: string;
|
||||||
|
changeDirectory: (path: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = ({ serverId, path, changeDirectory }: Props) => {
|
||||||
|
const onClickHandler = (e: React.MouseEvent) => {
|
||||||
|
const newPath = e.currentTarget.getAttribute("data-custom-attribute");
|
||||||
|
if (!newPath) return;
|
||||||
|
changeDirectory(newPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
const elements = path.split("/").filter((p) => p !== "");
|
||||||
|
console.log(elements);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="breadcrumbs text-sm">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<div className="mr-2">
|
||||||
|
<ServerIcon />
|
||||||
|
</div>
|
||||||
|
{serverId}
|
||||||
|
</li>
|
||||||
|
<li onClick={onClickHandler} data-custom-attribute="/">
|
||||||
|
<div className="mr-2">
|
||||||
|
<FolderIcon />
|
||||||
|
</div>
|
||||||
|
<a>/</a>
|
||||||
|
</li>
|
||||||
|
{elements.map((element, index) => {
|
||||||
|
const path = elements.slice(0, index + 1).join("/");
|
||||||
|
console.log("path", path);
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={index}
|
||||||
|
onClick={onClickHandler}
|
||||||
|
data-custom-attribute={"/" + path}
|
||||||
|
>
|
||||||
|
<div className="mr-2">
|
||||||
|
<FolderIcon />
|
||||||
|
</div>
|
||||||
|
<a>{element}</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<li>
|
||||||
|
<span className="inline-flex items-center gap-2">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
className="h-4 w-4 stroke-current"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
d="M9 13h6m-3-3v6m5 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
Add Document
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default index;
|
||||||
@@ -8,6 +8,7 @@ import MenuIcon from "@/components/Icons/Menu";
|
|||||||
import ContextMenuContainer from "./ContextMenu/container";
|
import ContextMenuContainer from "./ContextMenu/container";
|
||||||
import RenamePopup from "./ContextMenu/rename";
|
import RenamePopup from "./ContextMenu/rename";
|
||||||
import Pterodactyl from "@/components/Pterodactyl";
|
import Pterodactyl from "@/components/Pterodactyl";
|
||||||
|
import BreadCrumbs from "./BreadCrumbs";
|
||||||
|
|
||||||
interface FileAttributes {
|
interface FileAttributes {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -53,11 +54,11 @@ const Index = () => {
|
|||||||
);
|
);
|
||||||
const [selectedFile, setSelectedFile] = useState<FileProps | null>(null);
|
const [selectedFile, setSelectedFile] = useState<FileProps | null>(null);
|
||||||
const [ptero, setPtero] = useState<Pterodactyl | null>(null);
|
const [ptero, setPtero] = useState<Pterodactyl | null>(null);
|
||||||
const [serverId, setServerId] = useState<string>("");
|
const [serverId, setServerId] = useState<string>("ec46691a");
|
||||||
|
const [path, setPath] = useState<string>("/world");
|
||||||
|
|
||||||
const setCredentials = useCallback(async () => {
|
const setCredentials = useCallback(() => {
|
||||||
setApiKey("ptlc_N77A2hEczFmSwGXm4cEXh4Gw3ZP0Ygr5NaBkGlE7pjU");
|
setApiKey("ptlc_N77A2hEczFmSwGXm4cEXh4Gw3ZP0Ygr5NaBkGlE7pjU");
|
||||||
setServerId("ec46691a");
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const showRenamePopup = useCallback(() => {
|
const showRenamePopup = useCallback(() => {
|
||||||
@@ -69,21 +70,20 @@ const Index = () => {
|
|||||||
setRenamePopup(initialRenamePopupState);
|
setRenamePopup(initialRenamePopupState);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const formateDate = (isoDate: string) => {
|
const fetchFiles = useCallback(async (ptero: Pterodactyl) => {
|
||||||
const date = new Date(isoDate);
|
const files = await ptero.files.fetchFiles();
|
||||||
return formatDistanceToNow(date, { addSuffix: true });
|
setFileList(files);
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const handleRenameFile = useCallback(
|
const handleRenameFile = useCallback(
|
||||||
(file: FileProps, newName: string) => {
|
async (file: FileProps, newName: string) => {
|
||||||
if (ptero) {
|
if (ptero) {
|
||||||
ptero.files.rename(file, newName).then(() => {
|
await ptero.files.rename(file, newName);
|
||||||
ptero.files.fetchFiles().then(setFileList); // Pobierz zaktualizowaną listę plików po zmianie nazwy
|
await fetchFiles(ptero);
|
||||||
});
|
setRenamePopup(initialRenamePopupState);
|
||||||
}
|
}
|
||||||
setRenamePopup(initialRenamePopupState);
|
|
||||||
},
|
},
|
||||||
[ptero]
|
[ptero, fetchFiles]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClickContextMenu = useCallback(
|
const handleClickContextMenu = useCallback(
|
||||||
@@ -98,24 +98,30 @@ const Index = () => {
|
|||||||
setContextMenu(initialContextMenuState);
|
setContextMenu(initialContextMenuState);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const formatDate = useCallback((isoDate: string) => {
|
const changeDirectory = useCallback(
|
||||||
return formatDistanceToNow(new Date(isoDate), { addSuffix: true });
|
(newPath: string) => {
|
||||||
}, []);
|
if (ptero) {
|
||||||
|
ptero.helpers.setWorkingDirectory(newPath);
|
||||||
|
fetchFiles(ptero);
|
||||||
|
setPath(newPath);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[ptero, fetchFiles]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const setupApplication = async () => {
|
const setupApplication = async () => {
|
||||||
await setCredentials();
|
await setCredentials();
|
||||||
while (!apiKey) {
|
if (apiKey) {
|
||||||
await new Promise((r) => setTimeout(r, 200));
|
const pteroInstance = new Pterodactyl(serverId, apiKey);
|
||||||
|
pteroInstance.helpers.setWorkingDirectory(path);
|
||||||
|
setPtero(pteroInstance);
|
||||||
|
await fetchFiles(pteroInstance);
|
||||||
}
|
}
|
||||||
const pterodactylInstance = new Pterodactyl(serverId, apiKey);
|
|
||||||
setPtero(pterodactylInstance);
|
|
||||||
const files = await pterodactylInstance.files.fetchFiles();
|
|
||||||
setFileList(files);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
setupApplication();
|
setupApplication();
|
||||||
}, [apiKey, serverId, setCredentials]);
|
}, [apiKey, serverId, setCredentials, path, fetchFiles]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -136,6 +142,13 @@ const Index = () => {
|
|||||||
file={contextMenu.file}
|
file={contextMenu.file}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<div className="flex p-4 gap-4">
|
||||||
|
<BreadCrumbs
|
||||||
|
serverId={serverId}
|
||||||
|
path={path}
|
||||||
|
changeDirectory={changeDirectory}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{fileList.map((file: FileProps) => (
|
{fileList.map((file: FileProps) => (
|
||||||
<div
|
<div
|
||||||
@@ -147,10 +160,12 @@ const Index = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-64 text-left">{file.attributes.name}</div>
|
<div className="w-64 text-left">{file.attributes.name}</div>
|
||||||
<div className="w-48 text-right">
|
<div className="w-48 text-right">
|
||||||
{file.attributes.is_file ? file.attributes.size + " bytes" : ""}
|
{file.attributes.is_file ? `${file.attributes.size} bytes` : ""}
|
||||||
</div>
|
</div>
|
||||||
<div title={file.attributes.modified_at} className="w-60 text-right">
|
<div title={file.attributes.modified_at} className="w-60 text-right">
|
||||||
{formateDate(file.attributes.modified_at)}
|
{formatDistanceToNow(new Date(file.attributes.modified_at), {
|
||||||
|
addSuffix: true,
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div onClick={(e) => handleClickContextMenu(e, file)}>
|
<div onClick={(e) => handleClickContextMenu(e, file)}>
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
|
|||||||
24
app/components/Icons/Server/index.tsx
Normal file
24
app/components/Icons/Server/index.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const index = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
stroke="currentColor"
|
||||||
|
className="size-6"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M21.75 17.25v-.228a4.5 4.5 0 0 0-.12-1.03l-2.268-9.64a3.375 3.375 0 0 0-3.285-2.602H7.923a3.375 3.375 0 0 0-3.285 2.602l-2.268 9.64a4.5 4.5 0 0 0-.12 1.03v.228m19.5 0a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3m19.5 0a3 3 0 0 0-3-3H5.25a3 3 0 0 0-3 3m16.5 0h.008v.008h-.008v-.008Zm-3 0h.008v.008h-.008v-.008Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default index;
|
||||||
@@ -12,7 +12,7 @@ export default function files(pterodactyl: any) {
|
|||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: await pterodactyl.helpers.authHeader(),
|
headers: await pterodactyl.helpers.authHeader(),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
root: "/",
|
root: pterodactyl.workingDirectory,
|
||||||
files: [
|
files: [
|
||||||
{
|
{
|
||||||
from: from.attributes.name,
|
from: from.attributes.name,
|
||||||
@@ -34,7 +34,7 @@ export default function files(pterodactyl: any) {
|
|||||||
async fetchFiles() {
|
async fetchFiles() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${process.env.NEXT_PUBLIC_URL}/api/client/servers/${pterodactyl.server_id}/files/list`,
|
`${process.env.NEXT_PUBLIC_URL}/api/client/servers/${pterodactyl.server_id}/files/list?directory=${pterodactyl.workingDirectory}`,
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: await pterodactyl.helpers.authHeader(),
|
headers: await pterodactyl.helpers.authHeader(),
|
||||||
|
|||||||
@@ -18,5 +18,15 @@ export default function helpers(pterodactyl: any) {
|
|||||||
async setServerID(serverID: string) {
|
async setServerID(serverID: string) {
|
||||||
return (pterodactyl.server_id = serverID);
|
return (pterodactyl.server_id = serverID);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// setter for working directory
|
||||||
|
async setWorkingDirectory(workingDirectory: string) {
|
||||||
|
return (pterodactyl.workingDirectory = workingDirectory);
|
||||||
|
},
|
||||||
|
|
||||||
|
// getter for working directory
|
||||||
|
async getWorkingDirectory() {
|
||||||
|
return pterodactyl.workingDirectory;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ class Pterodactyl {
|
|||||||
api_key: string;
|
api_key: string;
|
||||||
files: any;
|
files: any;
|
||||||
helpers: any;
|
helpers: any;
|
||||||
|
workingDirectory: string = "/";
|
||||||
|
|
||||||
constructor(server_id: string, api_key: string) {
|
constructor(server_id: string, api_key: string) {
|
||||||
this.server_id = server_id;
|
this.server_id = server_id;
|
||||||
|
|||||||
Reference in New Issue
Block a user