multi value filtering added and font color fix for duplicates
This commit is contained in:
Regular → Executable
+120
-6
@@ -99,6 +99,33 @@
|
||||
{% if selected %}<input type="hidden" name="category_id" value="{{ selected.id }}">{% endif %}
|
||||
</form>
|
||||
{% endif %}
|
||||
<dialog id="software-compare-select-dialog" class="software-compare-select-dialog">
|
||||
<form method="dialog">
|
||||
<div class="dialog-heading">
|
||||
<h2>{{ t('software.compare.select_second_title', 'Zweites Asset auswählen') }}</h2>
|
||||
<button type="button" class="button button-secondary button-small" id="software-compare-dialog-close" aria-label="{{ t('common.close', 'Schließen')|e }}">×</button>
|
||||
</div>
|
||||
<p class="muted">{{ t('software.compare.select_second_help', 'Wähle das zweite Asset für den Vergleich. Das Auswahlfeld zeigt nur vorhandene Werte des gewählten Feldes.') }}</p>
|
||||
<label>{{ t('software.compare.first_asset', 'Erstes Asset') }}
|
||||
<input type="text" id="software-compare-first-name" readonly>
|
||||
</label>
|
||||
<label>{{ t('software.compare.select_by', 'Auswahl nach') }}
|
||||
<select id="software-compare-field-select">
|
||||
{% for option in compare_field_options %}<option value="{{ option.field_name }}"{% if option.field_name == 'name' %} selected{% endif %}>{{ option.label }}</option>{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<label>{{ t('software.compare.second_asset', 'Zweites Asset') }}
|
||||
<select id="software-compare-second-select" disabled>
|
||||
<option value="">{{ t('common.loading', 'Lade…') }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<p class="muted software-compare-selection-status" id="software-compare-selection-status" role="status" aria-live="polite"></p>
|
||||
<div class="form-actions">
|
||||
<button type="button" class="button button-secondary" id="software-compare-dialog-cancel">{{ t('common.cancel', 'Abbrechen') }}</button>
|
||||
<button type="button" class="button" id="software-compare-dialog-start" disabled>⇄ {{ t('software.compare.button', 'Software vergleichen') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
{% endif %}
|
||||
<div class="table-scrollbar-top" id="asset-table-scroll-top" aria-hidden="true"><div></div></div>
|
||||
<div class="table-scroll sticky-table" id="asset-table-scroll">
|
||||
@@ -120,7 +147,7 @@
|
||||
<th data-no-sort="1" data-no-filter="1" class="actions-column">{{ t('common.actions', 'Aktionen') }}</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
{% for a in assets %}<tr data-platform="{{ asset_platforms.get(a.id, 'unknown') }}">
|
||||
{% for a in assets %}<tr data-platform="{{ asset_platforms.get(a.id, 'unknown') }}" data-asset-id="{{ a.id }}" data-asset-name="{{ a.name|e }}">
|
||||
<td class="asset-visual-column" data-field="asset_visual">
|
||||
<a href="/assets/{{ a.id }}" class="asset-visual-link" aria-label="{{ a.name|e }}">
|
||||
{% set visual_source = a.visual_source or 'auto' %}
|
||||
@@ -387,6 +414,14 @@
|
||||
const deleteButton = document.getElementById('bulk-delete-button');
|
||||
const mergeButton = document.getElementById('merge-duplicates-button');
|
||||
const softwareCompareButton = document.getElementById('software-compare-button');
|
||||
const softwareCompareDialog = document.getElementById('software-compare-select-dialog');
|
||||
const softwareCompareField = document.getElementById('software-compare-field-select');
|
||||
const softwareCompareSecond = document.getElementById('software-compare-second-select');
|
||||
const softwareCompareFirstName = document.getElementById('software-compare-first-name');
|
||||
const softwareCompareStatus = document.getElementById('software-compare-selection-status');
|
||||
const softwareCompareStart = document.getElementById('software-compare-dialog-start');
|
||||
const softwareCompareClose = document.getElementById('software-compare-dialog-close');
|
||||
const softwareCompareCancel = document.getElementById('software-compare-dialog-cancel');
|
||||
const jobTypeSelect = document.getElementById('bulk-job-type');
|
||||
const jobStartButton = document.getElementById('bulk-job-start-button');
|
||||
const isVisible = box => {
|
||||
@@ -424,8 +459,10 @@
|
||||
mergeButton.textContent = count >= 2 ? `⧉ {{ t('duplicates.merge') }} (${count})` : '⧉ {{ t('duplicates.merge') }}';
|
||||
}
|
||||
if (softwareCompareButton) {
|
||||
softwareCompareButton.disabled = count !== 2;
|
||||
softwareCompareButton.textContent = count === 2 ? `⇄ {{ t('software.compare.button', 'Software vergleichen') }} (2)` : '⇄ {{ t('software.compare.button', 'Software vergleichen') }}';
|
||||
softwareCompareButton.disabled = count < 1 || count > 2;
|
||||
softwareCompareButton.textContent = (count === 1 || count === 2)
|
||||
? `⇄ {{ t('software.compare.button', 'Software vergleichen') }} (${count})`
|
||||
: '⇄ {{ t('software.compare.button', 'Software vergleichen') }}';
|
||||
}
|
||||
if (jobTypeSelect) { jobTypeSelect.disabled = count === 0; filterJobDefinitions(); }
|
||||
if (jobStartButton) {
|
||||
@@ -436,13 +473,70 @@
|
||||
}
|
||||
if (all) { all.checked = visible.length > 0 && count === visible.length; all.indeterminate = count > 0 && count < visible.length; }
|
||||
}
|
||||
function submit(formId, containerId) {
|
||||
function submitIds(formId, containerId, ids) {
|
||||
const form = document.getElementById(formId);
|
||||
const container = document.getElementById(containerId);
|
||||
if (!form || !container) return;
|
||||
container.innerHTML = '';
|
||||
selected().forEach(id => { const input = document.createElement('input'); input.type='hidden'; input.name='asset_ids'; input.value=id; container.appendChild(input); });
|
||||
ids.forEach(id => { const input = document.createElement('input'); input.type='hidden'; input.name='asset_ids'; input.value=id; container.appendChild(input); });
|
||||
form.requestSubmit();
|
||||
}
|
||||
function submit(formId, containerId) {
|
||||
submitIds(formId, containerId, selected());
|
||||
}
|
||||
function selectedAssetName(assetId) {
|
||||
const box = boxes().find(item => item.value === String(assetId));
|
||||
return box?.closest('tr')?.dataset.assetName || '';
|
||||
}
|
||||
async function loadSoftwareCompareOptions() {
|
||||
const ids = selected();
|
||||
if (ids.length !== 1 || !softwareCompareField || !softwareCompareSecond) return;
|
||||
const firstId = ids[0];
|
||||
softwareCompareSecond.disabled = true;
|
||||
softwareCompareSecond.innerHTML = `<option value="">{{ t('common.loading', 'Lade…')|e }}</option>`;
|
||||
if (softwareCompareStatus) softwareCompareStatus.textContent = '';
|
||||
if (softwareCompareStart) softwareCompareStart.disabled = true;
|
||||
const target = new URL('/api/assets/software-compare/options', window.location.origin);
|
||||
target.searchParams.set('field_name', softwareCompareField.value || 'name');
|
||||
target.searchParams.set('exclude_asset_id', firstId);
|
||||
try {
|
||||
const response = await fetch(target.toString(), {headers: {'Accept': 'application/json'}, cache: 'no-store'});
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
const payload = await response.json();
|
||||
const options = Array.isArray(payload.options) ? payload.options : [];
|
||||
softwareCompareSecond.innerHTML = '';
|
||||
const placeholder = document.createElement('option');
|
||||
placeholder.value = '';
|
||||
placeholder.textContent = options.length
|
||||
? {{ t('software.compare.choose_value', 'Wert auswählen …')|tojson }}
|
||||
: {{ t('software.compare.no_selectable_values', 'Keine passenden Werte vorhanden')|tojson }};
|
||||
softwareCompareSecond.appendChild(placeholder);
|
||||
options.forEach(item => {
|
||||
const option = document.createElement('option');
|
||||
option.value = String(item.asset_id);
|
||||
option.textContent = item.label || item.value || item.asset_name || String(item.asset_id);
|
||||
option.dataset.assetName = item.asset_name || '';
|
||||
softwareCompareSecond.appendChild(option);
|
||||
});
|
||||
softwareCompareSecond.disabled = options.length === 0;
|
||||
if (softwareCompareStatus) {
|
||||
softwareCompareStatus.textContent = options.length
|
||||
? {{ t('software.compare.available_values', '{count} Werte verfügbar')|tojson }}.replace('{count}', String(options.length))
|
||||
: {{ t('software.compare.no_selectable_values', 'Keine passenden Werte vorhanden')|tojson }};
|
||||
}
|
||||
} catch (error) {
|
||||
softwareCompareSecond.innerHTML = `<option value="">{{ t('software.compare.load_error', 'Auswahl konnte nicht geladen werden')|e }}</option>`;
|
||||
if (softwareCompareStatus) softwareCompareStatus.textContent = {{ t('software.compare.load_error', 'Auswahl konnte nicht geladen werden')|tojson }};
|
||||
}
|
||||
}
|
||||
async function openSoftwareCompareDialog() {
|
||||
const ids = selected();
|
||||
if (ids.length !== 1 || !softwareCompareDialog) return;
|
||||
if (softwareCompareFirstName) softwareCompareFirstName.value = selectedAssetName(ids[0]);
|
||||
if (softwareCompareField) softwareCompareField.value = 'name';
|
||||
softwareCompareDialog.showModal();
|
||||
await loadSoftwareCompareOptions();
|
||||
}
|
||||
table.addEventListener('change', event => {
|
||||
if (event.target.matches('.asset-select')) refresh();
|
||||
});
|
||||
@@ -450,7 +544,27 @@
|
||||
editButton?.addEventListener('click', () => submit('bulk-edit-form', 'bulk-edit-ids'));
|
||||
deleteButton?.addEventListener('click', () => submit('bulk-delete-form', 'bulk-delete-ids'));
|
||||
mergeButton?.addEventListener('click', () => submit('merge-duplicates-form', 'merge-duplicate-ids'));
|
||||
softwareCompareButton?.addEventListener('click', () => submit('software-compare-form', 'software-compare-ids'));
|
||||
softwareCompareButton?.addEventListener('click', () => {
|
||||
const ids = selected();
|
||||
if (ids.length === 2) {
|
||||
submitIds('software-compare-form', 'software-compare-ids', ids);
|
||||
return;
|
||||
}
|
||||
if (ids.length === 1) openSoftwareCompareDialog();
|
||||
});
|
||||
softwareCompareField?.addEventListener('change', loadSoftwareCompareOptions);
|
||||
softwareCompareSecond?.addEventListener('change', () => {
|
||||
if (softwareCompareStart) softwareCompareStart.disabled = !softwareCompareSecond.value;
|
||||
});
|
||||
softwareCompareStart?.addEventListener('click', () => {
|
||||
const ids = selected();
|
||||
const secondId = softwareCompareSecond?.value || '';
|
||||
if (ids.length !== 1 || !secondId) return;
|
||||
softwareCompareDialog?.close();
|
||||
submitIds('software-compare-form', 'software-compare-ids', [ids[0], secondId]);
|
||||
});
|
||||
softwareCompareClose?.addEventListener('click', () => softwareCompareDialog?.close());
|
||||
softwareCompareCancel?.addEventListener('click', () => softwareCompareDialog?.close());
|
||||
jobTypeSelect?.addEventListener('change', refresh);
|
||||
jobStartButton?.addEventListener('click', () => {
|
||||
const count = selected().length;
|
||||
|
||||
Reference in New Issue
Block a user