Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 95 additions & 66 deletions gateway/sds_gateway/static/js/actions/DownloadActionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class DownloadActionManager {
e.stopPropagation();

const captureUuid = button.getAttribute("data-capture-uuid");
const captureName = button.getAttribute("data-capture-name");

if (!this.permissions.canDownload()) {
this.showToast(
Expand All @@ -90,7 +89,7 @@ class DownloadActionManager {
return;
}

this.handleCaptureDownload(captureUuid, captureName, button);
this.handleCaptureDownload(captureUuid, button);
});
}
}
Expand Down Expand Up @@ -181,60 +180,101 @@ class DownloadActionManager {
}

/**
* Handle capture download
* Handle capture download (modal copy comes from web_download_modal.html)
* @param {string} captureUuid - Capture UUID
* @param {string} captureName - Capture name
* @param {Element} [button] - Optional row action button for loading state
*/
async handleCaptureDownload(captureUuid, captureName) {
// Update modal content for capture
const modalTitleElement = document.getElementById("webDownloadModalLabel");
const modalNameElement = document.getElementById("webDownloadDatasetName");
const confirmBtn = document.getElementById("confirmWebDownloadBtn");

if (modalTitleElement) {
await window.DOMUtils.renderContent(modalTitleElement, {
icon: "download",
text: "Download Capture",
});
async handleCaptureDownload(captureUuid, button) {
const modalId = `webDownloadModal-${captureUuid}`;
const modal = document.getElementById(modalId);
if (!modal) {
console.warn(`Web download modal not found for capture ${captureUuid}`);
return;
}

if (modalNameElement) {
modalNameElement.textContent = captureName || "Unnamed Capture";
const confirmBtn = document.getElementById(
`confirmWebDownloadBtn-${captureUuid}`,
);

if (!confirmBtn) {
console.warn(
`Web download confirm button not found for capture ${captureUuid}`,
);
return;
}

if (confirmBtn) {
// Update button text for capture
await window.DOMUtils.renderContent(confirmBtn, {
icon: "download",
text: "Yes, Download Capture",
});
const newConfirmBtn = confirmBtn.cloneNode(true);
confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);

// Update the dataset UUID to capture UUID for the API call
confirmBtn.dataset.datasetUuid = captureUuid;
confirmBtn.dataset.datasetName = captureName;

// Override the API endpoint for captures by temporarily modifying the fetch URL
const originalFetch = window.fetch;
window.fetch = (url, options) => {
const modifiedUrl = url.includes(
`/users/download-item/dataset/${captureUuid}/`,
)
? `/users/download-item/capture/${captureUuid}/`
: url;
return originalFetch(modifiedUrl, options);
};

// Restore fetch after modal is hidden
const modal = document.getElementById("webDownloadModal");
const restoreFetch = () => {
window.fetch = originalFetch;
modal.removeEventListener("hidden.bs.modal", restoreFetch);
};
modal.addEventListener("hidden.bs.modal", restoreFetch);
}
const originalRowButtonContent = button?.innerHTML;

// Show the modal
window.DOMUtils.openModal("webDownloadModal");
newConfirmBtn.onclick = async () => {
window.DOMUtils.closeModal(modalId);

if (button) {
await window.DOMUtils.renderLoading(button, "Processing...", {
format: "spinner",
size: "sm",
});
button.disabled = true;
}

try {
const response = await window.APIClient.post(
`/users/download-item/capture/${captureUuid}/`,
{},
);

if (response.success === true) {
if (button) {
await window.DOMUtils.renderContent(button, {
icon: "check-circle",
color: "success",
text: "Download Requested",
});
}
this.showToast(
response.message ||
"Download request submitted successfully! You will receive an email when ready.",
"success",
);
} else {
if (button) {
await window.DOMUtils.renderContent(button, {
icon: "exclamation-triangle",
color: "danger",
text: "Request Failed",
});
}
this.showToast(
response.message || "Download request failed. Please try again.",
"danger",
);
}
} catch (error) {
console.error("Download error:", error);
if (button) {
await window.DOMUtils.renderContent(button, {
icon: "exclamation-triangle",
color: "danger",
text: "Request Failed",
});
}
this.showToast(
error.message || "An error occurred while processing your request.",
"danger",
);
} finally {
if (button && originalRowButtonContent !== undefined) {
setTimeout(() => {
button.innerHTML = originalRowButtonContent;
button.disabled = false;
}, 3000);
}
}
};

window.DOMUtils.openModal(modalId);
}

/**
Expand All @@ -258,14 +298,13 @@ class DownloadActionManager {
e.stopPropagation();

const datasetUuid = button.getAttribute("data-dataset-uuid");
const datasetName = button.getAttribute("data-dataset-name");

if (!datasetUuid) {
console.warn("Web download button missing dataset-uuid attribute");
return;
}

this.openWebDownloadModal(datasetUuid, datasetName);
this.openWebDownloadModal(datasetUuid);
});
}
}
Expand Down Expand Up @@ -303,35 +342,26 @@ class DownloadActionManager {
}

/**
* Open web download modal for a specific dataset
* Open web download modal for a specific dataset (labels from web_download_modal.html)
* @param {string} datasetUuid - Dataset UUID
* @param {string} datasetName - Dataset name
*/
openWebDownloadModal(datasetUuid, datasetName) {
openWebDownloadModal(datasetUuid) {
const modalId = `webDownloadModal-${datasetUuid}`;
const modal = document.getElementById(modalId);
if (!modal) {
console.warn(`Web download modal not found for dataset ${datasetUuid}`);
return;
}

// Set the dataset name in the modal (find within this specific modal)
const nameElement = modal.querySelector("#webDownloadDatasetName");
if (nameElement) {
nameElement.textContent = datasetName || "this dataset";
}

// Store dataset info in the download button (find within this specific modal)
const confirmBtn = modal.querySelector("#confirmWebDownloadBtn");
const confirmBtn = document.getElementById(
`confirmWebDownloadBtn-${datasetUuid}`,
);

if (!confirmBtn) {
console.warn(`Confirm button not found for dataset ${datasetUuid}`);
return;
}

confirmBtn.dataset.datasetUuid = datasetUuid;
confirmBtn.dataset.datasetName = datasetName;

// Remove any existing event listeners by cloning
const newConfirmBtn = confirmBtn.cloneNode(true);
confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
Expand Down Expand Up @@ -490,7 +520,6 @@ class DownloadActionManager {
e.stopPropagation();

const captureUuid = button.getAttribute("data-capture-uuid");
const captureName = button.getAttribute("data-capture-name");

if (!this.permissions.canDownload()) {
this.showToast(
Expand All @@ -500,7 +529,7 @@ class DownloadActionManager {
return;
}

this.handleCaptureDownload(captureUuid, captureName, button);
this.handleCaptureDownload(captureUuid, button);
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ describe("DownloadActionManager", () => {
if (id === "downloadModal") return mockModal;
if (id === "downloadDatasetName") return { textContent: "" };
if (id === "confirmDownloadBtn") return mockButton;
if (id === "webDownloadModal") return mockModal;
if (id === "webDownloadModalLabel") return { innerHTML: "" };
if (id === "webDownloadDatasetName") return { textContent: "" };
if (id === "confirmWebDownloadBtn") return mockButton;
if (id.startsWith("webDownloadModal-")) return mockModal;
if (id.startsWith("webDownloadModalLabel-")) return { innerHTML: "" };
if (id.startsWith("webDownloadDatasetName-")) return { textContent: "" };
if (id.startsWith("confirmWebDownloadBtn-")) return mockButton;
return null;
});

Expand Down Expand Up @@ -102,7 +102,6 @@ describe("DownloadActionManager", () => {
Promise.resolve({ success: true, message: "Download requested" }),
}),
);
global.window.showWebDownloadModal = jest.fn();
global.window.showAlert = jest.fn();

// Mock bootstrap globally
Expand Down Expand Up @@ -319,18 +318,13 @@ describe("DownloadActionManager", () => {

test("should handle capture download click with permissions", async () => {
const captureUuid = "test-capture-uuid";
const captureName = "Test Capture";

// Ensure window.DOMUtils is properly set up
window.DOMUtils = global.window.DOMUtils;

// Test that the method exists and can be called without throwing
await expect(
downloadManager.handleCaptureDownload(
captureUuid,
captureName,
mockButton,
),
downloadManager.handleCaptureDownload(captureUuid, mockButton),
).resolves.not.toThrow();
});

Expand Down Expand Up @@ -385,15 +379,20 @@ describe("DownloadActionManager", () => {
innerHTML: "",
disabled: false,
};
document.getElementById = jest.fn(() => ({
id: modalId,
querySelector: jest.fn((sel) =>
sel === "#confirmWebDownloadBtn" ? confirmBtn : { textContent: "" },
),
addEventListener: jest.fn(),
}));
document.getElementById = jest.fn((id) => {
if (id === modalId) {
return { id: modalId, addEventListener: jest.fn() };
}
if (id === "webDownloadDatasetName-test-uuid") {
return { textContent: "" };
}
if (id === "confirmWebDownloadBtn-test-uuid") {
return confirmBtn;
}
return null;
});

downloadManager.openWebDownloadModal("test-uuid", "Test Dataset");
downloadManager.openWebDownloadModal("test-uuid");

expect(global.window.DOMUtils.openModal).toHaveBeenCalledWith(modalId);
});
Expand Down
2 changes: 1 addition & 1 deletion gateway/sds_gateway/static/js/file-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,7 @@ class FileListCapturesTableManager extends CapturesTableManager {
<button class="dropdown-item"
type="button"
data-bs-toggle="modal"
data-bs-target="#share-modal-${safeData.uuid}">
data-bs-target="#shareModal-${safeData.uuid}">
Share
</button>
</li>
Expand Down
8 changes: 5 additions & 3 deletions gateway/sds_gateway/templates/pages/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ <h5 class="card-title">
<a href="#"
class="dataset-name-link text-decoration-none"
data-bs-toggle="modal"
data-bs-target="#datasetDetailsModal"
data-bs-target="#datasetDetailsModal-{{ dataset.uuid }}"
data-dataset-uuid="{{ dataset.uuid }}">{{ dataset.name }}</a>
{% if dataset.is_public %}<i class="bi bi-globe ms-1 text-primary" title="Public"></i>{% endif %}
</h5>
Expand Down Expand Up @@ -161,8 +161,10 @@ <h2 class="card-title h5">SpectrumX Website</h2>
</div>
</div>
</main>
<!-- Dataset Details Modal -->
{% include "users/partials/dataset_details_modal.html" %}
<!-- Dataset details modals (one per card; IDs must match data-bs-target above) -->
{% for dataset in latest_datasets %}
{% include "users/partials/dataset_details_modal.html" with dataset=dataset %}
{% endfor %}
{% endblock body %}
{% block javascript %}
{{ block.super }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{% endcomment %}
{% for dataset in page_obj %}
{% include "users/partials/dataset_details_modal.html" with dataset=dataset %}
{% include "users/partials/web_download_modal.html" with dataset=dataset %}
{% include "users/partials/web_download_modal.html" with item=dataset item_type="dataset" %}
{% include "users/partials/share_modal.html" with item=dataset item_type="dataset" %}
{% include "users/partials/sdk_download_modal.html" with dataset=dataset %}
{% if dataset.is_owner or dataset.permission_level == 'co-owner' %}
Expand Down
Loading