Skip to content

Commit fb4d122

Browse files
committed
More updates to file manager
Not doing individual commits for this, tons of changes for tons of different aspects across multiple files.
1 parent fe9c573 commit fb4d122

File tree

12 files changed

+308
-164
lines changed

12 files changed

+308
-164
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
88
### Added
99
* Support for creating server without having to assign a node and allocation manually. Simply select the checkbox or pass `auto_deploy=true` to the API to auto-select a node and allocation given a location.
1010
* Support for setting IP Aliases through the panel on the node overview page. Also cleaned up allocation removal.
11+
* Support for renaming files through the panel's file mananger.
1112

1213
### Changed
1314
* Prevent clicking server start button until server is completely off, not just stopping.
1415
* Upon successful creation of a node it will redirect to the allocation tab and display a clearer message to add allocations.
1516
* Trying to add a new node if no location exists redirects user to location management page and alerts them to add a location first.
1617
* `Server\AjaxController@postSetConnection` is now `Server\AjaxController@postSetPrimary` and accepts one post parameter of `allocation` rather than a combined `ip:port` value.
1718
* Port allocations on server view are now cleaner and should make more sense.
19+
* Improved File Manager
20+
* Rewritten Javascript to load, rename, and handle other file actions.
21+
* Uses Ace Editor for editing files rather than a non-formatted textarea
22+
* File actions that were previously icons to the right are now contained in a menu that appears when right-clicking a file or folder.
1823

