Update-Pruefung gegen Gitea-Releases ergaenzen
Die App prueft ca. 60 s nach dem Start einmalig, ob auf dem Gitea-Server ein neueres Release vorliegt. Bei einem Treffer erscheint eine Systembenachrichtigung, und ein Symbol im Titelbalken bleibt sichtbar, bis aktualisiert wird -- Klick auf beides oeffnet die Release-Seite im Browser. Ueber die neue Einstellung "Nach Updates suchen" abschaltbar (Standard: aktiv).
This commit is contained in:
+23
-2
@@ -74,6 +74,7 @@ Position wird gemerkt.
|
||||
| Element | Bedeutung |
|
||||
|---|---|
|
||||
| Statuspunkt | Zeigt den Zustand der Datenquellen, siehe unten |
|
||||
| Pfeil-Symbol (nur bei neuem Release) | Öffnet die Release-Seite im Browser |
|
||||
| Zahnrad | Öffnet die Einstellungen |
|
||||
| `–` | Blendet das Fenster aus (Rückkehr über das Tray-Symbol) |
|
||||
|
||||
@@ -121,12 +122,19 @@ Das Zahnrad öffnet den Einstellungsdialog:
|
||||
der Anmeldung.
|
||||
- **Serverabfrage** — kann abgeschaltet werden, falls die Anzeige rein lokal
|
||||
arbeiten soll (dann sind alle Werte Näherungen statt exakter Zahlen).
|
||||
- **Nach Updates suchen** — prüft rund eine Minute nach dem Start einmalig,
|
||||
ob auf dem Projekt-Server eine neuere Version vorliegt. Falls ja,
|
||||
erscheint eine Systembenachrichtigung, und ein Pfeil-Symbol im
|
||||
Titelbalken bleibt sichtbar, bis aktualisiert wird. Klick auf
|
||||
Benachrichtigung oder Symbol öffnet die Release-Seite im Browser. Diese
|
||||
Einstellung wirkt erst beim nächsten Start.
|
||||
- **Bezugsgrößen, Gewichtung, Wochenfenster** — fortgeschrittene Feineinstellungen
|
||||
für den Fall, dass die Serverabfrage dauerhaft nicht zur Verfügung steht;
|
||||
im Normalbetrieb müssen Sie hier nichts anpassen.
|
||||
|
||||
Änderungen wirken sofort, ein Neustart ist nicht nötig. `Strg`+`S` speichert,
|
||||
`Esc` schließt den Dialog ohne zu speichern.
|
||||
Änderungen wirken sofort, ein Neustart ist nicht nötig (Ausnahme: „Nach
|
||||
Updates suchen", siehe oben). `Strg`+`S` speichert, `Esc` schließt den
|
||||
Dialog ohne zu speichern.
|
||||
|
||||
## Tray-Menü
|
||||
|
||||
@@ -154,6 +162,10 @@ und Beenden.
|
||||
selbst profitiert automatisch davon. Das geschieht ausschließlich auf
|
||||
Klick, nie automatisch im Hintergrund, und auch dabei wird kein Token
|
||||
protokolliert.
|
||||
- Ist „Nach Updates suchen" aktiviert, fragt die Anwendung rund eine Minute
|
||||
nach dem Start einmalig den selbst gehosteten Gitea-Server
|
||||
(`git.conatum.net`) nach der neuesten Versionsnummer ab — ohne
|
||||
Zugriffstoken und ohne weitere Daten. Abschaltbar in den Einstellungen.
|
||||
- Es findet keine Übertragung an Dritte statt.
|
||||
|
||||
## Deinstallation
|
||||
@@ -188,3 +200,12 @@ Abschnitt „Installation“ oben.
|
||||
**Nach einem Update sehe ich eine Benachrichtigung.** Das ist beabsichtigt:
|
||||
Die Anwendung erkennt neue Versionen automatisch und weist einmalig darauf
|
||||
hin. Ihre Einstellungen und Kalibrierung bleiben davon unberührt.
|
||||
|
||||
**Ich bekomme eine Benachrichtigung über eine neue Version / ein
|
||||
Pfeil-Symbol erscheint im Titelbalken.** Das ist eine andere Meldung als
|
||||
oben: Die Anwendung hat rund eine Minute nach dem Start auf dem
|
||||
Projekt-Server ein neueres Release gefunden. Ein Klick auf Benachrichtigung
|
||||
oder Symbol öffnet die Release-Seite im Browser — heruntergeladen oder
|
||||
installiert wird nichts automatisch. Das Symbol bleibt sichtbar, bis eine
|
||||
neuere Version installiert wurde. Abschaltbar über die Einstellung „Nach
|
||||
Updates suchen".
|
||||
|
||||
@@ -276,6 +276,19 @@ npm run dist
|
||||
`npm version` legt standardmäßig auch einen Git-Commit und -Tag an; ohne das
|
||||
genügt es, `version` in `package.json` von Hand zu ändern.
|
||||
|
||||
### Update-Prüfung beim Gitea-Server
|
||||
|
||||
Zusätzlich zur lokalen Erkennung oben prüft die Anwendung ca. 60 s nach dem
|
||||
Start einmalig aktiv, ob auf dem selbst gehosteten Gitea-Server
|
||||
(`git.conatum.net`, Repo `swinks/claude-live-dashboard`) ein neueres Release
|
||||
vorliegt (`GET .../releases/latest`, öffentlich ohne Authentifizierung). Bei
|
||||
einer neueren Version erscheint eine native Systembenachrichtigung, und ein
|
||||
Symbol im Titelbalken (zwischen Endpunkt-Status und Zahnrad) bleibt
|
||||
sichtbar, bis aktualisiert wird. Ein Klick auf Benachrichtigung oder Symbol
|
||||
öffnet die Release-Seite im Standardbrowser. Über die Einstellung „Nach
|
||||
Updates suchen" lässt sich dieser Netzwerkaufruf beim Start abschalten
|
||||
(`config.json:updateCheck.enabled`, Standard `true`).
|
||||
|
||||
## Release bauen
|
||||
|
||||
Gebaut wird jeweils auf dem Zielsystem — electron-builder kann `.deb` nicht
|
||||
|
||||
@@ -26,5 +26,9 @@
|
||||
"_oauth": "Serverabfrage für exakte Werte. Standardmäßig aktiv; mit enabled:false abschalten. endpoint nur setzen, um den Standard zu überschreiben.",
|
||||
"oauth": {
|
||||
"enabled": true
|
||||
},
|
||||
"_updateCheck": "Prüft ca. 60 s nach dem Start einmalig beim Gitea-Server auf ein neueres Release. Standardmäßig aktiv; mit enabled:false abschalten.",
|
||||
"updateCheck": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ const SOURCE_LABEL = {
|
||||
oauth: 'Server',
|
||||
app: 'App',
|
||||
refresh: 'Token',
|
||||
update: 'Update',
|
||||
};
|
||||
|
||||
let feedbackTimer = null;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
--good: #0ca30c;
|
||||
--warning: #fab219;
|
||||
--critical: #d03b3b;
|
||||
--update: #9b6bd6;
|
||||
|
||||
--font: system-ui, -apple-system, "Segoe UI", sans-serif;
|
||||
}
|
||||
@@ -228,6 +229,10 @@ dd[data-severity="critical"] .status-label {
|
||||
color: var(--good);
|
||||
}
|
||||
|
||||
.log-source[data-source="update"] {
|
||||
color: var(--update);
|
||||
}
|
||||
|
||||
.log-message {
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.4;
|
||||
|
||||
@@ -77,6 +77,11 @@ class Collector extends EventEmitter {
|
||||
this.errors = Array.isArray(store.data.errors) ? store.data.errors : [];
|
||||
this._localOk = true;
|
||||
this._lastOauthError = null;
|
||||
// Für das Titelleisten-Symbol: bleibt für die gesamte Sitzung gesetzt,
|
||||
// sobald ein neueres Release gefunden wurde — bewusst nicht gedrosselt
|
||||
// wie die Notification (store.data.updateCheck.notifiedTag), das Symbol
|
||||
// soll sichtbar bleiben, bis aktualisiert wird.
|
||||
this._updateAvailable = null;
|
||||
if (configError) this._note(configError, 'local');
|
||||
if (versionEvent) {
|
||||
const msg =
|
||||
@@ -214,6 +219,24 @@ class Collector extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hält ein gefundenes neueres Release fest — im Ereignisprotokoll (einmalig
|
||||
* pro Tag, dedupliziert über _note()) und als Live-State fürs
|
||||
* Titelleisten-Symbol (state.update, bleibt für die Sitzung gesetzt).
|
||||
* Ausgelöst einmalig ca. 60 s nach dem Start (siehe index.js/update-check.js).
|
||||
*/
|
||||
noteUpdateAvailable(tagName, htmlUrl) {
|
||||
this._updateAvailable = { tagName, htmlUrl };
|
||||
this._note(`Neue Version verfügbar: ${tagName} (${htmlUrl})`, 'update');
|
||||
this._recompute().catch(() => {});
|
||||
}
|
||||
|
||||
/** Hält einen gescheiterten Update-Check fest — stört den Betrieb nie, nur Protokoll. */
|
||||
noteUpdateCheckError(message) {
|
||||
this._note(`Update-Prüfung fehlgeschlagen: ${message}`, 'update');
|
||||
this._recompute().catch(() => {});
|
||||
}
|
||||
|
||||
async _poll() {
|
||||
if (this._polling) {
|
||||
this._pollAgain = true;
|
||||
@@ -411,6 +434,12 @@ class Collector extends EventEmitter {
|
||||
local: { ok: this._localOk },
|
||||
oauth: { ok: !oauthError, text: this.oauth.status().text },
|
||||
},
|
||||
// Titelleisten-Symbol: bleibt sichtbar, bis die Sitzung endet oder
|
||||
// aktualisiert wird — bewusst kein „gesehen"-Zustand wie bei der
|
||||
// Notification (store.data.updateCheck.notifiedTag).
|
||||
update: this._updateAvailable
|
||||
? { available: true, tagName: this._updateAvailable.tagName, htmlUrl: this._updateAvailable.htmlUrl }
|
||||
: { available: false, tagName: null, htmlUrl: null },
|
||||
errors: this.errors.slice(),
|
||||
stats: { lastPollMs: this._lastPollMs },
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ const { Store, loadConfig } = require('./store');
|
||||
const { Collector } = require('./collector');
|
||||
const { CONFIG_FILE, STATE_FILE, USER_DATA_DIR, ensureUserConfig } = require('./paths');
|
||||
const { getAutostart, setAutostart: applyAutostart } = require('./autostart');
|
||||
const { checkForUpdate } = require('./update-check');
|
||||
|
||||
const IS_LINUX = process.platform === 'linux';
|
||||
|
||||
@@ -29,6 +30,10 @@ const SETTINGS_HEIGHT = 660;
|
||||
const ERRORS_WIDTH = 420;
|
||||
const ERRORS_HEIGHT = 480;
|
||||
|
||||
/** Wartezeit vor der einmaligen Update-Prüfung — verzögert, damit sie den
|
||||
* Start nicht verlangsamt und nicht mit dem ersten Poll konkurriert. */
|
||||
const UPDATE_CHECK_DELAY_MS = 60 * 1000;
|
||||
|
||||
let win = null;
|
||||
let settingsWin = null;
|
||||
let errorsWin = null;
|
||||
@@ -410,6 +415,10 @@ function registerIpc() {
|
||||
if (!collector) return { ok: false, error: 'Anwendung startet noch' };
|
||||
return collector.refreshOauthToken();
|
||||
});
|
||||
ipcMain.on('open-release-page', () => {
|
||||
const info = collector?.state?.update;
|
||||
if (info?.available && info.htmlUrl) shell.openExternal(info.htmlUrl);
|
||||
});
|
||||
|
||||
ipcMain.handle('settings:load', () => ({
|
||||
config,
|
||||
@@ -509,6 +518,45 @@ async function main() {
|
||||
} catch (err) {
|
||||
console.error('[collector] Start fehlgeschlagen:', err);
|
||||
}
|
||||
|
||||
if (config.updateCheck?.enabled !== false) {
|
||||
const updateTimer = setTimeout(() => {
|
||||
checkForUpdate(app.getVersion())
|
||||
.then((result) => {
|
||||
console.log(result ? `[update-check] neue Version: ${result.tagName}` : '[update-check] keine neuere Version verfügbar');
|
||||
if (!result || !collector) return;
|
||||
|
||||
// Titelleisten-Symbol: sofort sichtbar, unabhängig von der
|
||||
// Notification-Drossel unten.
|
||||
collector.noteUpdateAvailable(result.tagName, result.htmlUrl);
|
||||
|
||||
// Notification nur einmal pro neu erschienenem Tag — sonst würde sie
|
||||
// bei jedem Start erneut aufpoppen, solange der Nutzer nicht
|
||||
// aktualisiert (die App läuft typischerweise per Autostart täglich).
|
||||
const alreadyNotified = store.data.updateCheck?.notifiedTag === result.tagName;
|
||||
store.data.updateCheck = { notifiedTag: result.tagName };
|
||||
store.save();
|
||||
if (alreadyNotified || !Notification.isSupported()) return;
|
||||
|
||||
const notification = new Notification({
|
||||
title: 'Neue Version verfügbar',
|
||||
body: `${result.tagName} steht bereit. Klicken, um die Release-Seite zu öffnen.`,
|
||||
icon: path.join(ROOT, 'assets', 'icon.png'),
|
||||
});
|
||||
notification.on('click', () => shell.openExternal(result.htmlUrl));
|
||||
notification.show();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn('[update-check] fehlgeschlagen:', err.message);
|
||||
if (collector) collector.noteUpdateCheckError(err.message);
|
||||
});
|
||||
}, UPDATE_CHECK_DELAY_MS);
|
||||
// Darf den App-Exit nie blockieren — anders als collector._timers wird
|
||||
// dieser einmalige Main-Prozess-Timer nicht von collector.stop() erfasst.
|
||||
if (updateTimer.unref) updateTimer.unref();
|
||||
} else {
|
||||
console.log('[update-check] übersprungen (in den Einstellungen deaktiviert)');
|
||||
}
|
||||
}
|
||||
|
||||
// Das Widget lebt im Tray weiter, auch wenn kein Fenster offen ist.
|
||||
|
||||
@@ -30,6 +30,9 @@ const DEFAULT_STATE = {
|
||||
errors: [],
|
||||
// Zuletzt gestartete App-Version, für die Neuinstallations-/Update-Erkennung.
|
||||
appVersion: null,
|
||||
// Zuletzt per Notification gemeldeter Release-Tag — verhindert, dass
|
||||
// dieselbe neue Version bei jedem Start erneut als Popup erscheint.
|
||||
updateCheck: { notifiedTag: null },
|
||||
};
|
||||
|
||||
class Store {
|
||||
@@ -54,6 +57,7 @@ class Store {
|
||||
window: { ...DEFAULT_STATE.window, ...(parsed.window || {}) },
|
||||
oauth: { ...DEFAULT_STATE.oauth, ...(parsed.oauth || {}) },
|
||||
oauthRefresh: { ...DEFAULT_STATE.oauthRefresh, ...(parsed.oauthRefresh || {}) },
|
||||
updateCheck: { ...DEFAULT_STATE.updateCheck, ...(parsed.updateCheck || {}) },
|
||||
errors: Array.isArray(parsed.errors) ? parsed.errors : [],
|
||||
};
|
||||
} catch (err) {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Einmalige Update-Prüfung, ca. 60 s nach dem Start ausgelöst (siehe
|
||||
* index.js). Fragt das öffentliche Gitea-API des eigenen Repos nach dem
|
||||
* neuesten Release ab — kein Zugriffstoken nötig, der Endpunkt ist ohne
|
||||
* Authentifizierung erreichbar (verifiziert per curl).
|
||||
*
|
||||
* Bewusst zustandslos und ohne Wiederholungslogik: Ein Check pro Sitzung
|
||||
* genügt der Anforderung „einmalig prüfen". Persistenz (welches Release
|
||||
* schon einmal per Notification gemeldet wurde) lebt bewusst außerhalb
|
||||
* dieses Moduls, in index.js/store.js.
|
||||
*/
|
||||
|
||||
const RELEASES_URL =
|
||||
'https://git.conatum.net/api/v1/repos/swinks/claude-live-dashboard/releases/latest';
|
||||
const ALLOWED_HOST = 'git.conatum.net';
|
||||
const REQUEST_TIMEOUT_MS = 10000;
|
||||
|
||||
/**
|
||||
* Vergleicht zwei MAJOR.MINOR.PATCH-Versionen ohne Suffixe.
|
||||
* @returns {number} negativ wenn a<b, 0 wenn gleich, positiv wenn a>b
|
||||
*/
|
||||
function compareVersions(a, b) {
|
||||
const pa = String(a).split('.').map(Number);
|
||||
const pb = String(b).split('.').map(Number);
|
||||
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
||||
const diff = (pa[i] || 0) - (pb[i] || 0);
|
||||
if (diff !== 0) return diff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fragt das neueste Release ab und vergleicht dessen Tag gegen currentVersion.
|
||||
* Drafts und Pre-Releases werden ignoriert.
|
||||
* @param {string} currentVersion z. B. app.getVersion() (ohne führendes "v")
|
||||
* @returns {Promise<{tagName: string, htmlUrl: string} | null>}
|
||||
*/
|
||||
async function checkForUpdate(currentVersion) {
|
||||
const url = new URL(RELEASES_URL);
|
||||
if (url.protocol !== 'https:' || url.hostname !== ALLOWED_HOST) {
|
||||
throw new Error('Gitea-Endpunkt zeigt nicht auf den erwarteten Host');
|
||||
}
|
||||
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
||||
try {
|
||||
const res = await fetch(RELEASES_URL, {
|
||||
method: 'GET',
|
||||
signal: controller.signal,
|
||||
headers: { Accept: 'application/json' },
|
||||
});
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
|
||||
const json = await res.json();
|
||||
if (json.draft || json.prerelease) return null;
|
||||
|
||||
const remoteVersion = String(json.tag_name || '').replace(/^v/, '').trim();
|
||||
if (!remoteVersion) return null;
|
||||
if (compareVersions(remoteVersion, currentVersion) <= 0) return null;
|
||||
|
||||
return { tagName: String(json.tag_name), htmlUrl: json.html_url };
|
||||
} catch (err) {
|
||||
throw new Error(err.name === 'AbortError' ? 'Zeitüberschreitung' : err.message);
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { checkForUpdate, compareVersions, RELEASES_URL };
|
||||
@@ -24,4 +24,6 @@ contextBridge.exposeInMainWorld('dashboard', {
|
||||
openSettings: () => ipcRenderer.send('open-settings'),
|
||||
/** Öffnet das Fehler-/Ereignis-Log. */
|
||||
openErrorLog: () => ipcRenderer.send('open-error-log'),
|
||||
/** Öffnet die Release-Seite eines gefundenen neuen Updates im Browser. */
|
||||
openReleasePage: () => ipcRenderer.send('open-release-page'),
|
||||
});
|
||||
|
||||
@@ -47,6 +47,7 @@ const el = {
|
||||
planLabel: $('plan-label'),
|
||||
staleBadge: $('stale-badge'),
|
||||
btnEndpointStatus: $('btn-endpoint-status'),
|
||||
btnUpdateAvailable: $('btn-update-available'),
|
||||
btnHide: $('btn-hide'),
|
||||
btnSettings: $('btn-settings'),
|
||||
btnExpand: $('btn-expand'),
|
||||
@@ -284,6 +285,15 @@ function renderEndpointStatus(s) {
|
||||
`Serverabfrage: ${ep.oauth.text || '—'}`;
|
||||
}
|
||||
|
||||
/** Titelleisten-Symbol für ein gefundenes neues Release. */
|
||||
function renderUpdateAvailable(s) {
|
||||
const update = s.update || { available: false };
|
||||
el.btnUpdateAvailable.hidden = !update.available;
|
||||
if (update.available) {
|
||||
el.btnUpdateAvailable.title = `Version ${update.tagName} verfügbar — Release-Seite öffnen`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderWeek(week, burn) {
|
||||
renderMeter('week', week);
|
||||
renderProjection(el.weekProjection, week.percent, burn.weekProjectedPercent, week.severity);
|
||||
@@ -397,6 +407,7 @@ function render(s) {
|
||||
renderWeek(s.week, s.burn);
|
||||
renderSpend(s.spend);
|
||||
renderEndpointStatus(s);
|
||||
renderUpdateAvailable(s);
|
||||
|
||||
if (expanded) {
|
||||
renderModels(s.block);
|
||||
@@ -462,6 +473,7 @@ el.btnExpand.addEventListener('click', () => applyExpanded(!expanded));
|
||||
el.btnHide.addEventListener('click', () => window.dashboard.hide());
|
||||
el.btnSettings.addEventListener('click', () => window.dashboard.openSettings());
|
||||
el.btnEndpointStatus.addEventListener('click', () => window.dashboard.openErrorLog());
|
||||
el.btnUpdateAvailable.addEventListener('click', () => window.dashboard.openReleasePage());
|
||||
|
||||
window.dashboard.onState(render);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<button class="icon-btn status" id="btn-endpoint-status" data-severity="ok" title="Endpunkt-Status" aria-label="Endpunkt-Status">
|
||||
<span class="status-icon" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button class="icon-btn" id="btn-update-available" hidden title="Neues Release verfügbar" aria-label="Neues Release verfügbar">↑</button>
|
||||
<button class="icon-btn" id="btn-settings" title="Einstellungen" aria-label="Einstellungen">
|
||||
<svg viewBox="0 0 16 16" width="13" height="13" aria-hidden="true" focusable="false">
|
||||
<path
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
--status-good: #0ca30c;
|
||||
--status-warning: #fab219;
|
||||
--status-critical: #d03b3b;
|
||||
--status-update: #9b6bd6;
|
||||
|
||||
/* Kategoriale Slots (dunkle Stufen), fest je Modellfamilie vergeben */
|
||||
--series-1: #3987e5;
|
||||
@@ -152,6 +153,10 @@ body {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
#btn-update-available {
|
||||
color: var(--status-update);
|
||||
}
|
||||
|
||||
/* ── Meter ───────────────────────────────────────────────────────────── */
|
||||
|
||||
.meters {
|
||||
|
||||
@@ -21,6 +21,7 @@ const el = {
|
||||
clickThrough: $('clickThrough'),
|
||||
autostart: $('autostart'),
|
||||
autostartLabel: $('autostart-label'),
|
||||
updateCheckEnabled: $('updateCheckEnabled'),
|
||||
|
||||
oauthEnabled: $('oauthEnabled'),
|
||||
oauthEndpoint: $('oauthEndpoint'),
|
||||
@@ -84,6 +85,9 @@ function fill(config, meta) {
|
||||
el.autostartLabel.textContent =
|
||||
meta.platform === 'win32' ? 'Mit Windows starten' : 'Mit dem System starten';
|
||||
|
||||
const updateCheck = config.updateCheck || {};
|
||||
el.updateCheckEnabled.checked = updateCheck.enabled !== false;
|
||||
|
||||
const oauth = config.oauth || {};
|
||||
el.oauthEnabled.checked = oauth.enabled !== false;
|
||||
el.oauthEndpoint.value = oauth.endpoint || '';
|
||||
@@ -137,6 +141,7 @@ function collect() {
|
||||
|
||||
patch.opacity = Number(el.opacity.value) / 100;
|
||||
patch.clickThrough = el.clickThrough.checked;
|
||||
patch.updateCheck = { enabled: el.updateCheckEnabled.checked };
|
||||
|
||||
patch.oauth = { enabled: el.oauthEnabled.checked };
|
||||
const endpoint = el.oauthEndpoint.value.trim();
|
||||
|
||||
@@ -42,6 +42,17 @@
|
||||
<span class="hint">Wird sofort übernommen, unabhängig vom Speichern.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label for="updateCheckEnabled">Nach Updates suchen</label>
|
||||
<div class="control">
|
||||
<input type="checkbox" id="updateCheckEnabled" />
|
||||
<span class="hint">
|
||||
Prüft rund eine Minute nach dem Start einmalig auf dem
|
||||
Projekt-Server, ob eine neuere Version vorliegt.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="group">
|
||||
|
||||
Reference in New Issue
Block a user