remove REVIEW.md from repo

This commit is contained in:
2026-09-10 11:50:12 +02:00
parent 4c12e8bb0c
commit b92f8d8914
15 changed files with 397 additions and 639 deletions
+46 -42
View File
@@ -408,7 +408,8 @@ function renderJobs(accountId, jobs) {
root.innerHTML = '';
if (!jobs.length) {
root.innerHTML = '<div class="empty-state"><p class="muted">No jobs yet. Start a scrape or export to see progress here.</p></div>';
root.innerHTML =
'<div class="empty-state"><p class="muted">No jobs yet. Start a scrape or export to see progress here.</p></div>';
return;
}
@@ -947,55 +948,58 @@ async function main() {
const addAccountForm = document.getElementById('add-account-form');
if (addAccountForm) {
addAccountForm.addEventListener('submit', async (event) => {
event.preventDefault();
const accountId = document.getElementById('add-account-id').value.trim();
const label = document.getElementById('add-account-label').value.trim();
const apiId = document.getElementById('add-account-api-id').value.trim();
const apiHash = document.getElementById('add-account-api-hash').value.trim();
if (!accountId) return;
event.preventDefault();
const accountId = document.getElementById('add-account-id').value.trim();
const label = document.getElementById('add-account-label').value.trim();
const apiId = document.getElementById('add-account-api-id').value.trim();
const apiHash = document.getElementById('add-account-api-hash').value.trim();
if (!accountId) return;
try {
await api('/api/accounts', {
method: 'POST',
body: JSON.stringify({
account_id: accountId,
label: label || accountId,
api_id: apiId ? parseInt(apiId) : undefined,
api_hash: apiHash || undefined,
}),
});
event.target.reset();
await loadAccounts();
if (!state.activeAccount) {
switchAccount(accountId);
try {
await api('/api/accounts', {
method: 'POST',
body: JSON.stringify({
account_id: accountId,
label: label || accountId,
api_id: apiId ? parseInt(apiId) : undefined,
api_hash: apiHash || undefined,
}),
});
event.target.reset();
await loadAccounts();
if (!state.activeAccount) {
switchAccount(accountId);
}
} catch (err) {
showToast('Failed to add account: ' + err.message, 'error');
}
} catch (err) {
showToast('Failed to add account: ' + err.message, 'error');
}
});
}
const importAccountFile = document.getElementById('import-account-file');
if (importAccountFile) {
importAccountFile.addEventListener('change', async (event) => {
const file = event.currentTarget.files?.[0];
if (!file) return;
try {
const payload = JSON.parse(await file.text());
const accountId = payload.account_id || payload.id;
if (!accountId) throw new Error('account_id is missing in import file');
await api('/api/accounts/import', {
method: 'POST',
body: JSON.stringify(payload),
});
event.currentTarget.value = '';
await loadAccounts();
switchAccount(accountId);
showToast(`Imported ${accountId}.`, 'success');
showToast('Credentials (api_id/api_hash) are not exported for security — re-enter them in Settings if needed.', 'warn');
} catch (err) {
showToast(`Failed to import account: ${err.message}`, 'error');
}
const file = event.currentTarget.files?.[0];
if (!file) return;
try {
const payload = JSON.parse(await file.text());
const accountId = payload.account_id || payload.id;
if (!accountId) throw new Error('account_id is missing in import file');
await api('/api/accounts/import', {
method: 'POST',
body: JSON.stringify(payload),
});
event.currentTarget.value = '';
await loadAccounts();
switchAccount(accountId);
showToast(`Imported ${accountId}.`, 'success');
showToast(
'Credentials (api_id/api_hash) are not exported for security — re-enter them in Settings if needed.',
'warn',
);
} catch (err) {
showToast(`Failed to import account: ${err.message}`, 'error');
}
});
}
+2 -4
View File
@@ -170,14 +170,12 @@
name="channel_id"
placeholder="ID or @username"
aria-label="Channel ID or username"
required
/>
required />
<input
class="add-channel-name"
name="name"
placeholder="Display name"
aria-label="Channel display name"
/>
aria-label="Channel display name" />
<button class="button primary" type="submit">Add</button>
</form>
</div>
+102 -101
View File
@@ -113,47 +113,49 @@
</div>
</div>
<div class="panel-body">
<form id="settings-add-account-form" class="stack-form">
<label class="field">
<span class="field-label">Account ID</span>
<input
id="settings-add-account-id"
name="account_id"
placeholder="Account ID (e.g. work)"
aria-label="Account ID"
required
/>
<span class="field-hint">Lowercase short id used in file names and URLs.</span>
<form id="settings-add-account-form" class="stack-form">
<label class="field">
<span class="field-label">Account ID</span>
<input
id="settings-add-account-id"
name="account_id"
placeholder="Account ID (e.g. work)"
aria-label="Account ID"
required />
<span class="field-hint">Lowercase short id used in file names and URLs.</span>
</label>
<label class="field">
<span class="field-label">Display name</span>
<input
id="settings-add-account-label"
name="label"
placeholder="Display name"
aria-label="Display name" />
</label>
<label class="field">
<span class="field-label">API ID</span>
<input id="settings-add-account-api-id" name="api_id" placeholder="API ID" aria-label="API ID" />
<span class="field-hint">From my.telegram.org &gt; API development tools.</span>
</label>
<label class="field">
<span class="field-label">API Hash</span>
<input
id="settings-add-account-api-hash"
name="api_hash"
placeholder="API Hash"
aria-label="API Hash" />
<span class="field-hint">Paste the hash exactly as shown on my.telegram.org.</span>
</label>
<button class="button primary button-block" type="submit">Add Account</button>
</form>
<label class="import-account-row">
<span class="field-label">Import account settings JSON</span>
<span class="muted small"
>Choose a file previously exported from Settings. It must be account JSON, for example:</span
>
<span class="file-example">{"account_id": "work", "api_id": 12345, ...}</span>
<input id="settings-import-account-file" type="file" accept="application/json,.json" />
</label>
<label class="field">
<span class="field-label">Display name</span>
<input
id="settings-add-account-label"
name="label"
placeholder="Display name"
aria-label="Display name"
/>
</label>
<label class="field">
<span class="field-label">API ID</span>
<input id="settings-add-account-api-id" name="api_id" placeholder="API ID" aria-label="API ID" />
<span class="field-hint">From my.telegram.org &gt; API development tools.</span>
</label>
<label class="field">
<span class="field-label">API Hash</span>
<input id="settings-add-account-api-hash" name="api_hash" placeholder="API Hash" aria-label="API Hash" />
<span class="field-hint">Paste the hash exactly as shown on my.telegram.org.</span>
</label>
<button class="button primary button-block" type="submit">Add Account</button>
</form>
<label class="import-account-row">
<span class="field-label">Import account settings JSON</span>
<span class="muted small"
>Choose a file previously exported from Settings. It must be account JSON, for example:</span
>
<span class="file-example">{"account_id": "work", "api_id": 12345, ...}</span>
<input id="settings-import-account-file" type="file" accept="application/json,.json" />
</label>
</div>
</div>
@@ -165,60 +167,59 @@
</div>
</div>
<div class="panel-body">
<p class="muted small" id="settings-credentials-hint">
Select an account first, then save API credentials and complete login below.
</p>
<form id="settings-credentials-form" class="stack-form">
<label class="field">
<span class="field-label">API ID</span>
<input id="settings-api-id-input" name="api_id" placeholder="API ID" aria-label="API ID" />
<span class="field-hint">From my.telegram.org &gt; API development tools.</span>
</label>
<label class="field">
<span class="field-label">API Hash</span>
<input id="settings-api-hash-input" name="api_hash" placeholder="API Hash" aria-label="API Hash" />
</label>
<button class="button" type="submit">Save credentials</button>
</form>
<p class="muted small" id="settings-credentials-hint">
Select an account first, then save API credentials and complete login below.
</p>
<form id="settings-credentials-form" class="stack-form">
<label class="field">
<span class="field-label">API ID</span>
<input id="settings-api-id-input" name="api_id" placeholder="API ID" aria-label="API ID" />
<span class="field-hint">From my.telegram.org &gt; API development tools.</span>
</label>
<label class="field">
<span class="field-label">API Hash</span>
<input id="settings-api-hash-input" name="api_hash" placeholder="API Hash" aria-label="API Hash" />
</label>
<button class="button" type="submit">Save credentials</button>
</form>
<div class="auth-actions">
<button class="button primary" id="settings-start-qr-btn" type="button">Start QR login</button>
</div>
<div class="auth-actions">
<button class="button primary" id="settings-start-qr-btn" type="button">Start QR login</button>
</div>
<div id="settings-qr-wrap" class="qr-wrap hidden">
<img id="settings-qr-image" alt="Telegram QR login" />
<p class="muted small">Open Telegram -> Settings -> Devices -> Scan QR.</p>
</div>
<div id="settings-qr-wrap" class="qr-wrap hidden">
<img id="settings-qr-image" alt="Telegram QR login" />
<p class="muted small">Open Telegram -> Settings -> Devices -> Scan QR.</p>
</div>
<form id="settings-phone-form" class="stack-form">
<label class="field">
<span class="field-label">Phone number</span>
<input id="settings-phone-input" name="phone" placeholder="+1234567890" aria-label="Phone number" />
</label>
<button class="button" type="submit">Send code</button>
</form>
<form id="settings-phone-form" class="stack-form">
<label class="field">
<span class="field-label">Phone number</span>
<input id="settings-phone-input" name="phone" placeholder="+1234567890" aria-label="Phone number" />
</label>
<button class="button" type="submit">Send code</button>
</form>
<form id="settings-code-form" class="stack-form hidden">
<label class="field">
<span class="field-label">Telegram code</span>
<input id="settings-code-input" name="code" placeholder="Telegram code" aria-label="Telegram code" />
</label>
<button class="button" type="submit">Confirm code</button>
</form>
<form id="settings-code-form" class="stack-form hidden">
<label class="field">
<span class="field-label">Telegram code</span>
<input id="settings-code-input" name="code" placeholder="Telegram code" aria-label="Telegram code" />
</label>
<button class="button" type="submit">Confirm code</button>
</form>
<form id="settings-password-form" class="stack-form hidden">
<label class="field">
<span class="field-label">2FA password</span>
<input
id="settings-password-input"
name="password"
type="password"
placeholder="2FA password"
aria-label="2FA password"
/>
</label>
<button class="button" type="submit">Confirm password</button>
</form>
<form id="settings-password-form" class="stack-form hidden">
<label class="field">
<span class="field-label">2FA password</span>
<input
id="settings-password-input"
name="password"
type="password"
placeholder="2FA password"
aria-label="2FA password" />
</label>
<button class="button" type="submit">Confirm password</button>
</form>
</div>
</div>
@@ -230,18 +231,18 @@
</div>
</div>
<div class="panel-body">
<label class="toggle-row">
<span>Download media</span>
<span class="switch">
<input id="settings-scrape-media-toggle" type="checkbox" />
<span class="switch-slider"></span>
</span>
</label>
<div class="settings-meta-list">
<div>Tracked channels: <span id="settings-channel-count">0</span></div>
<div>Messages: <span id="settings-message-count">0</span></div>
<div>Media: <span id="settings-media-count">0</span></div>
</div>
<label class="toggle-row">
<span>Download media</span>
<span class="switch">
<input id="settings-scrape-media-toggle" type="checkbox" />
<span class="switch-slider"></span>
</span>
</label>
<div class="settings-meta-list">
<div>Tracked channels: <span id="settings-channel-count">0</span></div>
<div>Messages: <span id="settings-message-count">0</span></div>
<div>Media: <span id="settings-media-count">0</span></div>
</div>
</div>
</div>
</section>
+7 -6
View File
@@ -207,10 +207,7 @@ function renderAccountData() {
setHealthState(document.getElementById('health-credentials'), Boolean(health.api_credentials));
document.getElementById('health-session').textContent =
health.session_ready || isAccountAuthorized(auth) ? 'Ready' : 'Missing';
setHealthState(
document.getElementById('health-session'),
Boolean(health.session_ready || isAccountAuthorized(auth)),
);
setHealthState(document.getElementById('health-session'), Boolean(health.session_ready || isAccountAuthorized(auth)));
document.getElementById('health-continuous').textContent = continuousStatus.running
? 'Running'
: continuousConfig.enabled
@@ -298,7 +295,10 @@ async function importAccount(event) {
await loadAccounts();
await loadAccount(accountId);
showToast(`Imported ${accountId}.`, 'success');
showToast('Credentials (api_id/api_hash) are not exported for security — re-enter them in Settings if needed.', 'warn');
showToast(
'Credentials (api_id/api_hash) are not exported for security — re-enter them in Settings if needed.',
'warn',
);
} catch (err) {
showToast(`Failed to import account: ${err.message}`, 'error');
}
@@ -380,7 +380,8 @@ async function exportAccount() {
async function deleteAccount() {
if (!settingsState.activeAccount) return;
const account = settingsState.accounts.find((item) => item.id === settingsState.activeAccount);
if (!(await confirmAction(`Remove account "${accountLabel(account)}"? All its account data will be deleted.`))) return;
if (!(await confirmAction(`Remove account "${accountLabel(account)}"? All its account data will be deleted.`)))
return;
await api(`/api/accounts/${encodeURIComponent(settingsState.activeAccount)}`, { method: 'DELETE' });
setActiveAccount(null);
await loadAccounts();
+2 -1
View File
@@ -38,7 +38,8 @@
--gutter: 18px;
--gap: 16px;
--font-ui: Inter, 'SF Pro Display', 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
--font-ui:
Inter, 'SF Pro Display', 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
--font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace;
/* Legacy aliases (single system — all map to opaque tokens) */