1924
### Fixed
2025
* Team Fortress named 'Insurgency' in panel in database seeder. ([#96](https://github.com/Pterodactyl/Panel/issues/96), PR by [@MeltedLux](https://github.com/MeltedLux))

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
## Pterodactyl Panel
2-
Pterodactyl is the free game server management panel designed by users, for users. Featuring support for Vanilla Minecraft, Spigot, Source Dedicated Servers, BungeeCord, and many more. Pterodactyl is built on the `Laravel PHP Framework (v5.2)`.
2+
Pterodactyl is the free game server management panel designed by users, for users. Featuring support for Vanilla Minecraft, Spigot, Source Dedicated Servers, BungeeCord, and many more. Pterodactyl is built on the `Laravel PHP Framework (v5.3)`.
33

44
## Support & Documentation
55
Support for using Pterodactyl can be found on our [wiki](https://github.com/Pterodactyl/Panel/wiki) or on our [Discord chat](https://discord.gg/0gYt8oU8QOkDhKLS).
@@ -28,6 +28,8 @@ SOFTWARE.
2828
```
2929

3030
### Credits
31+
Ace Editor - [license](https://github.com/ajaxorg/ace/blob/master/LICENSE) - [homepage](https://ace.c9.io)
32+
3133
Animate.css - [license](https://github.com/daneden/animate.css/blob/master/LICENSE) - [homepage](http://daneden.github.io/animate.css/)
3234

3335
Async.js - [license](https://github.com/caolan/async/blob/master/LICENSE) - [homepage](https://github.com/caolan/async/)
@@ -48,6 +50,8 @@ jQuery - [license](https://github.com/jquery/jquery/blob/master/LICENSE.txt) - [
4850

4951
jQuery Terminal - [license](https://github.com/jcubic/jquery.terminal/blob/master/LICENSE) - [homepage](http://terminal.jcubic.pl)
5052

53+
Lodash - [license](https://github.com/lodash/lodash/blob/master/LICENSE) - [homepage](https://lodash.com/)
54+
5155
MetricsGraphics.js - [license](https://github.com/mozilla/metrics-graphics/blob/master/LICENSE) - [homepage](http://metricsgraphicsjs.org/)
5256

5357
Socket.io - [license](https://github.com/socketio/socket.io/blob/master/LICENSE) - [homepage](http://socket.io)

app/Http/Controllers/Server/AjaxController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public function postDirectoryList(Request $request, $uuid)
137137
'server' => $server,
138138
'files' => $directoryContents->files,
139139
'folders' => $directoryContents->folders,
140-
'extensions' => Repositories\HelperRepository::editableFiles(),
140+
'editableMime' => Repositories\HelperRepository::editableFiles(),
141141
'directory' => $prevDir
142142
]);
143143

app/Http/Controllers/Server/ServerController.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ public function getEditFile(Request $request, $uuid, $file)
145145
'server' => $server,
146146
'node' => Models\Node::find($server->node),
147147
'file' => $file,
148-
'contents' => $fileContent->content,
149-
'directory' => (in_array($fileInfo->dirname, ['.', './', '/'])) ? '/' : trim($fileInfo->dirname, '/') . '/',
150-
'extension' => $fileInfo->extension
148+
'stat' => $fileContent['stat'],
149+
'contents' => $fileContent['file']->content,
150+
'directory' => (in_array($fileInfo->dirname, ['.', './', '/'])) ? '/' : trim($fileInfo->dirname, '/') . '/'
151151
]);
152152

153153
}

app/Repositories/Daemon/FileRepository.php

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public function __construct($uuid)
8585
* Get the contents of a requested file for the server.
8686
*
8787
* @param string $file
88-
* @return string
88+
* @return array
8989
*/
9090
public function returnFileContents($file)
9191
{
@@ -95,22 +95,39 @@ public function returnFileContents($file)
9595
}
9696

9797
$file = (object) pathinfo($file);
98-
if (!in_array($file->extension, HelperRepository::editableFiles())) {
99-
throw new DisplayException('You do not have permission to edit this type of file.');
100-
}
10198

10299
$file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/';
103100

104-
$res = $this->client->request('GET', '/server/file/' . rawurlencode($file->dirname.$file->basename), [
101+
$res = $this->client->request('GET', '/server/files/stat/' . rawurlencode($file->dirname.$file->basename) , [
102+
'headers' => $this->headers
103+
]);
104+
105+
$stat = json_decode($res->getBody());
106+
if($res->getStatusCode() !== 200 || !isset($stat->size)) {
107+
throw new DisplayException('The daemon provided a non-200 error code on stat lookup: HTTP\\' . $res->getStatusCode());
108+
}
109+
110+
if (!in_array($stat->mime, HelperRepository::editableFiles())) {
111+
throw new DisplayException('You cannot edit that type of file (' . $stat->mime . ') through the panel.');
112+
}
113+
114+
if ($stat->size > 5000000) {
115+
throw new DisplayException('That file is too large to open in the browser, consider using a SFTP client.');
116+
}
117+
118+
$res = $this->client->request('GET', '/server/file/' . rawurlencode($file->dirname.$file->basename) , [
105119
'headers' => $this->headers
106120
]);
107121

108122
$json = json_decode($res->getBody());
109123
if($res->getStatusCode() !== 200 || !isset($json->content)) {
110-
throw new DisplayException('Scales provided a non-200 error code: HTTP\\' . $res->getStatusCode());
124+
throw new DisplayException('The daemon provided a non-200 error code: HTTP\\' . $res->getStatusCode());
111125
}
112126

113-
return $json;
127+
return [
128+
'file' => $json,
129+
'stat' => $stat
130+
];
114131

115132
}
116133

@@ -130,11 +147,24 @@ public function saveFileContents($file, $content)
130147

131148
$file = (object) pathinfo($file);
132149

133-
if(!in_array($file->extension, HelperRepository::editableFiles())) {
134-
throw new DisplayException('You do not have permission to edit this type of file.');
150+
$file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/';
151+
152+
$res = $this->client->request('GET', '/server/files/stat/' . rawurlencode($file->dirname.$file->basename) , [
153+
'headers' => $this->headers
154+
]);
155+
156+
$stat = json_decode($res->getBody());
157+
if($res->getStatusCode() !== 200 || !isset($stat->size)) {
158+
throw new DisplayException('The daemon provided a non-200 error code on stat lookup: HTTP\\' . $res->getStatusCode());
135159
}
136160

137-
$file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/';
161+
if (!in_array($stat->mime, HelperRepository::editableFiles())) {
162+
throw new DisplayException('You cannot edit that type of file (' . $stat->mime . ') through the panel.');
163+
}
164+
165+
if ($stat->size > 5000000) {
166+
throw new DisplayException('That file is too large to save in the browser, consider using a SFTP client.');
167+
}
138168

139169
$res = $this->client->request('POST', '/server/file/' . rawurlencode($file->dirname.$file->basename), [
140170
'headers' => $this->headers,

app/Repositories/HelperRepository.php

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,20 @@ class HelperRepository {
3030
* @var array
3131
*/
3232
protected static $editable = [
33-
'txt',
34-
'yml',
35-
'yaml',
36-
'log',
37-
'conf',
38-
'config',
39-
'html',
40-
'json',
41-
'properties',
42-
'props',
43-
'cfg',
44-
'lang',
45-
'ini',
46-
'cmd',
47-
'sh',
48-
'lua',
49-
'0' // Supports BungeeCord Files
33+
'application/json',
34+
'application/javascript',
35+
'application/xml',
36+
'application/xhtml+xml',
37+
'text/xml',
38+
'text/css',
39+
'text/html',
40+
'text/plain',
41+
'text/x-perl',
42+
'text/x-shellscript',
43+
'inode/x-empty'
5044
];
5145

46+
5247
public function __construct()
5348
{
5449
//

public/themes/default/css/pterodactyl.css

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,41 @@ li.btn.btn-default.pill:active,li.btn.btn-default.pill:focus,li.btn.btn-default.
197197
.use-pointer {
198198
cursor: pointer !important;
199199
}
200+
201+
.dropdown-menu > li.bg-danger {
202+
background-color:#fdf7f7;
203+
color:#474a54;
204+
border-left: 4px solid #d9534f !important;
205+
}
206+
207+
.dropdown-menu > li.bg-info {
208+
background-color:#fcf8f2;
209+
color:#474a54;
210+
border-left: 4px solid #f0ad4e !important;
211+
}
212+
213+
.dropdown-menu > li.bg-success {
214+
background-color:#f4f8fa;
215+
color:#474a54;
216+
border-left: 4px solid #5bc0de !important;
217+
}
218+
219+
.dropdown-menu > li.bg-warning {
220+
background-color:#fdf7f7;
221+
color:#474a54;
222+
border-left: 4px solid #d9534f !important;
223+
}
224+
225+
.dropdown-menu > li.bg-default {
226+
border-left: 4px solid #bbbbbb !important;
227+
}
228+
229+
.dropdown-menu > li.bg-danger > a,
230+
.dropdown-menu > li.bg-info > a,
231+
.dropdown-menu > li.bg-success > a,
232+
.dropdown-menu > li.bg-warning > a,
233+
.dropdown-menu > li.bg-default > a {
234+
padding-left: 11px !important;
235+
}
236+
/*.bg-danger:active,.bg-danger:focus,.bg-danger:hover{color:#fff;background-color:#d32a0e;border-color:#b1240c}
237+
.bg-danger.disabled,.bg-danger.disabled:active,.bg-danger.disabled:focus,.bg-danger.disabled:hover,.bg-danger[disabled]{background-color:#f04124;border-color:#ea2f10}*/

resources/views/server/files/edit.blade.php

Lines changed: 46 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -26,83 +26,77 @@
2626
@section('content')
2727
<div class="col-md-12">
2828
<h3 class="nopad"><small>Editing File: /home/container/{{ $file }}</small></h3>
29-
<form method="post" id="editing_file">
30-
<div class="form-group">
31-
<div>
32-
@if (in_array($extension, ['yaml', 'yml']))
33-
<div class="alert alert-info">
34-
{!! trans('server.files.yaml_notice', [
35-
'dropdown' => '<select id="space_yaml">
36-
<option value="2">2</option>
37-
<option value="4" selected="selected">4</option>
38-
<option value="8">8</option>
39-
</select>'
40-
]) !!}
41-
</div>
42-
@endif
43-
<textarea name="file_contents" id="fileContent" style="border: 1px solid #dddddd;height:500px;" class="form-control console">{{ $contents }}</textarea>
44-
</div>
29+
<div class="row">
30+
<div class="col-md-12">
31+
<div id="editor" style="height:500px;">{{ $contents }}</div>
4532
</div>
46-
@can('save-files', $server)
47-
<div class="form-group">
48-
<div>
49-
<input type="hidden" name="file" value="{{ $file }}" />
50-
{!! csrf_field() !!}
51-
<button class="btn btn-primary btn-sm" id="save_file" type="submit">{{ trans('strings.save') }}</button>
52-
<a href="/server/{{ $server->uuidShort }}/files?dir={{ rawurlencode($directory) }}" class="text-muted pull-right"><small>{{ trans('server.files.back') }}</small></a>
53-
</div>
33+
</div>
34+
@can('save-files', $server)
35+
<div class="row">
36+
<div class="col-md-12">
37+
<hr />
38+
<input type="hidden" name="file" value="{{ $file }}" />
39+
<button class="btn btn-primary btn-sm" id="save_file" type="submit">{{ trans('strings.save') }}</button>
40+
<a href="/server/{{ $server->uuidShort }}/files?dir={{ rawurlencode($directory) }}" class="text-muted pull-right"><small>{{ trans('server.files.back') }}</small></a>
5441
</div>
55-
@endcan
56-
</form>
42+
</div>
43+
@endcan
5744
</div>
45+
{!! Theme::js('js/vendor/ace/ace.js') !!}
46+
{!! Theme::js('js/vendor/ace/ext-modelist.js') !!}
5847
<script>
5948
$(document).ready(function () {
6049
$('.server-files').addClass('active');
61-
$('textarea').keydown(function (e) {
62-
if (e.keyCode === 9) {
50+
const Editor = ace.edit('editor');
51+
const Modelist = ace.require('ace/ext/modelist')
6352
64-
var start = this.selectionStart;
65-
var end = this.selectionEnd;
66-
var value = $(this).val();
67-
var joinYML = '\t';
68-
var yamlSpaces = 1;
53+
Editor.setTheme('ace/theme/github');
54+
Editor.getSession().setMode(Modelist.getModeForPath('{{ $stat->name }}').mode);
55+
Editor.getSession().setUseWrapMode(true);
56+
Editor.setShowPrintMargin(false);
6957
70-
@if (in_array($extension, ['yaml', 'yml']))
71-
yamlSpaces = parseInt($("#space_yaml").val());
72-
joinYML = Array(yamlSpaces + 1).join(" ");
73-
@endif
74-
75-
$(this).val(value.substring(0, start) + joinYML + value.substring(end));
76-
this.selectionStart = this.selectionEnd = start + yamlSpaces;
77-
e.preventDefault();
78-
79-
}
80-
});
8158
@can('save-files', $server)
82-
$('#save_file').click(function (e) {
59+
Editor.commands.addCommand({
60+
name: 'save',
61+
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
62+
exec: function(editor) {
63+
save();
64+
},
65+
readOnly: false
66+
});
67+
68+
$('#save_file').on('click', function (e) {
8369
e.preventDefault();
70+
save();
71+
});
8472
73+
function save() {
8574
var fileName = $('input[name="file"]').val();
86-
var fileContents = $('#fileContent').val();
87-
8875
$('#save_file').append(' <i class="fa fa-spinner fa fa-spin"></i>').addClass('disabled');
8976
$.ajax({
9077
type: 'POST',
9178
url: '{{ route('server.files.save', $server->uuidShort) }}',
9279
headers: { 'X-CSRF-Token': '{{ csrf_token() }}' },
9380
data: {
9481
file: fileName,
95-
contents: fileContents
82+
contents: Editor.getValue()
9683
}
9784
}).done(function (data) {
98-
$('#tpl_messages').html('<div class="alert alert-success">{{ trans('server.files.saved') }}</div>').show().delay(3000).slideUp();
85+
$.notify({
86+
message: '{{ trans('server.files.saved') }}'
87+
}, {
88+
type: 'success'
89+
});
9990
}).fail(function (jqXHR) {
100-
$('#tpl_messages').html('<div class="alert alert-danger">' + jqXHR.responseText + '</div>');
91+
$.notify({
92+
message: jqXHR.responseText
93+
}, {
94+
type: 'danger'
95+
});
10196
}).always(function () {
10297
$('#save_file').html('{{ trans('strings.save') }}').removeClass('disabled');
10398
});
104-
105-
});
99+
}
106100
@endcan
107101
});
108102
</script>

0 commit comments

Comments
 (0)