Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple File Manager #2046

Merged
merged 65 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
ece823f
Created File Manager
KesterTan Jan 7, 2024
ca72d47
Added docs
KesterTan Jan 9, 2024
243c3c3
Changed paths to resource
KesterTan Jan 13, 2024
01aab28
Sanitized absolute paths
KesterTan Jan 13, 2024
18e68f9
Updated path sanitization
KesterTan Jan 14, 2024
2cbd5f8
Edited permissions for instructors
KesterTan Jan 15, 2024
7ceac2b
Restored path sanitization
KesterTan Jan 15, 2024
109ea6b
Fixed linting issues
KesterTan Jan 18, 2024
5acad98
More linting
KesterTan Jan 18, 2024
2f7881c
Erblint
KesterTan Jan 18, 2024
eb34446
Added logic for uploading files with duplicate names
KesterTan Jan 18, 2024
8659159
Added routes for base dir
KesterTan Jan 18, 2024
7b5db3d
Sanitize path in JS
KesterTan Jan 20, 2024
aaf8520
Removed extra code
KesterTan Jan 20, 2024
da5a1b1
Added selected option and uploading multiple files
KesterTan Feb 3, 2024
883aa04
Upload multiple, create folder, delete selected, checkboxes
KesterTan Feb 5, 2024
ad6d538
Styling and scroll-in-view
KesterTan Feb 8, 2024
060b881
Added some tests and added download all
KesterTan Feb 19, 2024
9e22aba
Changed equality check
KesterTan Feb 19, 2024
16ea44b
Removed download of ../ and at top level
KesterTan Feb 25, 2024
c2bcefa
Select all checkbox
KesterTan Feb 25, 2024
6427d60
Select all checkbox and some tests
KesterTan Feb 26, 2024
7d986cb
Instructor check for download
KesterTan Feb 26, 2024
c61297b
Rebased and added back button for files
KesterTan Feb 26, 2024
343a453
Added docs
KesterTan Jan 9, 2024
55fd1c2
Changed paths to resource
KesterTan Jan 13, 2024
ff66f40
Sanitized absolute paths
KesterTan Jan 13, 2024
1f45aa8
Updated path sanitization
KesterTan Jan 14, 2024
30d2800
Edited permissions for instructors
KesterTan Jan 15, 2024
6cdcd7b
Restored path sanitization
KesterTan Jan 15, 2024
9a23c57
Fixed linting issues
KesterTan Jan 18, 2024
e9cd2d5
More linting
KesterTan Jan 18, 2024
47a3e7c
Added logic for uploading files with duplicate names
KesterTan Jan 18, 2024
3f75dae
Added routes for base dir
KesterTan Jan 18, 2024
6831480
Removed extra code
KesterTan Jan 20, 2024
0ce2650
Added selected option and uploading multiple files
KesterTan Feb 3, 2024
6805815
Upload multiple, create folder, delete selected, checkboxes
KesterTan Feb 5, 2024
6b42b53
Styling and scroll-in-view
KesterTan Feb 8, 2024
3170af2
Added some tests and added download all
KesterTan Feb 19, 2024
b2b023a
Changed equality check
KesterTan Feb 19, 2024
21e59e3
Removed download of ../ and at top level
KesterTan Feb 25, 2024
047491b
Select all checkbox
KesterTan Feb 25, 2024
02ea5e5
Select all checkbox and some tests
KesterTan Feb 26, 2024
d4ca89b
Instructor check for download
KesterTan Feb 26, 2024
148e956
Rebased and added back button for files
KesterTan Feb 26, 2024
13e9c4a
Merge branch 'master' into file_manager
KesterTan Feb 27, 2024
493d1ab
Removed whitespace
KesterTan Feb 28, 2024
7bde44a
Addressed null and checkall bugs
KesterTan Mar 18, 2024
0e8a755
Changed permissions for root path
KesterTan Mar 21, 2024
63339df
Removed dead code
KesterTan Mar 21, 2024
96bd4ef
Fixed rename
KesterTan Mar 21, 2024
02c14d9
Disallow upload of files greater than 1 gb
KesterTan Mar 22, 2024
1ddf202
Added title indexing and updated documentation
KesterTan Mar 23, 2024
c47a0f3
Comments about docs and unused code
KesterTan Mar 25, 2024
f7b0380
Fixed expand path
KesterTan Mar 25, 2024
ff1a59c
Breadcrumbs and removed routes
KesterTan Mar 25, 2024
151dc84
Error messages and breadcrumbs
KesterTan Mar 27, 2024
653e249
Rubocop fix
KesterTan Mar 27, 2024
2aba2a2
erblint
KesterTan Mar 27, 2024
663f442
Addressed nits and tests
KesterTan Mar 31, 2024
0f9eb56
Merge branch 'master' into file_manager
KesterTan Mar 31, 2024
ee84a96
New name regex
KesterTan Mar 31, 2024
b921d44
Merge remote-tracking branch 'origin/file_manager' into file_manager
KesterTan Mar 31, 2024
a418f54
Changed Pathname to str and breadcrumbs
KesterTan Apr 1, 2024
c1382be
Removed myescape
KesterTan Apr 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 222 additions & 0 deletions app/assets/javascripts/file_manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
function rename(path) {
let new_name = prompt("Enter the new name:");
if (new_name !== null) {
let rel_path = decodeURIComponent(path.split("/file_manager/")[1]);
$.ajax({
url: "/file_manager/" + rel_path,
type: "PUT",
data: { new_name: new_name, relative_path: rel_path},
success: function(data) {
console.log(`Renamed: ${rel_path}`)
location.reload();
}
});
}
}

