Add CI/CD pipelines, NSIS installer, ES module bundling, and ruff linting
Lint & Test / test (push) Failing after 9s
Release / create-release (push) Successful in 1s
Release / build-windows (push) Successful in 59s

- Add Gitea Actions workflows: test.yml (lint + test on push/PR) and
  release.yml (build + NSIS installer + upload on v* tags)
- Add NSIS installer with optional desktop shortcut and auto-start
- Add esbuild bundler: ES module migration with IIFE bundle output
- Add build-dist-windows.sh for cross-building Windows distribution
- Fix all ruff lint errors (import sorting, unused imports, line length)
- Remove redundant scripts (start-server.bat, stop-server.bat,
  start-server-background.vbs)
- Update CLAUDE.md with CI/CD and release documentation
This commit is contained in:
2026-03-23 02:01:28 +03:00
parent be48318212
commit 5439af1955
41 changed files with 1702 additions and 310 deletions
+16 -13
View File
@@ -1,11 +1,13 @@
// ============================================================
// Display Brightness & Power Control
// Display Brightness & Power Control + Links Management
// ============================================================
import { t, showToast, escapeHtml, closeDialog, showConfirm, resolveMdiIcons, fetchMdiIcon } from './core.js';
let displayBrightnessTimers = {};
const DISPLAY_THROTTLE_MS = 50;
async function loadDisplayMonitors() {
export async function loadDisplayMonitors() {
const token = localStorage.getItem('media_server_token');
if (!token) return;
@@ -86,7 +88,7 @@ async function loadDisplayMonitors() {
}
}
function onDisplayBrightnessInput(monitorId, value) {
export function onDisplayBrightnessInput(monitorId, value) {
const label = document.getElementById(`brightness-val-${monitorId}`);
if (label) label.textContent = `${value}%`;
@@ -97,7 +99,7 @@ function onDisplayBrightnessInput(monitorId, value) {
}, DISPLAY_THROTTLE_MS);
}
function onDisplayBrightnessChange(monitorId, value) {
export function onDisplayBrightnessChange(monitorId, value) {
if (displayBrightnessTimers[monitorId]) {
clearTimeout(displayBrightnessTimers[monitorId]);
displayBrightnessTimers[monitorId] = null;
@@ -121,7 +123,7 @@ async function sendDisplayBrightness(monitorId, brightness) {
}
}
async function toggleDisplayPower(monitorId, monitorName) {
export async function toggleDisplayPower(monitorId, monitorName) {
const btn = document.getElementById(`power-btn-${monitorId}`);
const isOn = btn && btn.classList.contains('on');
const newState = !isOn;
@@ -157,7 +159,7 @@ async function toggleDisplayPower(monitorId, monitorName) {
// Header Quick Links
// ============================================================
async function loadHeaderLinks() {
export async function loadHeaderLinks() {
const token = localStorage.getItem('media_server_token');
if (!token) return;
@@ -197,9 +199,10 @@ async function loadHeaderLinks() {
// ============================================================
let _loadLinksPromise = null;
let linkFormDirty = false;
export let linkFormDirty = false;
export function setLinkFormDirty(value) { linkFormDirty = value; }
async function loadLinksTable() {
export async function loadLinksTable() {
if (_loadLinksPromise) return _loadLinksPromise;
_loadLinksPromise = _loadLinksTableImpl();
_loadLinksPromise.finally(() => { _loadLinksPromise = null; });
@@ -251,7 +254,7 @@ async function _loadLinksTableImpl() {
}
}
function showAddLinkDialog() {
export function showAddLinkDialog() {
const dialog = document.getElementById('linkDialog');
const form = document.getElementById('linkForm');
const title = document.getElementById('linkDialogTitle');
@@ -269,7 +272,7 @@ function showAddLinkDialog() {
dialog.showModal();
}
async function showEditLinkDialog(linkName) {
export async function showEditLinkDialog(linkName) {
const token = localStorage.getItem('media_server_token');
const dialog = document.getElementById('linkDialog');
const title = document.getElementById('linkDialogTitle');
@@ -320,7 +323,7 @@ async function showEditLinkDialog(linkName) {
}
}
async function closeLinkDialog() {
export async function closeLinkDialog() {
if (linkFormDirty) {
if (!await showConfirm(t('links.confirm.unsaved'))) {
return;
@@ -333,7 +336,7 @@ async function closeLinkDialog() {
document.body.classList.remove('dialog-open');
}
async function saveLink(event) {
export async function saveLink(event) {
event.preventDefault();
const submitBtn = event.target.querySelector('button[type="submit"]');
@@ -385,7 +388,7 @@ async function saveLink(event) {
}
}
async function deleteLinkConfirm(linkName) {
export async function deleteLinkConfirm(linkName) {
if (!await showConfirm(t('links.confirm.delete').replace('{name}', linkName))) {
return;
}