Răsfoiți Sursa

column mapping

VISHAL BHANUSHALI 2 luni în urmă
părinte
comite
24c8e0a386

+ 431 - 0
content_quality_tool_public/templates/attr-column-mapping-setting-old.html

@@ -0,0 +1,431 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Column Mapping</title>
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"/>
+<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
+<style>
+    .mapping-container {
+        max-width: 1000px;
+        margin: 30px auto;
+        background: #fff;
+        padding: 20px;
+        border-radius: 8px;
+        box-shadow: 0 4px 10px rgba(0,0,0,0.1);
+    }
+    .drag-item {
+        padding: 10px;
+        margin: 5px 0;
+        background: #f1f1f1;
+        border-radius: 4px;
+        cursor: grab;
+    }
+    .drop-zone {
+        min-height: 50px;
+        padding: 10px;
+        border: 2px dashed #ccc;
+        border-radius: 4px;
+        margin-bottom: 10px;
+        background: #fafafa;
+    }
+    .drop-zone.hover {
+        border-color: #007bff;
+        background: #e9f5ff;
+    }
+    .preview-table {
+        margin-top: 20px;
+    }
+</style>
+</head>
+<body>
+<div class="mapping-container">
+    <h3 class="text-center mb-4">Attribute Extraction File Upload Setting</h3>
+    <!-- File Upload -->
+    <div class="mb-3">
+        <label for="fileUpload" class="form-label">Upload CSV File</label>
+        <input type="file" class="form-control" id="fileUpload" accept="*">
+    </div>
+    <div class="row">
+        <!-- Uploaded Columns -->
+        <div class="col-md-5">
+            <h5>Uploaded Columns</h5>
+            <div id="uploaded-columns">
+                <!-- Draggable items -->
+            </div>
+        </div>
+        <!-- System Columns -->
+        <div class="col-md-7">
+            <h5>System Columns</h5>
+            <div id="system-columns">
+                <!-- Drop zones -->
+            </div>
+        </div>
+    </div>
+
+    <!-- Preview Section -->
+    <!-- <div class="preview-table">
+        <h5>Preview Data</h5>
+        <table class="table table-bordered">
+            <thead>
+                <tr id="preview-header"></tr>
+            </thead>
+            <tbody id="preview-body"></tbody>
+        </table>
+    </div> -->
+
+    <div class="text-end mt-3">
+        <button class="btn btn-secondary" id="resetBtn">Reset</button>
+        <button class="btn btn-primary" id="saveBtn">Save Mapping</button>
+    </div>
+</div>
+
+<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
+<script>
+const uploadedColumns = [];
+const systemColumns = ["PRODUCT NAME", "ITEM ID", "PRODUCT TYPE", "Product Short Description", "Product Long Description", "image_path"];
+const previewData = [
+    // {Name: "John", Email: "john@example.com", Phone: "1234567890", Address: "NY"},
+    // {Name: "Alice", Email: "alice@example.com", Phone: "9876543210", Address: "LA"}
+];
+
+$(document).ready(function() {
+    // Populate draggable uploaded columns
+    uploadedColumns.forEach(col => {
+        $("#uploaded-columns").append(`<div class="drag-item" draggable="true" data-col="${col}">${col}</div>`);
+    });
+
+    // Populate drop zones for system columns
+    systemColumns.forEach(col => {
+        $("#system-columns").append(`<div class="drop-zone" data-system="${col}">${col}</div>`);
+    });
+
+
+    // Handle file upload
+    // $("#fileUpload").on("change", function(e) {
+    //     const file = e.target.files[0];
+    //     if (!file) return;
+
+    //     const reader = new FileReader();
+    //     reader.onload = function(event) {
+    //         const text = event.target.result;
+    //         const rows = text.split("\n").map(r => r.split(","));
+    //         const headers = rows[0];
+    //         const sampleRows = rows.slice(1, 6); // first 5 rows for preview
+
+    //         // Populate uploaded columns
+    //         $("#uploaded-columns").empty();
+    //         headers.forEach(col => {
+    //             $("#uploaded-columns").append(`<div class="drag-item" draggable="true" data-col="${col}">${col}</div>`);
+    //         });
+
+    //         // Populate preview table
+    //         $("#preview-header").html(headers.map(h => `<th>${h}</th>`).join(''));
+    //         $("#preview-body").empty();
+    //         sampleRows.forEach(row => {
+    //             let tr = "<tr>";
+    //             headers.forEach((h, i) => tr += `<td>${row[i] || ""}</td>`);
+    //             tr += "</tr>";
+    //             $("#preview-body").append(tr);
+    //         });
+
+    //         // Enable drag-and-drop
+    //         $(".drag-item").on("dragstart", function(e) {
+    //             e.originalEvent.dataTransfer.setData("text", $(this).data("col"));
+    //         });
+    //     };
+    //     reader.readAsText(file);
+    // });
+
+    
+    // Handle Excel file upload
+    $("#fileUpload").on("change", function(e) {
+        const file = e.target.files[0];
+        if (!file) return;
+
+        const reader = new FileReader();
+        reader.onload = function(event) {
+            const data = new Uint8Array(event.target.result);
+            const workbook = XLSX.read(data, { type: "array" });
+            const sheetName = workbook.SheetNames[0];
+            const sheet = workbook.Sheets[sheetName];
+            const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1 });
+
+            const headers = jsonData[0];
+            const sampleRows = jsonData.slice(1, 6); // first 5 rows for preview
+
+            // Populate uploaded columns
+            $("#uploaded-columns").empty();
+            headers.forEach(col => {
+                $("#uploaded-columns").append(`<div class="drag-item" draggable="true" data-col="${col}">${col}</div>`);
+            });
+
+            // Populate preview table
+            $("#preview-header").html(headers.map(h => `<th>${h}</th>`).join(''));
+            $("#preview-body").empty();
+            sampleRows.forEach(row => {
+                let tr = "<tr>";
+                headers.forEach((h, i) => tr += `<td>${row[i] || ""}</td>`);
+                tr += "</tr>";
+                $("#preview-body").append(tr);
+            });
+
+            // Enable drag-and-drop
+            $(".drag-item").on("dragstart", function(e) {
+                e.originalEvent.dataTransfer.setData("text", $(this).data("col"));
+            });
+        };
+        reader.readAsArrayBuffer(file);
+    });
+
+
+
+    // Preview table
+    $("#preview-header").html(uploadedColumns.map(c => `<th>${c}</th>`).join(''));
+    previewData.forEach(row => {
+        let tr = "<tr>";
+        uploadedColumns.forEach(c => tr += `<td>${row[c]}</td>`);
+        tr += "</tr>";
+        $("#preview-body").append(tr);
+    });
+
+    // Drag and Drop Logic
+    $(".drag-item").on("dragstart", function(e) {
+        e.originalEvent.dataTransfer.setData("text", $(this).data("col"));
+    });
+
+    $(".drop-zone").on("dragover", function(e) {
+        e.preventDefault();
+        $(this).addClass("hover");
+    }).on("dragleave", function() {
+        $(this).removeClass("hover");
+    }).on("drop", function(e) {
+        e.preventDefault();
+        $(this).removeClass("hover");
+        const col = e.originalEvent.dataTransfer.getData("text");
+        $(this).html(`${$(this).data("system")} → <strong>${col}</strong>`);
+        $(this).data("mapped", col);
+    });
+
+    // $("#saveBtn").click(function() {
+    //     let mapping = {};
+    //     $(".drop-zone").each(function() {
+    //         mapping[$(this).data("system")] = $(this).data("mapped") || null;
+    //     });
+    //     console.log("Mapping:", mapping);
+    //     alert("Mapping saved successfully!");
+    // });
+
+    $("#saveBtn").click(function() {
+        let mapping = {};
+        let allMapped = true;
+
+        $(".drop-zone").each(function() {
+            const systemCol = $(this).data("system");
+            const mappedCol = $(this).data("mapped");
+            mapping[systemCol] = mappedCol || null;
+
+            if (!mappedCol) {
+                allMapped = false;
+            }
+        });
+
+        if (!allMapped) {
+            alert("Please map all system columns before saving.");
+            return;
+        }
+
+        console.log("Mapping:", mapping);
+        alert("Mapping saved successfully!");
+    });
+
+    $("#resetBtn").click(function() {
+        $(".drop-zone").each(function() {
+            $(this).html($(this).data("system"));
+            $(this).removeData("mapped");
+        });
+    });
+});
+</script>
+</body>
+</html>
+
+<!-- <script>
+const uploadedColumns = [];
+const systemColumns = ["PRODUCT NAME", "ITEM ID", "PRODUCT TYPE", "Product Short Description", "Product Long Description", "image_path"];
+let globalHeaders = []; // To store headers for preview
+
+$(document).ready(function() {
+    // --- Initial Drop Zone Setup ---
+    systemColumns.forEach(col => {
+        $("#system-columns").append(`
+            <div class="drop-zone" data-system="${col}">
+                <span class="system-label">${col}</span>
+                <span class="mapped-content">
+                    <span class="text-muted">No column mapped</span>
+                </span>
+            </div>
+        `);
+    });
+
+    // --- File Upload Handler (Supports CSV/Excel) ---
+    $("#fileUpload").on("change", function(e) {
+        const file = e.target.files[0];
+        if (!file) return;
+
+        const reader = new FileReader();
+        reader.onload = function(event) {
+            let jsonData;
+            try {
+                const data = new Uint8Array(event.target.result);
+                const workbook = XLSX.read(data, { type: "array" });
+                const sheetName = workbook.SheetNames[0];
+                const sheet = workbook.Sheets[sheetName];
+                // Use { header: 1 } to get an array of arrays, preserving the first row as headers
+                jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1 });
+            } catch (err) {
+                alert("Error reading file. Ensure it is a valid CSV or Excel file.");
+                console.error(err);
+                return;
+            }
+
+            const headers = jsonData[0];
+            const sampleRows = jsonData.slice(1, 6); 
+            globalHeaders = headers; // Store headers globally
+
+            // Populate uploaded columns
+            $("#uploaded-columns").empty();
+            headers.forEach(col => {
+                // Check if the column name is not empty or null
+                if (col && String(col).trim() !== "") { 
+                    $("#uploaded-columns").append(`<div class="drag-item" draggable="true" data-col="${col}">${col}</div>`);
+                }
+            });
+            
+            // Remove placeholder text
+            $("#upload-placeholder").hide();
+
+            // Populate preview table
+            $("#preview-header").html(headers.map(h => `<th scope="col">${h}</th>`).join(''));
+            $("#preview-body").empty();
+            if (sampleRows.length > 0) {
+                sampleRows.forEach(row => {
+                    let tr = "<tr>";
+                    headers.forEach((h, i) => tr += `<td>${row[i] || "-"}</td>`);
+                    tr += "</tr>";
+                    $("#preview-body").append(tr);
+                });
+            } else {
+                 $("#preview-body").html('<tr><td colspan="100%" class="text-center text-warning">File uploaded, but no data rows found.</td></tr>');
+            }
+
+            // Re-enable drag-and-drop for new items
+            enableDragDrop();
+        };
+        reader.readAsArrayBuffer(file);
+    });
+
+    // --- Drag and Drop Logic ---
+    function enableDragDrop() {
+        // Drag Start
+        $(".drag-item").off("dragstart").on("dragstart", function(e) {
+            e.originalEvent.dataTransfer.setData("text/plain", $(this).data("col"));
+            // Add a class to the item being dragged
+            $(this).addClass("dragging-active"); 
+        });
+
+        // Drag End (optional, for cleanup)
+        $(".drag-item").off("dragend").on("dragend", function() {
+             $(this).removeClass("dragging-active");
+        });
+
+        // Drop Zone Events
+        $(".drop-zone").off("dragover").on("dragover", function(e) {
+            e.preventDefault();
+            $(this).addClass("hover");
+            e.originalEvent.dataTransfer.dropEffect = "move";
+        }).off("dragleave").on("dragleave", function() {
+            $(this).removeClass("hover");
+        }).off("drop").on("drop", function(e) {
+            e.preventDefault();
+            $(this).removeClass("hover");
+            const col = e.originalEvent.dataTransfer.getData("text/plain");
+            const systemCol = $(this).data("system");
+            
+            
+            // Update the drop zone content
+            $(this).find('.mapped-content').html(`
+                <strong>${col}</strong>
+                <span class="reset-map" title="Unmap Column" data-system="${systemCol}">✖️</span>
+            `);
+            $(this).data("mapped", col);
+            $(this).removeClass("border-danger").addClass("border-success");
+
+            // Visually "move" the item from the uploaded list (optional, for a cleaner look)
+            // $(`.drag-item[data-col="${col}"]`).hide();
+        });
+    }
+
+    // --- Reset Single Mapping ---
+    $(document).on("click", ".reset-map", function() {
+        const dropZone = $(this).closest(".drop-zone");
+        const systemCol = dropZone.data("system");
+        const mappedCol = dropZone.data("mapped");
+
+        // Reset drop zone appearance and data
+        dropZone.find('.mapped-content').html(`<span class="text-muted">No column mapped</span>`);
+        dropZone.removeData("mapped");
+        dropZone.removeClass("border-success").addClass("border-danger");
+        
+        // Show the uploaded column item again
+        if (mappedCol) {
+             $(`.drag-item[data-col="${mappedCol}"]`).show();
+        }
+    });
+
+    // --- Reset All Button ---
+    $("#resetBtn").click(function() {
+        $(".drop-zone").each(function() {
+            $(this).find('.mapped-content').html(`<span class="text-muted">No column mapped</span>`);
+            $(this).removeData("mapped");
+            $(this).removeClass("border-success border-danger");
+        });
+        // Show all uploaded columns again
+        $(".drag-item").show();
+    });
+
+    // --- Save Button with Validation ---
+    $("#saveBtn").click(function() {
+        let mapping = {};
+        let missingMaps = [];
+        let allMapped = true;
+
+        $(".drop-zone").each(function() {
+            const systemCol = $(this).data("system");
+            const mappedCol = $(this).data("mapped");
+            
+            mapping[systemCol] = mappedCol || null;
+
+            if (!mappedCol) {
+                allMapped = false;
+                missingMaps.push(systemCol);
+                $(this).addClass("border-danger"); // Highlight missing map
+            } else {
+                 $(this).removeClass("border-danger");
+            }
+        });
+
+        if (!allMapped) {
+            alert(`Please map all system columns before saving. Missing: ${missingMaps.join(', ')}`);
+            return;
+        }
+
+        console.log("Final Mapping:", mapping);
+        alert(`Mapping saved successfully! System Columns Mapped: ${Object.keys(mapping).length}`);
+    });
+    
+    // Initial call to enable drag/drop for any pre-populated items (though none are currently)
+    enableDragDrop();
+});
+</script> -->