function deleteSelected(path) {
return new Promise(function(resolve, reject) {
$.ajax({
url: path,
type: "DELETE",
success: function () {
console.log(`Deleted: ${path}`);
resolve();
},
error: function (xhr, status, error) {
reject(error);
}
});
})
}

function downloadSelected(path) {
return new Promise(function(resolve, reject) {
$.ajax({
url: '/file_manager/download_tar/',
type: "POST",
data: {
path: path
},
success: function (data) {
let blob = new Blob([data], { type: 'application/x-tar' });
let url = URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = url;
let parts = path.split("/")
a.download = parts[parts.length - 1]
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
console.log(`Downloaded: ${data.filename}`);
resolve();
},
error: function (xhr, status, error) {
console.error(`Failed to download ${path}: ${error}`);
reject(error);
}
});
})
}

function uploadFile(file, path, name) {
let formData;
let pathSegments = path.split('/');
pathSegments.pop();
let modifiedPath = pathSegments.join('/');
formData = new FormData();
formData.append('file', file);
formData.append('name', name);
return new Promise(function(resolve, reject) {
$.ajax({
url: modifiedPath,
type: "POST",
data: formData,
contentType: false,
processData: false,
success: function () {
console.log("Uploaded file successfully");
resolve();
},
error: function (xhr, status, error) {
console.error(`Failed to upload file: ${error}`);
reject(error);
}
});
});
}

function uploadAllFiles(path) {
let inputElement = document.getElementById('fileInput');
let files = inputElement.files;
const uploadPromises = [];
for (let i = 0; i < files.length; i++) {
let file = files[i];
uploadPromises.push(uploadFile(file, path, ""));
}
if (files.length > 0) {
Promise.all(uploadPromises)
.then(() => {
alert("All files uploaded successfully.");
location.reload();
})
.catch((error) => {
alert("Some files failed to upload successfully. Ensure that you are not in the root directory, the file is smaller than 1 GB, and does not already exist.");
location.reload();
});
} else {
console.log('No files selected.');
}
}

function getSelectedItems() {
let selectedItems = $("input[type='checkbox'][class='check']:checked");
let paths = [];
selectedItems.each(function(index, element) {
paths.push(jQuery(element).prop('value'));
});
return paths
}

