Fix account tab persistence and viewer fallback
This commit is contained in:
@@ -142,7 +142,7 @@ kubectl apply -f k8s/telegram-scraper.yaml
|
|||||||
Then open:
|
Then open:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
http://<server-ip>:8080
|
http://<server-ip>:7887
|
||||||
```
|
```
|
||||||
|
|
||||||
### Volumes (Docker)
|
### Volumes (Docker)
|
||||||
|
|||||||
+38
-7
@@ -10,6 +10,8 @@ const state = {
|
|||||||
authStates: {},
|
authStates: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ACTIVE_ACCOUNT_STORAGE_KEY = "telegramScraper.activeAccount";
|
||||||
|
|
||||||
/* ── API helper ─────────────────────────────────────── */
|
/* ── API helper ─────────────────────────────────────── */
|
||||||
|
|
||||||
async function api(path, options = {}) {
|
async function api(path, options = {}) {
|
||||||
@@ -78,6 +80,33 @@ function isAccountAuthorized(auth) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveActiveAccount(accountId) {
|
||||||
|
if (accountId) {
|
||||||
|
localStorage.setItem(ACTIVE_ACCOUNT_STORAGE_KEY, accountId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSavedActiveAccount(accounts) {
|
||||||
|
let savedId = localStorage.getItem(ACTIVE_ACCOUNT_STORAGE_KEY);
|
||||||
|
if (!savedId) {
|
||||||
|
savedId = localStorage.getItem("activeAccount");
|
||||||
|
if (savedId) {
|
||||||
|
localStorage.setItem(ACTIVE_ACCOUNT_STORAGE_KEY, savedId);
|
||||||
|
localStorage.removeItem("activeAccount");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (savedId && accounts.some((account) => account.id === savedId)) {
|
||||||
|
return savedId;
|
||||||
|
}
|
||||||
|
if (savedId) {
|
||||||
|
localStorage.removeItem(ACTIVE_ACCOUNT_STORAGE_KEY);
|
||||||
|
}
|
||||||
|
if (state.activeAccount && accounts.some((account) => account.id === state.activeAccount)) {
|
||||||
|
return state.activeAccount;
|
||||||
|
}
|
||||||
|
return accounts[0]?.id || null;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Account tab management ─────────────────────────── */
|
/* ── Account tab management ─────────────────────────── */
|
||||||
|
|
||||||
function renderAccountTabs(accounts) {
|
function renderAccountTabs(accounts) {
|
||||||
@@ -175,9 +204,8 @@ function renderAccountPanel(accountId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function switchAccount(accountId) {
|
function switchAccount(accountId) {
|
||||||
if (state.activeAccount === accountId) return;
|
|
||||||
state.activeAccount = accountId;
|
state.activeAccount = accountId;
|
||||||
localStorage.setItem("activeAccount", accountId);
|
saveActiveAccount(accountId);
|
||||||
|
|
||||||
// Update tabs
|
// Update tabs
|
||||||
document.querySelectorAll(".account-tab").forEach((tab) => {
|
document.querySelectorAll(".account-tab").forEach((tab) => {
|
||||||
@@ -490,9 +518,10 @@ async function loadAccounts() {
|
|||||||
accounts.forEach((acc) => renderAccountPanel(acc.id));
|
accounts.forEach((acc) => renderAccountPanel(acc.id));
|
||||||
|
|
||||||
// Determine active account (persisted across reloads)
|
// Determine active account (persisted across reloads)
|
||||||
const savedId = localStorage.getItem("activeAccount");
|
const activeId = loadSavedActiveAccount(accounts);
|
||||||
const activeId = (savedId && accounts.some(a => a.id === savedId)) ? savedId : (state.activeAccount || accounts[0].id);
|
if (activeId) {
|
||||||
switchAccount(activeId);
|
switchAccount(activeId);
|
||||||
|
}
|
||||||
|
|
||||||
// Update settings
|
// Update settings
|
||||||
renderSettingsAccounts();
|
renderSettingsAccounts();
|
||||||
@@ -524,11 +553,13 @@ function renderSettingsAccounts() {
|
|||||||
node.querySelector(".account-remove-btn").addEventListener("click", async () => {
|
node.querySelector(".account-remove-btn").addEventListener("click", async () => {
|
||||||
if (!confirmAction(`Remove account "${acc.label || acc.id}"? All its data will be deleted.`)) return;
|
if (!confirmAction(`Remove account "${acc.label || acc.id}"? All its data will be deleted.`)) return;
|
||||||
try {
|
try {
|
||||||
|
const removingActive = state.activeAccount === acc.id;
|
||||||
await api(`/api/accounts/${acc.id}`, { method: "DELETE" });
|
await api(`/api/accounts/${acc.id}`, { method: "DELETE" });
|
||||||
await loadAccounts();
|
if (removingActive) {
|
||||||
if (state.activeAccount === acc.id) {
|
|
||||||
state.activeAccount = null;
|
state.activeAccount = null;
|
||||||
|
localStorage.removeItem(ACTIVE_ACCOUNT_STORAGE_KEY);
|
||||||
}
|
}
|
||||||
|
await loadAccounts();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(`Failed to remove account: ${err.message}`);
|
alert(`Failed to remove account: ${err.message}`);
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-9
@@ -87,6 +87,25 @@ function scrollToBottom() {
|
|||||||
setTimeout(go, 150);
|
setTimeout(go, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeScrollSentinel() {
|
||||||
|
const sentinel = document.createElement("div");
|
||||||
|
sentinel.id = "scroll-sentinel";
|
||||||
|
sentinel.className = "scroll-sentinel";
|
||||||
|
return sentinel;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetMessageView(title = "Select a channel", subtitle = "Reading messages from the local SQLite database.") {
|
||||||
|
const root = document.getElementById("messages-list");
|
||||||
|
if (root) {
|
||||||
|
root.innerHTML = "";
|
||||||
|
root.appendChild(makeScrollSentinel());
|
||||||
|
}
|
||||||
|
document.getElementById("viewer-title").textContent = title;
|
||||||
|
document.getElementById("viewer-subtitle").textContent = subtitle;
|
||||||
|
viewerState.oldestMessageId = null;
|
||||||
|
viewerState.newestMessageId = null;
|
||||||
|
}
|
||||||
|
|
||||||
function renderChannelList() {
|
function renderChannelList() {
|
||||||
const root = document.getElementById("viewer-channel-list");
|
const root = document.getElementById("viewer-channel-list");
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
@@ -179,6 +198,13 @@ async function switchViewerAccount(accountId) {
|
|||||||
renderChannelList();
|
renderChannelList();
|
||||||
if (viewerState.channelId) {
|
if (viewerState.channelId) {
|
||||||
await loadChannel(viewerState.channelId);
|
await loadChannel(viewerState.channelId);
|
||||||
|
} else {
|
||||||
|
resetMessageView(
|
||||||
|
"No channels",
|
||||||
|
viewerState.accountId
|
||||||
|
? "This account has no tracked channels yet."
|
||||||
|
: "No local legacy channels found."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,10 +216,10 @@ async function loadViewerAccount(params) {
|
|||||||
} catch {
|
} catch {
|
||||||
viewerState.accounts = [];
|
viewerState.accounts = [];
|
||||||
}
|
}
|
||||||
viewerState.accountId =
|
const requestedExists = requested && viewerState.accounts.some((acc) => acc.id === requested);
|
||||||
requested ||
|
viewerState.accountId = requestedExists
|
||||||
viewerState.accounts[0]?.id ||
|
? requested
|
||||||
null;
|
: viewerState.accounts[0]?.id || null;
|
||||||
|
|
||||||
renderAccountSelector();
|
renderAccountSelector();
|
||||||
|
|
||||||
@@ -289,8 +315,9 @@ function makeDateSep(text) {
|
|||||||
|
|
||||||
function renderMessages(payload, append = false) {
|
function renderMessages(payload, append = false) {
|
||||||
const root = document.getElementById("messages-list");
|
const root = document.getElementById("messages-list");
|
||||||
const sentinel = document.getElementById("scroll-sentinel");
|
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
|
let sentinel = document.getElementById("scroll-sentinel");
|
||||||
|
if (!sentinel) sentinel = makeScrollSentinel();
|
||||||
|
|
||||||
const channel = payload.channel;
|
const channel = payload.channel;
|
||||||
document.getElementById("viewer-title").textContent =
|
document.getElementById("viewer-title").textContent =
|
||||||
@@ -408,14 +435,24 @@ async function main() {
|
|||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
await loadViewerAccount(params);
|
await loadViewerAccount(params);
|
||||||
viewerState.channels = await api(channelsEndpoint());
|
viewerState.channels = await api(channelsEndpoint());
|
||||||
viewerState.channelId =
|
const requestedChannel = params.get("channel");
|
||||||
params.get("channel") ||
|
const requestedChannelExists =
|
||||||
viewerState.channels[0]?.channel_id ||
|
requestedChannel &&
|
||||||
null;
|
viewerState.channels.some((channel) => channel.channel_id === requestedChannel);
|
||||||
|
viewerState.channelId = requestedChannelExists
|
||||||
|
? requestedChannel
|
||||||
|
: viewerState.channels[0]?.channel_id || null;
|
||||||
renderChannelList();
|
renderChannelList();
|
||||||
|
|
||||||
if (viewerState.channelId) {
|
if (viewerState.channelId) {
|
||||||
await loadChannel(viewerState.channelId);
|
await loadChannel(viewerState.channelId);
|
||||||
|
} else {
|
||||||
|
resetMessageView(
|
||||||
|
"No channels",
|
||||||
|
viewerState.accountId
|
||||||
|
? "This account has no tracked channels yet."
|
||||||
|
: "No local legacy channels found."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setupInfiniteScroll();
|
setupInfiniteScroll();
|
||||||
|
|||||||
Reference in New Issue
Block a user