|
$(function () {
|
|
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
|
|
if (sessionStorage.getItem('token') !== null) {
|
|
if(!window.grafanaBootData.user.login){
|
|
sessionStorage.setItem('isLoggedOut', '1');
|
|
}
|
|
}
|
|
|
|
sessionStorage.setItem('current_dashboard', '');
|
|
|
|
if (urlParams.has('auth_token')) {
|
|
|
|
const token = urlParams.get('auth_token');
|
|
if ( token && sessionStorage.getItem('isLoggedOut') == '1' &&
|
|
sessionStorage.getItem('token') !== null && token === sessionStorage.getItem('token')) {
|
|
// 清除 URL
|
|
//sessionStorage.removeItem('token');
|
|
window.history.replaceState({}, document.title, window.location.pathname);
|
|
window.location.href = '/logout';
|
|
}else{
|
|
// 儲存到 sessionStorage
|
|
sessionStorage.removeItem('isLoggedOut');
|
|
sessionStorage.setItem('token', token);
|
|
//console.log('auth_token 已儲存至 sessionStorage');
|
|
}
|
|
|
|
}
|
|
|
|
//console.log(window.grafanaBootData);
|
|
|
|
if( 'admin' != window.grafanaBootData.user.login ){
|
|
resizeDashboard();
|
|
}
|
|
|
|
//for (const [key, value] of urlParams.entries()) {
|
|
//console.log(`${key} = ${value}`);
|
|
//}
|
|
/*
|
|
if (urlParams.has('kiosk') ) {
|
|
setTimeout(function () {
|
|
applyKioskLayout();
|
|
}, 100);
|
|
}
|
|
if('admin' != window.grafanaBootData.user.login ){
|
|
setTimeout(function () {
|
|
hideAdminOnlyUI();
|
|
}, 100);
|
|
}
|
|
*/
|
|
/*
|
|
observer.observe(target, {
|
|
childList: true,
|
|
subtree: true,
|
|
//attributeFilter: ['class']
|
|
});
|
|
*/
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
//console.log('begin load custom js');
|
|
const target = document.body;
|
|
//const target = document.querySelector('.react-grid-layout');
|
|
//console.log(target);
|
|
|
|
const observer = new MutationObserver((mutationsList, observer) => {
|
|
|
|
//console.log('👀 mutation triggered!');
|
|
//console.log(mutationsList);
|
|
|
|
//const navToolbar = $('div[data-testid="data-testid Nav toolbar"]');
|
|
//const toolbar = $('div.css-1ntsjus-NavToolbar-actions');
|
|
|
|
//for (const [key, value] of urlParams.entries()) {
|
|
// console.log(`${key} = ${value}`);
|
|
//}
|
|
|
|
|
|
for (const mutation of mutationsList) {
|
|
|
|
if (mutation.target.closest && (
|
|
mutation.target.closest('.react-grid-layout') ||
|
|
mutation.target.closest('header')
|
|
)
|
|
) {
|
|
|
|
//console.log('mutation triggered:' + $(mutation.target));
|
|
if (urlParams.has('kiosk') ) {
|
|
applyKioskLayout();
|
|
}else {
|
|
if('admin' != window.grafanaBootData.user.login ){
|
|
hideAdminOnlyUI();
|
|
}
|
|
}
|
|
|
|
const currentPath = new URL(window.location.href).pathname;
|
|
const storedPath = sessionStorage.getItem('current_dashboard');
|
|
|
|
if (currentPath !== storedPath){
|
|
if( 'admin' != window.grafanaBootData.user.login ){
|
|
reloadDashboard();
|
|
}
|
|
}
|
|
sessionStorage.setItem('current_dashboard', currentPath);
|
|
updateLocaleSettings();
|
|
/*
|
|
if( 'admin' != window.grafanaBootData.user.login ){
|
|
console.log('reload dashboard');
|
|
reloadDashboard();
|
|
}
|
|
*/
|
|
}
|
|
|
|
//$('ul[aria-label="Navigation"]').hide();
|
|
//
|
|
//$('button[title="Menu"]').hide();
|
|
//$('button[data-testid="data-testid Toggle menu"]').hide();
|
|
//$('button[data-testid="data-testid Share dashboard"]').hide();
|
|
//$('button[aria-label="New"]').hide();
|
|
|
|
}
|
|
});
|
|
|
|
if (!target) {
|
|
console.warn('#reactRoot 不存在');
|
|
return;
|
|
}
|
|
//console.log("🚀 observer will now attach");
|
|
observer.observe(target, {
|
|
childList: true,
|
|
subtree: true,
|
|
attributeFilter: ['class']
|
|
});
|
|
//console.log(observer);
|
|
}, 100);
|
|
|
|
|
|
|
|
});
|
|
|
|
function createToolbarLogout(){
|
|
|
|
const toolbar = $('div.css-1ntsjus-NavToolbar-actions');
|
|
if (toolbar.is(':visible') && toolbar.find('a[href="/logout"]').length === 0 ) {
|
|
if($('header').find('button[aria-label="Help"]').length > 0){
|
|
$('button[title="Toggle top search bar"]').trigger('click');
|
|
}
|
|
}
|
|
toolbar.append(
|
|
$('<a>', {
|
|
href: '/logout',
|
|
text: 'Logout',
|
|
target: '_self',
|
|
css: {
|
|
'text-decoration': 'none',
|
|
'padding': '2px 8px',
|
|
'margin-left': 'auto',
|
|
'border-radius': '4px',
|
|
//'background': '#f9f9f9',
|
|
'border': '1px solid #ccc',
|
|
'cursor': 'pointer'
|
|
}
|
|
})
|
|
);
|
|
|
|
}
|
|
|
|
function createControlsLogout(){
|
|
|
|
const controls = $('div[data-testid="data-testid dashboard controls"]');
|
|
if(controls && controls.is(':visible') && controls.find('a[href="/logout"]').length === 0){
|
|
controls.append(
|
|
$('<a>', {
|
|
href: '/logout',
|
|
text: 'Logout',
|
|
target: '_self',
|
|
css: {
|
|
'text-decoration': 'none',
|
|
'padding': '2px 8px',
|
|
'margin-left': 'auto',
|
|
'border-radius': '4px',
|
|
//'background': '#f9f9f9',
|
|
'border': '1px solid #ccc',
|
|
'cursor': 'pointer'
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
let resizeTimer;
|
|
|
|
function reloadDashboard(){
|
|
|
|
clearTimeout(resizeTimer);
|
|
resizeTimer = setTimeout(function () {
|
|
rearrangePanel();
|
|
}, 1*500);
|
|
|
|
}
|
|
|
|
function resizeDashboard(){
|
|
|
|
$(window).on('resize', function() {
|
|
clearTimeout(resizeTimer);
|
|
resizeTimer = setTimeout(function () {
|
|
rearrangePanel();
|
|
}, 1*500);
|
|
});
|
|
|
|
}
|
|
|
|
function applyKioskLayout(){
|
|
|
|
const navToolbar = $('div[data-testid="data-testid Nav toolbar"]');
|
|
const toolbar = $('div.css-1ntsjus-NavToolbar-actions');
|
|
|
|
navToolbar.closest('header').closest('div').children(':not(header)').filter('div').first().css( 'padding-top','0px');
|
|
$('div[data-testid="data-testid dashboard controls"]').parent().closest('div').css('top','0px');
|
|
navToolbar.closest('header').hide();
|
|
$('button[title="Menu"]').css('display', 'none');
|
|
|
|
}
|
|
|
|
function hideAdminOnlyUI() {
|
|
//data-testid Toggle menu
|
|
//Toggle menu
|
|
//$('button[data-testid="data-testid Toggle menu"]').hide();
|
|
//console.log('hide admin only');
|
|
$('button[data-testid*="Toggle menu"]').hide();
|
|
$('button[title="Menu"]').hide();
|
|
|
|
const toolbar = $('div.css-1ntsjus-NavToolbar-actions');
|
|
if (toolbar.is(':visible')) {
|
|
if (toolbar.find('a[href="/logout"]').length === 0) {
|
|
createToolbarLogout();
|
|
}
|
|
toolbar.children().each(function () {
|
|
if (!$(this).is('a[href="/logout"]')) {
|
|
$(this).hide();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
let rearangeStatus = false;
|
|
|
|
function isPanelReady() {
|
|
return $('.react-grid-layout').find('div.react-grid-layout').length > 0;
|
|
}
|
|
|
|
function rearrangePanel (){
|
|
|
|
if(!isPanelReady()){
|
|
reloadDashboard();
|
|
return;
|
|
}
|
|
|
|
//console.log('rearrange panel...');
|
|
|
|
const gridLayout = $('.react-grid-layout .react-grid-layout').first();
|
|
const gridItems = gridLayout.children('.react-grid-item').get();
|
|
|
|
const matched = $(gridItems).filter('[data-griditem-key^="grid-item-"]');
|
|
|
|
const layoutWidth = parseInt($(gridLayout).css('width'),10);
|
|
const firstPanelWidth = parseInt($(matched[0]).css('width'), 10);
|
|
|
|
//console.log('layoutWidth:'+layoutWidth+' / firstPanelWidth:'+firstPanelWidth);
|
|
|
|
if( layoutWidth - firstPanelWidth < 30 ){
|
|
|
|
gridItems.sort((a, b) => {
|
|
const idA = parseInt($(a).attr('data-griditem-key').match(/\d+$/)[0] || '0');
|
|
const idB = parseInt($(b).attr('data-griditem-key').match(/\d+$/)[0] || '0');
|
|
//console.log('idA:'+idA+' / idB:'+idB);
|
|
return idA - idB;
|
|
});
|
|
|
|
gridLayout.empty().append(gridItems);
|
|
|
|
let currentY = 0;
|
|
|
|
//if(!rearangeStatus){
|
|
|
|
$(gridItems).each(function (index) {
|
|
|
|
const height = $(this).outerHeight(true); // 包含 margin/padding 的實際高度
|
|
const x = 0;
|
|
const y = currentY;
|
|
if(index > 1)
|
|
$(this).css('transform', `translate(${x}px, ${y}px)`);
|
|
|
|
//console.log('before = '+height+':'+currentY);
|
|
currentY += height+6; // 下一個 panel 的起始 y
|
|
//console.log(currentY);
|
|
});
|
|
rearangeStatus = true;
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
//window.dispatchEvent(new Event('resize'));
|
|
}
|
|
|
|
const translations = {
|
|
"Logout": "登出",
|
|
"No data": "查無資訊",
|
|
"The query didn't return any results.": "查無資訊",
|
|
"Dashboard": "儀表板",
|
|
"User": "使用者"
|
|
};
|
|
|
|
const translatedDashboards = ['R970100', 'R970101'];
|
|
|
|
|
|
|
|
function updateLocaleSettings(){
|
|
|
|
const currentDashboard = sessionStorage.getItem('current_dashboard');
|
|
|
|
const shouldTranslate = translatedDashboards.some(code =>
|
|
currentDashboard?.includes(code)
|
|
);
|
|
|
|
if (shouldTranslate) {
|
|
translatePageText();
|
|
} else {
|
|
restoreOriginalText();
|
|
}
|
|
/*
|
|
if (currentDashboard && currentDashboard.includes('R970100')) {
|
|
translatePageText();
|
|
}else{
|
|
restoreOriginalText();
|
|
}
|
|
*/
|
|
}
|
|
|
|
function escapeRegExp(str) {
|
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
}
|
|
|
|
function translateTextNode(originalText) {
|
|
return Object.entries(translations).reduce((text, [en, zh]) => {
|
|
const pattern = escapeRegExp(en);
|
|
return text.replace(new RegExp(pattern, 'g'), zh);
|
|
}, originalText);
|
|
}
|
|
|
|
function translatePageText() {
|
|
|
|
const walker = document.createTreeWalker(
|
|
document.body,
|
|
NodeFilter.SHOW_TEXT,
|
|
null,
|
|
false
|
|
);
|
|
|
|
let node;
|
|
while ((node = walker.nextNode())) {
|
|
|
|
const parentTag = node.parentNode?.nodeName?.toLowerCase();
|
|
|
|
// 跳過 style, script, meta, title, head 等不該修改的區域
|
|
if (['style', 'script', 'meta', 'title', 'noscript', 'head'].includes(parentTag)) {
|
|
continue;
|
|
}
|
|
/*
|
|
const originalText = node.nodeValue;
|
|
console.log(originalText);
|
|
const replacedText = Object.entries(translations).reduce((text, [en, zh]) => {
|
|
return text.replace(new RegExp(`\\b${en}\\b`, 'g'), zh);
|
|
}, originalText);
|
|
|
|
if (originalText !== replacedText) {
|
|
node.nodeValue = replacedText;
|
|
}
|
|
*/
|
|
|
|
const originalText = node.nodeValue;
|
|
const replacedText = translateTextNode(originalText);
|
|
|
|
if (originalText !== replacedText) {
|
|
node.parentNode.setAttribute('data-original-text', originalText);
|
|
node.nodeValue = replacedText;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
function restoreOriginalText() {
|
|
const walker = document.createTreeWalker(
|
|
document.body,
|
|
NodeFilter.SHOW_TEXT,
|
|
null,
|
|
false
|
|
);
|
|
|
|
let node;
|
|
while ((node = walker.nextNode())) {
|
|
|
|
const parentTag = node.parentNode?.nodeName?.toLowerCase();
|
|
|
|
// 跳過 style, script, meta, title, head 等不該修改的區域
|
|
if (['style', 'script', 'meta', 'title', 'noscript', 'head'].includes(parentTag)) {
|
|
continue;
|
|
}
|
|
|
|
const parent = node.parentNode;
|
|
const backup = parent?.getAttribute('data-original-text');
|
|
|
|
if (backup) {
|
|
node.nodeValue = backup;
|
|
parent.removeAttribute('data-original-text'); // 移除標記
|
|
}
|
|
}
|
|
}
|