Skip to content

Commit 27165d6

Browse files
Merge pull request #9 from app-generator/file-manager
File manager
2 parents 0d8f808 + 7d0691c commit 27165d6

File tree

3 files changed

+106
-66
lines changed

3 files changed

+106
-66
lines changed

home/views.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import uuid
23
from django.shortcuts import render, redirect
34
from django.http import HttpResponse, FileResponse, Http404
45
from django.conf import settings
@@ -33,12 +34,14 @@ def get_files_from_directory(directory_path):
3334

3435

3536
def get_breadcrumbs(request):
36-
path_components = [component for component in request.path.split('/') if component]
37+
path_components = [component for component in request.path.split(os.sep) if component]
3738
breadcrumbs = []
3839
url = ''
3940

4041
for component in path_components:
41-
url += f'/{component}'
42+
url += f'{os.sep}{component}'
43+
if component == "file-manager":
44+
component = "root"
4245
breadcrumbs.append({'name': component, 'url': url})
4346

4447
return breadcrumbs
@@ -70,9 +73,10 @@ def generate_nested_directory(root_path, current_path):
7073
directories = []
7174
for name in os.listdir(current_path):
7275
if os.path.isdir(os.path.join(current_path, name)):
76+
unique_id = str(uuid.uuid4())
7377
nested_path = os.path.join(current_path, name)
7478
nested_directories = generate_nested_directory(root_path, nested_path)
75-
directories.append({'name': name, 'path': os.path.relpath(nested_path, root_path), 'directories': nested_directories})
79+
directories.append({'id': unique_id, 'name': name, 'path': os.path.relpath(nested_path, root_path), 'directories': nested_directories})
7680
return directories
7781

7882

templates/includes/subdirectories.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
{% for subdirectory in directory.directories %}
22
{% if subdirectory.directories %}
33
<li
4-
id="collapse{{directory.name}}"
5-
class="ms-{{depth}} collapse {% if subdirectory.name in request.get_full_path %} show {% endif %}"
4+
id="collapse{{directory.id}}"
5+
class="ms-{{depth}} collapse show"
66
>
77
<i class="fa-solid fa-folder"></i>
88
<a
99
data-bs-toggle="collapse"
10-
href="#collapse{{subdirectory.name}}"
10+
href="#collapse{{subdirectory.id}}"
1111
role="button"
1212
aria-expanded="false"
13-
aria-controls="collapse{{subdirectory.name}}"
13+
aria-controls="collapse{{subdirectory.id}}"
1414
>
1515
{{ subdirectory.name }}
1616
</a>
1717
</li>
1818
{% include 'includes/subdirectories.html' with directory=subdirectory depth=depth|add:"2" %}
1919
{% else %}
2020
<li
21-
id="collapse{{directory.name}}"
22-
class="ms-{{depth}} collapse {% if subdirectory.name in request.get_full_path %} show {% endif %} "
21+
id="collapse{{directory.id}}"
22+
class="ms-{{depth}} collapse show"
2323
>
2424
<i class="fa-solid fa-folder"></i>
2525
<a href="{% url 'file_manager' subdirectory.path %}">{{ subdirectory.name }}</a>

templates/pages/file-manager.html

Lines changed: 93 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
ul li {
77
list-style-type: none;
88
}
9+
.dot-separator {
10+
height: 2px;
11+
width: 2px;
12+
background: #000;
13+
border-radius: 50%;
14+
}
15+
.actions span {
16+
cursor: pointer;
17+
}
918
</style>
1019
{% endblock extrastyle %}
1120

