feat(import-window): implement drag, minimize, maximize, close + rename refs
- Add window management functions: applyWindowPositionAndSize, initWindowFromSession, startWindowDrag, moveWindowDrag, endWindowDrag, minimizeWindow, maximizeWindow, restoreWindow - Wire window control button event listeners - Rename openImportModal→openImportWindow, closeImportModal→closeImportWindow - Update all element references from modal*→window* names - Remove selectDescendantsButton references - openImportWindow now calls initWindowFromSession on open Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
35d1db4fd7
commit
947cef19ec
@ -461,7 +461,7 @@
|
|||||||
currentCards: [],
|
currentCards: [],
|
||||||
collectionTree: [],
|
collectionTree: [],
|
||||||
isImportWindowOpen: false,
|
isImportWindowOpen: false,
|
||||||
isImportModalOpen: false,
|
isImportWindowOpen: false,
|
||||||
windowX: typeof windowSessionState.x === "number" ? windowSessionState.x : null,
|
windowX: typeof windowSessionState.x === "number" ? windowSessionState.x : null,
|
||||||
windowY: typeof windowSessionState.y === "number" ? windowSessionState.y : null,
|
windowY: typeof windowSessionState.y === "number" ? windowSessionState.y : null,
|
||||||
windowWidth: typeof windowSessionState.width === "number" ? windowSessionState.width : null,
|
windowWidth: typeof windowSessionState.width === "number" ? windowSessionState.width : null,
|
||||||
@ -562,6 +562,110 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyWindowPositionAndSize() {
|
||||||
|
const fw = elements.importWindow;
|
||||||
|
if (!fw) return;
|
||||||
|
fw.style.left = state.windowX !== null ? `${state.windowX}px` : "";
|
||||||
|
fw.style.top = state.windowY !== null ? `${state.windowY}px` : "";
|
||||||
|
fw.style.width = state.windowWidth !== null ? `${state.windowWidth}px` : "";
|
||||||
|
fw.style.height = state.windowHeight !== null ? `${state.windowHeight}px` : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function initWindowFromSession() {
|
||||||
|
const fw = elements.importWindow;
|
||||||
|
const bar = elements.importWindowMinimizedBar;
|
||||||
|
if (state.isWindowMinimized) {
|
||||||
|
fw.classList.add("minimized");
|
||||||
|
fw.classList.remove("maximized");
|
||||||
|
bar.hidden = false;
|
||||||
|
} else if (state.isWindowMaximized) {
|
||||||
|
fw.classList.add("maximized");
|
||||||
|
fw.classList.remove("minimized");
|
||||||
|
fw.style.width = "100vw";
|
||||||
|
fw.style.height = "100vh";
|
||||||
|
fw.style.left = "0";
|
||||||
|
fw.style.top = "0";
|
||||||
|
bar.hidden = true;
|
||||||
|
} else {
|
||||||
|
if (state.windowX !== null) {
|
||||||
|
applyWindowPositionAndSize();
|
||||||
|
}
|
||||||
|
fw.classList.remove("minimized", "maximized");
|
||||||
|
bar.hidden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startWindowDrag(event) {
|
||||||
|
const fw = elements.importWindow;
|
||||||
|
if (!fw || fw.classList.contains("maximized") || fw.classList.contains("minimized")) return;
|
||||||
|
event.preventDefault();
|
||||||
|
state.isWindowDragging = true;
|
||||||
|
state.windowDragStartX = event.clientX;
|
||||||
|
state.windowDragStartY = event.clientY;
|
||||||
|
state.windowDragStartLeft = parseFloat(fw.style.left) || 0;
|
||||||
|
state.windowDragStartTop = parseFloat(fw.style.top) || 0;
|
||||||
|
fw.style.transition = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveWindowDrag(event) {
|
||||||
|
if (!state.isWindowDragging) return;
|
||||||
|
event.preventDefault();
|
||||||
|
const fw = elements.importWindow;
|
||||||
|
const dx = event.clientX - state.windowDragStartX;
|
||||||
|
const dy = event.clientY - state.windowDragStartY;
|
||||||
|
let newLeft = state.windowDragStartLeft + dx;
|
||||||
|
let newTop = state.windowDragStartTop + dy;
|
||||||
|
const maxLeft = window.innerWidth - (parseFloat(fw.style.width) || fw.offsetWidth);
|
||||||
|
const maxTop = window.innerHeight - (parseFloat(fw.style.height) || fw.offsetHeight);
|
||||||
|
newLeft = Math.max(0, Math.min(newLeft, maxLeft));
|
||||||
|
newTop = Math.max(0, Math.min(newTop, maxTop));
|
||||||
|
fw.style.left = `${newLeft}px`;
|
||||||
|
fw.style.top = `${newTop}px`;
|
||||||
|
state.windowX = newLeft;
|
||||||
|
state.windowY = newTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
function endWindowDrag() {
|
||||||
|
if (!state.isWindowDragging) return;
|
||||||
|
state.isWindowDragging = false;
|
||||||
|
persistWindowSessionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
function minimizeWindow() {
|
||||||
|
state.isWindowMinimized = true;
|
||||||
|
state.isWindowMaximized = false;
|
||||||
|
elements.importWindow.classList.add("minimized");
|
||||||
|
elements.importWindow.classList.remove("maximized");
|
||||||
|
elements.importWindowMinimizedBar.hidden = false;
|
||||||
|
persistWindowSessionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
function maximizeWindow() {
|
||||||
|
state.isWindowMaximized = !state.isWindowMaximized;
|
||||||
|
if (state.isWindowMaximized) {
|
||||||
|
state.isWindowMinimized = false;
|
||||||
|
elements.importWindow.classList.add("maximized");
|
||||||
|
elements.importWindow.classList.remove("minimized");
|
||||||
|
elements.importWindowMinimizedBar.hidden = true;
|
||||||
|
elements.importWindow.style.width = "100vw";
|
||||||
|
elements.importWindow.style.height = "100vh";
|
||||||
|
elements.importWindow.style.left = "0";
|
||||||
|
elements.importWindow.style.top = "0";
|
||||||
|
} else {
|
||||||
|
elements.importWindow.classList.remove("maximized");
|
||||||
|
applyWindowPositionAndSize();
|
||||||
|
}
|
||||||
|
persistWindowSessionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreWindow() {
|
||||||
|
state.isWindowMinimized = false;
|
||||||
|
elements.importWindow.classList.remove("minimized");
|
||||||
|
elements.importWindowMinimizedBar.hidden = true;
|
||||||
|
applyWindowPositionAndSize();
|
||||||
|
persistWindowSessionState();
|
||||||
|
}
|
||||||
|
|
||||||
function setStatus(target, message, isError = false) {
|
function setStatus(target, message, isError = false) {
|
||||||
target.textContent = message || "";
|
target.textContent = message || "";
|
||||||
target.classList.toggle("error", Boolean(isError));
|
target.classList.toggle("error", Boolean(isError));
|
||||||
@ -677,7 +781,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderSelectedCount() {
|
function renderSelectedCount() {
|
||||||
elements.selectedCount.textContent = `已选 ${state.selectedItemKeys.size} 篇`;
|
elements.windowSelectedCount.textContent = `已选 ${state.selectedItemKeys.size} 篇`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetCollectionItemsLoadingState(clearItems = false) {
|
function resetCollectionItemsLoadingState(clearItems = false) {
|
||||||
@ -694,21 +798,20 @@
|
|||||||
if (currentProject) {
|
if (currentProject) {
|
||||||
const label = `当前项目:${currentProject.name}`;
|
const label = `当前项目:${currentProject.name}`;
|
||||||
elements.currentProjectLabel.textContent = label;
|
elements.currentProjectLabel.textContent = label;
|
||||||
elements.importModalProjectLabel.textContent = label;
|
elements.windowProjectLabel.textContent = label;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
elements.currentProjectLabel.textContent = "当前未选择项目。";
|
elements.currentProjectLabel.textContent = "当前未选择项目。";
|
||||||
elements.importModalProjectLabel.textContent = "未选择项目";
|
elements.windowProjectLabel.textContent = "未选择项目";
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateImportActionState() {
|
function updateImportActionState() {
|
||||||
const hasProject = Boolean(state.currentProjectId);
|
const hasProject = Boolean(state.currentProjectId);
|
||||||
const hasSelection = state.selectedItemKeys.size > 0;
|
const hasSelection = state.selectedItemKeys.size > 0;
|
||||||
syncCurrentProjectLabels();
|
syncCurrentProjectLabels();
|
||||||
elements.importSelectedItemsButton.disabled = !hasProject || !hasSelection;
|
elements.windowImportSelectedItemsButton.disabled = !hasProject || !hasSelection;
|
||||||
elements.importSelectedItemsButton.title = !hasProject ? "请先选择项目" : (hasSelection ? "" : "请先选择文献");
|
elements.windowImportSelectedItemsButton.title = !hasProject ? "请先选择项目" : (hasSelection ? "" : "请先选择文献");
|
||||||
elements.selectDescendantsButton.disabled = !state.collectionItemsLoaded || !state.visibleCollectionItems.length;
|
elements.windowClearSelectionButton.disabled = !state.selectedItemKeys.size;
|
||||||
elements.clearSelectionButton.disabled = !state.selectedItemKeys.size;
|
|
||||||
renderSelectedCount();
|
renderSelectedCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -752,11 +855,11 @@
|
|||||||
|
|
||||||
function renderCollectionTree() {
|
function renderCollectionTree() {
|
||||||
if (!state.collectionTree.length) {
|
if (!state.collectionTree.length) {
|
||||||
elements.collectionTree.innerHTML = '<div class="empty">暂无 collection。</div>';
|
elements.windowCollectionTree.innerHTML = '<div class="empty">暂无 collection。</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.collectionTree.innerHTML = "";
|
elements.windowCollectionTree.innerHTML = "";
|
||||||
const fragment = document.createDocumentFragment();
|
const fragment = document.createDocumentFragment();
|
||||||
|
|
||||||
function appendNode(node, depth) {
|
function appendNode(node, depth) {
|
||||||
@ -801,7 +904,7 @@
|
|||||||
`;
|
`;
|
||||||
button.addEventListener("click", () => {
|
button.addEventListener("click", () => {
|
||||||
loadCollectionItems(node.collection_key).catch((error) => {
|
loadCollectionItems(node.collection_key).catch((error) => {
|
||||||
setStatus(elements.collectionStatus, error.message, true);
|
setStatus(elements.windowCollectionStatus, error.message, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
row.appendChild(button);
|
row.appendChild(button);
|
||||||
@ -818,29 +921,29 @@
|
|||||||
for (const node of state.collectionTree) {
|
for (const node of state.collectionTree) {
|
||||||
appendNode(node, 0);
|
appendNode(node, 0);
|
||||||
}
|
}
|
||||||
elements.collectionTree.appendChild(fragment);
|
elements.windowCollectionTree.appendChild(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderCollectionItems() {
|
function renderCollectionItems() {
|
||||||
if (!state.selectedCollectionKey) {
|
if (!state.selectedCollectionKey) {
|
||||||
elements.collectionItems.innerHTML = '<div class="empty">先选择一个 collection。</div>';
|
elements.windowCollectionItems.innerHTML = '<div class="empty">先选择一个 collection。</div>';
|
||||||
updateImportActionState();
|
updateImportActionState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!state.collectionItemsLoaded) {
|
if (!state.collectionItemsLoaded) {
|
||||||
elements.collectionItems.innerHTML = state.loadingCollectionKey === state.selectedCollectionKey
|
elements.windowCollectionItems.innerHTML = state.loadingCollectionKey === state.selectedCollectionKey
|
||||||
? '<div class="empty">正在加载当前 collection 文献。</div>'
|
? '<div class="empty">正在加载当前 collection 文献。</div>'
|
||||||
: '<div class="empty">当前 collection 文献尚未加载。</div>';
|
: '<div class="empty">当前 collection 文献尚未加载。</div>';
|
||||||
updateImportActionState();
|
updateImportActionState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!state.visibleCollectionItems.length) {
|
if (!state.visibleCollectionItems.length) {
|
||||||
elements.collectionItems.innerHTML = '<div class="empty">当前目录及子目录下没有可导入文献。</div>';
|
elements.windowCollectionItems.innerHTML = '<div class="empty">当前目录及子目录下没有可导入文献。</div>';
|
||||||
updateImportActionState();
|
updateImportActionState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.collectionItems.innerHTML = "";
|
elements.windowCollectionItems.innerHTML = "";
|
||||||
for (const item of state.visibleCollectionItems) {
|
for (const item of state.visibleCollectionItems) {
|
||||||
const row = document.createElement("label");
|
const row = document.createElement("label");
|
||||||
row.className = "project-item";
|
row.className = "project-item";
|
||||||
@ -856,13 +959,13 @@
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
row.querySelector("input").addEventListener("change", () => toggleItemSelection(item.item_key));
|
row.querySelector("input").addEventListener("change", () => toggleItemSelection(item.item_key));
|
||||||
elements.collectionItems.appendChild(row);
|
elements.windowCollectionItems.appendChild(row);
|
||||||
}
|
}
|
||||||
updateImportActionState();
|
updateImportActionState();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadCollectionTree() {
|
async function loadCollectionTree() {
|
||||||
setStatus(elements.collectionStatus, "正在加载 collection...");
|
setStatus(elements.windowCollectionStatus, "正在加载 collection...");
|
||||||
const payload = await api("/api/zotero/collections/tree");
|
const payload = await api("/api/zotero/collections/tree");
|
||||||
state.collectionTree = Array.isArray(payload.collections) ? payload.collections : [];
|
state.collectionTree = Array.isArray(payload.collections) ? payload.collections : [];
|
||||||
normalizeSelectedCollectionKey();
|
normalizeSelectedCollectionKey();
|
||||||
@ -876,7 +979,7 @@
|
|||||||
state.visibleCollectionItems = [];
|
state.visibleCollectionItems = [];
|
||||||
resetCollectionItemsLoadingState();
|
resetCollectionItemsLoadingState();
|
||||||
renderCollectionItems();
|
renderCollectionItems();
|
||||||
setStatus(elements.collectionStatus, "");
|
setStatus(elements.windowCollectionStatus, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadCollectionItems(collectionKey) {
|
async function loadCollectionItems(collectionKey) {
|
||||||
@ -888,7 +991,7 @@
|
|||||||
resetCollectionItemsLoadingState(true);
|
resetCollectionItemsLoadingState(true);
|
||||||
renderCollectionTree();
|
renderCollectionTree();
|
||||||
renderCollectionItems();
|
renderCollectionItems();
|
||||||
setStatus(elements.collectionStatus, state.selectedCollectionKey ? "已切换到可用 collection。" : "");
|
setStatus(elements.windowCollectionStatus, state.selectedCollectionKey ? "已切换到可用 collection。" : "");
|
||||||
if (state.selectedCollectionKey) {
|
if (state.selectedCollectionKey) {
|
||||||
await loadCollectionItems(state.selectedCollectionKey);
|
await loadCollectionItems(state.selectedCollectionKey);
|
||||||
}
|
}
|
||||||
@ -903,7 +1006,7 @@
|
|||||||
state.nextCollectionItemsRequestToken = requestToken;
|
state.nextCollectionItemsRequestToken = requestToken;
|
||||||
state.activeCollectionItemsRequestToken = requestToken;
|
state.activeCollectionItemsRequestToken = requestToken;
|
||||||
renderCollectionItems();
|
renderCollectionItems();
|
||||||
setStatus(elements.collectionStatus, "正在加载文献...");
|
setStatus(elements.windowCollectionStatus, "正在加载文献...");
|
||||||
try {
|
try {
|
||||||
const payload = await api(`/api/zotero/collections/${collectionKey}/items`);
|
const payload = await api(`/api/zotero/collections/${collectionKey}/items`);
|
||||||
if (state.activeCollectionItemsRequestToken !== requestToken || state.selectedCollectionKey !== collectionKey) {
|
if (state.activeCollectionItemsRequestToken !== requestToken || state.selectedCollectionKey !== collectionKey) {
|
||||||
@ -915,7 +1018,7 @@
|
|||||||
renderCollectionItems();
|
renderCollectionItems();
|
||||||
const visibleCount = state.visibleCollectionItems.length;
|
const visibleCount = state.visibleCollectionItems.length;
|
||||||
setStatus(
|
setStatus(
|
||||||
elements.collectionStatus,
|
elements.windowCollectionStatus,
|
||||||
visibleCount ? `当前目录及子目录共 ${visibleCount} 篇文献。` : "当前目录及子目录下没有可导入文献。"
|
visibleCount ? `当前目录及子目录共 ${visibleCount} 篇文献。` : "当前目录及子目录下没有可导入文献。"
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -959,7 +1062,7 @@
|
|||||||
updateImportActionState();
|
updateImportActionState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setStatus(elements.collectionStatus, "正在导入...");
|
setStatus(elements.windowCollectionStatus, "正在导入...");
|
||||||
const payload = await api(`/api/projects/${state.currentProjectId}/imports/item-keys`, {
|
const payload = await api(`/api/projects/${state.currentProjectId}/imports/item-keys`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ item_keys: Array.from(state.selectedItemKeys) }),
|
body: JSON.stringify({ item_keys: Array.from(state.selectedItemKeys) }),
|
||||||
@ -968,22 +1071,24 @@
|
|||||||
persistImportSessionState();
|
persistImportSessionState();
|
||||||
renderCollectionItems();
|
renderCollectionItems();
|
||||||
renderCards(payload.project_view?.cards || []);
|
renderCards(payload.project_view?.cards || []);
|
||||||
setStatus(elements.collectionStatus, "导入完成。");
|
setStatus(elements.windowCollectionStatus, "导入完成。");
|
||||||
updateImportActionState();
|
updateImportActionState();
|
||||||
closeImportModal();
|
closeImportWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openImportModal() {
|
async function openImportWindow() {
|
||||||
state.isImportModalOpen = true;
|
state.isImportWindowOpen = true;
|
||||||
elements.importModal.hidden = false;
|
elements.importWindowShell.hidden = false;
|
||||||
elements.importModal.setAttribute("aria-hidden", "false");
|
elements.importWindowShell.setAttribute("aria-hidden", "false");
|
||||||
document.body.classList.toggle("modal-open", true);
|
document.body.classList.toggle("modal-open", true);
|
||||||
|
cancelAbstractPreview();
|
||||||
updateImportActionState();
|
updateImportActionState();
|
||||||
|
initWindowFromSession();
|
||||||
if (!state.collectionTree.length) {
|
if (!state.collectionTree.length) {
|
||||||
try {
|
try {
|
||||||
await loadCollectionTree();
|
await loadCollectionTree();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatus(elements.collectionStatus, error.message, true);
|
setStatus(elements.windowCollectionStatus, error.message, true);
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
state.selectedCollectionKey &&
|
state.selectedCollectionKey &&
|
||||||
@ -992,7 +1097,7 @@
|
|||||||
try {
|
try {
|
||||||
await loadCollectionItems(state.selectedCollectionKey);
|
await loadCollectionItems(state.selectedCollectionKey);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatus(elements.collectionStatus, error.message, true);
|
setStatus(elements.windowCollectionStatus, error.message, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
renderCollectionTree();
|
renderCollectionTree();
|
||||||
@ -1000,11 +1105,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeImportModal() {
|
function closeImportWindow() {
|
||||||
state.isImportModalOpen = false;
|
state.isImportWindowOpen = false;
|
||||||
elements.importModal.hidden = true;
|
elements.importWindowShell.hidden = true;
|
||||||
elements.importModal.setAttribute("aria-hidden", "true");
|
elements.importWindowShell.setAttribute("aria-hidden", "true");
|
||||||
document.body.classList.toggle("modal-open", false);
|
document.body.classList.toggle("modal-open", false);
|
||||||
|
cancelAbstractPreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadProjects() {
|
async function loadProjects() {
|
||||||
@ -1071,20 +1177,28 @@
|
|||||||
elements.refreshProjectsButton.addEventListener("click", loadProjects);
|
elements.refreshProjectsButton.addEventListener("click", loadProjects);
|
||||||
|
|
||||||
elements.openImportModalButton.addEventListener("click", () => {
|
elements.openImportModalButton.addEventListener("click", () => {
|
||||||
openImportModal();
|
openImportWindow();
|
||||||
});
|
});
|
||||||
elements.closeImportModalButton.addEventListener("click", closeImportModal);
|
elements.windowCloseButton.addEventListener("click", closeImportWindow);
|
||||||
elements.importModalOverlay.addEventListener("click", closeImportModal);
|
elements.windowMinimizeButton.addEventListener("click", minimizeWindow);
|
||||||
elements.selectDescendantsButton.addEventListener("click", selectVisibleItems);
|
elements.windowMaximizeButton.addEventListener("click", maximizeWindow);
|
||||||
elements.clearSelectionButton.addEventListener("click", clearSelectedItems);
|
elements.windowRestoreButton.addEventListener("click", restoreWindow);
|
||||||
elements.importSelectedItemsButton.addEventListener("click", () => {
|
elements.importWindowMinimizedBar.addEventListener("click", (e) => {
|
||||||
|
if (e.target === elements.windowRestoreButton) return;
|
||||||
|
restoreWindow();
|
||||||
|
});
|
||||||
|
elements.windowToolbar.addEventListener("pointerdown", startWindowDrag);
|
||||||
|
document.addEventListener("pointermove", moveWindowDrag);
|
||||||
|
document.addEventListener("pointerup", endWindowDrag);
|
||||||
|
elements.windowClearSelectionButton.addEventListener("click", clearSelectedItems);
|
||||||
|
elements.windowImportSelectedItemsButton.addEventListener("click", () => {
|
||||||
importSelectedItems().catch((error) => {
|
importSelectedItems().catch((error) => {
|
||||||
setStatus(elements.collectionStatus, error.message, true);
|
setStatus(elements.windowCollectionStatus, error.message, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
document.addEventListener("keydown", (event) => {
|
document.addEventListener("keydown", (event) => {
|
||||||
if (event.key === "Escape" && state.isImportModalOpen) {
|
if (event.key === "Escape" && state.isImportWindowOpen) {
|
||||||
closeImportModal();
|
closeImportWindow();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1139,7 +1253,7 @@
|
|||||||
elements.recommendTab.addEventListener("click", () => activateTab("recommend"));
|
elements.recommendTab.addEventListener("click", () => activateTab("recommend"));
|
||||||
elements.planTab.addEventListener("click", () => activateTab("plan"));
|
elements.planTab.addEventListener("click", () => activateTab("plan"));
|
||||||
|
|
||||||
closeImportModal();
|
closeImportWindow();
|
||||||
updateImportActionState();
|
updateImportActionState();
|
||||||
loadProjects().catch((error) => {
|
loadProjects().catch((error) => {
|
||||||
setStatus(elements.projectStatus, error.message, true);
|
setStatus(elements.projectStatus, error.message, true);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user