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:
@@ -62,13 +62,14 @@ export function createPatternTemplateCard(pt) {
|
||||
<span class="stream-card-prop">▭ ${rectCount} rect${rectCount !== 1 ? 's' : ''}</span>
|
||||
</div>
|
||||
<div class="template-card-actions">
|
||||
<button class="btn btn-icon btn-secondary" onclick="clonePatternTemplate('${pt.id}')" title="${t('common.clone')}">📋</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="showPatternTemplateEditor('${pt.id}')" title="${t('common.edit')}">✏️</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
export async function showPatternTemplateEditor(templateId = null) {
|
||||
export async function showPatternTemplateEditor(templateId = null, cloneData = null) {
|
||||
try {
|
||||
// Load sources for background capture
|
||||
const sourcesResp = await fetchWithAuth('/picture-sources').catch(() => null);
|
||||
@@ -98,6 +99,12 @@ export async function showPatternTemplateEditor(templateId = null) {
|
||||
document.getElementById('pattern-template-description').value = tmpl.description || '';
|
||||
document.getElementById('pattern-template-modal-title').textContent = t('pattern.edit');
|
||||
setPatternEditorRects((tmpl.rectangles || []).map(r => ({ ...r })));
|
||||
} else if (cloneData) {
|
||||
document.getElementById('pattern-template-id').value = '';
|
||||
document.getElementById('pattern-template-name').value = (cloneData.name || '') + ' (Copy)';
|
||||
document.getElementById('pattern-template-description').value = cloneData.description || '';
|
||||
document.getElementById('pattern-template-modal-title').textContent = t('pattern.add');
|
||||
setPatternEditorRects((cloneData.rectangles || []).map(r => ({ ...r })));
|
||||
} else {
|
||||
document.getElementById('pattern-template-id').value = '';
|
||||
document.getElementById('pattern-template-name').value = '';
|
||||
@@ -180,6 +187,18 @@ export async function savePatternTemplate() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function clonePatternTemplate(templateId) {
|
||||
try {
|
||||
const resp = await fetch(`${API_BASE}/pattern-templates/${templateId}`, { headers: getHeaders() });
|
||||
if (!resp.ok) throw new Error('Failed to load pattern template');
|
||||
const tmpl = await resp.json();
|
||||
showPatternTemplateEditor(null, tmpl);
|
||||
} catch (error) {
|
||||
console.error('Failed to clone pattern template:', error);
|
||||
showToast('Failed to clone pattern template', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
export async function deletePatternTemplate(templateId) {
|
||||
const confirmed = await showConfirm(t('pattern.delete.confirm'));
|
||||
if (!confirmed) return;
|
||||
|
||||
Reference in New Issue
Block a user