374 lines
15 KiB
JavaScript
374 lines
15 KiB
JavaScript
import {
|
|
create_dataframe,
|
|
create_selection,
|
|
create_uploaded_file_radio,
|
|
showLoader,
|
|
clearPreviousContent,
|
|
resetContainers,
|
|
showSuccess,
|
|
showElement,
|
|
showError,
|
|
hideElement,
|
|
openModal,
|
|
closeModal
|
|
} from './methods.js';
|
|
|
|
$(document).ready(function () {
|
|
// --- Fade-in Animation on Scroll ---
|
|
const fadeElements = $('.fade-in');
|
|
function handleFadeAnimation() {
|
|
fadeElements.each(function () {
|
|
if ($(this).offset().top <= $(window).scrollTop() + $(window).height()) {
|
|
$(this).addClass('visible');
|
|
}
|
|
});
|
|
}
|
|
$(window).on('scroll', handleFadeAnimation);
|
|
handleFadeAnimation();
|
|
|
|
// --- Cached DOM Elements ---
|
|
const $newOrLoad = $('#new_or_load');
|
|
const $viewPreTrainedButton = $('#viewPreTrainedButton');
|
|
const $datasetButtons = $('.btn-dataset');
|
|
const $timeseriesDatasets = $('#timeseries-datasets input[type="radio"]');
|
|
const $radioButtons = $('#radio_buttons');
|
|
const $uploadBtn = $('#upload_btn');
|
|
const $labelSelectionModal = $('#labelSelectionModal');
|
|
const $positiveDropdown = $('#positive-label');
|
|
const $negativeDropdown = $('#negative-label');
|
|
const $saveLabelChoicesBtn = $('#save-label-choices');
|
|
const $loader = $('#loader');
|
|
|
|
// --- Utility Functions ---
|
|
function showOrHideViewModelsButton() {
|
|
if (localStorage.getItem('datasetSelected') === 'true') {
|
|
$newOrLoad.show();
|
|
} else {
|
|
$newOrLoad.hide();
|
|
}
|
|
}
|
|
|
|
function updateDropdownOptions($dropdown, options, exclude, currentValue = null) {
|
|
$dropdown.empty();
|
|
$dropdown.append('<option value="" disabled>Select a label</option>');
|
|
options.forEach(option => {
|
|
if (option !== exclude) {
|
|
$dropdown.append(
|
|
`<option value="${option}" ${option === currentValue ? "selected" : ""}>${option}</option>`
|
|
);
|
|
}
|
|
});
|
|
if (exclude === currentValue) {
|
|
$dropdown.val("");
|
|
}
|
|
}
|
|
|
|
function validateSelection(positive, negative, showErrorMsg = false) {
|
|
const $errorContainer = $("#selection-error");
|
|
if (!positive || !negative) {
|
|
if (showErrorMsg) $errorContainer.text("You must select both a positive and a negative label!").removeClass("d-none");
|
|
return false;
|
|
}
|
|
if (positive === negative) {
|
|
if (showErrorMsg) $errorContainer.text("Positive and Negative labels must be different!").removeClass("d-none");
|
|
return false;
|
|
}
|
|
$errorContainer.addClass("d-none").text("");
|
|
return true;
|
|
}
|
|
|
|
// --- AJAX Helpers ---
|
|
function postData(url, data, onSuccess, onError, showLoaders = []) {
|
|
showLoaders.forEach(sel => showElement($(sel)));
|
|
$.ajax({
|
|
method: 'POST',
|
|
url: url,
|
|
headers: { 'X-CSRFToken': $("[name=csrfmiddlewaretoken]").val() },
|
|
data: data,
|
|
success: function (resp) {
|
|
showLoaders.forEach(sel => hideElement($(sel)));
|
|
onSuccess(resp);
|
|
},
|
|
error: function (err) {
|
|
showLoaders.forEach(sel => hideElement($(sel)));
|
|
if (onError) onError(err);
|
|
else showError('An error occurred. Please try again.', 'error-message');
|
|
}
|
|
});
|
|
}
|
|
|
|
// --- Dataset Fetch and Render ---
|
|
function fetchAndRenderDataset(df_name) {
|
|
showLoader(true);
|
|
postData(
|
|
'',
|
|
{ action: "dataset", df_name: df_name },
|
|
function (values) {
|
|
showLoader(false);
|
|
clearPreviousContent();
|
|
if (!values) return;
|
|
const datasetType = values["dataset_type"];
|
|
localStorage.setItem("selectedDatasetType", datasetType);
|
|
if (datasetType === "tabular") renderTabularDataset(values);
|
|
else if (datasetType === "timeseries") renderTimeseriesDataset(values);
|
|
$newOrLoad.show();
|
|
}
|
|
);
|
|
}
|
|
|
|
function renderTabularDataset(ret) {
|
|
const { data_to_display: df, fig, features, feature1, feature2, labels, curlabel } = ret;
|
|
const selection1 = create_selection(features, "feature1", null, feature1);
|
|
const selection2 = create_selection(features, "feature2", null, feature2);
|
|
const selection3 = create_selection(labels, "label", null, curlabel);
|
|
const tb = create_dataframe(df, "df_container");
|
|
|
|
$("#model_container, #df, #df_stats").fadeIn(200);
|
|
$("#df_div").append(tb);
|
|
if ($("#selection").is(":visible")) {
|
|
$("#selection").empty().append(selection1, selection2, selection3);
|
|
} else if ($("#selection").is(":hidden")) {
|
|
$("#stats_div").prepend(
|
|
$("<div>", { class: "d-flex mb-3", id: "selection" })
|
|
.append(selection1, selection2, selection3)
|
|
);
|
|
}
|
|
|
|
// Update or create stats_container
|
|
if ($("#stats_container").length > 0) {
|
|
$("#stats_container").html(fig);
|
|
} else {
|
|
$("#stats_div").append($("<div>", { id: 'stats_container', class: "plotly_fig" }).html(fig));
|
|
}
|
|
}
|
|
|
|
function renderTimeseriesDataset(ret) {
|
|
const { fig, fig1 } = ret;
|
|
$("#ts_stats, #ts_confidence").fadeIn(200);
|
|
$("#ts_stats_div").append($("<div>", { id: 'ts_confidence_container', class: "plotly_fig" }).html(fig));
|
|
$("#ts_confidence_div").append($("<div>", { id: 'ts_stats_container', class: "plotly_fig" }).html(fig1));
|
|
}
|
|
|
|
// --- Dataset Button Click Handler ---
|
|
function handleDatasetClick(elementId) {
|
|
const df_name = elementId === "upload" ? "upload" : elementId;
|
|
$("#new_or_load_cached").hide();
|
|
resetContainers();
|
|
$("#upload_col").toggle(df_name === "upload");
|
|
$("#timeseries-datasets").toggle(df_name === "timeseries");
|
|
$(`#${elementId}`).toggleClass("active").siblings().removeClass("active");
|
|
$(`#${elementId}`).addClass("active");
|
|
const timeseries_dataset = df_name === "timeseries" ? $("input:radio[name=timeseries_dataset]:checked").val() : "";
|
|
if (timeseries_dataset || (df_name !== "timeseries")) {
|
|
fetchAndRenderDataset(timeseries_dataset || df_name);
|
|
localStorage.setItem('datasetSelected', 'true');
|
|
} else {
|
|
$newOrLoad.hide();
|
|
localStorage.setItem('datasetSelected', 'false');
|
|
}
|
|
}
|
|
|
|
// --- Event Bindings ---
|
|
$datasetButtons.on('click', function () {
|
|
handleDatasetClick($(this).attr('id'));
|
|
});
|
|
$('#timeseries-datasets').on('click', function () {
|
|
handleDatasetClick('timeseries');
|
|
});
|
|
|
|
// --- Uploaded Dataset Radio Change ---
|
|
$radioButtons.on('change', function () {
|
|
const uploaded_dataset = $("input:radio[name=uploaded_file]:checked").val();
|
|
if (!uploaded_dataset) return;
|
|
resetContainers();
|
|
showElement($("#loader_ds"));
|
|
showElement($("#loader_stats"));
|
|
postData(
|
|
'',
|
|
{ action: "uploaded_datasets", df_name: uploaded_dataset },
|
|
function (values) {
|
|
hideElement($("#loader_ds"));
|
|
hideElement($("#loader_stats"));
|
|
$newOrLoad.show();
|
|
clearPreviousContent();
|
|
if (!values) return;
|
|
const dataset_type = values["dataset_type"];
|
|
localStorage.setItem("selectedDatasetType", dataset_type);
|
|
if (dataset_type === "tabular") renderTabularDataset(values);
|
|
else if (dataset_type === "timeseries") renderTimeseriesDataset(values);
|
|
}
|
|
);
|
|
});
|
|
|
|
// --- Pre-trained Models Button ---
|
|
$viewPreTrainedButton.on('click', function () {
|
|
window.location.href = '/charts.html';
|
|
});
|
|
|
|
// --- Show/Hide View Models Button on Load ---
|
|
showOrHideViewModelsButton();
|
|
|
|
// --- File Upload Handler ---
|
|
$uploadBtn.on('click', async function (event) {
|
|
event.preventDefault();
|
|
const datasetType = $('input[name="dataset_type"]:checked').val();
|
|
const fileInput = $('#doc')[0].files[0];
|
|
const csrfToken = $('input[name="csrfmiddlewaretoken"]').val();
|
|
let valid = true, message = "";
|
|
if (!datasetType && !fileInput) {
|
|
valid = false; message = 'Please select a dataset type and choose a file to upload.';
|
|
} else if (!datasetType) {
|
|
valid = false; message = 'Please define the type of the uploaded dataset.';
|
|
} else if (!fileInput) {
|
|
valid = false; message = 'Please choose a file to upload.';
|
|
}
|
|
if (!valid) {
|
|
showError(message, "error-message");
|
|
return;
|
|
}
|
|
const formData = new FormData();
|
|
formData.append('action', 'upload_dataset');
|
|
formData.append('dataset_type', datasetType);
|
|
formData.append('excel_file', fileInput);
|
|
formData.append('csrfmiddlewaretoken', csrfToken);
|
|
hideElement($uploadBtn);
|
|
showElement($('#cfbtn_loader'));
|
|
try {
|
|
const response = await fetch('', {
|
|
method: 'POST',
|
|
headers: { 'X-CSRFToken': csrfToken, 'X-Requested-With': 'XMLHttpRequest' },
|
|
body: formData
|
|
});
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
handleUploadResponse(data);
|
|
hideElement($('#cfbtn_loader'));
|
|
showElement($uploadBtn);
|
|
hideElement($('#default-non-uploaded'));
|
|
} else {
|
|
throw new Error(await response.text() || 'Unknown server error');
|
|
}
|
|
} catch (error) {
|
|
showError(`An error occurred during upload: ${error.message}`, "error-message");
|
|
} finally {
|
|
hideElement($('#cfbtn_loader'));
|
|
}
|
|
});
|
|
|
|
function handleUploadResponse(data) {
|
|
const { df_name, uploaded_files, target_labels } = data;
|
|
const counter = uploaded_files - 1;
|
|
hideElement($("#default-non-uploaded"));
|
|
$radioButtons.append(create_uploaded_file_radio(df_name, counter));
|
|
if (target_labels) populateLabelModal(target_labels);
|
|
showSuccess('File uploaded successfully!', "success-message");
|
|
}
|
|
|
|
function populateLabelModal(targetLabels) {
|
|
updateDropdownOptions($positiveDropdown, targetLabels);
|
|
updateDropdownOptions($negativeDropdown, targetLabels);
|
|
showError(null);
|
|
openModal($labelSelectionModal[0]);
|
|
let selectedPositive = null, selectedNegative = null;
|
|
$positiveDropdown.on('change', function () {
|
|
selectedPositive = $(this).val();
|
|
updateDropdownOptions($negativeDropdown, targetLabels, selectedPositive);
|
|
validateSelection(selectedPositive, selectedNegative);
|
|
});
|
|
$negativeDropdown.on('change', function () {
|
|
selectedNegative = $(this).val();
|
|
updateDropdownOptions($positiveDropdown, targetLabels, selectedNegative);
|
|
validateSelection(selectedPositive, selectedNegative);
|
|
});
|
|
}
|
|
|
|
$saveLabelChoicesBtn.on('click', async function () {
|
|
const selectedPositive = $positiveDropdown.val();
|
|
const selectedNegative = $negativeDropdown.val();
|
|
if (!validateSelection(selectedPositive, selectedNegative, true)) {
|
|
showError("Labels cannot be assigned the same value.", "selection-error");
|
|
return;
|
|
}
|
|
const csrfToken = $('input[name="csrfmiddlewaretoken"]').val();
|
|
const formData = new FormData();
|
|
formData.append('action', 'select_class_labels_for_uploaded_timeseries');
|
|
formData.append('positive_label', selectedPositive);
|
|
formData.append('negative_label', selectedNegative);
|
|
formData.append('csrfmiddlewaretoken', csrfToken);
|
|
showElement($loader);
|
|
$saveLabelChoicesBtn.prop('disabled', true);
|
|
try {
|
|
const response = await fetch('', {
|
|
method: 'POST',
|
|
headers: { 'X-CSRFToken': csrfToken, 'X-Requested-With': 'XMLHttpRequest' },
|
|
body: formData
|
|
});
|
|
if (response.ok) {
|
|
closeModal($labelSelectionModal[0]);
|
|
showSuccess('Labels saved successfully!', "success-message");
|
|
} else {
|
|
throw new Error(await response.text() || 'Unknown server error');
|
|
}
|
|
} catch (error) {
|
|
showError(error.message || 'An error occurred while saving labels.', "selection-error");
|
|
} finally {
|
|
hideElement($loader);
|
|
$saveLabelChoicesBtn.prop('disabled', false);
|
|
}
|
|
});
|
|
|
|
// --- Selection Change for Tabular Stats ---
|
|
$('#stats_div').on('change', function () {
|
|
const feature1 = $('#feature1').val();
|
|
const feature2 = $('#feature2').val();
|
|
const label = $('#label').val();
|
|
$("#stats_container").remove();
|
|
showElement($('#loader_stats'));
|
|
postData(
|
|
'',
|
|
{ action: "stat", feature1, feature2, label },
|
|
function (ret) {
|
|
hideElement($('#loader_stats'));
|
|
$("#stats_div").append($('<div>', { id: 'stats_container' }).html(ret["fig"]));
|
|
}
|
|
);
|
|
});
|
|
|
|
// --- Delete Uploaded File ---
|
|
$('#confirmDeleteButton').on('click', function () {
|
|
const fileName = $(this).data('file');
|
|
const uploaded_dataset = $("input:radio[name=uploaded_file]:checked").val();
|
|
hideElement($("#cancel_delete_buttons_modal_delete"));
|
|
showElement($("#loader_modal_delete"));
|
|
postData(
|
|
'',
|
|
{ action: 'delete_uploaded_file', dataset_name: fileName, csrfmiddlewaretoken: $("[name=csrfmiddlewaretoken]").val() },
|
|
function () {
|
|
hideElement($("#loader_modal_delete"));
|
|
$(`[data-file="${fileName}"]`).closest('.form-check').remove();
|
|
if ($('#radio_buttons .form-check').length === 0) showElement($('#default-non-uploaded'));
|
|
showElement($("#success-message-modal-delete"));
|
|
if (fileName === uploaded_dataset) resetContainers();
|
|
}
|
|
);
|
|
});
|
|
|
|
// --- Dismiss Alerts ---
|
|
$(document).on('click', '.alert', function () {
|
|
$(this).hide();
|
|
});
|
|
|
|
// --- Pre-trained Models Button (duplicate for legacy support) ---
|
|
$('#viewModelsButton').on('click', function () {
|
|
window.location.href = "/charts.html";
|
|
});
|
|
|
|
// --- Restore UI State on Reload ---
|
|
const savedDataset = localStorage.getItem('selectedDatasetType');
|
|
if (savedDataset === 'tabular') {
|
|
$("#df, #df_stats").show();
|
|
} else if (savedDataset === 'timeseries') {
|
|
$("#ts_confidence, #ts_stats").show();
|
|
}
|
|
showOrHideViewModelsButton();
|
|
}); |