fix: file browser deletion bug + parent directory
Underscore matters! - fixed both bugs for the browser Extra: - style for toasts quickfix generic modals
Alessandro committed
Nov 28, 2024 at 01:13 UTC
bb980ea6b93a074b24cf86c54b0be69596b34cb1
9 files changed
+154
-73
python/helpers/file_browser.py
+10
-2
@@ -133,8 +133,16 @@ class FileBrowser:
133
# Get parent directory path if not at root
134
parent_path = ""
135
if current_path:
136
- parent = (Path(current_path).parent)
137
- parent_path = str(parent) if parent != Path(".") else ""
136
+ try:
137
+ # Get the absolute path of current directory
138
+ current_abs = (self.base_dir / current_path).resolve()
139
+
140
+ # parent_path is empty only if we're already at root
141
+ if str(current_abs) != str(self.base_dir):
142
+ parent_path = str(Path(current_path).parent)
143
+
144
+ except Exception as e:
145
+ parent_path = ""
146
147
return {
148
"entries": all_entries,
webui/css/file_browser.css
+8
-2
@@ -123,8 +123,14 @@
123
background-color: var(--color-secondary-dark);
124
}
125
126
-.current-path {
127
- font-family: monospace;
126
+#current-path {
127
+ opacity: 0.9;
128
+}
129
+
130
+#path-text {
131
+ font-family: 'Roboto Mono', monospace;
132
+ font-optical-sizing: auto;
133
+ -webkit-font-optical-sizing: auto;
134
opacity: 0.9;
135
}
136
webui/css/modals.css
+20
-16
@@ -40,16 +40,10 @@
40
}
41
42
.modal-header h2 {
43
- color: var(--color-primary);
43
font-size: var(--font-size-large);
44
margin: 0;
45
}
46
48
-.modal-header > svg {
49
- fill: var(--color-primary);
50
- max-height: 30px !important;
51
-}
52
-
47
.modal-subheader {
48
padding: 0.7rem 1.5rem;
49
display: inline;
@@ -220,34 +214,44 @@ h2 {
214
}
215
216
@media (max-width: 768px) {
217
+ .modal-header {
218
+ padding-left: 1.1rem;
219
+ text-wrap: nowrap;
220
+ }
221
.modal-content {
224
- padding: 1rem;
225
- overflow-y: auto;
226
- flex-grow: 1;
222
+ padding: 0.5rem 0.5rem 0rem 0.5rem;
223
+ overflow-y: auto;
224
+ flex-grow: 1;
225
}
226
.modal-footer {
229
- padding: var(--spacing-md) 0rem var(--spacing-md) 0 !important;
227
+ padding: var(--spacing-sm) 0rem var(--spacing-sm) 0 !important;
228
}
229
.section {
232
- margin-bottom: 1.5rem;
233
- padding: 1rem;
234
- border: 1px solid var(--color-border);
235
- border-radius: 0.5rem;
230
+ margin-bottom: 1.5rem;
231
+ padding: 1rem;
232
+ border: 1px solid var(--color-border);
233
+ border-radius: 0.5rem;
234
}
235
#buttons-container {
236
margin: 0 auto;
237
}
238
+ .btn {
239
+ padding: 0.5rem 1.7rem;
240
+ }
241
}
242
243
@media (max-width: 540px) {
243
- .modal-header {
244
- text-wrap: nowrap;
244
+ .modal-header h2 {
245
+ font-size: var(--font-size-normal);
246
+ margin: 0;
247
}
248
#buttons-container {
249
max-height: 50px;
250
}
251
.btn {
252
text-wrap: wrap;
253
+ font-size: var(--font-size-small);
254
+ padding: 0.5rem 0.85rem;
255
}
256
.btn-upload {
257
margin: 0 auto;
webui/css/settings.css
+4
@@ -223,6 +223,10 @@ nav ul li a img {
223
background-color: var(--color-secondary-light);
224
}
225
226
+.light-mode textarea:focus {
227
+ background-color: #dddddd;
228
+}
229
+
230
@media (max-width: 768px) {
231
.field-control {
232
width: 100%;
webui/css/toast.css
+70
-38
@@ -1,43 +1,75 @@
1
#toast {
2
- /* position: fixed;
3
- bottom: 20px;
4
- left: 50%;
5
- transform: translateX(-50%); */
6
- margin: 0.5em;
7
- background-color: #333;
8
- color: #fff;
9
- padding: 0.3em;
10
- border-radius: 0.3125em;
11
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
12
- display: none;
13
- align-items: center;
14
- z-index: 9999;
2
+ position: relative;
3
+ width: 98.5%;
4
+ bottom: var(--spacing-xs);
5
+ left: var(--spacing-xs);
6
+ background-color: #333;
7
+ color: #fff;
8
+ padding: 0.3em;
9
+ border-radius: 0.3125em;
10
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
11
+ display: none;
12
+ align-items: center;
13
+ z-index: 9999;
14
+}
15
+
16
+#toast.show {
17
+ display: flex;
18
+ animation: toastIn 0.3s ease-out forwards;
19
+}
20
+
21
+#toast.hide {
22
+ animation: toastOut 0.3s ease-in forwards;
23
+}
24
+
25
+#toast.toast--success {
26
+ background-color: #4CAF50;
27
+}
28
+
29
+#toast.toast--error {
30
+ background-color: #731811;
31
+}
32
+
33
+#toast.toast--info {
34
+ background-color: #2196F3;
35
+}
36
+
37
+.toast__message {
38
+ margin-left: var(--spacing-xs);
39
+ margin-right: 16px;
40
+ flex-grow: 1;
41
+}
42
+
43
+.toast__close,
44
+.toast__copy {
45
+ background-color: transparent;
46
+ border: none;
47
+ color: #fff;
48
+ cursor: pointer;
49
+ font-size: 16px;
50
+ margin-left: 8px;
51
+}
52
+
53
+/* Animations */
54
+
55
+@keyframes toastIn {
56
+ from {
57
+ opacity: 0;
58
+ transform: translateY(20px);
59
}
16
-
17
- #toast.toast--success {
18
- background-color: #4CAF50;
60
+ to {
61
+ opacity: 1;
62
+ transform: translateY(0);
63
}
20
-
21
- #toast.toast--error {
22
- background-color: #731811;
64
+}
65
+
66
+@keyframes toastOut {
67
+ from {
68
+ opacity: 1;
69
+ transform: translateY(0);
70
}
24
-
25
- #toast.toast--info {
26
- background-color: #2196F3;
71
+ to {
72
+ opacity: 0;
73
+ transform: translateY(20px);
74
}
28
-
29
- .toast__message {
30
- margin-left: var(--spacing-xs);
31
- margin-right: 16px;
32
- flex-grow: 1;
33
- }
34
-
35
- .toast__close,
36
- .toast__copy {
37
- background-color: transparent;
38
- border: none;
39
- color: #fff;
40
- cursor: pointer;
41
- font-size: 16px;
42
- margin-left: 8px;
43
- }
\ No newline at end of file
75
+}
\ No newline at end of file
webui/index.html
+4
-2
@@ -195,7 +195,7 @@
195
</div>
196
<div id="toast" class="toast">
197
<div class="toast__message"></div>
198
- <button class="toast__copy">Copy</button>
198
+ <button class="toast__copy" style="display: none;">Copy</button>
199
<button class="toast__close">Close</button>
200
</div>
201
<div id="progress-bar-box" x-data="{ isSpeaking: false }" x-init="
@@ -538,7 +538,9 @@
538
Up
539
</button>
540
541
- <span class="current-path" x-text="browser.currentPath || 'Current Path: /'"></span>
541
+ <div id="current-path">
542
+ <span id="path-text" x-text="browser.currentPath"></span>
543
+ </div>
544
</div>
545
546
<div class="files-list">
webui/index.js
+34
-12
@@ -652,21 +652,31 @@ function removeClassFromElement(element, className) {
652
653
function toast(text, type = 'info') {
654
const toast = document.getElementById('toast');
655
-
655
+
656
// Update the toast content and type
657
- toast.querySelector('#toast .toast__message').textContent = text;
657
+ toast.querySelector('.toast__message').textContent = text;
658
toast.className = `toast toast--${type}`;
659
+
660
+ // Remove any existing animation classes
661
+ toast.classList.remove('show', 'hide');
662
+
663
+ // Show the toast and trigger animation
664
toast.style.display = 'flex';
660
-
665
+ // Force a reflow to ensure the animation triggers
666
+ void toast.offsetWidth;
667
+ toast.classList.add('show');
668
+
669
+ // Show/hide copy button based on toast type
670
+ const copyButton = toast.querySelector('.toast__copy');
671
+ copyButton.style.display = type === 'error' ? 'inline-block' : 'none';
672
+
673
// Add the close button event listener
662
- const closeButton = toast.querySelector('#toast .toast__close');
674
+ const closeButton = toast.querySelector('.toast__close');
675
closeButton.onclick = () => {
664
- toast.style.display = 'none';
665
- clearTimeout(toast.timeoutId);
676
+ hideToast();
677
};
667
-
678
+
679
// Add the copy button event listener
669
- const copyButton = toast.querySelector('#toast .toast__copy');
680
copyButton.onclick = () => {
681
navigator.clipboard.writeText(text);
682
copyButton.textContent = 'Copied!';
@@ -674,15 +684,27 @@ function toast(text, type = 'info') {
684
copyButton.textContent = 'Copy';
685
}, 2000);
686
};
677
-
687
+
688
// Clear any existing timeout
689
clearTimeout(toast.timeoutId);
680
-
681
- // Automatically close the toast after 5 seconds
690
+
691
+ // Automatically close the toast after 10 seconds
692
toast.timeoutId = setTimeout(() => {
683
- toast.style.display = 'none';
693
+ hideToast();
694
}, 10000);
695
}
696
+
697
+ function hideToast() {
698
+ const toast = document.getElementById('toast');
699
+ toast.classList.remove('show');
700
+ toast.classList.add('hide');
701
+
702
+ // Remove the element from display after animation completes
703
+ setTimeout(() => {
704
+ toast.style.display = 'none';
705
+ toast.classList.remove('hide');
706
+ }, 300); // Match this with animation duration
707
+}
708
709
function scrollChanged(isAtBottom) {
710
const inputAS = Alpine.$data(autoScrollSwitch);
webui/js/file_browser.js
+1
-1
@@ -110,7 +110,7 @@ const fileBrowserModalProxy = {
110
}
111
112
try {
113
- const response = await fetch('/deleteWorkDirFile', {
113
+ const response = await fetch('/delete_work_dir_file', {
114
method: 'POST',
115
headers: {
116
'Content-Type': 'application/json',
webui/js/modal.js
+3
@@ -1,6 +1,9 @@
1
const genericModalProxy = {
2
isOpen: false,
3
isLoading: false,
4
+ title: '',
5
+ description: '',
6
+ html: '',
7
8
async openModal(title, description, html) {
9
const modalEl = document.getElementById('genericModal');