diff --git a/.DS_Store b/.DS_Store
index 79b194b..79e8c00 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.gitignore b/.gitignore
index f4fa156..317860e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@ yarn-error.log
/.vscode
/.zed
package-lock.json
+*.DS_Store*
diff --git a/app/.DS_Store b/app/.DS_Store
index baf8fde..4529371 100644
Binary files a/app/.DS_Store and b/app/.DS_Store differ
diff --git a/app/Actions/Filemanager/GetFileContentsAction.php b/app/Actions/Filemanager/GetFileContentsAction.php
index d790e49..97098a6 100644
--- a/app/Actions/Filemanager/GetFileContentsAction.php
+++ b/app/Actions/Filemanager/GetFileContentsAction.php
@@ -36,6 +36,7 @@ class GetFileContentsAction
'text/x-typescript', // .ts, .tsx
'text/x-jsx', // .jsx, .tsx
'application/x-sh', // .sh
+ 'application/x-sql', // .sql
];
diff --git a/app/Actions/Filemanager/UploadFileAction.php b/app/Actions/Filemanager/UploadFileAction.php
new file mode 100644
index 0000000..294b6bf
--- /dev/null
+++ b/app/Actions/Filemanager/UploadFileAction.php
@@ -0,0 +1,44 @@
+validate([
+ 'file' => 'required|file',
+ 'chunkIndex' => 'required|integer|min:0',
+ 'totalChunks' => 'required|integer|min:1',
+ 'originalName' => 'required|string|max:255',
+ 'path' => 'required|string',
+ ]);
+
+ $file = $r->file('file');
+
+ $path = $this->path . '/' . $r->path;
+
+ File::append($path . '/' . $r->originalName, $file->get());
+
+ /* $handle = fopen($file->getPathname(), 'rb'); */
+ /* $destination = fopen($path . '/' . $r->originalName, 'ab'); */
+ /**/
+ /* if ($handle && $destination) { */
+ /* stream_copy_to_stream($handle, $destination); // Append chunk data */
+ /* fclose($handle); */
+ /* fclose($destination); */
+ /* } */
+
+ return response()->json([
+ 'message' => 'Chunk uploaded',
+ 'chunkIndex' => $r->chunkIndex,
+ 'totalChunks' => $r->totalChunks,
+ 'toDestination' => $path . '/' . $r->originalName
+ ]);
+ }
+}
diff --git a/app/Http/Controllers/FilemanagerController.php b/app/Http/Controllers/FilemanagerController.php
index aebf82c..5df9ef5 100644
--- a/app/Http/Controllers/FilemanagerController.php
+++ b/app/Http/Controllers/FilemanagerController.php
@@ -12,12 +12,14 @@ use App\Actions\Filemanager\GetDirectoryContentsAction;
use App\Actions\Filemanager\GetFileContentsAction;
use App\Actions\Filemanager\RenameFileAction;
use App\Actions\Filemanager\UpdateFileContentsAction;
+use App\Actions\Filemanager\UploadFileAction;
use League\Flysystem\UnixVisibility\PortableVisibilityConverter;
use Illuminate\Http\StreamedResponse;
class FilemanagerController extends Controller
{
public Filesystem $filesystem;
+ public string $path;
public function __construct()
{
@@ -26,6 +28,7 @@ class FilemanagerController extends Controller
$adapter = new LocalFilesystemAdapter($path, null, LOCK_EX, LocalFilesystemAdapter::DISALLOW_LINKS);
$this->filesystem = new Filesystem($adapter);
+ $this->path = $path;
}
public function index()
@@ -62,4 +65,9 @@ class FilemanagerController extends Controller
{
return (new DeleteFilesAction($this->filesystem))->execute($r);
}
+
+ public function uploadFile(Request $r)
+ {
+ return (new UploadFileAction($this->path))->execute($r);
+ }
}
diff --git a/database/.DS_Store b/database/.DS_Store
index b2313ca..4c2883b 100644
Binary files a/database/.DS_Store and b/database/.DS_Store differ
diff --git a/public/.DS_Store b/public/.DS_Store
index 3568b76..ada1f43 100644
Binary files a/public/.DS_Store and b/public/.DS_Store differ
diff --git a/resources/js/Pages/Filemanager/Components/UploadFile.jsx b/resources/js/Pages/Filemanager/Components/UploadFile.jsx
new file mode 100644
index 0000000..5c54f56
--- /dev/null
+++ b/resources/js/Pages/Filemanager/Components/UploadFile.jsx
@@ -0,0 +1,57 @@
+import { useState } from "react";
+import axios from "axios";
+import { toast } from "react-toastify";
+
+import PrimaryButton from "@/Components/PrimaryButton";
+import Modal from "@/Components/Modal";
+import SecondaryButton from "@/Components/SecondaryButton";
+
+const CHUNK_SIZE = 2 * 1024 * 1024; // 4MB per chunk
+
+const UploadFile = ({ showUploadFile, setShowUploadFile, refreshFiles, path }) => {
+
+ const [file, setFile] = useState(null);
+ const [progress, setProgress] = useState(0);
+
+ const uploadFile = async () => {
+ if (!file) return;
+
+ const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
+ let uploadedChunks = 0;
+
+ for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
+ const start = chunkIndex * CHUNK_SIZE;
+ const end = Math.min(start + CHUNK_SIZE, file.size);
+ const chunk = file.slice(start, end);
+
+ const formData = new FormData();
+ formData.append("file", chunk);
+ formData.append("chunkIndex", chunkIndex);
+ formData.append("totalChunks", totalChunks);
+ formData.append("originalName", file.name);
+ formData.append("path", path);
+
+ await axios.post("/filemanager/upload-file", formData);
+
+ uploadedChunks++;
+ setProgress(Math.round((uploadedChunks / totalChunks) * 100));
+ }
+
+ refreshFiles(path);
+ setShowUploadFile(false);
+ toast('File uploaded successfully', { type: 'success' });
+ };
+
+ return (
+ Upload Progress: {progress}%