+ 447 - 0
content_quality_tool_public/templates/attr-column-mapping-setting.html

@@ -0,0 +1,447 @@
+{% load static %}
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Column Mapping</title>
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
+<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/source-sans-3@5.0.12/index.css"
+        integrity="sha256-tXJfXfp6Ewt1ilPzLDtQnJV4hclT9XuaZUKyUvmyr+Q=" crossorigin="anonymous">
+    <!--end::Fonts--><!--begin::Third Party Plugin(OverlayScrollbars)-->
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.3.0/styles/overlayscrollbars.min.css"
+        integrity="sha256-dSokZseQNT08wYEWiz5iLI8QPlKxG+TswNRD8k35cpg=" crossorigin="anonymous">
+    <!--end::Third Party Plugin(OverlayScrollbars)--><!--begin::Third Party Plugin(Bootstrap Icons)-->
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.min.css"
+        integrity="sha256-Qsx5lrStHZyR9REqhUF8iQt73X06c8LGIUPzpOhwRrI=" crossorigin="anonymous">
+    <!--end::Third Party Plugin(Bootstrap Icons)--><!--begin::Required Plugin(AdminLTE)-->
+    <link rel="stylesheet" href="{% static './css/adminlte.css' %}"><!--end::Required Plugin(AdminLTE)--><!-- apexcharts -->
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/apexcharts@3.37.1/dist/apexcharts.css"
+        integrity="sha256-4MX+61mt9NVvvuPjUWdUdyfZfxSB1/Rf9WtqRHgG5S0=" crossorigin="anonymous">
+    <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
+    <link rel="stylesheet" href="{% static './css/select2-bootstrap4.min.css' %}">
+    <link rel="stylesheet" href="{% static './css/custom.css' %}">
+<style>
+    /* General Container and Layout */
+    body {
+        background-color: #f8f9fa; /* Light grey background */
+    }
+    .mapping-container {
+        max-width: 1200px;
+        margin: 40px auto;
+        background: #ffffff;
+        padding: 30px;
+        border-radius: 12px;
+        box-shadow: 0 8px 25px rgba(0,0,0,0.08);
+    }
+    /* Uploaded Columns (Source) */
+    #uploaded-columns-wrapper {
+        border: 1px solid #dee2e6;
+        border-radius: 6px;
+        padding: 10px;
+        min-height: 200px;
+        background-color: #e9ecef; /* Slightly darker background for source */
+    }
+    .drag-item {
+        padding: 8px 15px;
+        margin: 8px 0;
+        background: #007bff; /* Primary blue for drag items */
+        color: white;
+        border-radius: 4px;
+        cursor: grab;
+        transition: transform 0.1s, box-shadow 0.1s;
+        font-weight: 500;
+        display: inline-block;
+        width: 100%;
+    }
+    .drag-item:hover {
+        background: #0056b3;
+        box-shadow: 0 2px 5px rgba(0,0,0,0.2);
+    }
+    /* System Columns (Destination/Drop Zones) */
+    .drop-zone-container {
+        padding: 15px;
+        border: 1px solid #dee2e6;
+        border-radius: 6px;
+        min-height: 200px;
+    }
+    .drop-zone {
+        min-height: 45px;
+        padding: 10px;
+        margin-bottom: 10px;
+        border: 2px dashed #adb5bd; /* Subtler dashed border */
+        border-radius: 6px;
+        background: #f1f3f5; /* Light grey background for drop zone */
+        font-weight: bold;
+        color: #495057;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        transition: background-color 0.2s, border-color 0.2s;
+    }
+    .drop-zone.hover {
+        border-color: #28a745; /* Green on hover */
+        background: #e6ffed; /* Light green background on hover */
+    }
+    .drop-zone strong {
+        color: #dc3545; /* Red for the mapped column name */
+        font-weight: 600;
+        padding: 4px 8px;
+        background-color: #ffe8e8;
+        border-radius: 4px;
+    }
+    .drop-zone .system-label {
+        color: #495057;
+    }
+    .drop-zone .mapped-content {
+        display: flex;
+        align-items: center;
+    }
+    .drop-zone .mapped-content .reset-map {
+        margin-left: 10px;
+        cursor: pointer;
+        color: #6c757d;
+        font-size: 1.2rem;
+        transition: color 0.2s;
+    }
+    .drop-zone .mapped-content .reset-map:hover {
+        color: #dc3545;
+    }
+    /* Preview Table */
+    .preview-table {
+        margin-top: 30px;
+        border-top: 2px solid #007bff;
+        padding-top: 20px;
+    }
+    .preview-table th {
+        background-color: #007bff;
+        color: white;
+    }
+</style>
+</head>
+<!-- <body> -->
+
+<body class="layout-fixed sidebar-expand-lg sidebar-mini app-loaded sidebar-collapse">
+    <!--begin::App Wrapper-->
+    <div class="app-wrapper"> <!--begin::Header-->
+        {% include 'header.html' %}
+        {% include 'sidebar.html' %}
+        <main class="app-main"> <!--begin::App Content Header-->
+            <div class="app-content-header"> <!--begin::Container-->
+                <div class="container-fluid"> <!--begin::Row-->
+                    <div class="row">
+                        <div class="col-sm-6">
+                            <h3 class="mb-0">⚙️ Attribute Extraction File Column Mapping</h3>
+                        </div>
+                        <div class="col-sm-6">
+                            <ol class="breadcrumb float-sm-end">
+                                <li class="breadcrumb-item"><a href="{% url 'file-upload' %}">Home</a></li>
+                                <li class="breadcrumb-item active" aria-current="page"><a href="{% url 'content-scorecard' %}"></a>
+                                   ⚙️ Attribute Extraction File Column Mapping</a>
+                                </li>
+                            </ol>
+                        </div>
+                    </div> <!--end::Row-->
+                </div> <!--end::Container-->
+            </div>
+            <div class="app-content"> <!--begin::Container-->
+                <div class="container-fluid"> <!-- Info boxes -->
+                    <div id="full-page-loader" style="display: none;">
+                    <div class="loader-overlay">
+                        <div class="spinner-border text-light" role="status">
+                            <!-- <span class="sr-only">Loading...</span> -->
+                        </div>
+                    </div>
+                </div>    
+
+    <div class="mapping-container">
+        <!-- <h2 class="text-center mb-4 text-primary">⚙️ Data Attribute Mapping Tool</h2> -->
+        <p class="text-center text-muted mb-4"><strong>Step 1:</strong> Upload your file. <strong>Step 2:</strong> Drag columns from the left to their corresponding system fields on the right. <strong>Step 3:</strong> Save Mapping.</p>
+        
+        <div class="mb-4 p-3 bg-light rounded border">
+            <label for="fileUpload" class="form-label fs-5 mb-2">📥 Upload Source File (CSV/Excel)</label>
+            <input type="file" class="form-control" id="fileUpload" accept=".csv, .xls, .xlsx">
+        </div>
+
+        <div class="row">
+            <div class="col-md-5">
+                <h5 class="mb-3 text-secondary">Source File Columns (Drag)</h5>
+                <div id="uploaded-columns-wrapper">
+                    <div id="uploaded-columns" class="list-group">
+                        <p class="text-center text-muted" id="upload-placeholder">Upload a file to see columns here.</p>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="col-md-7">
+                <h5 class="mb-3 text-success">Target System Attributes (Drop)</h5>
+                <div id="system-columns" class="drop-zone-container">
+                    </div>
+            </div>
+        </div>
+
+        <!-- <div class="preview-table">
+            <h5 class="text-primary">👀 Data Preview (First 5 Rows)</h5>
+            <div class="table-responsive">
+                <table class="table table-striped table-bordered">
+                    <thead>
+                        <tr id="preview-header">
+                            <th colspan="100%" class="text-center text-white bg-secondary">No data loaded for preview.</th>
+                        </tr>
+                    </thead>
+                    <tbody id="preview-body">
+                        <tr>
+                            <td colspan="100%" class="text-center text-muted">A sample of your file data will appear here upon upload.</td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
+        </div> -->
+
+        <div class="text-end mt-4 pt-3 border-top">
+            <button class="btn btn-outline-secondary me-2" id="resetBtn">↩️ Reset Mapping</button>
+            <button class="btn btn-success" id="saveBtn">✅ Save & Confirm Mapping</button>
+        </div>
+    </div>
+
+         </div> <!--end::Container-->
+            </div> <!--end::App Content-->
+        </main> <!--end::App Main--> <!--begin::Footer-->
+        {% include 'footer.html' %}
+
+    </div> 
+
+    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.3.0/browser/overlayscrollbars.browser.es6.min.js"
+        integrity="sha256-H2VM7BKda+v2Z4+DRy69uknwxjyDRhszjXFhsL4gD3w=" crossorigin="anonymous"></script>
+    <!--end::Third Party Plugin(OverlayScrollbars)--><!--begin::Required Plugin(popperjs for Bootstrap 5)-->
+    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
+        integrity="sha256-whL0tQWoY1Ku1iskqPFvmZ+CHsvmRWx/PIoEvIeWh4I=" crossorigin="anonymous"></script>
+    <!--end::Required Plugin(popperjs for Bootstrap 5)--><!--begin::Required Plugin(Bootstrap 5)-->
+    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"
+        integrity="sha256-YMa+wAM6QkVyz999odX7lPRxkoYAan8suedu4k2Zur8=" crossorigin="anonymous"></script>
+    <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
+    <!--end::Required Plugin(Bootstrap 5)--><!--begin::Required Plugin(AdminLTE)-->
+    <script src="{% static './js/adminlte.js' %}"></script>
+    <!--end::Required Plugin(AdminLTE)--><!--begin::OverlayScrollbars Configure-->
+    <script>
+        const SELECTOR_SIDEBAR_WRAPPER = ".sidebar-wrapper";
+        const Default = {
+            scrollbarTheme: "os-theme-light",
+            scrollbarAutoHide: "leave",
+            scrollbarClickScroll: true,
+        };
+        document.addEventListener("DOMContentLoaded", function () {
+            const sidebarWrapper = document.querySelector(SELECTOR_SIDEBAR_WRAPPER);
+            if (
+                sidebarWrapper &&
+                typeof OverlayScrollbarsGlobal?.OverlayScrollbars !== "undefined"
+            ) {
+                OverlayScrollbarsGlobal.OverlayScrollbars(sidebarWrapper, {
+                    scrollbars: {
+                        theme: Default.scrollbarTheme,
+                        autoHide: Default.scrollbarAutoHide,
+                        clickScroll: Default.scrollbarClickScroll,
+                    },
+                });
+            }
+        });
+    </script> 
+    <script>
+    const uploadedColumns = [];
+    const systemColumns = ["PRODUCT NAME", "ITEM ID", "PRODUCT TYPE", "Product Short Description", "Product Long Description", "image_path"];
+    let globalHeaders = []; // To store headers for preview
+
+    $(document).ready(function() {
+        // --- Initial Drop Zone Setup ---
+        systemColumns.forEach(col => {
+            $("#system-columns").append(`
+                <div class="drop-zone" data-system="${col}">
+                    <span class="system-label">${col}</span>
+                    <span class="mapped-content">
+                        <span class="text-muted">No column mapped</span>
+                    </span>
+                </div>
+            `);
+        });
+
+        // --- File Upload Handler (Supports CSV/Excel) ---
+        $("#fileUpload").on("change", function(e) {
+            const file = e.target.files[0];
+            if (!file) return;
+
+            const reader = new FileReader();
+            reader.onload = function(event) {
+                let jsonData;
+                try {
+                    const data = new Uint8Array(event.target.result);
+                    const workbook = XLSX.read(data, { type: "array" });
+                    const sheetName = workbook.SheetNames[0];
+                    const sheet = workbook.Sheets[sheetName];
+                    jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1 });
+                } catch (err) {
+                    alert("Error reading file. Ensure it is a valid CSV or Excel file.");
+                    console.error(err);
+                    return;
+                }
+
+                const headers = jsonData[0];
+                const sampleRows = jsonData.slice(1, 6); 
+                globalHeaders = headers; 
+
+                // Populate uploaded columns
+                $("#uploaded-columns").empty();
+                headers.forEach(col => {
+                    if (col && String(col).trim() !== "") { 
+                        $("#uploaded-columns").append(`<div class="drag-item" draggable="true" data-col="${col}">${col}</div>`);
+                    }
+                });
+                
+                // Reset mappings and remove placeholder text
+                $("#upload-placeholder").hide();
+                $("#resetBtn").click(); // Reset any previous mappings upon new file upload
+
+                // Populate preview table
+                $("#preview-header").html(headers.map(h => `<th scope="col">${h}</th>`).join(''));
+                $("#preview-body").empty();
+                if (sampleRows.length > 0) {
+                    sampleRows.forEach(row => {
+                        let tr = "<tr>";
+                        headers.forEach((h, i) => tr += `<td>${row[i] || "-"}</td>`);
+                        tr += "</tr>";
+                        $("#preview-body").append(tr);
+                    });
+                } else {
+                    $("#preview-body").html('<tr><td colspan="100%" class="text-center text-warning">File uploaded, but no data rows found.</td></tr>');
+                }
+
+                // Re-enable drag-and-drop for new items
+                enableDragDrop();
+            };
+            reader.readAsArrayBuffer(file);
+        });
+
+        // --- Drag and Drop Logic ---
+        function enableDragDrop() {
+            // Drag Start
+            $(".drag-item").off("dragstart").on("dragstart", function(e) {
+                e.originalEvent.dataTransfer.setData("text/plain", $(this).data("col"));
+                $(this).addClass("dragging-active"); 
+            });
+
+            // Drag End (optional, for cleanup)
+            $(".drag-item").off("dragend").on("dragend", function() {
+                $(this).removeClass("dragging-active");
+            });
+
+            // Drop Zone Events
+            $(".drop-zone").off("dragover").on("dragover", function(e) {
+                e.preventDefault();
+                $(this).addClass("hover");
+                e.originalEvent.dataTransfer.dropEffect = "move";
+            }).off("dragleave").on("dragleave", function() {
+                $(this).removeClass("hover");
+            }).off("drop").on("drop", function(e) {
+                e.preventDefault();
+                $(this).removeClass("hover");
+                const col = e.originalEvent.dataTransfer.getData("text/plain");
+                const systemCol = $(this).data("system");
+                
+                // 1. ONE-TO-ONE MAPPING CHECK: Is this uploaded column already mapped?
+                let isAlreadyMapped = false;
+                $(".drop-zone").each(function() {
+                    if ($(this).data("mapped") === col) {
+                        isAlreadyMapped = true;
+                        return false; // Exit the loop early
+                    }
+                });
+
+                if (isAlreadyMapped) {
+                    alert(`The column "${col}" is already mapped to another system attribute. Please unmap it first.`);
+                    return; // Stop the drop action
+                }
+
+                // 2. UNMAP PREVIOUS COLUMN (if the drop zone already has a value)
+                const previousMappedCol = $(this).data("mapped");
+                if (previousMappedCol) {
+                    // Show the previously mapped column item again in the source list
+                    $(`.drag-item[data-col="${previousMappedCol}"]`).show();
+                }
+
+                // 3. APPLY NEW MAPPING
+                $(this).find('.mapped-content').html(`
+                    <strong>${col}</strong>
+                    <span class="reset-map" title="Unmap Column" data-system="${systemCol}">✖️</span>
+                `);
+                $(this).data("mapped", col);
+                $(this).removeClass("border-danger").addClass("border-success");
+
+                // 4. Hide the newly mapped column item from the uploaded list
+                $(`.drag-item[data-col="${col}"]`).hide();
+            });
+        }
+
+        // --- Reset Single Mapping ---
+        $(document).on("click", ".reset-map", function() {
+            const dropZone = $(this).closest(".drop-zone");
+            const mappedCol = dropZone.data("mapped");
+
+            // Reset drop zone appearance and data
+            dropZone.find('.mapped-content').html(`<span class="text-muted">No column mapped</span>`);
+            dropZone.removeData("mapped");
+            dropZone.removeClass("border-success border-danger");
+            
+            // Show the uploaded column item again
+            if (mappedCol) {
+                $(`.drag-item[data-col="${mappedCol}"]`).show();
+            }
+        });
+
+        // --- Reset All Button ---
+        $("#resetBtn").click(function() {
+            $(".drop-zone").each(function() {
+                $(this).find('.mapped-content').html(`<span class="text-muted">No column mapped</span>`);
+                $(this).removeData("mapped");
+                $(this).removeClass("border-success border-danger");
+            });
+            // Show all uploaded columns again
+            $(".drag-item").show();
+        });
+
+        // --- Save Button with Validation ---
+        $("#saveBtn").click(function() {
+            let mapping = {};
+            let missingMaps = [];
+            let allMapped = true;
+
+            $(".drop-zone").each(function() {
+                const systemCol = $(this).data("system");
+                const mappedCol = $(this).data("mapped");
+                
+                mapping[systemCol] = mappedCol || null;
+
+                if (!mappedCol) {
+                    allMapped = false;
+                    missingMaps.push(systemCol);
+                    $(this).addClass("border-danger"); 
+                } else {
+                    $(this).removeClass("border-danger");
+                }
+            });
+
+            if (!allMapped) {
+                alert(`Please map all system columns before saving. Missing: ${missingMaps.join(', ')}`);
+                return;
+            }
+
+            console.log("Final Mapping:", mapping);
+            alert(`Mapping saved successfully! System Columns Mapped: ${Object.keys(mapping).length}`);
+        });
+        
+        // Initial call to enable drag/drop 
+        enableDragDrop();
+    });
+    </script>
+</body>
+</html>

