restored delete refresh and rename for categories
This commit is contained in:
parent
99474ccd75
commit
eeccc6c5f9
|
|
@ -104,6 +104,19 @@ function createTreeNode(node, source = 'm2') {
|
|||
label.appendChild(labelText);
|
||||
label.appendChild(badge);
|
||||
|
||||
// Add rename button for Magento 2 categories only (except system root)
|
||||
if (canDelete && source === 'm2') {
|
||||
const renameBtn = document.createElement('button');
|
||||
renameBtn.className = 'tree-rename-btn';
|
||||
renameBtn.textContent = 'Rename';
|
||||
renameBtn.title = 'Rename this category';
|
||||
renameBtn.onclick = function(e) {
|
||||
e.stopPropagation();
|
||||
startRenameCategory(nodeDiv, node, source);
|
||||
};
|
||||
label.appendChild(renameBtn);
|
||||
}
|
||||
|
||||
if (canDelete) {
|
||||
const deleteBtn = document.createElement('button');
|
||||
deleteBtn.className = 'tree-delete-btn';
|
||||
|
|
@ -253,6 +266,7 @@ function deleteCategory(categoryId, categoryName, source) {
|
|||
loadM1Tree();
|
||||
} else {
|
||||
loadM2Tree();
|
||||
// Reload page to refresh statistics and M2 Categories Not Found in M1 section
|
||||
location.reload();
|
||||
}
|
||||
} else {
|
||||
|
|
@ -266,3 +280,260 @@ function deleteCategory(categoryId, categoryName, source) {
|
|||
});
|
||||
}
|
||||
|
||||
// Start renaming a category
|
||||
function startRenameCategory(nodeDiv, node, source) {
|
||||
const label = nodeDiv.querySelector('.tree-label');
|
||||
const labelText = label.querySelector('.tree-label-text');
|
||||
const originalName = node.name || 'Unnamed Category';
|
||||
|
||||
// Hide the label text and badge
|
||||
labelText.style.display = 'none';
|
||||
const badge = label.querySelector('.tree-badge');
|
||||
if (badge) badge.style.display = 'none';
|
||||
|
||||
// Hide rename and delete buttons
|
||||
const renameBtn = label.querySelector('.tree-rename-btn');
|
||||
const deleteBtn = label.querySelector('.tree-delete-btn');
|
||||
if (renameBtn) renameBtn.style.display = 'none';
|
||||
if (deleteBtn) deleteBtn.style.display = 'none';
|
||||
|
||||
// Create input field
|
||||
const input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
input.className = 'tree-rename-input';
|
||||
input.value = originalName;
|
||||
input.onclick = function(e) {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
// Create action buttons
|
||||
const actionsDiv = document.createElement('div');
|
||||
actionsDiv.className = 'tree-rename-actions';
|
||||
|
||||
const saveBtn = document.createElement('button');
|
||||
saveBtn.className = 'tree-rename-save-btn';
|
||||
saveBtn.textContent = 'Save';
|
||||
saveBtn.onclick = function(e) {
|
||||
e.stopPropagation();
|
||||
saveRenameCategory(nodeDiv, node, input.value, source);
|
||||
};
|
||||
|
||||
const cancelBtn = document.createElement('button');
|
||||
cancelBtn.className = 'tree-rename-cancel-btn';
|
||||
cancelBtn.textContent = 'Cancel';
|
||||
cancelBtn.onclick = function(e) {
|
||||
e.stopPropagation();
|
||||
cancelRenameCategory(nodeDiv, labelText, badge, renameBtn, deleteBtn);
|
||||
};
|
||||
|
||||
actionsDiv.appendChild(saveBtn);
|
||||
actionsDiv.appendChild(cancelBtn);
|
||||
|
||||
label.appendChild(input);
|
||||
label.appendChild(actionsDiv);
|
||||
|
||||
// Focus and select input
|
||||
input.focus();
|
||||
input.select();
|
||||
|
||||
// Handle Enter and Escape keys
|
||||
input.onkeydown = function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
saveRenameCategory(nodeDiv, node, input.value, source);
|
||||
} else if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
cancelRenameCategory(nodeDiv, labelText, badge, renameBtn, deleteBtn);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Save category rename
|
||||
function saveRenameCategory(nodeDiv, node, newName, source) {
|
||||
const categoryId = node.id;
|
||||
const label = nodeDiv.querySelector('.tree-label');
|
||||
const input = label.querySelector('.tree-rename-input');
|
||||
const actionsDiv = label.querySelector('.tree-rename-actions');
|
||||
|
||||
if (!newName || newName.trim() === '') {
|
||||
alert('Category name cannot be empty');
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable input and buttons
|
||||
input.disabled = true;
|
||||
const saveBtn = actionsDiv.querySelector('.tree-rename-save-btn');
|
||||
const cancelBtn = actionsDiv.querySelector('.tree-rename-cancel-btn');
|
||||
if (saveBtn) saveBtn.disabled = true;
|
||||
if (cancelBtn) cancelBtn.disabled = true;
|
||||
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content;
|
||||
const renameRoute = routes.renameCategory.replace(':id', categoryId);
|
||||
|
||||
fetch(renameRoute, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': csrfToken
|
||||
},
|
||||
body: JSON.stringify({ name: newName.trim() })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Update the node name
|
||||
node.name = data.new_name;
|
||||
|
||||
// Update the label text
|
||||
const labelText = label.querySelector('.tree-label-text');
|
||||
labelText.textContent = `[${node.id}] ${data.new_name}`;
|
||||
|
||||
// Restore display
|
||||
labelText.style.display = '';
|
||||
const badge = label.querySelector('.tree-badge');
|
||||
if (badge) badge.style.display = '';
|
||||
const renameBtn = label.querySelector('.tree-rename-btn');
|
||||
const deleteBtn = label.querySelector('.tree-delete-btn');
|
||||
if (renameBtn) renameBtn.style.display = '';
|
||||
if (deleteBtn) deleteBtn.style.display = '';
|
||||
|
||||
// Remove input and actions
|
||||
label.removeChild(input);
|
||||
label.removeChild(actionsDiv);
|
||||
|
||||
// Reload M2 Categories Not Found in M1 section
|
||||
loadM2CategoriesNotInM1();
|
||||
} else {
|
||||
alert('Error: ' + (data.message || 'Failed to rename category'));
|
||||
// Re-enable input and buttons
|
||||
input.disabled = false;
|
||||
if (saveBtn) saveBtn.disabled = false;
|
||||
if (cancelBtn) cancelBtn.disabled = false;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Error: ' + error.message);
|
||||
// Re-enable input and buttons
|
||||
input.disabled = false;
|
||||
if (saveBtn) saveBtn.disabled = false;
|
||||
if (cancelBtn) cancelBtn.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
// Cancel category rename
|
||||
function cancelRenameCategory(nodeDiv, labelText, badge, renameBtn, deleteBtn) {
|
||||
const label = nodeDiv.querySelector('.tree-label');
|
||||
const input = label.querySelector('.tree-rename-input');
|
||||
const actionsDiv = label.querySelector('.tree-rename-actions');
|
||||
|
||||
// Restore display
|
||||
labelText.style.display = '';
|
||||
if (badge) badge.style.display = '';
|
||||
if (renameBtn) renameBtn.style.display = '';
|
||||
if (deleteBtn) deleteBtn.style.display = '';
|
||||
|
||||
// Remove input and actions
|
||||
if (input) label.removeChild(input);
|
||||
if (actionsDiv) label.removeChild(actionsDiv);
|
||||
}
|
||||
|
||||
// Load M2 Categories Not Found in M1 section
|
||||
function loadM2CategoriesNotInM1() {
|
||||
const tbody = document.getElementById('m2-categories-not-in-m1-tbody');
|
||||
const wrapper = document.getElementById('m2-categories-not-in-m1-table-wrapper');
|
||||
const totalDiv = document.getElementById('m2-categories-not-in-m1-total');
|
||||
const emptyDiv = document.getElementById('m2-categories-not-in-m1-empty');
|
||||
|
||||
if (!tbody && !wrapper && !totalDiv && !emptyDiv) {
|
||||
// Section doesn't exist on this page
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(routes.m2CategoriesNotInM1)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const categories = data.categories || [];
|
||||
const count = data.count || 0;
|
||||
|
||||
// Remove existing content
|
||||
if (tbody) tbody.innerHTML = '';
|
||||
if (totalDiv) totalDiv.style.display = 'none';
|
||||
if (emptyDiv) emptyDiv.style.display = 'none';
|
||||
if (wrapper) wrapper.style.display = 'none';
|
||||
|
||||
if (count > 0) {
|
||||
// Show table and populate it
|
||||
if (wrapper) wrapper.style.display = 'block';
|
||||
if (totalDiv) {
|
||||
totalDiv.style.display = 'block';
|
||||
totalDiv.innerHTML = `<strong>Total:</strong> ${count} ${count === 1 ? 'category' : 'categories'} found in Magento 2 but not in Magento 1.`;
|
||||
}
|
||||
|
||||
if (tbody) {
|
||||
categories.forEach(category => {
|
||||
const row = document.createElement('tr');
|
||||
row.style.borderBottom = '1px solid #dee2e6';
|
||||
|
||||
const activeClass = category.is_active ? 'active' : 'inactive';
|
||||
const activeText = category.is_active ? 'Active' : 'Inactive';
|
||||
|
||||
let rootCategoryHtml = '<span style="color: #999;">N/A</span>';
|
||||
if (category.root_category_name && category.root_category_name !== 'N/A') {
|
||||
rootCategoryHtml = `<span style="font-weight: 500;">${escapeHtml(category.root_category_name)}</span>`;
|
||||
if (category.root_category_id) {
|
||||
rootCategoryHtml += ` <span style="font-size: 0.85em; color: #666;">(ID: ${category.root_category_id})</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
// Create delete button with event listener
|
||||
const deleteBtn = document.createElement('button');
|
||||
deleteBtn.className = 'tree-delete-btn';
|
||||
deleteBtn.textContent = 'Delete';
|
||||
deleteBtn.title = 'Delete this category';
|
||||
deleteBtn.onclick = function(e) {
|
||||
e.stopPropagation();
|
||||
showDeleteConfirmPopup(deleteBtn, category.entity_id, category.name, 'm2', false, 0);
|
||||
};
|
||||
|
||||
row.innerHTML = `
|
||||
<td style="padding: 10px 12px;">${category.entity_id}</td>
|
||||
<td style="padding: 10px 12px; font-weight: 500;">${escapeHtml(category.name)}</td>
|
||||
<td style="padding: 10px 12px;">${category.level}</td>
|
||||
<td style="padding: 10px 12px;">
|
||||
<span class="tree-badge ${activeClass}">${activeText}</span>
|
||||
</td>
|
||||
<td style="padding: 10px 12px;">${rootCategoryHtml}</td>
|
||||
<td style="padding: 10px 12px; font-size: 0.9em; color: #666;">${escapeHtml(category.path)}</td>
|
||||
<td style="padding: 10px 12px;"></td>
|
||||
`;
|
||||
|
||||
// Append delete button to the actions cell
|
||||
const actionsCell = row.querySelector('td:last-child');
|
||||
if (actionsCell) {
|
||||
actionsCell.appendChild(deleteBtn);
|
||||
}
|
||||
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Show empty message
|
||||
if (emptyDiv) {
|
||||
emptyDiv.style.display = 'block';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading M2 categories not in M1:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to escape HTML
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,9 @@ class="tree-delete-btn"
|
|||
window.categoryRoutes = {
|
||||
magento1CategoryTree: '{{ route("categories.magento1-category-tree") }}',
|
||||
magento2CategoryTree: '{{ route("categories.magento2-category-tree") }}',
|
||||
deleteCategory: '{{ route("categories.delete-category", ["categoryId" => ":id"]) }}'
|
||||
deleteCategory: '{{ route("categories.delete-category", ["categoryId" => ":id"]) }}',
|
||||
renameCategory: '{{ route("categories.rename-category", ["categoryId" => ":id"]) }}',
|
||||
m2CategoriesNotInM1: '{{ route("categories.m2-categories-not-in-m1") }}'
|
||||
};
|
||||
</script>
|
||||
@endpush
|
||||
|
|
|
|||
Loading…
Reference in New Issue