feat: Ordnerstruktur, Medienupload und erweiterten Editor ergänzen
- NetBox-4.6-Verknüpfungsformular korrigieren - hierarchische Dokumentationsordner hinzufügen - breite Editoransicht und Fokusmodus implementieren - sicheren direkten Bild-Upload integrieren - Ordner über Suche und REST-API bereitstellen
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
<div class="card"><div class="card-body rendered-markdown">{{ object.rendered_body|safe }}</div></div>
|
||||
</div>
|
||||
<div class="col col-md-3">
|
||||
{% if object.category %}<div class="card mb-3"><h5 class="card-header">Ordner</h5><a class="list-group-item list-group-item-action" href="{{ object.category.get_absolute_url }}"><i class="mdi mdi-folder"></i> {{ object.category }}</a></div>{% endif %}
|
||||
<div class="card"><h5 class="card-header">Zuordnungen</h5><div class="list-group list-group-flush">
|
||||
{% for assignment in object.assignments.all %}<a class="list-group-item" href="{{ assignment.assigned_object.get_absolute_url }}">{{ assignment.assigned_object_type }}: {{ assignment.assigned_object }}</a>{% empty %}<div class="list-group-item text-muted">Noch nicht zugeordnet</div>{% endfor %}
|
||||
</div></div>
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
{% extends 'generic/object_edit.html' %}
|
||||
{% block javascript %}
|
||||
{{ block.super }}
|
||||
<style>
|
||||
body.documentation-editor-page .container-xl { max-width: none !important; }
|
||||
body.documentation-editor-focus #form_fields .field-group:not(.documentation-content-group) { display: none; }
|
||||
body.documentation-editor-focus #form_fields .documentation-content-group { margin-bottom: 0 !important; }
|
||||
</style>
|
||||
<script src="{% url 'plugins:netbox_documentation:editor_asset' asset_path='tinymce.min.js' %}"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
document.body.classList.add('documentation-editor-page');
|
||||
const bodyField = document.querySelector('#id_body');
|
||||
if (bodyField) {
|
||||
const contentGroup = bodyField.closest('.field-group');
|
||||
if (contentGroup) contentGroup.classList.add('documentation-content-group');
|
||||
}
|
||||
const editorAssetBase = "{% url 'plugins:netbox_documentation:editor_asset' asset_path='_' %}".replace(/_$/, '');
|
||||
if (typeof tinymce === 'undefined') {
|
||||
const editor = document.querySelector('[data-rich-text-editor]');
|
||||
@@ -25,7 +36,7 @@
|
||||
plugins: 'advlist anchor autolink charmap code fullscreen image link lists media preview searchreplace table visualblocks wordcount',
|
||||
toolbar: [
|
||||
'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | forecolor backcolor',
|
||||
'alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table link image media | removeformat code fullscreen'
|
||||
'alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table link image media | removeformat code netboxfocus fullscreen'
|
||||
],
|
||||
toolbar_mode: 'sliding',
|
||||
table_toolbar: 'tableprops tablecellprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol | tablemergecells tablesplitcells | tabledelete',
|
||||
@@ -38,7 +49,43 @@
|
||||
branding: false,
|
||||
convert_unsafe_embeds: true,
|
||||
relative_urls: false
|
||||
{% if object.pk %},
|
||||
images_file_types: 'jpg,jpeg,png,gif,webp',
|
||||
automatic_uploads: true,
|
||||
images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
|
||||
const data = new FormData();
|
||||
data.append('file', blobInfo.blob(), blobInfo.filename());
|
||||
fetch("{% url 'plugins:netbox_documentation:document_media_upload' pk=object.pk %}", {
|
||||
method: 'POST',
|
||||
headers: {'X-CSRFToken': document.querySelector('input[name=csrfmiddlewaretoken]').value},
|
||||
body: data,
|
||||
credentials: 'same-origin'
|
||||
}).then(async response => {
|
||||
const payload = await response.json();
|
||||
if (!response.ok) throw new Error(payload.error || 'Upload fehlgeschlagen');
|
||||
resolve(payload.location);
|
||||
}).catch(error => reject(error.message));
|
||||
})
|
||||
{% endif %},
|
||||
setup: (editor) => {
|
||||
editor.ui.registry.addToggleButton('netboxfocus', {
|
||||
icon: 'expand',
|
||||
tooltip: 'Fokusmodus im NetBox-Fenster',
|
||||
onAction: api => {
|
||||
const active = document.body.classList.toggle('documentation-editor-focus');
|
||||
const container = editor.getContainer();
|
||||
container.style.height = active ? 'calc(100vh - 190px)' : '650px';
|
||||
api.setActive(active);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock javascript %}
|
||||
|
||||
{% block pre_form_fields %}
|
||||
{% if not object.pk %}
|
||||
<div class="alert alert-info">Speichere die neue Dokumentation einmal. Danach können Bilder direkt über die Editor-Werkzeugleiste hochgeladen werden.</div>
|
||||
{% endif %}
|
||||
{% endblock pre_form_fields %}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col col-md-4">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Unterordner</h5>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for child in object.children.all %}
|
||||
<a class="list-group-item list-group-item-action" href="{{ child.get_absolute_url }}"><i class="mdi mdi-folder"></i> {{ child.name }}</a>
|
||||
{% empty %}<div class="list-group-item text-muted">Keine Unterordner</div>{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-md-8">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Dokumentationen</h5>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for document in object.documents.all %}
|
||||
<a class="list-group-item list-group-item-action" href="{{ document.get_absolute_url }}"><strong>{{ document.title }}</strong>{% if document.summary %}<br><small>{{ document.summary }}</small>{% endif %}</a>
|
||||
{% empty %}<div class="list-group-item text-muted">Keine Dokumentationen in diesem Ordner</div>{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
@@ -7,5 +7,5 @@
|
||||
</a>
|
||||
{% empty %}<div class="list-group-item text-muted">Keine Dokumentation zugeordnet.</div>{% endfor %}
|
||||
</div>
|
||||
{% if perms.netbox_documentation.add_documentassignment %}<div class="card-footer"><a href="{% url 'plugins:netbox_documentation:documentassignment_add' %}?assigned_object_type={{ content_type.pk }}&assigned_object_id={{ object.pk }}" class="btn btn-sm btn-primary"><i class="mdi mdi-link-plus"></i> Zuordnen</a></div>{% endif %}
|
||||
{% if perms.netbox_documentation.add_documentassignment %}<div class="card-footer"><a href="{% url 'plugins:netbox_documentation:documentassignment_add' %}?assigned_object_type={{ content_type.pk }}&assigned_object={{ object.pk }}" class="btn btn-sm btn-primary"><i class="mdi mdi-link-plus"></i> Zuordnen</a></div>{% endif %}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user