+ 24 - 0
content_quality_tool_public/templates/sidebar.html

@@ -37,6 +37,30 @@
                 <li class="nav-item"> <a href="{% url 'cia' %}" target="_blank" class="nav-link {% if request.path == '/ca/cia/' %}active{% endif %}"> <i
                             class="nav-icon bi bi-graph-up"></i>
                         <p>Competitor Intelligence Report</p>
+                    </a> </li> 
+                    
+                    <!-- <li class="nav-item has-treeview">
+                        <a href="#" class="nav-link {% if request.path == '/attribure-column-mapping-setting/' %}active{% endif %}">
+                            <i class="nav-icon bi bi-gear"></i>
+                            <p>
+                                Settings
+                                <i class="right bi bi-chevron-left"></i> </p>
+                        </a>
+                        
+                        <ul class="nav nav-treeview">
+                            
+                            <li class="nav-item">
+                                <a href="{% url 'attribure-column-mapping-setting' %}" class="nav-link {% if request.path == '/attribure-column-mapping-setting/' %}active{% endif %}">
+                                    <i class="nav-icon bi bi-map"></i> <p>Product Attribute Column Mapping</p>
+                                </a>
+                            </li> 
+                            
+                            </ul>
+                    </li> -->
+                 
+                <li class="nav-item"> <a href="{% url 'attribure-column-mapping-setting' %}"  class="nav-link {% if request.path == '/attribure-column-mapping-setting/' %}active{% endif %}"> <i
+                            class="nav-icon bi bi-gear"></i>
+                        <p>Product Attribute Column Mapping</p>
                     </a> </li>    
                 
 

+ 2 - 0
content_quality_tool_public/urls.py

@@ -13,6 +13,8 @@ urlpatterns = [
     path('product-attributes/', views.getProductAttributes, name='product-attributes'),
     path('attribute-extraction/', views.getAttributeExtraction, name='attribute-extraction'),
     path('content-quality-analytics/', views.contentQualityAnalysis, name='content-quality-analytics'),
+    
+    path('attribure-column-mapping-setting/', views.dataAttributionMappingToolSetting, name='attribure-column-mapping-setting'),
 ]
 
 if settings.DEBUG:

+ 5 - 1
content_quality_tool_public/views.py

@@ -110,4 +110,8 @@ def getProductAttributes(request):
 
 @login_required
 def contentQualityAnalysis(request):
-    return render(request, 'product-performance-analysis.html')
+    return render(request, 'product-performance-analysis.html')
+
+@login_required
+def dataAttributionMappingToolSetting(request):
+    return render(request, 'attr-column-mapping-setting.html')