85 lines
8.2 KiB
HTML
85 lines
8.2 KiB
HTML
{% extends 'base.html' %}{% block content %}
|
||
<h1>{% if duplicate_mode %}{{t('assets.duplicate')}}{% elif asset %}{{t('common.edit')}} {{t('app.assets')}}{% else %}{{t('assets.create')}}{% endif %}</h1>
|
||
{% if duplicate_mode %}<p class="notice">The original asset data was copied. Asset tag and MeshCentral node ID were cleared.</p>{% endif %}
|
||
<form method="post" action="{% if duplicate_mode or not asset %}/assets/new{% else %}/assets/{{asset.id}}/edit{% endif %}" enctype="multipart/form-data" data-category-form>
|
||
<label>{{t('assets.category')}}<select name="category_id" onchange="location.href='{% if duplicate_mode %}/assets/new{% elif asset %}/assets/{{asset.id}}/edit{% else %}/assets/new{% endif %}?category_id='+this.value">{% for c in categories %}<option value="{{c.id}}" {% if selected and c.id==selected.id %}selected{% endif %}>{{c.name}}</option>{% endfor %}</select></label>
|
||
{% if selected %}{% for f in selected.visible_fields if f.active %}{% set d=f.definition %}{% set custom=d and not d.is_system %}{% set value=custom_values.get(f.field_name) if custom else (asset|attr(f.field_name) if asset else '') %}
|
||
<label>{{t(d.translation_key, d.label) if d else f.label}}{% if f.required %} *{% endif %}{% if d and d.description %}<small class="muted">{{d.description}}</small>{% endif %}
|
||
{% if f.field_name == 'parent_asset_id' %}<select name="parent_asset_id" {% if f.required %}required{% endif %}><option value="">–</option>{% for candidate in parent_candidates %}<option value="{{candidate.id}}" {% if asset and asset.parent_asset_id==candidate.id %}selected{% endif %}>{{candidate.name}}{% if candidate.asset_tag %} ({{candidate.asset_tag}}){% endif %}</option>{% endfor %}</select>
|
||
{% elif f.field_name == 'mesh_node_id' and asset and not duplicate_mode %}
|
||
<div class="mesh-node-id-editor">
|
||
<input id="mesh-node-id-input" name="mesh_node_id" value="{{value or ''}}" autocomplete="off" spellcheck="false" class="mesh-node-id-input">
|
||
<div class="mesh-node-id-actions">
|
||
<a class="button button-secondary" href="/assets/{{asset.id}}/mesh-link">{{ t('mesh.link.select_existing', 'MeshCentral-Gerät auswählen') }}</a>
|
||
<button type="button" class="button button-secondary" id="mesh-node-id-clear">{{ t('mesh.link.clear_field', 'Node-ID leeren') }}</button>
|
||
</div>
|
||
<small class="muted">{{ t('mesh.link.edit_help', 'Die Node-ID kann direkt bearbeitet werden. Ein leeres Feld löst die Verknüpfung beim Speichern. Andere Assetdaten werden erst beim nächsten MeshCentral-Sync aktualisiert.') }}</small>
|
||
</div>
|
||
{% elif (d and d.readonly) or field_readonly(f) %}<input value="{{value or ''}}" readonly aria-readonly="true">
|
||
{% elif d and d.data_type == 'long_text' %}<textarea name="{{f.field_name}}" {% if f.required %}required{% endif %}>{{value or ''}}</textarea>
|
||
{% elif d and d.data_type == 'boolean' %}<select name="{{f.field_name}}"><option value="">–</option><option value="true" {% if value in [true,'true','1'] %}selected{% endif %}>{{t('common.yes')}}</option><option value="false" {% if value in [false,'false','0'] %}selected{% endif %}>{{t('common.no')}}</option></select>
|
||
{% elif f.field_name == 'status' or (d and d.data_type == 'status') %}<select name="{{f.field_name}}" {% if f.required %}required{% endif %}><option value="">–</option>{% for option in status_options %}<option value="{{option.name}}" {% if value==option.name %}selected{% endif %}>{{option.name}}</option>{% endfor %}</select>
|
||
{% elif d and d.data_type in ['date','datetime'] %}<input type="{{'datetime-local' if d.data_type=='datetime' else 'date'}}" name="{{f.field_name}}" value="{{html_field_value(value, d.data_type)}}" {% if f.required %}required{% endif %}>
|
||
{% elif d and d.data_type in ['integer','decimal'] %}<input type="number" {% if d.data_type=='decimal' %}step="any"{% endif %} name="{{f.field_name}}" value="{{value or ''}}" {% if f.required %}required{% endif %}>
|
||
{% elif d and d.data_type == 'json' %}<textarea name="{{f.field_name}}">{{value|tojson if value else ''}}</textarea>
|
||
{% else %}<input name="{{f.field_name}}" value="{{value or ''}}" {% if f.required %}required{% endif %}>{% endif %}</label>{% endfor %}{% endif %}
|
||
<div class="form-field asset-image-editor" data-image-editor>
|
||
<label for="asset-image-input">{{t('assets.image', 'Image')}}</label>
|
||
<div class="asset-edit-image-preview" id="asset-current-image-preview" data-image-preview {% if not (asset and not duplicate_mode and asset.image_path) %}hidden style="display:none"{% endif %}>
|
||
<img src="{{ asset.image_path if asset and not duplicate_mode and asset.image_path else '' }}" alt="" class="asset-edit-preview-image">
|
||
<div class="asset-edit-image-preview-actions">
|
||
<span class="muted">{{ t('assets.current_image', 'Aktuelles Assetbild') }}</span>
|
||
<button type="button" class="button button-danger button-small" id="remove-asset-image-button" data-image-remove aria-pressed="false" {% if not (asset and not duplicate_mode and asset.image_path) %}hidden disabled{% endif %}>{{ t('assets.remove_image', 'Assetbild entfernen') }}</button>
|
||
</div>
|
||
</div>
|
||
<input type="hidden" name="remove_image" id="remove-asset-image" value="0" data-image-remove-input>
|
||
<div class="image-remove-pending" data-image-remove-pending hidden>{{ t('assets.image_remove_pending', 'Assetbild wird beim Speichern entfernt.') }}</div>
|
||
<div class="standard-image-library">
|
||
<strong>{{ t('images.library', 'Standardbild-Bibliothek') }}</strong>
|
||
<div class="muted image-library-help">{{ t('images.library_help', 'Wähle ein bereits vorhandenes Standardbild oder füge ein Bild einmalig zur Bibliothek hinzu.') }}</div>
|
||
{% if standard_images %}
|
||
<div class="standard-image-grid">
|
||
{% for item in standard_images %}
|
||
<label class="standard-image-choice" title="{{ item.name }}">
|
||
<input type="radio" name="library_image" value="{{ item.path }}" data-image-library-choice data-image-src="{{ item.path }}" {% if asset and not duplicate_mode and asset.image_path == item.path %}checked{% endif %}>
|
||
<img src="{{ item.path }}" alt="">
|
||
<span>{{ item.name }}</span>
|
||
</label>
|
||
{% endfor %}
|
||
</div>
|
||
{% else %}
|
||
<div class="muted image-library-empty">{{ t('images.library_empty', 'Noch keine Standardbilder vorhanden.') }}</div>
|
||
{% endif %}
|
||
<label class="image-upload-label">{{ t('images.library_upload', 'Neues Standardbild hinzufügen und verwenden') }}
|
||
<input type="file" name="library_upload" accept="image/*" data-image-library-upload>
|
||
</label>
|
||
<small class="muted">{{ t('images.library_upload_help', 'Das Bild wird einmal in der gemeinsamen Bibliothek gespeichert und kann danach bei weiteren Assets und Kategorien wiederverwendet werden.') }}</small>
|
||
</div>
|
||
</div>
|
||
<label>{{ t('assets.visual_source', 'Anzeigequelle') }}
|
||
<select name="visual_source">
|
||
{% set current_visual_source = asset.visual_source if asset and asset.visual_source else 'auto' %}
|
||
<option value="auto" {% if current_visual_source == 'auto' %}selected{% endif %}>{{ t('assets.visual_source.auto', 'Automatisch: Assetbild → Kategoriebild → MeshCentral-Icon') }}</option>
|
||
<option value="asset_image" {% if current_visual_source == 'asset_image' %}selected{% endif %}>{{ t('assets.visual_source.asset_image', 'Nur Assetbild') }}</option>
|
||
<option value="category_image" {% if current_visual_source == 'category_image' %}selected{% endif %}>{{ t('assets.visual_source.category_image', 'Kategoriebild') }}</option>
|
||
<option value="mesh_icon" {% if current_visual_source == 'mesh_icon' %}selected{% endif %}>{{ t('assets.visual_source.mesh_icon', 'MeshCentral-Icon') }}</option>
|
||
</select>
|
||
<small class="muted">{{ t('assets.visual_source.help', 'Legt fest, welches Bild oder Icon für dieses Asset in Listen und Details bevorzugt angezeigt wird.') }}</small>
|
||
</label><button class="button button-save">💾 {{t('common.save')}}</button></form>
|
||
{% if asset and not duplicate_mode %}
|
||
<script>
|
||
(() => {
|
||
const input = document.getElementById('mesh-node-id-input');
|
||
const clearButton = document.getElementById('mesh-node-id-clear');
|
||
if (input && clearButton) {
|
||
clearButton.addEventListener('click', () => {
|
||
input.value = '';
|
||
input.focus();
|
||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||
});
|
||
}
|
||
})();
|
||
</script>
|
||
{% endif %}
|
||
{% endblock %}
|