@@ -29,8 +38,13 @@
2938
{% if directory.directories %}
3039
<li class="">
3140
<i class="fa-solid fa-folder"></i>
32-
<a data-bs-toggle="collapse" href="#collapse{{directory.name}}" role="button" aria-expanded="false"
33-
aria-controls="collapse{{directory.name}}">
41+
<a
42+
data-bs-toggle="collapse"
43+
href="#collapse{{directory.id}}"
44+
role="button"
45+
aria-expanded="false"
46+
aria-controls="collapse{{directory.id}}"
47+
>
3448
{{ directory.name }}
3549
</a>
3650
</li>
@@ -46,70 +60,92 @@
4660
</div>
4761
<div class="col-lg-9 border py-2">
4862
{% if files %}
49-
<div class="d-flex justify-content-end mb-3">
50-
<label for="fileInput">
51-
<i class="fa-solid fa-upload text-primary fs-3"></i>
52-
</label>
53-
<form method="post" action="{% url 'upload_file' %}" id="upload-file" enctype="multipart/form-data">
54-
{% csrf_token %}
55-
<input type="hidden" name="directory" value="{{ selected_directory }}">
56-
<input id="fileInput" class="d-none" onchange="submitForm()" type="file" name="file" required>
57-
</form>
58-
</div>
59-
<ul>
60-
<div class="row">
63+
<div class="table-responsive">
64+
<table class="table">
65+
<tr>
66+
<th scope="col">File Name</th>
67+
<th scope="col">File Type</th>
68+
<th scope="col">Actions</th>
69+
</tr>
6170
{% for file in files %}
62-
<div class="col-lg-3 mb-3 rounded p-1 shadow-sm">
63-
{% if file.filename|file_extension in ".jpg, .png, .gif" %}
64-
<img height="170px" data-bs-toggle="modal" data-bs-target="#file-{{forloop.counter}}" class="w-100"
65-
src="/media/{{ file.file }}" alt="df">
66-
{% elif file.filename|file_extension in ".mp4, .webm, .ogg" %}
67-
<video height="170px" data-bs-toggle="modal" data-bs-target="#file-{{forloop.counter}}" class="w-100"
68-
src="/media/{{ file.file }}"></video>
69-
{% else %}
70-
{% if file.file|file_extension in ".csv, .txt" %}
71-
<a href="/media/{{ file.file }}">{{ file.filename }}</a>
72-
{% elif file.file|file_extension == '.pdf' %}
73-
<object class="d-block" data="/media/{{ file.file }}" type="application/pdf" width="100%" height="170px">
74-
<a href="/media/{{ file.file }}">{{ file.filename }}</a>
75-
</object>
76-
{% endif %}
77-
{% endif %}
78-
<!-- Modal -->
79-
<div class="modal fade" id="file-{{forloop.counter}}" data-bs-backdrop="static" data-bs-keyboard="false"
80-
tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
81-
<div class="modal-dialog modal-dialog-centered modal-lg">
82-
<div class="modal-content">
83-
<div class="modal-header">
84-
<h1 class="modal-title fs-5" id="staticBackdropLabel">{{ file.filename }}</h1>
85-
<div class="" data-bs-dismiss="modal" aria-label="Close">
86-
<i class="fa-solid fa-circle-xmark fs-5"></i>
87-
</div>
88-
</div>
89-
<div class="modal-body">
90-
{% if file.filename|file_extension in ".jpg, .png, .gif" %}
91-
<img class="w-100" src="/media/{{ file.file }}" alt="df">
92-
{% elif file.filename|file_extension in ".mp4, .webm, .ogg" %}
93-
<video class="w-100" height="240" controls>
94-
<source src="/media/{{ file.file }}" type="video/mp4">
95-
</video>
96-
{% endif %}
71+
<tr>
72+
<td>{{ file.filename }}</td>
73+
<td>{{ file.filename|file_extension|cut:"."|upper }}</td>
74+
<td>
75+
<div class="d-flex align-items-center actions">
76+
{% if file.file|file_extension in ".csv, .txt" %}
77+
<a href="/media/{{ file.file }}">
78+
<i title="View" class="fa-solid fa-eye text-primary"></i>
79+
</a>
80+
{% elif file.file|file_extension == '.pdf' %}
81+
<object data="/media/{{ file.file }}" type="application/pdf">
82+
<a href="/media/{{ file.file }}">
83+
<i title="View" class="fa-solid fa-eye text-primary"></i>
84+
</a>
85+
</object>
86+
{% else %}
87+
<span data-bs-toggle="modal" data-bs-target="#file-{{forloop.counter}}">
88+
<i title="View" class="fa-solid fa-eye text-primary"></i>
89+
</span>
90+
{% endif %}
91+
<div class="dot-separator mx-2"></div>
92+
<span>
93+
<a href="{% url 'download_file' file.file|encoded_file_path %}">
94+
<i title="Download" class="fa-solid fa-download text-success"></i>
95+
</a>
96+
</span>
97+
<div class="dot-separator mx-2"></div>
98+
<span data-bs-toggle="modal" data-bs-target="#delete-{{forloop.counter}}">
99+
<i title="Delete" class="fa-solid fa-trash text-danger"></i>
100+
</span>
101+
</div>
102+
</td>
103+
</tr>
104+
<!-- Modal -->
105+
<div class="modal fade" id="file-{{forloop.counter}}" data-bs-backdrop="static" data-bs-keyboard="false"
106+
tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
107+
<div class="modal-dialog modal-dialog-centered modal-lg">
108+
<div class="modal-content">
109+
<div class="modal-header">
110+
<h1 class="modal-title fs-5" id="staticBackdropLabel">{{ file.filename }}</h1>
111+
<div class="" data-bs-dismiss="modal" aria-label="Close">
112+
<i class="fa-solid fa-circle-xmark fs-5"></i>
97113
</div>
98114
</div>
115+
<div class="modal-body">
116+
{% if file.filename|file_extension in ".jpg, .png, .gif" %}
117+
<img class="w-100" src="/media/{{ file.file }}" alt="df">
118+
{% elif file.filename|file_extension in ".mp4, .webm, .ogg" %}
119+
<video class="w-100" height="240" controls>
120+
<source src="/media/{{ file.file }}" type="video/mp4">
121+
</video>
122+
{% endif %}
123+
</div>
99124
</div>
100125
</div>
101-
<hr />
102-
<div class="">
103-
<a href="{% url 'delete_file' file.file|encoded_file_path %}"><i class="fa-solid fa-trash text-danger"></i></a>
104-
<span>.</span>
105-
<a href="{% url 'download_file' file.file|encoded_file_path %}"><i class="fa-solid fa-download text-success"></i></a>
126+
</div>
127+
<!-- Delete Modal -->
128+
<div class="modal fade" id="delete-{{forloop.counter}}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
129+
<div class="modal-dialog">
130+
<div class="modal-content">
131+
<div class="modal-header">
132+
<h1 class="modal-title fs-5" id="exampleModalLabel">Delete File</h1>
133+
</div>
134+
<div class="modal-body">
135+
{{file.filename}}
136+
</div>
137+
<div class="modal-footer">
138+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
139+
<a class="btn btn-danger" href="{% url 'delete_file' file.file|encoded_file_path %}">Delete</a>
140+
</div>
141+
</div>
106142
</div>
107143
</div>
108144
{% endfor %}
109-
</div>
110-
</ul>
145+
</table>
146+
</div>
111147
{% else %}
112-
<p>Select a directory</p>
148+
<p>No files</p>
113149
{% endif %}
114150
</div>
115151
</div>

0 commit comments

Comments
 (0)