Улучшить unwrap, UI и админку; обновить документацию.
- Неверный пароль не сжигает wrap сразу: Argon2-гейт до consume и лимит попыток (по умолчанию 3) в настройках - Подсветка синтаксиса, автоопределение языка, спиннеры, размеры файлов, пагинация audit - make push (git, Ctrl-D) и актуальный README
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{% extends "admin_base.html" %}
|
||||
{% block admin_content %}
|
||||
<section class="audit-page">
|
||||
<form class="audit-filters" method="get" action="/admin/audit">
|
||||
<form class="audit-filters" id="audit-filter-form" method="get" action="/admin/audit">
|
||||
<input type="hidden" name="page" value="1" />
|
||||
<label class="audit-field">
|
||||
<span data-i18n="admin.audit.eventType">Event type</span>
|
||||
@@ -16,6 +16,14 @@
|
||||
<span data-i18n="admin.audit.wrapId">Wrap ID</span>
|
||||
<input name="wrap_id" value="{{ wrap_id }}" class="mono" placeholder="…" autocomplete="off" />
|
||||
</label>
|
||||
<label class="audit-field">
|
||||
<span data-i18n="admin.audit.perPage">Per page</span>
|
||||
<select name="per_page" id="audit-per-page">
|
||||
{% for n in per_page_options %}
|
||||
<option value="{{ n }}" {% if per_page == n %}selected{% endif %}>{{ n }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<button class="btn primary audit-filter-btn" type="submit" data-i18n="admin.audit.filter">Filter</button>
|
||||
</form>
|
||||
|
||||
@@ -46,7 +54,7 @@
|
||||
<tbody>
|
||||
{% for e in events %}
|
||||
<tr class="{% if not e.success %}audit-row-fail{% endif %}">
|
||||
<td class="mono audit-time">{{ e.created_at }}</td>
|
||||
<td class="mono audit-time" data-ts="{{ e.created_at.isoformat() if e.created_at else '' }}">{{ e.created_at }}</td>
|
||||
<td><span class="audit-event-pill">{{ e.event_type }}</span></td>
|
||||
<td>
|
||||
{% if e.success %}
|
||||
@@ -69,34 +77,39 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if pages > 1 %}
|
||||
{% if show_pagination %}
|
||||
<nav class="pagination" aria-label="Pagination">
|
||||
{% if has_prev %}
|
||||
<a class="btn" href="/admin/audit?page={{ page - 1 }}&event_type={{ event_type|urlencode }}&wrap_id={{ wrap_id|urlencode }}">
|
||||
<a class="btn pagination-nav" href="/admin/audit?page={{ page - 1 }}&per_page={{ per_page }}&event_type={{ event_type|urlencode }}&wrap_id={{ wrap_id|urlencode }}">
|
||||
<i class="fa-solid fa-chevron-left" aria-hidden="true"></i>
|
||||
<span data-i18n="admin.audit.prev">Prev</span>
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="btn" aria-disabled="true" disabled>
|
||||
<span class="btn pagination-nav" aria-disabled="true">
|
||||
<i class="fa-solid fa-chevron-left" aria-hidden="true"></i>
|
||||
<span data-i18n="admin.audit.prev">Prev</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
<span class="pagination-status">
|
||||
<span data-i18n="admin.audit.page">Page</span>
|
||||
{{ page }}
|
||||
<span data-i18n="admin.audit.of">of</span>
|
||||
{{ pages }}
|
||||
</span>
|
||||
<div class="pagination-pages">
|
||||
{% for p in page_window %}
|
||||
{% if p is none %}
|
||||
<span class="pagination-ellipsis" aria-hidden="true">…</span>
|
||||
{% elif p == page %}
|
||||
<span class="pagination-page is-current" aria-current="page">{{ p }}</span>
|
||||
{% else %}
|
||||
<a class="pagination-page" href="/admin/audit?page={{ p }}&per_page={{ per_page }}&event_type={{ event_type|urlencode }}&wrap_id={{ wrap_id|urlencode }}">{{ p }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if has_next %}
|
||||
<a class="btn" href="/admin/audit?page={{ page + 1 }}&event_type={{ event_type|urlencode }}&wrap_id={{ wrap_id|urlencode }}">
|
||||
<a class="btn pagination-nav" href="/admin/audit?page={{ page + 1 }}&per_page={{ per_page }}&event_type={{ event_type|urlencode }}&wrap_id={{ wrap_id|urlencode }}">
|
||||
<span data-i18n="admin.audit.next">Next</span>
|
||||
<i class="fa-solid fa-chevron-right" aria-hidden="true"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="btn" aria-disabled="true" disabled>
|
||||
<span class="btn pagination-nav" aria-disabled="true">
|
||||
<span data-i18n="admin.audit.next">Next</span>
|
||||
<i class="fa-solid fa-chevron-right" aria-hidden="true"></i>
|
||||
</span>
|
||||
@@ -104,9 +117,7 @@
|
||||
</nav>
|
||||
{% endif %}
|
||||
</section>
|
||||
<script>
|
||||
document.getElementById("audit-event-type")?.addEventListener("change", (e) => {
|
||||
e.target.form?.requestSubmit();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block admin_scripts %}
|
||||
<script src="/static/js/admin-audit.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -68,5 +68,6 @@
|
||||
<script src="/static/js/i18n.js"></script>
|
||||
<script src="/static/js/theme.js"></script>
|
||||
<script src="/static/js/modal.js"></script>
|
||||
{% block admin_scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -80,6 +80,20 @@
|
||||
</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
<label class="admin-field-spaced">
|
||||
<span data-i18n="admin.password.maxAttempts">Wrong password attempts (unwrap)</span>
|
||||
<input
|
||||
name="password_max_attempts"
|
||||
type="number"
|
||||
min="1"
|
||||
max="50"
|
||||
step="1"
|
||||
value="{{ settings.password_max_attempts or 3 }}"
|
||||
/>
|
||||
<small class="hint" data-i18n="admin.password.maxAttemptsHint">
|
||||
After this many wrong passwords the wrap is destroyed. Default: 3.
|
||||
</small>
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<section class="admin-tabpanel" data-panel="captcha" role="tabpanel" hidden>
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
<link rel="icon" href="/static/favicon.ico" sizes="any" />
|
||||
<link rel="apple-touch-icon" href="/static/apple-touch-icon.png" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<link id="hljs-theme-dark" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github-dark.min.css" />
|
||||
<link id="hljs-theme-light" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github.min.css" disabled />
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
@@ -68,8 +70,11 @@
|
||||
· <a href="https://devops.org.ru" target="_blank" rel="noopener noreferrer">devops.org.ru</a>
|
||||
</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="/static/js/i18n.js"></script>
|
||||
<script src="/static/js/theme.js"></script>
|
||||
<script src="/static/js/ui.js"></script>
|
||||
<script src="/static/js/highlight-ui.js"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+30
-19
@@ -2,27 +2,26 @@
|
||||
{% block content %}
|
||||
<section class="hero-panel create-panel">
|
||||
<div class="composer">
|
||||
<div class="field-row">
|
||||
<label for="text-language" data-i18n="create.language">Language</label>
|
||||
<select id="text-language">
|
||||
<option value="plaintext" data-i18n="lang.plaintext">Обычный текст</option>
|
||||
<option value="markdown" data-i18n="lang.markdown">Markdown</option>
|
||||
<option value="json" data-i18n="lang.json">JSON</option>
|
||||
<option value="yaml" data-i18n="lang.yaml">YAML</option>
|
||||
<option value="python" data-i18n="lang.python">Python</option>
|
||||
<option value="javascript" data-i18n="lang.javascript">JavaScript</option>
|
||||
<option value="typescript" data-i18n="lang.typescript">TypeScript</option>
|
||||
<option value="go" data-i18n="lang.go">Go</option>
|
||||
<option value="rust" data-i18n="lang.rust">Rust</option>
|
||||
<option value="sql" data-i18n="lang.sql">SQL</option>
|
||||
<option value="bash" data-i18n="lang.bash">Bash</option>
|
||||
<option value="html" data-i18n="lang.html">HTML</option>
|
||||
<option value="css" data-i18n="lang.css">CSS</option>
|
||||
</select>
|
||||
<div class="lang-bar">
|
||||
<div class="lang-current">
|
||||
<span class="lang-label" data-i18n="create.language">Highlight language</span>
|
||||
<button type="button" class="lang-chip" id="lang-chip" aria-haspopup="dialog">
|
||||
<span id="lang-chip-text">Plain text</span>
|
||||
<i class="fa-solid fa-chevron-down" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn tiny ghost" id="lang-change" data-i18n="create.languageChange">
|
||||
Change type
|
||||
</button>
|
||||
<input type="hidden" id="text-language" value="plaintext" />
|
||||
</div>
|
||||
<p id="lang-hint" class="lang-hint hidden"></p>
|
||||
|
||||
<label class="sr-only" for="payload-text" data-i18n="create.text">Text</label>
|
||||
<textarea id="payload-text" class="code-input" spellcheck="false" data-i18n-placeholder="create.textPlaceholder" placeholder="Paste secrets, configs, notes…"></textarea>
|
||||
<div class="code-editor" id="code-editor">
|
||||
<pre class="code-highlight" aria-hidden="true"><code id="code-highlight" class="hljs"></code></pre>
|
||||
<textarea id="payload-text" class="code-input" spellcheck="false" data-i18n-placeholder="create.textPlaceholder" placeholder="Paste secrets, configs, notes…"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="dropzone" class="dropzone" tabindex="0">
|
||||
<p data-i18n="create.drop">Drop files here, click to browse, or paste a screenshot (⌘V / Ctrl+V)</p>
|
||||
@@ -71,10 +70,22 @@
|
||||
<input id="share-token" class="mono" readonly />
|
||||
<button type="button" class="btn" id="copy-token" data-i18n="common.copy">Copy</button>
|
||||
</div>
|
||||
<p class="meta" id="expires-meta"></p>
|
||||
<p class="expires-meta" id="expires-meta"></p>
|
||||
<button type="button" class="btn ghost" id="create-another" data-i18n="create.another">Create another</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="lang-modal" class="modal-root hidden" role="dialog" aria-modal="true" aria-labelledby="lang-modal-title">
|
||||
<div class="modal-backdrop" data-lang-close></div>
|
||||
<div class="modal-panel lang-modal-panel" role="document">
|
||||
<h2 class="modal-title" id="lang-modal-title" data-i18n="create.languagePickTitle">Text type</h2>
|
||||
<p class="modal-message" data-i18n="create.languagePickHint">Choose how the text should be highlighted.</p>
|
||||
<div class="lang-grid" id="lang-grid"></div>
|
||||
<div class="modal-actions">
|
||||
<button type="button" class="btn" data-lang-close data-i18n="modal.confirm.cancel">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script src="/static/js/crypto.js"></script>
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
</div>
|
||||
<div id="captcha-slot" class="captcha-slot"></div>
|
||||
<p id="form-error" class="error hidden"></p>
|
||||
<button type="button" id="unwrap-btn" class="btn primary" data-i18n="unwrap.submit">Unwrap</button>
|
||||
<div class="actions actions-center">
|
||||
<button type="button" id="unwrap-btn" class="btn primary" data-i18n="unwrap.submit">Unwrap</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="result-panel" class="result-panel hidden">
|
||||
|
||||
Reference in New Issue
Block a user