Compare commits
6 Commits
breadCrumb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ec8894d44 | |||
| 7302b27dc3 | |||
| e677a45ecd | |||
| fb7d3e6061 | |||
| 25605200e1 | |||
| faa45f7fcf |
@@ -1,24 +1,60 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useCallback } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
import TextEditor from "@/components/TextEditor";
|
import TextEditor from "@/components/TextEditor";
|
||||||
|
import LanguageSelector from "@/components/TextEditor/LanguageSelector";
|
||||||
|
import { languages } from "@/components/TextEditor/LanguageSelector/languages";
|
||||||
|
|
||||||
import BreadCrumbs from "@/components/BreadCrumbs";
|
import BreadCrumbs from "@/components/BreadCrumbs";
|
||||||
import ServerIcon from "@/components/Icons/Server";
|
import ServerIcon from "@/components/Icons/Server";
|
||||||
import FolderIcon from "@/components/Icons/Folder";
|
import FolderIcon from "@/components/Icons/Folder";
|
||||||
|
import Pterodactyl from "@/components/Pterodactyl";
|
||||||
|
import Panel from "@/components/Panel";
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const serverId = searchParams.get("serverid") || "";
|
const serverId = searchParams.get("serverid") || "";
|
||||||
const path = searchParams.get("path") || "";
|
const path = searchParams.get("path") || "";
|
||||||
|
const [code, setCode] = useState("");
|
||||||
|
const [language, setLanguage] = useState("plaintext");
|
||||||
|
|
||||||
const changeDirectory = useCallback((path: string) => {
|
const setLanguageHandler = (event: any) => {
|
||||||
console.log("changeDirectory", path);
|
setLanguage(event.target.value);
|
||||||
}, []);
|
};
|
||||||
|
|
||||||
|
const saveFile = async () => {
|
||||||
|
const panelApp = new Panel();
|
||||||
|
const pterodactyl = new Pterodactyl();
|
||||||
|
|
||||||
|
const credentials = await panelApp.getCredentials();
|
||||||
|
pterodactyl.setApiKey(credentials.api_key);
|
||||||
|
pterodactyl.setServerId(serverId);
|
||||||
|
await pterodactyl.files.saveContent(path, code);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
function () {
|
||||||
|
async function startupApp() {
|
||||||
|
const panelApp = new Panel();
|
||||||
|
const pterodactyl = new Pterodactyl();
|
||||||
|
|
||||||
|
const credentials = await panelApp.getCredentials();
|
||||||
|
pterodactyl.setApiKey(credentials.api_key);
|
||||||
|
pterodactyl.setServerId(serverId);
|
||||||
|
setCode(await pterodactyl.files.getContent(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverId && path) {
|
||||||
|
startupApp();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[serverId, path]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className="flex mb-4 justify-between">
|
||||||
<BreadCrumbs>
|
<BreadCrumbs>
|
||||||
<li>
|
<li>
|
||||||
<div className="mr-2">
|
<div className="mr-2">
|
||||||
@@ -54,7 +90,17 @@ function Page() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</BreadCrumbs>
|
</BreadCrumbs>
|
||||||
<TextEditor />;
|
<div className="flex justify-end gap-4">
|
||||||
|
<LanguageSelector onChange={setLanguageHandler} />
|
||||||
|
<button
|
||||||
|
className="ml-auto btn btn-base-100 text-success"
|
||||||
|
onClick={saveFile}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<TextEditor code={code} language={language} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,27 @@
|
|||||||
import Header from "@/components/Header"
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import Popup from "@/components/Popup";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
|
const [number, addNumber] = useState(0);
|
||||||
|
const [showPopup, setShowPopup] = useState(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<Header name='Testowy test' age={18} isMan={true} />
|
<Popup
|
||||||
<Header name='Ala ma kota' age={24} isMan={false} />
|
show={showPopup}
|
||||||
Main page test
|
title="Popup Title"
|
||||||
</div>
|
onClick={() => setShowPopup(false)}
|
||||||
)
|
>
|
||||||
|
<span className="text-base-content">{number}</span>
|
||||||
|
<button className="btn btn-sm" onClick={() => addNumber(number + 1)}>
|
||||||
|
Add{" "}
|
||||||
|
</button>
|
||||||
|
</Popup>
|
||||||
|
<button className="btn btn-sm" onClick={() => setShowPopup(!showPopup)}>
|
||||||
|
Toggle Popup
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
74
app/components/FilesEditor/AddDocument/index.tsx
Normal file
74
app/components/FilesEditor/AddDocument/index.tsx
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState, useRef } from "react";
|
||||||
|
import AddDocumentIcon from "@/components/Icons/AddDocument";
|
||||||
|
import Popup from "@/components/Popup";
|
||||||
|
import Pterodactyl from "@/components/Pterodactyl";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
|
const Index = () => {
|
||||||
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
const [fileName, setFileName] = useState("");
|
||||||
|
const urlParams = useSearchParams();
|
||||||
|
const serverId = urlParams.get("serverid") || "";
|
||||||
|
const pathParam = urlParams.get("path") || "/";
|
||||||
|
const apiKey = `${process.env.NEXT_PUBLIC_API_KEY}`;
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const pterodactyl = new Pterodactyl();
|
||||||
|
|
||||||
|
function togglePopup() {
|
||||||
|
setShowPopup(!showPopup);
|
||||||
|
if (!showPopup) {
|
||||||
|
// set focus on input
|
||||||
|
setTimeout(() => {
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOk() {
|
||||||
|
console.log({ fileName });
|
||||||
|
if (fileName) {
|
||||||
|
pterodactyl.setApiKey(apiKey);
|
||||||
|
pterodactyl.setServerId(serverId);
|
||||||
|
pterodactyl.helpers.setWorkingDirectory(pathParam);
|
||||||
|
pterodactyl.files.createFile(fileName);
|
||||||
|
}
|
||||||
|
setShowPopup(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Popup
|
||||||
|
title="New file name"
|
||||||
|
show={showPopup}
|
||||||
|
onClickClose={togglePopup}
|
||||||
|
onClickOk={handleOk}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
ref={inputRef}
|
||||||
|
type="text"
|
||||||
|
className="input input-sm input-bordered mb-4 text-base-content"
|
||||||
|
placeholder="File name"
|
||||||
|
value={fileName}
|
||||||
|
onChange={(e) => setFileName(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Popup>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setFileName("");
|
||||||
|
togglePopup();
|
||||||
|
}}
|
||||||
|
className="btn btn-sm"
|
||||||
|
>
|
||||||
|
<AddDocumentIcon />
|
||||||
|
Add Document
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Index;
|
||||||
@@ -11,6 +11,7 @@ import RenamePopup from "./ContextMenu/rename";
|
|||||||
import Pterodactyl from "@/components/Pterodactyl";
|
import Pterodactyl from "@/components/Pterodactyl";
|
||||||
import BreadCrumbs from "@/components/BreadCrumbs";
|
import BreadCrumbs from "@/components/BreadCrumbs";
|
||||||
import { useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
|
import AddDocument from "./AddDocument";
|
||||||
|
|
||||||
interface FileAttributes {
|
interface FileAttributes {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -23,6 +24,12 @@ interface FileProps {
|
|||||||
attributes: FileAttributes;
|
attributes: FileAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface NewDocumentState {
|
||||||
|
show: boolean;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface ContextMenuState {
|
interface ContextMenuState {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
x: number;
|
x: number;
|
||||||
@@ -34,6 +41,12 @@ interface RenamePopupState {
|
|||||||
show: boolean;
|
show: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initialNewDocumentState: NewDocumentState = {
|
||||||
|
show: false,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
|
||||||
const initialContextMenuState: ContextMenuState = {
|
const initialContextMenuState: ContextMenuState = {
|
||||||
show: false,
|
show: false,
|
||||||
x: 0,
|
x: 0,
|
||||||
@@ -57,7 +70,7 @@ const Index = () => {
|
|||||||
initialRenamePopupState
|
initialRenamePopupState
|
||||||
);
|
);
|
||||||
const [selectedFile, setSelectedFile] = useState<FileProps | null>(null);
|
const [selectedFile, setSelectedFile] = useState<FileProps | null>(null);
|
||||||
const [ptero, setPtero] = useState<Pterodactyl | null>(null);
|
const pterodactyl = useMemo(() => new Pterodactyl(), []);
|
||||||
const urlParams = useSearchParams();
|
const urlParams = useSearchParams();
|
||||||
const serverId = urlParams.get("serverid");
|
const serverId = urlParams.get("serverid");
|
||||||
const pathParam = urlParams.get("path") || "/";
|
const pathParam = urlParams.get("path") || "/";
|
||||||
@@ -71,21 +84,20 @@ const Index = () => {
|
|||||||
setRenamePopup(initialRenamePopupState);
|
setRenamePopup(initialRenamePopupState);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchFiles = useCallback(async (ptero: Pterodactyl) => {
|
const fetchFiles = useCallback(async () => {
|
||||||
console.log("chwytam pliki");
|
const files = await pterodactyl.files.fetchFiles();
|
||||||
const files = await ptero.files.fetchFiles();
|
|
||||||
setFileList(files);
|
setFileList(files);
|
||||||
}, []);
|
}, [pterodactyl]);
|
||||||
|
|
||||||
const handleRenameFile = useCallback(
|
const handleRenameFile = useCallback(
|
||||||
async (file: FileProps, newName: string) => {
|
async (file: FileProps, newName: string) => {
|
||||||
if (ptero) {
|
if (pterodactyl) {
|
||||||
await ptero.files.rename(file, newName);
|
await pterodactyl.files.rename(file, newName);
|
||||||
await fetchFiles(ptero);
|
await fetchFiles();
|
||||||
setRenamePopup(initialRenamePopupState);
|
setRenamePopup(initialRenamePopupState);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ptero, fetchFiles]
|
[pterodactyl, fetchFiles]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClickContextMenu = useCallback(
|
const handleClickContextMenu = useCallback(
|
||||||
@@ -100,31 +112,15 @@ const Index = () => {
|
|||||||
setContextMenu(initialContextMenuState);
|
setContextMenu(initialContextMenuState);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const changeDirectory = useCallback(
|
|
||||||
(newPath: string) => {
|
|
||||||
if (ptero) {
|
|
||||||
ptero.helpers.setWorkingDirectory(newPath);
|
|
||||||
fetchFiles(ptero);
|
|
||||||
// setPath(newPath);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[ptero, fetchFiles]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const setupApplication = () => {
|
|
||||||
if (!apiKey || !serverId) return; // Upewniamy się, że mamy apiKey i serverId
|
if (!apiKey || !serverId) return; // Upewniamy się, że mamy apiKey i serverId
|
||||||
if (!ptero) {
|
|
||||||
const pteroInstance = new Pterodactyl(serverId, apiKey);
|
|
||||||
setPtero(pteroInstance);
|
|
||||||
|
|
||||||
pteroInstance.helpers.setWorkingDirectory(pathParam);
|
pterodactyl.setApiKey(apiKey);
|
||||||
fetchFiles(pteroInstance); // Wywołanie fetchFiles raz po ustawieniu instancji
|
pterodactyl.setServerId(serverId);
|
||||||
}
|
pterodactyl.helpers.setWorkingDirectory(pathParam);
|
||||||
};
|
|
||||||
|
|
||||||
setupApplication();
|
fetchFiles(); // Wywołanie fetchFiles raz po ustawieniu instancji
|
||||||
}, [apiKey, serverId, ptero, pathParam, fetchFiles]);
|
}, [apiKey, serverId, pterodactyl, pathParam, fetchFiles]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -147,7 +143,7 @@ const Index = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{serverId && (
|
{serverId && (
|
||||||
<div className="flex p-4 gap-4">
|
<div className="flex gap-4">
|
||||||
<BreadCrumbs>
|
<BreadCrumbs>
|
||||||
<li>
|
<li>
|
||||||
<div className="mr-2">
|
<div className="mr-2">
|
||||||
@@ -184,20 +180,7 @@ const Index = () => {
|
|||||||
})}
|
})}
|
||||||
<li>
|
<li>
|
||||||
<span className="inline-flex items-center gap-2">
|
<span className="inline-flex items-center gap-2">
|
||||||
<svg
|
<AddDocument />
|
||||||
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>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</BreadCrumbs>
|
</BreadCrumbs>
|
||||||
|
|||||||
25
app/components/Icons/AddDocument/index.tsx
Normal file
25
app/components/Icons/AddDocument/index.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
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"
|
||||||
|
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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default index;
|
||||||
16
app/components/Panel/index.tsx
Normal file
16
app/components/Panel/index.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
interface Credentials {
|
||||||
|
api_key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Panel {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
// this method is responsible for fetching credentials from the server
|
||||||
|
async getCredentials(): Promise<Credentials> {
|
||||||
|
return {
|
||||||
|
api_key: `${process.env.NEXT_PUBLIC_API_KEY}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Panel;
|
||||||
69
app/components/Popup/index.tsx
Normal file
69
app/components/Popup/index.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
|
||||||
|
interface PopupProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
|
show?: boolean;
|
||||||
|
title?: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
onClickClose?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
|
onClickOk?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Popup: React.FC<PopupProps> = ({
|
||||||
|
show = false,
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
onClickClose,
|
||||||
|
onClickOk,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === "Escape" && onClickClose) {
|
||||||
|
onClickClose(event as unknown as React.MouseEvent<HTMLButtonElement>);
|
||||||
|
}
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
if (onClickOk) {
|
||||||
|
onClickOk(event as unknown as React.MouseEvent<HTMLButtonElement>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (show) {
|
||||||
|
window.addEventListener("keydown", handleKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("keydown", handleKeyDown);
|
||||||
|
};
|
||||||
|
}, [show, onClickClose]);
|
||||||
|
|
||||||
|
if (!show) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="fixed top-0 left-0 w-full h-full bg-black opacity-75 z-10"></div>
|
||||||
|
<div className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-20">
|
||||||
|
<div className="bg-base-100 p-8 rounded-lg">
|
||||||
|
{title && (
|
||||||
|
<h2 className="text-xl font-bold mb-4 text-base-content">
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<button onClick={onClickClose} className="btn btn-sm">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
<button onClick={onClickOk} className="btn btn-sm btn-success">
|
||||||
|
Ok
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Popup;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { get } from "http";
|
||||||
import { File } from "./interfaces";
|
import { File } from "./interfaces";
|
||||||
|
|
||||||
export default function files(pterodactyl: any) {
|
export default function files(pterodactyl: any) {
|
||||||
@@ -57,5 +58,48 @@ export default function files(pterodactyl: any) {
|
|||||||
console.error("Error fetching data:", error);
|
console.error("Error fetching data:", error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async getContent(filename: string) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.NEXT_PUBLIC_URL}/api/client/servers/${pterodactyl.server_id}/files/contents?file=${filename}`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: await pterodactyl.helpers.authHeader(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.text();
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveContent(filename: string, content: string) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.NEXT_PUBLIC_URL}/api/client/servers/${pterodactyl.server_id}/files/write?file=${filename}`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: await pterodactyl.helpers.authHeader("application/text"),
|
||||||
|
body: "'test'",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async createFile(filename: string) {
|
||||||
|
this.saveContent(filename, "");
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
export default function helpers(pterodactyl: any) {
|
export default function helpers(pterodactyl: any) {
|
||||||
return {
|
return {
|
||||||
// helper what return auth header
|
// helper what return auth header
|
||||||
async authHeader() {
|
async authHeader(contentType: string = "application/json") {
|
||||||
return {
|
return {
|
||||||
Authorization: `Bearer ${pterodactyl.api_key}`,
|
Authorization: `Bearer ${pterodactyl.api_key}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": contentType,
|
||||||
Accept: "Application/vnd.pterodactyl.v1+json",
|
Accept: "Application/vnd.pterodactyl.v1+json",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -28,5 +28,16 @@ export default function helpers(pterodactyl: any) {
|
|||||||
async getWorkingDirectory() {
|
async getWorkingDirectory() {
|
||||||
return pterodactyl.workingDirectory;
|
return pterodactyl.workingDirectory;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// helper that get main site and get csrf token from it
|
||||||
|
async getCsrfToken() {
|
||||||
|
const response = await fetch(`${process.env.NEXT_PUBLIC_URL}`, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
const text = await response.text();
|
||||||
|
const match = text.match(/<meta name="csrf-token" content="(.*)">/);
|
||||||
|
const csrfToken = match ? match[1] : null;
|
||||||
|
return csrfToken;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,21 @@ import filesModule from "./files";
|
|||||||
import helpersModule from "./helpers";
|
import helpersModule from "./helpers";
|
||||||
|
|
||||||
class Pterodactyl {
|
class Pterodactyl {
|
||||||
server_id: string;
|
server_id: string = "";
|
||||||
api_key: string;
|
api_key: string = "";
|
||||||
files: any;
|
files: any;
|
||||||
helpers: any;
|
helpers: any;
|
||||||
workingDirectory: string = "/";
|
workingDirectory: string = "/";
|
||||||
|
|
||||||
constructor(server_id: string, api_key: string) {
|
setApiKey(api_key: string) {
|
||||||
this.server_id = server_id;
|
|
||||||
this.api_key = api_key;
|
this.api_key = api_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
setServerId(server_id: string) {
|
||||||
|
this.server_id = server_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
this.files = filesModule(this);
|
this.files = filesModule(this);
|
||||||
this.helpers = helpersModule(this);
|
this.helpers = helpersModule(this);
|
||||||
}
|
}
|
||||||
|
|||||||
46
app/components/TextEditor/LanguageSelector/index.tsx
Normal file
46
app/components/TextEditor/LanguageSelector/index.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { languages } from "./languages";
|
||||||
|
|
||||||
|
interface LanguageSelectorProps {
|
||||||
|
onChange: (event: any) => void;
|
||||||
|
defaultLanguage?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Index = (props: LanguageSelectorProps) => {
|
||||||
|
const { onChange } = props;
|
||||||
|
let { defaultLanguage } = props;
|
||||||
|
|
||||||
|
if (!defaultLanguage) {
|
||||||
|
defaultLanguage = "plaintext";
|
||||||
|
}
|
||||||
|
|
||||||
|
const [selectedLanguage, setSelectedLanguage] =
|
||||||
|
useState<string>(defaultLanguage);
|
||||||
|
|
||||||
|
const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
setSelectedLanguage(event.target.value);
|
||||||
|
onChange(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
className="select bg-base-200 text-base-content w-full max-w-xs"
|
||||||
|
value={selectedLanguage}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{Object.entries(languages).map(([key, value]) => (
|
||||||
|
<option
|
||||||
|
disabled={selectedLanguage === key}
|
||||||
|
defaultValue={selectedLanguage}
|
||||||
|
// selected={selectedLanguage === key}
|
||||||
|
key={key}
|
||||||
|
value={key}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Index;
|
||||||
73
app/components/TextEditor/LanguageSelector/languages.tsx
Normal file
73
app/components/TextEditor/LanguageSelector/languages.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// interface of supported languages what are available at https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages
|
||||||
|
export const languages = {
|
||||||
|
abap: "ABAP",
|
||||||
|
apex: "Apex",
|
||||||
|
azcli: "Azure CLI",
|
||||||
|
bat: "Batch",
|
||||||
|
cameligo: "Cameligo",
|
||||||
|
clojure: "Clojure",
|
||||||
|
coffee: "CoffeeScript",
|
||||||
|
cpp: "C++",
|
||||||
|
csharp: "C#",
|
||||||
|
csp: "CSP",
|
||||||
|
css: "CSS",
|
||||||
|
dart: "Dart",
|
||||||
|
dockerfile: "Dockerfile",
|
||||||
|
ebnf: "EBNF",
|
||||||
|
fsharp: "F#",
|
||||||
|
go: "Go",
|
||||||
|
graphql: "GraphQL",
|
||||||
|
handlebars: "Handlebars",
|
||||||
|
hcl: "HCL",
|
||||||
|
html: "HTML",
|
||||||
|
ini: "INI",
|
||||||
|
java: "Java",
|
||||||
|
javascript: "JavaScript",
|
||||||
|
json: "JSON",
|
||||||
|
julia: "Julia",
|
||||||
|
kotlin: "Kotlin",
|
||||||
|
less: "Less",
|
||||||
|
lexon: "Lexon",
|
||||||
|
lua: "Lua",
|
||||||
|
markdown: "Markdown",
|
||||||
|
mips: "MIPS",
|
||||||
|
msdax: "MSDAX",
|
||||||
|
mysql: "MySQL",
|
||||||
|
objectivec: "Objective-C",
|
||||||
|
pascal: "Pascal",
|
||||||
|
pascaligo: "Pascaligo",
|
||||||
|
perl: "Perl",
|
||||||
|
pgsql: "PL/pgSQL",
|
||||||
|
php: "PHP",
|
||||||
|
plaintext: "Plain Text",
|
||||||
|
postiats: "Postiats",
|
||||||
|
powerquery: "Power Query",
|
||||||
|
powershell: "PowerShell",
|
||||||
|
pug: "Pug",
|
||||||
|
python: "Python",
|
||||||
|
r: "R",
|
||||||
|
razor: "Razor",
|
||||||
|
redis: "Redis",
|
||||||
|
redshift: "Redshift",
|
||||||
|
restructuredtext: "reStructuredText",
|
||||||
|
ruby: "Ruby",
|
||||||
|
rust: "Rust",
|
||||||
|
sb: "SB",
|
||||||
|
scala: "Scala",
|
||||||
|
scheme: "Scheme",
|
||||||
|
scss: "SCSS",
|
||||||
|
shell: "Shell",
|
||||||
|
solidity: "Solidity",
|
||||||
|
sql: "SQL",
|
||||||
|
st: "ST",
|
||||||
|
swift: "Swift",
|
||||||
|
systemverilog: "SystemVerilog",
|
||||||
|
tcl: "Tcl",
|
||||||
|
twig: "Twig",
|
||||||
|
typescript: "TypeScript",
|
||||||
|
vb: "VB",
|
||||||
|
vba: "VBA",
|
||||||
|
verilog: "Verilog",
|
||||||
|
xml: "XML",
|
||||||
|
yaml: "YAML",
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import MonacoEditor, { OnChange } from "@monaco-editor/react";
|
import MonacoEditor, { OnChange } from "@monaco-editor/react";
|
||||||
|
|
||||||
interface EditorProps {
|
interface EditorProps {
|
||||||
@@ -6,11 +6,14 @@ interface EditorProps {
|
|||||||
width?: string;
|
width?: string;
|
||||||
theme?: string;
|
theme?: string;
|
||||||
language?: string;
|
language?: string;
|
||||||
|
code?: string;
|
||||||
onChange?: OnChange;
|
onChange?: OnChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Editor = (props: EditorProps) => {
|
const Editor = (props: EditorProps) => {
|
||||||
const [code, setCode] = useState<string>('console.log("Hello, Monaco!");');
|
const [code, setCode] = useState<string>(
|
||||||
|
props.code || 'console.log("Hello, Monaco!");'
|
||||||
|
);
|
||||||
|
|
||||||
const handleEditorChange: OnChange = (value) => {
|
const handleEditorChange: OnChange = (value) => {
|
||||||
setCode(value || "");
|
setCode(value || "");
|
||||||
@@ -21,16 +24,23 @@ const Editor = (props: EditorProps) => {
|
|||||||
width = "100%",
|
width = "100%",
|
||||||
theme = "vs-dark",
|
theme = "vs-dark",
|
||||||
language = "typescript",
|
language = "typescript",
|
||||||
|
code: _code = code, // z props, jeśli jest dostępne
|
||||||
onChange = handleEditorChange,
|
onChange = handleEditorChange,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
// Efekt do synchronizacji props.code z wewnętrznym stanem code
|
||||||
|
useEffect(() => {
|
||||||
|
if (_code !== undefined) {
|
||||||
|
setCode(_code);
|
||||||
|
}
|
||||||
|
}, [_code]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
height={height}
|
height={height}
|
||||||
width={width}
|
width={width}
|
||||||
language={language}
|
language={language}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
defaultValue={code}
|
|
||||||
value={code}
|
value={code}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user