Add clone support for all entity types
Clone button on every card opens the editor in create mode pre-filled with copied data and a "(Copy)" name suffix. Cancelling discards the clone — entity is only persisted on Save. Supported: LED targets, color strip sources, KC targets, pattern templates, picture sources, capture templates, PP templates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -148,6 +148,9 @@ export function createKCTargetCard(target, sourceMap, patternTemplateMap) {
|
||||
<button class="btn btn-icon btn-secondary" onclick="testKCTarget('${target.id}')" title="${t('kc.test')}">
|
||||
🧪
|
||||
</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="cloneKCTarget('${target.id}')" title="${t('common.clone')}">
|
||||
📋
|
||||
</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="showKCEditor('${target.id}')" title="${t('common.edit')}">
|
||||
✏️
|
||||
</button>
|
||||
@@ -345,7 +348,7 @@ function _autoGenerateKCName() {
|
||||
document.getElementById('kc-editor-name').value = `${sourceName} \u00b7 ${patName} (${modeName})`;
|
||||
}
|
||||
|
||||
export async function showKCEditor(targetId = null) {
|
||||
export async function showKCEditor(targetId = null, cloneData = null) {
|
||||
try {
|
||||
// Load sources and pattern templates in parallel
|
||||
const [sourcesResp, patResp] = await Promise.all([
|
||||
@@ -395,6 +398,18 @@ export async function showKCEditor(targetId = null) {
|
||||
document.getElementById('kc-editor-smoothing-value').textContent = kcSettings.smoothing ?? 0.3;
|
||||
patSelect.value = kcSettings.pattern_template_id || '';
|
||||
document.getElementById('kc-editor-title').textContent = t('kc.edit');
|
||||
} else if (cloneData) {
|
||||
const kcSettings = cloneData.key_colors_settings || {};
|
||||
document.getElementById('kc-editor-id').value = '';
|
||||
document.getElementById('kc-editor-name').value = (cloneData.name || '') + ' (Copy)';
|
||||
sourceSelect.value = cloneData.picture_source_id || '';
|
||||
document.getElementById('kc-editor-fps').value = kcSettings.fps ?? 10;
|
||||
document.getElementById('kc-editor-fps-value').textContent = kcSettings.fps ?? 10;
|
||||
document.getElementById('kc-editor-interpolation').value = kcSettings.interpolation_mode ?? 'average';
|
||||
document.getElementById('kc-editor-smoothing').value = kcSettings.smoothing ?? 0.3;
|
||||
document.getElementById('kc-editor-smoothing-value').textContent = kcSettings.smoothing ?? 0.3;
|
||||
patSelect.value = kcSettings.pattern_template_id || '';
|
||||
document.getElementById('kc-editor-title').textContent = t('kc.add');
|
||||
} else {
|
||||
document.getElementById('kc-editor-id').value = '';
|
||||
document.getElementById('kc-editor-name').value = '';
|
||||
@@ -409,12 +424,12 @@ export async function showKCEditor(targetId = null) {
|
||||
}
|
||||
|
||||
// Auto-name
|
||||
set_kcNameManuallyEdited(!!targetId);
|
||||
set_kcNameManuallyEdited(!!(targetId || cloneData));
|
||||
document.getElementById('kc-editor-name').oninput = () => { set_kcNameManuallyEdited(true); };
|
||||
sourceSelect.onchange = () => _autoGenerateKCName();
|
||||
document.getElementById('kc-editor-interpolation').onchange = () => _autoGenerateKCName();
|
||||
patSelect.onchange = () => _autoGenerateKCName();
|
||||
if (!targetId) _autoGenerateKCName();
|
||||
if (!targetId && !cloneData) _autoGenerateKCName();
|
||||
|
||||
kcEditorModal.snapshot();
|
||||
kcEditorModal.open();
|
||||
@@ -502,6 +517,18 @@ export async function saveKCEditor() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function cloneKCTarget(targetId) {
|
||||
try {
|
||||
const resp = await fetch(`${API_BASE}/picture-targets/${targetId}`, { headers: getHeaders() });
|
||||
if (!resp.ok) throw new Error('Failed to load target');
|
||||
const target = await resp.json();
|
||||
showKCEditor(null, target);
|
||||
} catch (error) {
|
||||
console.error('Failed to clone KC target:', error);
|
||||
showToast('Failed to clone key colors target', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteKCTarget(targetId) {
|
||||
const confirmed = await showConfirm(t('kc.delete.confirm'));
|
||||
if (!confirmed) return;
|
||||
|
||||
Reference in New Issue
Block a user