remove REVIEW.md from repo
This commit is contained in:
+46
-42
@@ -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
@@ -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
@@ -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 > 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 > 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 > 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 > 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
@@ -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
@@ -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) */
|
||||
|
||||
Reference in New Issue
Block a user