function createFolder(path) {
let name = prompt("Name of folder: ");
if (name !== "" && name !== null) {
uploadFile("", path, name)
.then(() => {
alert("Folder created successfully.");
location.reload();
})
.catch((error) => {
alert("Failed to create folder. Check that you are not in the root directory and that the tile/folder does not already exist.");
})
;
}
}

function handleDownloadClick() {
let paths = getSelectedItems();
if (paths.length > 0 && confirm("Download selected files?")) {
let downloadPromises = [];
paths.forEach(path => {
downloadPromises.push(downloadSelected(path));
});
Promise.all(downloadPromises)
.then(() => {
alert("All files downloaded successfully.");
})
.catch((error) => {
alert("Some files failed to download.");
});
}
}

function handleDeleteSelected() {
let paths = getSelectedItems();
if (paths.length > 0 && confirm("Delete selected files?")) {
let deletePromises = [];
paths.forEach(path => {
deletePromises.push(deleteSelected(path));
});
Promise.all(deletePromises)
.then(() => {
alert("All files deleted successfully.");
location.reload();
})
.catch((error) => {
alert("Unable to delete files in the root directory.")
location.reload();
});
}
}

function selectDeleteSelected(path) {
if (confirm("Delete selected file")) {
deleteSelected(path)
.then(() => {
alert("File deleted successfully.")
location.reload();
})
.catch(() => {
alert("Unable to delete files in the root directory.")
location.reload();
})
}
}

function updateButtonStatesAndStyle(button, parent) {
parent.style.backgroundColor = button.disabled ? "grey" : "rgba(153, 0, 0, 0.9)";
parent.style.pointerEvents = button.disabled ? "none" : "auto";
}

function handleSelectionChange() {
const downloadBtn = document.getElementById('download-selected');
const deleteBtn = document.getElementById('delete-selected');
const downloadParent = document.getElementById('download-parent');
const deleteParent = document.getElementById('delete-parent');

let selectedItems = getSelectedItems();
downloadBtn.disabled = selectedItems.length === 0;
updateButtonStatesAndStyle(downloadBtn, downloadParent);

deleteBtn.disabled = selectedItems.length === 0;
updateButtonStatesAndStyle(deleteBtn, deleteParent);
}

document.addEventListener('DOMContentLoaded', function() {
const otherCheckboxes = document.querySelectorAll('.check');
handleSelectionChange();

$(".check-all").click(function() {
const isChecked = this.checked;
otherCheckboxes.forEach(function(checkbox) {
checkbox.checked = isChecked;
});
handleSelectionChange();
});

$(".check").click(function() {
handleSelectionChange();
})
});
91 changes: 91 additions & 0 deletions app/assets/stylesheets/file_manager.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
.div-row {
display: flex;
flex-direction: row;
gap: 5rem;
}

[type="checkbox"]:not(:checked) {
opacity: 100;
position: relative;
display: flex;
justify-content: center;
align-items: center;
pointer-events: auto;
}

[type="checkbox"]:checked {
position: relative;
opacity: 1;
pointer-events: unset;
}

.table-col-center {
display: flex;
justify-content: center;
align-items: center;
padding-top: 35%;
}

.table-scroll {
height: 40rem;
overflow-y: auto;
}

.div-row-cols {
display: flex;
align-items: center;
}

.button-file {
position: relative;
overflow: hidden;
}

.button-file input[type=submit] {
left: -10px;
right: 0;
padding: 0;
}

.button-file input {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 100px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
outline: none;
background: green;
display: block;
}

.button-file a {
color: white;
}

@media screen and (max-width: 1164px) {
.div-row {
display: grid;
grid-template-columns: auto auto;
gap: 1rem;
}
.button-file {
width: 200px;
}
.div-row-cols {
margin: 0;
padding: 0;
}
}

@media screen and (max-width: 478px) {
.div-row {
display: grid;
grid-template-columns: auto;
gap: 1rem;
}
}

Loading