Add "Copy host list (JSON)" button to WATO folder pages
Copies hostname, alias, IPv4 address and monitored site for every host in the list (folder browsing or host search results) to the clipboard as JSON.
This commit is contained in:
parent
5fa0506bdd
commit
a5f7b1a934
3 changed files with 106 additions and 1 deletions
|
|
@ -5,6 +5,11 @@ All notable changes to **Checkmk SwissKnife** are documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2.19.0] - 2026-07-31
|
||||
|
||||
### Added
|
||||
- "Copy host list (JSON)" button in the WATO menu bar on any host-list page (folder browsing or host search results). Copies hostname, alias, IPv4 address and monitored site for every visible host to the clipboard as JSON.
|
||||
|
||||
## [2.18.0] - 2026-07-30
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ A [Tampermonkey](https://www.tampermonkey.net/) userscript that enhances the Che
|
|||
| **Site Status Filters** | Adds Disabled / Online / Timeout / Not running toggle buttons below "Add connection" to quickly filter the site connections list | `addSitesFilterBar` |
|
||||
| **ListChoice Filter Bar** | Adds a search box, a "N / total selected" counter and a "Selected only" toggle above large checkbox lists (e.g. "Deploy custom files with agent") | `addListChoiceFilter` |
|
||||
| **Extra Column Toggle** | Adds an ON/OFF button to the menu bar to show/hide the Extra column; the choice is remembered across reloads | `addExtraColumnToggle` |
|
||||
| **Copy Host List (JSON)** | Adds a button to the menu bar that copies hostname, alias, IPv4 address and monitored site for every host in the list to the clipboard as JSON | `addHostListCopyButton` |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -159,6 +160,13 @@ Checkmk's native checkbox-list widget (used by rules like "Deploy custom files w
|
|||
|
||||
Applies to: any WATO rule editor page containing a large checkbox-list value (with or without sidebar).
|
||||
|
||||
---
|
||||
|
||||
### Copy Host List (JSON)
|
||||
Adds a **"Copy host list (JSON)"** button to the menu bar on any WATO host-list page — plain folder browsing or host search results. Clicking it copies hostname, alias, IPv4 address and monitored site for every host currently listed to the clipboard as a JSON array, ready to paste into a script, ticket, or spreadsheet.
|
||||
|
||||
Applies to: `wato.py?mode=folder` (folder browsing and host search results, with or without sidebar).
|
||||
|
||||
## How it works
|
||||
|
||||
The script injects enhancements at page load and re-applies them on SPA navigation (Checkmk reloads content inside an `<iframe>` without a full page reload). Each feature is independent — a feature that does not apply to the current page does nothing and stops polling.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name Checkmk SwissKnife
|
||||
// @namespace https://luigidacunto.com/
|
||||
// @version 2.18.0
|
||||
// @version 2.19.0
|
||||
// @checkmk 2.3.x - 2.4.x
|
||||
// @description Collection of UI improvements for Checkmk WATO. Each fix or enhancement is added here as an independent feature.
|
||||
// @author Luigi D'Acunto
|
||||
|
|
@ -1360,6 +1360,7 @@
|
|||
let attemptsSitesFilter = 0;
|
||||
let attemptsListchoice = 0;
|
||||
let attemptsExtraColToggle = 0;
|
||||
let attemptsHostListCopy = 0;
|
||||
|
||||
function tryEnhanceFolderSelect() {
|
||||
const iDoc = getWatoDoc(FOLDER_SELECT_ID);
|
||||
|
|
@ -1468,6 +1469,90 @@
|
|||
addWatoFolderMonitorButtons(doc);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// FEATURE: Copy host list as JSON
|
||||
//
|
||||
// Adds a button to the WATO menu bar on any host-list table (plain folder
|
||||
// browsing or host search results — both render mode=folder with the same
|
||||
// table.data columns) that copies hostname/alias/IPv4/monitored site for
|
||||
// every visible row to the clipboard as JSON.
|
||||
// =========================================================================
|
||||
|
||||
function addHostListCopyButton(doc) {
|
||||
if (doc.body.dataset.cmkHostListCopy === '1') return;
|
||||
const menues = doc.querySelector('td.menues');
|
||||
if (!menues) return;
|
||||
|
||||
const tables = [...doc.querySelectorAll('table.data')].filter(t =>
|
||||
[...t.querySelectorAll('tr th')].some(th => th.textContent.trim() === 'Host name'));
|
||||
if (!tables.length) return;
|
||||
|
||||
doc.body.dataset.cmkHostListCopy = '1';
|
||||
|
||||
injectStyles(doc, 'cmk-sk-hostlist-copy-style', `
|
||||
.cmk-sk-hostlist-copy-btn {
|
||||
margin-left: 8px; padding: 2px 8px; border-radius: 3px; font-size: 12px;
|
||||
cursor: pointer; background: transparent; color: #5ab4d6; border: 1px solid #5ab4d6;
|
||||
}
|
||||
.cmk-sk-hostlist-copy-btn:hover { background: rgba(90,180,214,0.15); }
|
||||
.cmk-sk-hostlist-copy-btn.copied { color: #4caf50; border-color: #4caf50; background: rgba(76,175,80,0.15); }
|
||||
`);
|
||||
|
||||
const btn = doc.createElement('button');
|
||||
btn.className = 'cmk-sk-hostlist-copy-btn';
|
||||
btn.type = 'button';
|
||||
btn.textContent = 'Copy host list (JSON)';
|
||||
btn.title = 'Copy hostname, alias, IPv4 address and monitored site as JSON';
|
||||
|
||||
btn.addEventListener('click', () => {
|
||||
const hosts = [];
|
||||
tables.forEach(table => {
|
||||
const headerRow = [...table.querySelectorAll('tr')].find(tr => tr.querySelector('th'));
|
||||
if (!headerRow) return;
|
||||
const headerCells = [...headerRow.querySelectorAll('th')].map(th => th.textContent.trim());
|
||||
const hostIdx = headerCells.indexOf('Host name');
|
||||
const aliasIdx = headerCells.indexOf('Alias');
|
||||
const ipIdx = headerCells.indexOf('IPv4 address');
|
||||
const siteIdx = headerCells.indexOf('Monitored on site');
|
||||
if (hostIdx === -1) return;
|
||||
|
||||
table.querySelectorAll('tr.data').forEach(tr => {
|
||||
const cells = [...tr.children];
|
||||
const link = cells[hostIdx] && cells[hostIdx].querySelector('a[href*="mode=edit_host"]');
|
||||
if (!link) return;
|
||||
const hostname = new URLSearchParams((link.getAttribute('href') || '').split('?')[1] || '').get('host');
|
||||
if (!hostname) return;
|
||||
hosts.push({
|
||||
hostname,
|
||||
alias: aliasIdx !== -1 ? cells[aliasIdx].textContent.trim() : '',
|
||||
ipv4: ipIdx !== -1 ? cells[ipIdx].textContent.trim() : '',
|
||||
site: siteIdx !== -1 ? cells[siteIdx].textContent.trim() : '',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
navigator.clipboard.writeText(JSON.stringify(hosts, null, 2)).then(() => {
|
||||
const orig = btn.textContent;
|
||||
btn.classList.add('copied');
|
||||
btn.textContent = `Copied ${hosts.length} hosts`;
|
||||
setTimeout(() => { btn.classList.remove('copied'); btn.textContent = orig; }, 1500);
|
||||
});
|
||||
});
|
||||
|
||||
menues.appendChild(btn);
|
||||
}
|
||||
|
||||
function tryAddHostListCopyButton() {
|
||||
const doc = getTargetDoc();
|
||||
if (!doc || !doc.body) {
|
||||
if (++attemptsHostListCopy < MAX_ATTEMPTS) setTimeout(tryAddHostListCopyButton, POLL_INTERVAL_MS);
|
||||
return;
|
||||
}
|
||||
try { if (!/\/wato\.py/.test(doc.location.pathname)) return; } catch (e) { return; }
|
||||
if (getPageMode(doc) !== 'folder') return;
|
||||
addHostListCopyButton(doc);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Collapse All / Expand All buttons in the top menu bar.
|
||||
// Works on edit_host / bulkedit / editfolder (table.nform accordions)
|
||||
|
|
@ -1661,6 +1746,7 @@
|
|||
attemptsSitesFilter = 0;
|
||||
attemptsListchoice = 0;
|
||||
attemptsExtraColToggle = 0;
|
||||
attemptsHostListCopy = 0;
|
||||
// Folder select: self-stops if element not found, always schedules.
|
||||
setTimeout(tryEnhanceFolderSelect, 800);
|
||||
// Accordion: only on pages in ACCORDION_MODES.
|
||||
|
|
@ -1677,6 +1763,8 @@
|
|||
setTimeout(tryAddInventoryButtons, 500);
|
||||
// Monitor button: on wato.py mode=folder, self-stops if not applicable.
|
||||
setTimeout(tryAddWatoFolderMonitorButtons, 500);
|
||||
// Copy host list button: on wato.py mode=folder, self-stops if not applicable.
|
||||
setTimeout(tryAddHostListCopyButton, 500);
|
||||
// WATO menu: on view.py with host rows, self-stops if not applicable.
|
||||
setTimeout(tryAddViewWatoMenu, 800);
|
||||
// Auto-check foreign activation: only on mode=changelog.
|
||||
|
|
@ -1726,6 +1814,10 @@
|
|||
attemptsFolderMon = 0;
|
||||
setTimeout(tryAddWatoFolderMonitorButtons, 300);
|
||||
}
|
||||
if (mode === 'folder' && iDoc.body && !iDoc.body.dataset.cmkHostListCopy) {
|
||||
attemptsHostListCopy = 0;
|
||||
setTimeout(tryAddHostListCopyButton, 300);
|
||||
}
|
||||
const tDoc = getTargetDoc();
|
||||
if (tDoc && tDoc.body && !tDoc.body.dataset.cmkViewWatoMenu) {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue