sshler 0.3.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sshler/__init__.py +10 -0
- sshler/cli.py +161 -0
- sshler/config.py +425 -0
- sshler/scripts/install-sshler-task.ps1 +28 -0
- sshler/scripts/remove-sshler-task.ps1 +15 -0
- sshler/scripts/run-sshler.ps1 +24 -0
- sshler/ssh.py +329 -0
- sshler/ssh_config.py +134 -0
- sshler/state.py +230 -0
- sshler/static/base.js +305 -0
- sshler/static/favicon-terminal.svg +8 -0
- sshler/static/favicon.svg +8 -0
- sshler/static/file-edit.js +81 -0
- sshler/static/file-view.js +60 -0
- sshler/static/style.css +158 -0
- sshler/static/term.js +304 -0
- sshler/templates/base.html +41 -0
- sshler/templates/box.html +53 -0
- sshler/templates/docs.html +40 -0
- sshler/templates/file_edit.html +30 -0
- sshler/templates/file_view.html +31 -0
- sshler/templates/index.html +49 -0
- sshler/templates/new_box.html +42 -0
- sshler/templates/partials/dir_listing.html +91 -0
- sshler/templates/term.html +67 -0
- sshler/webapp.py +1897 -0
- sshler-0.3.2.dist-info/METADATA +245 -0
- sshler-0.3.2.dist-info/RECORD +31 -0
- sshler-0.3.2.dist-info/WHEEL +5 -0
- sshler-0.3.2.dist-info/entry_points.txt +2 -0
- sshler-0.3.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
|
|
2
|
+
{% set current_target = target_id if target_id is defined else 'browser' %}
|
|
3
|
+
{% set dir_url = urls.list %}
|
|
4
|
+
{% set touch_url = urls.touch %}
|
|
5
|
+
{% set upload_url = urls.upload %}
|
|
6
|
+
{% set fav_url = urls.favorite %}
|
|
7
|
+
{% set preview_url = urls.preview %}
|
|
8
|
+
{% set edit_url = urls.edit %}
|
|
9
|
+
{% set term_url = urls.term %}
|
|
10
|
+
<div class="dir-header">
|
|
11
|
+
<span class="mono">{{ directory_path }}</span>
|
|
12
|
+
<a class="btn small" href="{{ term_url }}?host={{ box.name }}&dir={{ directory_path|urlencode }}" target="_blank">Open Terminal Here</a>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="dir-tools">
|
|
15
|
+
<form class="dir-tool" hx-post="{{ touch_url }}" hx-target="#{{ current_target }}" hx-swap="innerHTML">
|
|
16
|
+
<input type="hidden" name="directory" value="{{ directory_path }}">
|
|
17
|
+
<input type="hidden" name="target" value="{{ current_target }}">
|
|
18
|
+
<input type="text" name="filename" placeholder="new_file.txt" required>
|
|
19
|
+
<button type="submit" class="action-btn">Create</button>
|
|
20
|
+
</form>
|
|
21
|
+
<form class="dir-tool" hx-post="{{ upload_url }}" hx-target="#{{ current_target }}" hx-swap="innerHTML" hx-encoding="multipart/form-data">
|
|
22
|
+
<input type="hidden" name="directory" value="{{ directory_path }}">
|
|
23
|
+
<input type="hidden" name="target" value="{{ current_target }}">
|
|
24
|
+
<input type="file" name="file" required>
|
|
25
|
+
<button type="submit" class="action-btn">Upload</button>
|
|
26
|
+
</form>
|
|
27
|
+
</div>
|
|
28
|
+
{% if error %}
|
|
29
|
+
<div class="alert error">{{ error }}</div>
|
|
30
|
+
{% endif %}
|
|
31
|
+
<table class="dir dir-table">
|
|
32
|
+
<thead><tr><th>Name</th><th>Type</th><th class="actions-col">Actions</th></tr></thead>
|
|
33
|
+
<tbody>
|
|
34
|
+
{% set parent_directory = directory_path.rsplit('/', 1)[0] if '/' in directory_path and directory_path != '/' else '/' %}
|
|
35
|
+
{% if parent_directory.endswith(':') %}
|
|
36
|
+
{% set parent_directory = parent_directory ~ '/' %}
|
|
37
|
+
{% endif %}
|
|
38
|
+
{% if directory_path != '/' and parent_directory != directory_path %}
|
|
39
|
+
<tr class="fs-row">
|
|
40
|
+
<td class="fs-name">
|
|
41
|
+
<a class="fs-entry up" hx-get="{{ dir_url }}?path={{ parent_directory|urlencode }}&target={{ current_target }}"
|
|
42
|
+
hx-target="#{{ current_target }}" hx-swap="innerHTML">..</a>
|
|
43
|
+
</td>
|
|
44
|
+
<td class="fs-type">parent</td>
|
|
45
|
+
<td class="fs-actions"></td>
|
|
46
|
+
</tr>
|
|
47
|
+
{% endif %}
|
|
48
|
+
{% for entry in entries %}
|
|
49
|
+
<tr class="fs-row">
|
|
50
|
+
{% set target_path = (directory_path.rstrip('/') ~ '/' ~ entry.name) if directory_path != '/' else '/' ~ entry.name %}
|
|
51
|
+
<td class="fs-name">
|
|
52
|
+
{% if entry.is_directory %}
|
|
53
|
+
<a class="fs-entry folder" hx-get="{{ dir_url }}?path={{ target_path|urlencode }}&target={{ current_target }}"
|
|
54
|
+
hx-target="#{{ current_target }}" hx-swap="innerHTML">
|
|
55
|
+
<span class="fs-icon folder"></span>
|
|
56
|
+
<span class="fs-label">{{ entry.name }}</span>
|
|
57
|
+
</a>
|
|
58
|
+
{% else %}
|
|
59
|
+
<a class="fs-entry file" href="{{ preview_url }}?path={{ target_path|urlencode }}" target="_blank">
|
|
60
|
+
<span class="fs-icon file"></span>
|
|
61
|
+
<span class="fs-label">{{ entry.name }}</span>
|
|
62
|
+
</a>
|
|
63
|
+
{% endif %}
|
|
64
|
+
</td>
|
|
65
|
+
<td class="fs-type">{{ "dir" if entry.is_directory else "file" }}</td>
|
|
66
|
+
<td class="fs-actions">
|
|
67
|
+
{% if entry.is_directory %}
|
|
68
|
+
<a class="action-btn" href="{{ term_url }}?host={{ box.name }}&dir={{ target_path|urlencode }}" target="_blank" title="Open terminal">
|
|
69
|
+
Term
|
|
70
|
+
</a>
|
|
71
|
+
{% set is_favorite = target_path in (box.favorites or []) %}
|
|
72
|
+
<button class="icon-btn star{{ ' active' if is_favorite else '' }}"
|
|
73
|
+
aria-label="Toggle favorite"
|
|
74
|
+
hx-post="{{ fav_url }}?path={{ target_path|urlencode }}"
|
|
75
|
+
hx-swap="none">{{ '★' if is_favorite else '☆' }}</button>
|
|
76
|
+
{% else %}
|
|
77
|
+
<a class="action-btn" href="{{ preview_url }}?path={{ target_path|urlencode }}" target="_blank" title="Preview file">Preview</a>
|
|
78
|
+
<a class="action-btn" href="{{ edit_url }}?path={{ target_path|urlencode }}" target="_blank" title="Edit file">Edit</a>
|
|
79
|
+
<button class="action-btn danger-btn delete-file-btn"
|
|
80
|
+
data-box="{{ box.name }}"
|
|
81
|
+
data-path="{{ target_path }}"
|
|
82
|
+
data-directory="{{ directory_path }}"
|
|
83
|
+
data-target="{{ current_target }}"
|
|
84
|
+
data-filename="{{ entry.name }}"
|
|
85
|
+
title="Delete file">Delete</button>
|
|
86
|
+
{% endif %}
|
|
87
|
+
</td>
|
|
88
|
+
</tr>
|
|
89
|
+
{% endfor %}
|
|
90
|
+
</tbody>
|
|
91
|
+
</table>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
|
|
2
|
+
{% extends "base.html" %}
|
|
3
|
+
{% block head_extra %}
|
|
4
|
+
<link rel="stylesheet" href="https://unpkg.com/xterm/css/xterm.css" />
|
|
5
|
+
<script src="https://unpkg.com/xterm/lib/xterm.js"></script>
|
|
6
|
+
<script src="https://unpkg.com/xterm-addon-fit/lib/xterm-addon-fit.js"></script>
|
|
7
|
+
{% endblock %}
|
|
8
|
+
{% block content %}
|
|
9
|
+
{% set raw_dir = directory.rstrip('/') %}
|
|
10
|
+
{% if raw_dir == '' %}
|
|
11
|
+
{% set dir_label = '/' %}
|
|
12
|
+
{% else %}
|
|
13
|
+
{% set dir_label = raw_dir.rsplit('/', 1)[-1] %}
|
|
14
|
+
{% endif %}
|
|
15
|
+
<div class="term-page"
|
|
16
|
+
data-term-root
|
|
17
|
+
data-box-name="{{ box.name }}"
|
|
18
|
+
data-host="{{ box.name }}"
|
|
19
|
+
data-directory="{{ directory }}"
|
|
20
|
+
data-session="{{ session }}"
|
|
21
|
+
data-dir-label="{{ dir_label }}">
|
|
22
|
+
<div class="term-header">
|
|
23
|
+
<div class="term-banner">
|
|
24
|
+
<div class="term-banner__host">{{ box.name }}</div>
|
|
25
|
+
<div class="term-banner__primary mono">{{ dir_label }}</div>
|
|
26
|
+
<div class="term-banner__meta mono">Session: {{ session }}</div>
|
|
27
|
+
<div class="term-banner__actions">
|
|
28
|
+
<a class="btn secondary small" href="/box/{{ box.name }}">Back</a>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="term-banner__path mono">{{ directory }}</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
<div id="tmux-tabs" class="tmux-tabs"></div>
|
|
34
|
+
<div class="term-shell">
|
|
35
|
+
<div class="term-toolbar" id="term-toolbar">
|
|
36
|
+
<button class="btn secondary small" data-command="scroll-mode">Scroll Mode</button>
|
|
37
|
+
<button class="btn secondary small" data-command="escape">Escape</button>
|
|
38
|
+
<button class="btn secondary small" data-command="ctrl-t">Ctrl+T</button>
|
|
39
|
+
<button class="btn secondary small" data-command="ctrl-c">Ctrl+C</button>
|
|
40
|
+
<button class="btn secondary small" data-command="split-h">Split %</button>
|
|
41
|
+
<button class="btn secondary small" data-command="split-v">Split "</button>
|
|
42
|
+
<button class="btn secondary small" data-command="new-window">New Window</button>
|
|
43
|
+
<button class="btn secondary small" data-command="rename-window">Rename Window</button>
|
|
44
|
+
<button class="btn secondary small" data-command="kill-pane">Kill Pane</button>
|
|
45
|
+
<button class="btn secondary small" data-command="next">Next Window</button>
|
|
46
|
+
<button class="btn secondary small" data-command="prev">Prev Window</button>
|
|
47
|
+
<button class="btn secondary small" data-command="detach">Detach</button>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="term-wrapper" id="term-wrapper">
|
|
50
|
+
<div id="term" class="term"></div>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="file-panel hidden" id="file-panel">
|
|
53
|
+
<div id="file-browser" class="file-browser-content"
|
|
54
|
+
hx-get="/box/{{ box.name }}/ls?path={{ directory|urlencode }}&target=file-browser"
|
|
55
|
+
hx-trigger="revealed"
|
|
56
|
+
hx-target="#file-browser"
|
|
57
|
+
hx-swap="innerHTML">
|
|
58
|
+
<div class="muted">Loading files…</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
{% endblock %}
|
|
64
|
+
|
|
65
|
+
{% block extra_scripts %}
|
|
66
|
+
<script defer src="/static/term.js"></script>
|
|
67
|
+
{% endblock %}
|