From c55db5e4f76f4eefba57eae4a3b66ec41b48e4fa Mon Sep 17 00:00:00 2001 From: rdkartono Date: Wed, 1 Oct 2025 13:57:20 +0700 Subject: [PATCH] commit 01/10/2025 --- .../assets/css/Login-Form-Basic-icons.css | 17 + html/webpage/assets/css/styles.css | 71 ++- html/webpage/assets/js/broadcastzones.js | 50 +-- html/webpage/assets/js/languagelink.js | 40 +- html/webpage/assets/js/log.js | 32 +- html/webpage/assets/js/messagebank.js | 40 +- html/webpage/assets/js/schedulebank.js | 26 +- html/webpage/assets/js/script.js | 104 +++-- html/webpage/assets/js/soundbank.js | 54 +-- html/webpage/assets/js/soundchannel.js | 29 +- html/webpage/assets/js/usermanagement.js | 128 ++++++ html/webpage/broadcastzones.html | 70 +-- html/webpage/home.html | 4 + html/webpage/language.html | 16 +- html/webpage/log.html | 13 +- html/webpage/messagebank.html | 28 +- html/webpage/overview.html | 414 +++++++++--------- html/webpage/setting.html | 2 +- html/webpage/soundbank.html | 30 +- html/webpage/streamerstatus.html | 8 +- html/webpage/timer.html | 62 +-- html/webpage/usermanagement.html | 153 +++++++ src/web/WebApp.kt | 21 +- 23 files changed, 895 insertions(+), 517 deletions(-) create mode 100644 html/webpage/assets/js/usermanagement.js create mode 100644 html/webpage/usermanagement.html diff --git a/html/webpage/assets/css/Login-Form-Basic-icons.css b/html/webpage/assets/css/Login-Form-Basic-icons.css index 7bf803b..a732f70 100644 --- a/html/webpage/assets/css/Login-Form-Basic-icons.css +++ b/html/webpage/assets/css/Login-Form-Basic-icons.css @@ -60,3 +60,20 @@ align-items: center; } +.pad-relay { + padding-left: 1.5rem; + padding-top: 0.5rem; +} + +.pad-time { + margin: 0.7rem auto; +} + +.pad-day { + margin-top: 0.5rem; +} + +.class100 { + width: 100% !important; +} + diff --git a/html/webpage/assets/css/styles.css b/html/webpage/assets/css/styles.css index bb49fba..06d32fc 100644 --- a/html/webpage/assets/css/styles.css +++ b/html/webpage/assets/css/styles.css @@ -1,5 +1,6 @@ body { background-color: #f8f9fd; + /*background-color: #edf1fb;*/ overflow-x: hidden; width: 100%; } @@ -13,8 +14,9 @@ body { } .search { - display: flex; - align-items: center; + /*display: flex;*/ + /*align-items: center;*/ + margin-top: -0.2rem; } .text-header { @@ -188,3 +190,68 @@ nav-item:focus { border: none; } +.pad-card { + padding-top: 1rem; +} + +.pad-search { + padding-top: 0.5rem; +} + +.pad-row-search { + margin-bottom: 0.7rem; +} + +.bg-heading1 { + background-color: #c6d8ee; + color: #2d3578; +} + +.bg-heading2 { + background-color: #dce5f4; + color: #2d3578; +} + +.bg-heading3 { + background-color: #e9ecf8; + color: #2d3578; +} + +.accordion-item { + /*background: rgba(255, 255, 255, 0.55);*/ + /*backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px);*/ + /*border-radius: 16px;*/ + /*box-shadow: 8px 8px 16px rgba(0, 0, 0, 0.12), -8px -8px 16px rgba(255, 255, 255, 0.6);*/ + /*transition: all 0.3s ease;*/ +} + +.accordion-item.active { + /*background: rgba(45, 53, 120, 0.15);*/ + /*box-shadow: inset 4px 4px 10px rgba(45, 53, 120, 0.25), inset -4px -4px 10px rgba(255, 255, 255, 0.8);*/ +} + +.bg-accordion { + border: white 2px; + /*border-radius: 10px;*/ + background: #f8f9fd; +} + +.card-channel { + border-radius: 12px; + background: #ffffff; + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + transition: transform 0.2s ease, box-shadow 0.2s ease; + border: #ffffff solid 2px !important; + /*padding-left: 2px;*/ + /*padding-right: 5px;*/ + padding-top: 12px; + padding-bottom: 12px; +} + +.pad-accordion { + border-radius: 40px; + border: white solid 3px; +} + diff --git a/html/webpage/assets/js/broadcastzones.js b/html/webpage/assets/js/broadcastzones.js index bfa21f5..f3bf763 100644 --- a/html/webpage/assets/js/broadcastzones.js +++ b/html/webpage/assets/js/broadcastzones.js @@ -11,13 +11,13 @@ * List of broadcast zones available * @type {BroadcastZone[]} */ -let BroadcastZoneList = []; +window.BroadcastZoneList ??= []; /** * Currently selected broadcast zone row in the table * @type {JQuery|null} */ -let selectedBroadcastZoneRow = null; +window.selectedBroadcastZoneRow = null; /** * Fill broadcast zone table body with values @@ -31,23 +31,23 @@ function fill_broadcastzonetablebody(vv) { ${item.index} ${item.description} ${item.soundChannel} - ${item.box} - ${item.relay} + ${item.id} + ${item.bp} `; $('#broadcastzonetablebody').append(row); let $addedrow = $('#broadcastzonetablebody tr:last'); $addedrow.click(function () { - if (selectedBroadcastZoneRow) { - selectedBroadcastZoneRow.find('td').css('background-color', ''); - if (selectedBroadcastZoneRow.is($(this))) { - selectedBroadcastZoneRow = null; + if (window.selectedBroadcastZoneRow) { + window.selectedBroadcastZoneRow.find('td').css('background-color', ''); + if (window.selectedBroadcastZoneRow.is($(this))) { + window.selectedBroadcastZoneRow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $(this).find('td').css('background-color', '#ffeeba'); - selectedBroadcastZoneRow = $(this); + window.selectedBroadcastZoneRow = $(this); $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); @@ -60,12 +60,12 @@ function fill_broadcastzonetablebody(vv) { * @param {String} APIURL API URL endpoint (default "BroadcastZones/") */ function reloadBroadcastZones(APIURL = "BroadcastZones/") { - BroadcastZoneList = []; + window.BroadcastZoneList = []; fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { //console.log("reloadBroadcastZones : ", okdata) - BroadcastZoneList = okdata; - fill_broadcastzonetablebody(BroadcastZoneList); + window.BroadcastZoneList.push(...okdata); + fill_broadcastzonetablebody(window.BroadcastZoneList); } else console.log("reloadBroadcastZones: okdata is not array"); }, (errdata) => { alert("Error loading broadcast zones : " + errdata.message); @@ -74,7 +74,7 @@ function reloadBroadcastZones(APIURL = "BroadcastZones/") { $(document).ready(function () { console.log("broadcastzones.js loaded successfully"); - selectedBroadcastZoneRow = null; + window.selectedBroadcastZoneRow = null; let $btnClear = $('#btnClear'); let $btnAdd = $('#btnAdd'); let $btnEdit = $('#btnEdit'); @@ -98,12 +98,12 @@ $(document).ready(function () { $findzone.on('input', function () { let searchTerm = $findzone.val().trim().toLowerCase(); if (searchTerm.length > 0) { - selectedBroadcastZoneRow = null; - let filtered = broadcastzonedata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.box.toLowerCase().includes(searchTerm) || item.soundChannel.toLowerCase().includes(searchTerm) || item.relay.toLowerCase().includes(searchTerm)); + window.selectedBroadcastZoneRow = null; + let filtered = window.BroadcastZoneList.filter(item => item.description.toLowerCase().includes(searchTerm) || item.id.toLowerCase().includes(searchTerm) || item.soundChannel.toLowerCase().includes(searchTerm) || item.bp.toLowerCase().includes(searchTerm)); fill_broadcastzonetablebody(filtered); } else { - selectedBroadcastZoneRow = null; - fill_broadcastzonetablebody(broadcastzonedata); + window.selectedBroadcastZoneRow = null; + fill_broadcastzonetablebody(window.BroadcastZoneList); } }); @@ -204,8 +204,8 @@ $(document).ready(function () { }); $btnRemove.click(() => { - if (selectedBroadcastZoneRow) { - let cells = selectedBroadcastZoneRow.find('td'); + if (window.selectedBroadcastZoneRow) { + let cells = window.selectedBroadcastZoneRow.find('td'); /** @type {BroadcastZone} */ let bz = { index: cells.eq(0).text(), @@ -226,8 +226,8 @@ $(document).ready(function () { }); $btnEdit.click(() => { - if (selectedBroadcastZoneRow) { - let cells = selectedBroadcastZoneRow.find('td'); + if (window.selectedBroadcastZoneRow) { + let cells = window.selectedBroadcastZoneRow.find('td'); /** @type {BroadcastZone} */ let bz = { index: cells.eq(0).text(), @@ -236,15 +236,15 @@ $(document).ready(function () { Box: cells.eq(3).text(), Relay: cells.eq(4).text() }; - if (confirm(`Are you sure to edit broadcast zone [${bz.index}] Description=${bz.description} SoundChannel=${bz.SoundChannel} Box=${bz.Box} Relay=${bz.Relay}?`)) { + if (confirm(`Are you sure to edit broadcast zone [${bz.index}] Description=${bz.description} SoundChannel=${bz.SoundChannel} Box=${bz.id} Relay=${bz.bp}?`)) { $broadcastzonemodal.modal('show'); clearBroadcastZoneModal(); $broadcastzoneindex.val(bz.index); $broadcastzonedescription.val(bz.description); $broadcastzonesoundchannel.val(bz.SoundChannel); - $broadcastzonebox.val(bz.Box); - if (bz.Relay) { - bz.Relay.split(';').forEach(relayId => { + $broadcastzonebox.val(bz.id); + if (bz.bp) { + bz.bp.split(';').forEach(relayId => { let id = parseInt(relayId, 10); cbRelay(id).prop('checked', true); }); diff --git a/html/webpage/assets/js/languagelink.js b/html/webpage/assets/js/languagelink.js index 638a498..d48b31c 100644 --- a/html/webpage/assets/js/languagelink.js +++ b/html/webpage/assets/js/languagelink.js @@ -9,12 +9,12 @@ /** List of Languagebank data loaded from server * @type {LanguageBank[]} */ -let languagebankdata = []; +window.languagebankdata = []; /** * Currently selected languagebank row in the table * @type {JQuery|null} */ -let selectedlanguagerow = null; +window.selectedlanguagerow = null; /** * Fill languagebank table body with values @@ -32,17 +32,17 @@ function fill_languagebanktablebody(vv) { $('#languagebanktablebody').append(row); let $addedrow = $('#languagebanktablebody tr:last'); $addedrow.click(function () { - if (selectedlanguagerow) { - selectedlanguagerow.find('td').css('background-color', ''); - if (selectedlanguagerow.is($(this))) { - selectedlanguagerow = null; + if (window.selectedlanguagerow) { + window.selectedlanguagerow.find('td').css('background-color', ''); + if (window.selectedlanguagerow.is($(this))) { + window.selectedlanguagerow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $addedrow.find('td').css('background-color', '#ffeeba'); - selectedlanguagerow = $addedrow; + window.selectedlanguagerow = $addedrow; $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); @@ -55,12 +55,12 @@ function fill_languagebanktablebody(vv) { * @param {string} APIURL API URL endpoint, default "LanguageLink/" */ function reloadLanguageBank(APIURL = "LanguageLink/") { - languagebankdata = []; + window.languagebankdata = []; fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { - languagebankdata = okdata; - selectedlanguagerow = null; - fill_languagebanktablebody(languagebankdata); + window.languagebankdata.push(...okdata); + window.selectedlanguagerow = null; + fill_languagebanktablebody(window.languagebankdata); } }, (errdata) => { alert("Error loading languagebank : " + errdata.message); @@ -71,7 +71,7 @@ $(document).ready(function () { console.log('languagebank.js loaded'); $('#languagebanktablebody').empty(); - selectedlanguagerow = null; + window.selectedlanguagerow = null; let $btnClear = $('#btnClear'); let $btnAdd = $('#btnAdd'); let $btnRemove = $('#btnRemove'); @@ -106,12 +106,12 @@ $(document).ready(function () { $findlanguage.on('input', function () { let searchTerm = $findlanguage.val().toLowerCase(); if (searchTerm.length > 0) { - selectedlanguagerow = null; - let filtered = languagebankdata.filter(item => item.tag.toLowerCase().includes(searchTerm) || item.language.toLowerCase().includes(searchTerm)); + window.selectedlanguagerow = null; + let filtered = window.languagebankdata.filter(item => item.tag.toLowerCase().includes(searchTerm) || item.language.toLowerCase().includes(searchTerm)); fill_languagebanktablebody(filtered); } else { - selectedlanguagerow = null; - fill_languagebanktablebody(languagebankdata); + window.selectedlanguagerow = null; + fill_languagebanktablebody(window.languagebankdata); } }); @@ -171,8 +171,8 @@ $(document).ready(function () { }); }); $btnRemove.click(() => { - if (selectedlanguagerow) { - let cells = selectedlanguagerow.find('td'); + if (window.selectedlanguagerow) { + let cells = window.selectedlanguagerow.find('td'); /** @type {Language} */ let ll = { index: cells.eq(0).text(), @@ -190,8 +190,8 @@ $(document).ready(function () { } }); $btnEdit.click(() => { - if (selectedlanguagerow) { - let cells = selectedlanguagerow.find('td'); + if (window.selectedlanguagerow) { + let cells = window.selectedlanguagerow.find('td'); /** @type {Language} */ let ll = { index: cells.eq(0).text(), diff --git a/html/webpage/assets/js/log.js b/html/webpage/assets/js/log.js index 8401eb6..793e1ee 100644 --- a/html/webpage/assets/js/log.js +++ b/html/webpage/assets/js/log.js @@ -10,7 +10,7 @@ /** List of Log data loaded from server * @type {Log[]} */ -let logdata = []; +window.logdata = []; /** * Fill log table body with values @@ -18,9 +18,11 @@ let logdata = []; */ function fill_logtablebody(vv) { $('#logtablebody').empty(); - $('#btnExport').prop('disabled', true); - $('#searchfilter').prop('disabled', true); - if (!Array.isArray(vv) || vv.length === 0) return; + + if (!Array.isArray(vv) || vv.length === 0) { + $('#btnExport').prop('disabled', true); + return; + } vv.forEach(item => { const row = ` ${item.index} @@ -33,7 +35,6 @@ function fill_logtablebody(vv) { }); $('#tablesize').text("Table Size: " + vv.length); $('#btnExport').prop('disabled', false); - $('#searchfilter').prop('disabled', false); } /** @@ -47,10 +48,11 @@ function reloadLogs(APIURL = "Log/", date, filter) { date: date, filter: filter }) + window.logdata = []; fetchAPI(APIURL + "List?" + params.toString(), "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { - logdata = okdata; - fill_logtablebody(okdata); + window.logdata.push(...okdata); + fill_logtablebody(window.logdata); } }, (errdata) => { alert("Error loading logs : " + errdata.message); @@ -59,26 +61,22 @@ function reloadLogs(APIURL = "Log/", date, filter) { $(document).ready(function () { console.log("log.js ready"); - const $logdate = $('#logdate'); - const $searchfilter = $('#searchfilter'); - const $logtable = $('#logtablebody') - const $btnExport = $('#btnExport'); let selectedlogdate = ""; let logfilter = ""; let APIURL = "Log/"; - $logtable.empty(); + $('#logtablebody').empty(); - if (!$logdate.val()) { + if (!$('#logdate').val()) { const today = new Date(); const dd = String(today.getDate()).padStart(2, '0'); const mm = String(today.getMonth() + 1).padStart(2, '0'); const yyyy = today.getFullYear(); - $logdate.val(`${yyyy}-${mm}-${dd}`); + $('#logdate').val(`${yyyy}-${mm}-${dd}`); selectedlogdate = `${dd}-${mm}-${yyyy}`; reloadLogs(APIURL, selectedlogdate, logfilter); } - $logdate.off('change').on('change', function () { + $('#logdate').off('change').on('change', function () { const selected = $(this).val(); if (selected) { const [year, month, day] = selected.split('-'); @@ -87,11 +85,11 @@ $(document).ready(function () { } }); - $searchfilter.off('input').on('input', function () { + $('#searchfilter').off('input').on('input', function () { logfilter = $(this).val(); reloadLogs(APIURL, selectedlogdate, logfilter); }); - $btnExport.off('click').on('click', function () { + $('#btnExport').off('click').on('click', function () { DoExport(APIURL, "log.xlsx", { date: selectedlogdate, filter: logfilter }); }); }); \ No newline at end of file diff --git a/html/webpage/assets/js/messagebank.js b/html/webpage/assets/js/messagebank.js index 17f48cb..1acf321 100644 --- a/html/webpage/assets/js/messagebank.js +++ b/html/webpage/assets/js/messagebank.js @@ -13,12 +13,12 @@ * List of Messagebank data loaded from server * @type {MessageBank[]} */ -let messagebankdata = []; +window.messagebankdata ??= []; /** * Currently selected messagebank row in the table * @type {JQuery|null} */ -let selectedmessagerow = null; +window.selectedmessagerow = null; /** * Fill messagebank table body with values @@ -40,17 +40,17 @@ function fill_messagebanktablebody(vv) { $('#messagebanktablebody').append(row); let $addedrow = $('#messagebanktablebody tr:last'); $addedrow.click(function () { - if (selectedmessagerow) { - selectedmessagerow.find('td').css('background-color', ''); - if (selectedmessagerow.is($(this))) { - selectedmessagerow = null; + if (window.selectedmessagerow) { + window.selectedmessagerow.find('td').css('background-color', ''); + if (window.selectedmessagerow.is($(this))) { + window.selectedmessagerow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $addedrow.find('td').css('background-color', '#ffeeba'); - selectedmessagerow = $addedrow; + window.selectedmessagerow = $addedrow; $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); @@ -64,12 +64,12 @@ function fill_messagebanktablebody(vv) { * @param {string} APIURL API URL endpoint, default "MessageBank/" */ function reloadMessageBank(APIURL = "MessageBank/") { - messagebankdata = []; + window.messagebankdata ??= []; fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { - messagebankdata = okdata; - selectedmessagerow = null; - fill_messagebanktablebody(messagebankdata); + window.messagebankdata.push(...okdata); + window.selectedmessagerow = null; + fill_messagebanktablebody(window.messagebankdata); } }, (errdata) => { alert("Error loading messagebank : " + errdata.message); @@ -79,7 +79,7 @@ function reloadMessageBank(APIURL = "MessageBank/") { $(document).ready(function () { console.log("messagebank.js loaded"); $('#messagebanktablebody').empty(); - selectedmessagerow = null; + window.selectedmessagerow = null; let $btnClear = $('#btnClear'); let $btnAdd = $('#btnAdd'); let $btnRemove = $('#btnRemove'); @@ -198,12 +198,12 @@ $(document).ready(function () { $findmessage.on('input', function () { let searchTerm = $findmessage.val().toLowerCase(); if (searchTerm.length > 0) { - selectedmessagerow = null; - let filtered = messagebankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.message_Detail.toLowerCase().includes(searchTerm) || item.message_TAGS.toLowerCase().includes(searchTerm)); + window.selectedmessagerow = null; + let filtered = window.messagebankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.message_Detail.toLowerCase().includes(searchTerm) || item.message_TAGS.toLowerCase().includes(searchTerm)); fill_messagebanktablebody(filtered); } else { - selectedmessagerow = null; - fill_messagebanktablebody(messagebankdata); + window.selectedmessagerow = null; + fill_messagebanktablebody(window.messagebankdata); } }); @@ -301,8 +301,8 @@ $(document).ready(function () { }); }); $btnRemove.click(() => { - if (selectedmessagerow) { - let cells = selectedmessagerow.find('td'); + if (window.selectedmessagerow) { + let cells = window.selectedmessagerow.find('td'); /** @type {MessageBank} */ let mb = { index: cells.eq(0).text(), @@ -325,8 +325,8 @@ $(document).ready(function () { } }); $btnEdit.click(() => { - if (selectedmessagerow) { - let cells = selectedmessagerow.find('td'); + if (window.selectedmessagerow) { + let cells = window.selectedmessagerow.find('td'); /** @type {MessageBank} */ let mb = { index: cells.eq(0).text(), diff --git a/html/webpage/assets/js/schedulebank.js b/html/webpage/assets/js/schedulebank.js index 419ffb6..6c9e437 100644 --- a/html/webpage/assets/js/schedulebank.js +++ b/html/webpage/assets/js/schedulebank.js @@ -14,12 +14,12 @@ /** List of Schedulebank data loaded from server * @type {ScheduleBank[]} */ -let schedulebankdata = []; +window.schedulebankdata = []; /** * Currently selected schedulebank row in the table * @type {JQuery|null} */ -let selectedschedulerow = null; +window.selectedschedulerow = null; /** * Fill schedulebank table body with values @@ -66,12 +66,12 @@ function fill_schedulebanktablebody(vv) { * @param {string} APIURL API URL endpoint, default "ScheduleBank/" */ function reloadTimerBank(APIURL = "ScheduleBank/") { - schedulebankdata = []; + window.schedulebankdata = []; fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { - schedulebankdata = okdata; + window.schedulebankdata.push(...okdata); selectedschedulerow = null; - fill_schedulebanktablebody(schedulebankdata); + fill_schedulebanktablebody(window.schedulebankdata); } }, (errdata) => { alert("Error loading schedulebank : " + errdata.message); @@ -158,15 +158,15 @@ $(document).ready(function () { $findschedule.on('input', function () { let searchTerm = $findschedule.val().toLowerCase(); if (searchTerm.length > 0) { - selectedtimerow = null; - let filtered = schedulebankdata.filter(item => + window.selectedschedulerow = null; + let filtered = window.schedulebankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.soundpath.toLowerCase().includes(searchTerm) || item.broadcastZones.toLowerCase().includes(searchTerm)); fill_schedulebanktablebody(filtered); } else { - selectedtimerow = null; - fill_schedulebanktablebody(schedulebankdata); + window.selectedschedulerow = null; + fill_schedulebanktablebody(window.schedulebankdata); } }); @@ -246,8 +246,8 @@ $(document).ready(function () { }); }); $btnRemove.click(() => { - if (selectedtimerow) { - let cells = selectedtimerow.find('td'); + if (window.selectedschedulerow) { + let cells = window.selectedschedulerow.find('td'); /** @type {ScheduleBank} */ let sr = { index: cells.eq(0).text(), @@ -271,8 +271,8 @@ $(document).ready(function () { } }); $btnEdit.click(() => { - if (selectedtimerow) { - let cells = selectedtimerow.find('td'); + if (window.selectedschedulerow) { + let cells = window.selectedschedulerow.find('td'); /** @type {ScheduleBank} */ let sr = { index: cells.eq(0).text(), diff --git a/html/webpage/assets/js/script.js b/html/webpage/assets/js/script.js index 353f21b..7f0b14a 100644 --- a/html/webpage/assets/js/script.js +++ b/html/webpage/assets/js/script.js @@ -2,23 +2,23 @@ * List of voice types available * @type {string[]} */ -let voiceTypes = []; +window.voiceTypes = []; /** * List of categories available * @type {string[]} */ -let categories = []; +window.categories = []; /** * List of languages available * @type {string[]} */ -let languages = []; +window.languages = []; /** * List of scheduled days available * @type {string[]} */ -let scheduledays = [] +window.scheduledays = [] /** * Create a list item element @@ -34,7 +34,7 @@ function ListItem(text, className = "") { * WebSocket connection * @type {WebSocket} */ -let ws = null; +window.ws = null; /** * Send a command to the WebSocket server. @@ -42,8 +42,8 @@ let ws = null; * @param {String} data data to send */ function sendCommand(command, data) { - if (ws.readyState === WebSocket.OPEN) { - ws.send(JSON.stringify({ command, data })); + if (window.ws.readyState === WebSocket.OPEN) { + window.ws.send(JSON.stringify({ command, data })); } } @@ -118,11 +118,11 @@ function fetchImg(url, cbOK, cbError) { * Reload voice types from server */ function getVoiceTypes() { - voiceTypes = []; + window.voiceTypes = []; fetchAPI("VoiceType", "GET", {}, null, (okdata) => { // okdata is a string contains elements separated by semicolon ; if (Array.isArray(okdata)) { - voiceTypes = okdata.filter(item => item.trim().length > 0); + window.voiceTypes = okdata.filter(item => item.trim().length > 0); //console.log("Loaded " + voiceTypes.length + " voice types : " + voiceTypes.join(", ")); } else console.log("getVoiceTypes: okdata is not array"); }, (errdata) => { @@ -134,11 +134,11 @@ function getVoiceTypes() { * Reload categories from server */ function getCategories() { - categories = []; + window.categories = []; fetchAPI("Category", "GET", {}, null, (okdata) => { // okdata is a string contains elements separated by semicolon ; if (Array.isArray(okdata)) { - categories = okdata.filter(item => item.trim().length > 0); + window.categories = okdata.filter(item => item.trim().length > 0); //console.log("Loaded " + categories.length + " categories : " + categories.join(", ")); } else console.log("getCategories: okdata is not array"); }, (errdata) => { @@ -150,11 +150,11 @@ function getCategories() { * Reload languages from server */ function getLanguages() { - languages = []; + window.languages = []; fetchAPI("Language", "GET", {}, null, (okdata) => { // okdata is a string contains elements separated by semicolon ; if (Array.isArray(okdata)) { - languages = okdata.filter(item => item.trim().length > 0); + window.languages = okdata.filter(item => item.trim().length > 0); //console.log("Loaded " + languages.length + " languages : " + languages.join(", ") ); } else console.log("getLanguages: okdata is not array"); }, (errdata) => { @@ -166,11 +166,11 @@ function getLanguages() { * Reload scheduled days from server */ function getScheduledDays() { - scheduledays = []; + window.scheduledays = []; fetchAPI("ScheduleDay", "GET", {}, null, (okdata) => { // okdata is a string contains elements separated by semicolon ; if (Array.isArray(okdata)) { - scheduledays = okdata.filter(item => item.trim().length > 0); + window.scheduledays = okdata.filter(item => item.trim().length > 0); //console.log("Loaded " + scheduledays.length + " scheduled days : " + scheduledays.join(", ") ); } else console.log("getScheduledDays: okdata is not array"); }, (errdata) => { @@ -273,43 +273,36 @@ function DoImport(APIURL, cbOK, cbError) { fileInput.remove(); } -let $onlineindicator = null; -let $cpustatus = null; -let $ramstatus = null; -let $diskstatus = null; -let $networkstatus = null; -let $datetimetext = null; -let greencircle = null; -let redcircle = null; +window.greencircle = null; +window.redcircle = null; /** * App entry point */ $(document).ready(function () { document.title = "Automatic Announcement System" - fetchImg('green_circle.png', (url) => { greencircle = url; }, (err) => { console.error("Error loading green_circle.png : ", err); }); - fetchImg('red_circle.png', (url) => { redcircle = url; }, (err) => { console.error("Error loading red_circle.png : ", err); }); + if (window.greencircle === null){ + fetchImg('green_circle.png', (url) => { window.greencircle = url; }, (err) => { console.error("Error loading green_circle.png : ", err); }); + } + if (window.redcircle === null){ + fetchImg('red_circle.png', (url) => { window.redcircle = url; }, (err) => { console.error("Error loading red_circle.png : ", err); }); + } const wsURL = window.location.pathname + '/ws' if (chrome && chrome.runtime && chrome.runtime.lastError) { alert("Runtime error: " + chrome.runtime.lastError.message); return; } - $onlineindicator = $('#onlineindicator'); - $cpustatus = $('#cpustatus'); - $ramstatus = $('#ramstatus'); - $diskstatus = $('#diskstatus'); - $networkstatus = $('#networkstatus'); - $datetimetext = $('#datetimetext'); + // reset status indicators function resetStatusIndicators() { - $onlineindicator.attr('src', redcircle); - $cpustatus.text("CPU : N/A"); - $ramstatus.text("RAM : N/A"); - $diskstatus.text("Disk : N/A"); - $networkstatus.text("Network : N/A"); - $datetimetext.text("Date/Time : N/A"); + $('#onlineindicator').attr('src', window.redcircle); + $('#cpustatus').text("CPU : N/A"); + $('#ramstatus').text("RAM : N/A"); + $('#diskstatus').text("Disk : N/A"); + $('#networkstatus').text("Network : N/A"); + $('#datetimetext').text("Date/Time : N/A"); } @@ -321,44 +314,47 @@ $(document).ready(function () { // Initialize WebSocket connection - ws = new WebSocket(wsURL); + window.ws = new WebSocket(wsURL); - ws.onopen = () => { + window.ws.onopen = () => { console.log('WebSocket connection established'); - $onlineindicator.attr('src', greencircle); + $('#onlineindicator').attr('src', window.greencircle); }; - ws.onmessage = (event) => { + window.ws.onmessage = (event) => { + if ($('#onlineindicator').attr('src') !== window.greencircle) { + $('#onlineindicator').attr('src', window.greencircle); + } let rep = JSON.parse(event.data); let cmd = rep.reply let data = rep.data; if (cmd && cmd.length > 0) { switch (cmd) { case "getCPUStatus": - $cpustatus.text("CPU : " + data) + $('#cpustatus').text("CPU : " + data) break; case "getMemoryStatus": - $ramstatus.text("RAM : " + data) + $('#ramstatus').text("RAM : " + data) break; case "getDiskStatus": - $diskstatus.text("Disk : " + data) + $('#diskstatus').text("Disk : " + data) break; case "getNetworkStatus": - $networkstatus.text("Network : " + data) + $('#networkstatus').text("Network : " + data) break; case "getSystemTime": - $datetimetext.text(data) + $('#datetimetext').text(data) break; } } }; - ws.onclose = () => { + window.ws.onclose = () => { console.log('WebSocket connection closed'); resetStatusIndicators(); }; - // ws.onerror = (error) => { + // window.ws.onerror = (error) => { // console.error('WebSocket error:', error); // }; @@ -457,6 +453,18 @@ $(document).ready(function () { } }); }) + $('#usermanagement').click(() => { + sidemenu.hide(); + $('#content').load('usermanagement.html', function (response, status, xhr) { + if (status === "success") { + console.log("User Management content loaded successfully"); + // pindah ke usermanagement.js + + } else { + console.error("Error loading user management content:", xhr.status, xhr.statusText); + } + }); + }); $('#settinglink').click(() => { sidemenu.hide(); $('#content').load('setting.html', function (response, status, xhr) { diff --git a/html/webpage/assets/js/soundbank.js b/html/webpage/assets/js/soundbank.js index 3ec96d8..59ecfb7 100644 --- a/html/webpage/assets/js/soundbank.js +++ b/html/webpage/assets/js/soundbank.js @@ -19,38 +19,38 @@ * List of Soundbank data loaded from server * @type {SoundBank[]} */ -let soundbankdata = []; +window.soundbankdata = []; /** * Currently selected soundbank row in the table * @type {JQuery|null} */ -let selectedsoundrow = null; +window.selectedsoundrow = null; /** * List of sound files in the soundbank directory, that ends with .wav or .mp3 * @type {string[]} */ -let soundbankfiles = []; +window.soundbankfiles = []; /** * Select2 data source * See https://select2.org/data-sources/formats * @type {Select2item[]} */ -let select2data = []; +window.select2data = []; /** * Reload sound bank from server * @param {String} APIURL API URL endpoint, default "SoundBank/" */ function reloadSoundBank(APIURL = "SoundBank/") { - soundbankdata = []; + window.soundbankdata = []; fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { - soundbankdata = okdata; - selectedsoundrow = null; - fill_soundbanktablebody(soundbankdata); + window.soundbankdata.push(...okdata); + window.selectedsoundrow = null; + fill_soundbanktablebody(window.soundbankdata); } }, (errdata) => { alert("Error loading soundbank : " + errdata.message); @@ -77,17 +77,17 @@ function fill_soundbanktablebody(vv) { $('#soundbanktablebody').append(row); let $addedrow = $('#soundbanktablebody tr:last'); $addedrow.on('click', function () { - if (selectedsoundrow) { - selectedsoundrow.find('td').css('background-color', ''); - if (selectedsoundrow.is($(this))) { - selectedsoundrow = null; + if (window.selectedsoundrow) { + window.selectedsoundrow.find('td').css('background-color', ''); + if (window.selectedsoundrow.is($(this))) { + window.selectedsoundrow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $(this).find('td').css('background-color', '#ffeeba'); - selectedsoundrow = $(this); + window.selectedsoundrow = $(this); $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); @@ -103,13 +103,13 @@ function fill_soundbanktablebody(vv) { * @param {String} APIURL API URL endpoint (default "SoundBank/") */ function reloadSoundbankFiles(APIURL = "SoundBank/") { - soundbankfiles = []; + window.soundbankfiles = []; fetchAPI(APIURL + "ListFiles", "GET", {}, null, (okdata) => { // okdata is a string contains elements separated by semicolon ; if (Array.isArray(okdata)) { - soundbankfiles = okdata.filter(item => item.trim().length > 0); + window.soundbankfiles = okdata.filter(item => item.trim().length > 0); // refill select2data - select2data = soundbankfiles.map((item, index) => ({ id: index + 1, text: item })); + window.select2data = window.soundbankfiles.map((item, index) => ({ id: index + 1, text: item })); } else console.log("reloadSoundbankFiles: okdata is not array"); }, (errdata) => { alert("Error loading soundbank files : " + errdata.message); @@ -120,7 +120,7 @@ $(document).ready(function () { console.log("soundbank.js loaded successfully"); reloadSoundbankFiles(); $('#soundbanktablebody').empty(); - selectedsoundrow = null; + window.selectedsoundrow = null; let $btnClear = $('#btnClear'); let $btnAdd = $('#btnAdd'); let $btnRemove = $('#btnRemove'); @@ -166,9 +166,9 @@ $(document).ready(function () { $modalvoicetype.val(null); // fill modalpath options from soundbankfiles[] // TODO read https://jeesite.com/front/jquery-select2/4.0/index.htm - console.log("select2data has " + select2data.length + " items"); + console.log("window.select2data has " + window.select2data.length + " items"); $('#modalpath').select2({ - data: select2data + data: window.select2data }) } @@ -176,12 +176,12 @@ $(document).ready(function () { $('#findsoundbank').on('input', function () { let searchTerm = $(this).val().trim().toLowerCase(); if (searchTerm.length > 0) { - selectedsoundrow = null; - let filtered = soundbankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.tag.toLowerCase().includes(searchTerm) || item.path.toLowerCase().includes(searchTerm)); + window.selectedsoundrow = null; + let filtered = window.soundbankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.tag.toLowerCase().includes(searchTerm) || item.path.toLowerCase().includes(searchTerm)); fill_soundbanktablebody(filtered); } else { - selectedsoundrow = null; - fill_soundbanktablebody(soundbankdata); + window.selectedsoundrow = null; + fill_soundbanktablebody(window.soundbankdata); } }); $btnClear.click(() => { @@ -208,8 +208,8 @@ $(document).ready(function () { }); }); $btnRemove.click(() => { - if (selectedsoundrow) { - let cells = selectedsoundrow.find('td'); + if (window.selectedsoundrow) { + let cells = window.selectedsoundrow.find('td'); /** @type {SoundBank} */ let sb = { index: cells.eq(0).text(), @@ -231,8 +231,8 @@ $(document).ready(function () { } }); $btnEdit.click(() => { - if (selectedsoundrow) { - let cells = selectedsoundrow.find('td'); + if (window.selectedsoundrow) { + let cells = window.selectedsoundrow.find('td'); /** @type {SoundBank} */ let sb = { index: cells.eq(0).text(), diff --git a/html/webpage/assets/js/soundchannel.js b/html/webpage/assets/js/soundchannel.js index e66b862..2935eac 100644 --- a/html/webpage/assets/js/soundchannel.js +++ b/html/webpage/assets/js/soundchannel.js @@ -8,20 +8,21 @@ /** * @type {SoundChannel[]} */ -let soundChannels = []; +window.soundChannels = []; // Currently selected sound channel row in the table -let selectedSoundChannel = null; +window.selectedSoundChannel = null; /** * Fills the sound channel table body with the provided data. * @param {SoundChannel[]} vv Sound channel data to populate the table. */ function fill_soundchanneltablebody(vv) { - const $tbody = $('#soundchanneltablebody'); - const $btnEditSoundChannel = $('#btnEditSoundChannel'); - const $tablesizeSoundChannel = $('#tablesizeSoundChannel'); + let $tbody = $('#soundchanneltablebody'); + let $btnEditSoundChannel = $('#btnEditSoundChannel'); + let $tablesizeSoundChannel = $('#tablesizeSoundChannel'); $tbody.empty(); + $tablesizeSoundChannel.text('Table Length : N/A'); if (!Array.isArray(vv) || vv.length === 0) return; @@ -55,12 +56,12 @@ function fill_soundchanneltablebody(vv) { * @param {String} APIURL API URL endpoint (default "SoundChannel/") */ function reloadSoundChannel(APIURL = "SoundChannel/") { - SoundChannelList = []; + window.soundChannels = []; fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { //console.log("reloadSoundChannel : ", okdata) - SoundChannelList = okdata; - fill_soundchanneltablebody(SoundChannelList); + window.soundChannels.push(...okdata); + fill_soundchanneltablebody(window.soundChannels); } else console.log("reloadSoundChannel: okdata is not array"); }, (errdata) => { alert("Error loading sound channels : " + errdata.message); @@ -85,12 +86,14 @@ $(document).ready(function () { $findsoundchannel.on('input', function () { let searchTerm = $(this).val().toLowerCase(); if (searchTerm.length==0){ - fill_soundchanneltablebody(SoundChannelList); + window.selectedSoundChannel = null; + fill_soundchanneltablebody(window.soundChannels); } else { - let filteredChannels = SoundChannelList.filter(channel => - channel.index.toString().includes(searchTerm) || - channel.description.toLowerCase().includes(searchTerm) || - channel.ip.toLowerCase().includes(searchTerm) + window.selectedSoundChannel = null; + let filteredChannels = window.soundChannels.filter(xx => + xx.index.toString().includes(searchTerm) || + xx.channel.toLowerCase().includes(searchTerm) || + xx.ip.toLowerCase().includes(searchTerm) ); fill_soundchanneltablebody(filteredChannels); } diff --git a/html/webpage/assets/js/usermanagement.js b/html/webpage/assets/js/usermanagement.js new file mode 100644 index 0000000..5dc01b3 --- /dev/null +++ b/html/webpage/assets/js/usermanagement.js @@ -0,0 +1,128 @@ +/** + * @typedef {Object} UserDB + * @property {number} index Index number + * @property {string} username Username + * @property {string} password Password (plain) + * @property {string} location Location + * @property {string} soundbank_tags Soundbank variable tags separated by semicolon ; + * @property {string} messagebank_ann_id Messagebank announcement ID separated by semicolon ; + * @property {string} broadcastzones Broadcast zones separated by semicolon ; + */ + +/** List of UserDB data loaded from server + * @type {UserDB[]} + */ +window.userdb = []; + +/** + * Currently selected user row in table + * @type {JQuery|null} + */ +window.selecteduserrow = null; + +/** + * Fill user table body with values + * @param {UserDB[]} vv values to fill + */ +function fill_usertablebody(vv) { + $('#usertablebody').empty(); + + if (!Array.isArray(vv) || vv.length === 0) { + $('#btnExport').prop('disabled', true); + return; + } + vv.forEach(item => { + const row = ` + ${item.index} + ${item.datenya} + ${item.timenya} + ${item.machine} + ${item.description} + `; + $('#usertablebody').append(row); + let $addedrow = $('#usertablebody tr:last'); + $addedrow.on('click', function () { + if (window.selecteduserrow) { + window.selecteduserrow.find('td').css('background-color', ''); + if (window.selecteduserrow.is($(this))) { + window.selecteduserrow = null; + $('#btnRemove').prop('disabled', true); + $('#btnEdit').prop('disabled', true); + return; + } + } + $(this).find('td').css('background-color', '#ffeeba'); + window.selecteduserrow = $(this); + $('#btnRemove').prop('disabled', false); + $('#btnEdit').prop('disabled', false); + }); + }); + $('#tablesize').text("Table Size: " + vv.length); + $('#btnExport').prop('disabled', false); +} + +/** + * Reload UserDB from server with date and filter + * @param {String} APIURL API URL endpoint , default "User/" + */ +function reloaduserDB(APIURL = "User/") { + window.userdb = []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + window.userdb.push(...okdata); + fill_usertablebody(window.userdb); + } + }, (errdata) => { + alert("Error loading user database : " + errdata.message); + }); +} + +$(document).ready(function () { + console.log("usermanagement.js ready"); + let $usertablebody = $('#usertablebody'); + let $finduser = $('#finduser'); + let $btnClear = $('#btnClear'); + let $btnAdd = $('#btnAdd'); + let $btnRemove = $('#btnRemove'); + let $btnEdit = $('#btnEdit'); + let $btnExport = $('#btnExport'); + let $btnImport = $('#btnImport'); + let APIURL = "User/"; + + // add / edit modal elements + let $addmodal = $('#addmodal'); + let $modalindex = $('#modalindex'); + let $modalusername = $('#modalusername'); + let $modalpassword = $('#modalpassword'); + let $modalverifypassword = $('#modalverifypassword'); + let $modalsoundbank = $('#modalsoundbank'); + let $modalmessagebank = $('#modalmessagebank'); + let $modalbroadcastzones = $('#modalbroadcastzones'); + let $btnShowSoundbankModal = $('#btnShowSoundbankModal'); + let $btnShowMessagebankModal = $('#btnShowMessagebankModal'); + let $btnShowBroaadcastZoneModal = $('#btnShowBroaadcastZoneModal'); + let $usermanagementsave = $('#usermanagementsave'); + let $usermanagementclose = $('#usermanagementclose'); + + // soundbank selection modal elements + let $soundbankmodal = $('#soundbankmodal'); + let $soundbankselection = $('#soundbankselection'); + let $soundbankselectionsave = $('#soundbankselectionsave'); + let $soundbankselectionclose = $('#soundbankselectionclose'); + + // broadcast zone selection modal elements + let $broadcastzonemodal = $('#broadcastzonemodal'); + let $broadcastzoneselection = $('#broadcastzoneselection'); + let $broadcastzoneselectionsave = $('#broadcastzoneselectionsave'); + let $broadcastzoneselectionclose = $('#broadcastzoneselectionclose'); + + // messagebank selection modal elements + let $messagebankmodal = $('#messagebankmodal'); + let $messagebankselection = $('#messagebankselection'); + let $messagebankselectionsave = $('#messagebankselectionsave'); + let $messagebankselectionclose = $('#messagebankselectionclose'); + + $usertablebody.empty(); + $finduser.on('input', function () { + }); +}); \ No newline at end of file diff --git a/html/webpage/broadcastzones.html b/html/webpage/broadcastzones.html index 9b86ba6..70f0bd3 100644 --- a/html/webpage/broadcastzones.html +++ b/html/webpage/broadcastzones.html @@ -4,7 +4,7 @@ - AAS_NewGen_03Sept25 + AAS_NewGen_30Sept25 @@ -24,34 +24,34 @@