Skip to content

Commit 14f1285

Browse files
committed
Refactor serving-group topology visual to new schema and simplify layout
- align topology parser with updated groups schema using modems object and us sc_qam - add one-line tree labels and group cable modems by model with modem count - normalize channel type labels to SCQAM OFDM OFDMA and apply CF or Range BW text rules - remove per-channel section from SG cards and keep topology tree plus modem table only - keep tree interactions and SG summary metadata consistent with updated payload fields - 2026-03-08 21:15:58
1 parent 8b6130a commit 14f1285

17 files changed

Lines changed: 3355 additions & 1 deletion

File tree

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>PyPNM-CMTS / ServingGroup / Opertions / Get / cableModems</title>
7+
<style>
8+
body {
9+
margin: 0;
10+
padding: 12px;
11+
background: #f8fafc;
12+
color: #111827;
13+
font-family: ui-sans-serif, system-ui, sans-serif;
14+
}
15+
.frame {
16+
background: #ffffff;
17+
border: 1px solid #d1d5db;
18+
border-radius: 8px;
19+
padding: 12px;
20+
}
21+
.error {
22+
white-space: pre-wrap;
23+
color: #fecaca;
24+
background: #450a0a;
25+
border: 1px solid #7f1d1d;
26+
padding: 8px;
27+
border-radius: 6px;
28+
}
29+
@media (prefers-color-scheme: dark) {
30+
body {
31+
background: #0f172a;
32+
color: #e5e7eb;
33+
}
34+
.frame {
35+
background: #111827;
36+
border-color: #374151;
37+
}
38+
}
39+
</style>
40+
<script src="https://cdn.jsdelivr.net/npm/handlebars@4.7.8/dist/handlebars.min.js"></script>
41+
</head>
42+
<body>
43+
<div id="app" class="frame"></div>
44+
<script>
45+
(function() {
46+
const sampleData = {"status": 0, "message": "Stub sample for /cmts/servingGroup/operations/get/cableModems", "cmts": {"serving_group": {"id": []}}, "refresh": {"mode": "none", "wait_for_cache": false, "timeout_seconds": 8}, "data": []};
47+
const visualSource = "// Postman Visualizer: PyPNM-CMTS/ServingGroup/Opertions/Get/cableModems\n// Last Update: 2026-03-08 20:05:00 MST\n// Visual Constraints: Follow canonical visual rules in CODING_AGENTS.md.\n\n(function () {\n const response = pm.response.json();\n\n const template = `\n <style>\n body { background:#141821; color:#e7edf8; font-family:Arial,sans-serif; margin:0; padding:16px; }\n .wrap { max-width:1600px; margin:0 auto; }\n .card { background:#1b2332; border:1px solid rgba(255,255,255,0.09); border-radius:10px; padding:14px; }\n .title { margin:0 0 8px 0; color:#f3f6ff; text-align:center; font-size:20px; font-weight:700; }\n .meta { color:#dbe3ff; font-size:12px; margin-bottom:10px; text-align:center; }\n pre { margin:0; padding:10px; border-radius:6px; background:#1a1a1a; border:1px solid #4d4d4d; overflow:auto; font-size:12px; }\n </style>\n <div class=\"wrap\">\n <div class=\"card\">\n <h1 class=\"title\">Serving Group Operations Get Cable Modems</h1>\n <div class=\"meta\">POST /cmts/servingGroup/operations/get/cableModems</div>\n <pre>{{raw}}</pre>\n </div>\n </div>\n `;\n\n pm.visualizer.set(template, { raw: JSON.stringify(response, null, 2) });\n})();\n";
48+
const app = document.getElementById("app");
49+
let visualizerData = sampleData;
50+
let lastTemplate = null;
51+
52+
function showError(prefix, err) {
53+
const msg = String(err && err.stack || err);
54+
app.innerHTML = '<div class="error">' + prefix + '\n' + msg + '</div>';
55+
}
56+
57+
async function executeRenderedScripts(root) {
58+
const scripts = Array.from(root.querySelectorAll("script"));
59+
for (const oldScript of scripts) {
60+
const newScript = document.createElement("script");
61+
for (const attr of oldScript.attributes) {
62+
newScript.setAttribute(attr.name, attr.value);
63+
}
64+
const parent = oldScript.parentNode;
65+
if (!parent) continue;
66+
67+
if (oldScript.src) {
68+
await new Promise((resolve, reject) => {
69+
newScript.onload = resolve;
70+
newScript.onerror = function() {
71+
reject(new Error('Failed to load script: ' + oldScript.src));
72+
};
73+
parent.replaceChild(newScript, oldScript);
74+
});
75+
continue;
76+
}
77+
78+
newScript.textContent = oldScript.textContent;
79+
parent.replaceChild(newScript, oldScript);
80+
}
81+
}
82+
83+
function renderTemplate(template, data) {
84+
lastTemplate = template;
85+
visualizerData = data == null ? sampleData : data;
86+
try {
87+
const looksLikeHandlebars =
88+
typeof template === "string" &&
89+
template.indexOf("{") !== -1 &&
90+
template.indexOf("}") !== -1;
91+
if (window.Handlebars && looksLikeHandlebars) {
92+
const compiled = window.Handlebars.compile(template);
93+
app.innerHTML = compiled(visualizerData);
94+
void executeRenderedScripts(app).catch((err) => showError('Rendered script execution error', err));
95+
} else if (typeof template === "string") {
96+
app.innerHTML = template;
97+
void executeRenderedScripts(app).catch((err) => showError('Rendered script execution error', err));
98+
} else {
99+
app.textContent = String(template);
100+
}
101+
} catch (err) {
102+
showError('Template render error', err);
103+
}
104+
}
105+
106+
function makeKVStore() {
107+
const store = Object.create(null);
108+
return {
109+
get: function(key) { return Object.prototype.hasOwnProperty.call(store, key) ? store[key] : undefined; },
110+
set: function(key, value) { store[key] = value; return value; },
111+
unset: function(key) { delete store[key]; }
112+
};
113+
}
114+
115+
window.pm = {
116+
response: {
117+
json: function() { return sampleData; },
118+
text: function() { return JSON.stringify(sampleData); }
119+
},
120+
request: {
121+
body: {
122+
raw: "{}"
123+
}
124+
},
125+
environment: makeKVStore(),
126+
globals: makeKVStore(),
127+
variables: makeKVStore(),
128+
getData: function(cb) {
129+
if (typeof cb === "function") cb(null, visualizerData);
130+
},
131+
visualizer: {
132+
set: function(template, data) {
133+
renderTemplate(template, data);
134+
}
135+
}
136+
};
137+
138+
window.console = window.console || { log(){}, warn(){}, error(){} };
139+
window.addEventListener('error', function(ev) {
140+
if (ev && ev.error) showError('Window error', ev.error);
141+
});
142+
window.addEventListener('unhandledrejection', function(ev) {
143+
showError('Unhandled promise rejection', ev && ev.reason);
144+
});
145+
146+
if (sampleData && typeof sampleData === 'object' && sampleData.__error__) {
147+
app.innerHTML = '<div class="error">Preview unavailable\nInvalid sample JSON fixture\n' + String(sampleData.__error__) + '</div>';
148+
return;
149+
}
150+
151+
try {
152+
const fn = new Function(visualSource);
153+
fn();
154+
if (!lastTemplate && !app.innerHTML.trim()) {
155+
app.innerHTML = '<div class="error">No visualizer output produced. The script may require unsupported Postman APIs.</div>';
156+
}
157+
} catch (err) {
158+
showError('Script execution error', err);
159+
}
160+
})();
161+
</script>
162+
</body>
163+
</html>
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>PyPNM-CMTS / ServingGroup / Opertions / Get / ids</title>
7+
<style>
8+
body {
9+
margin: 0;
10+
padding: 12px;
11+
background: #f8fafc;
12+
color: #111827;
13+
font-family: ui-sans-serif, system-ui, sans-serif;
14+
}
15+
.frame {
16+
background: #ffffff;
17+
border: 1px solid #d1d5db;
18+
border-radius: 8px;
19+
padding: 12px;
20+
}
21+
.error {
22+
white-space: pre-wrap;
23+
color: #fecaca;
24+
background: #450a0a;
25+
border: 1px solid #7f1d1d;
26+
padding: 8px;
27+
border-radius: 6px;
28+
}
29+
@media (prefers-color-scheme: dark) {
30+
body {
31+
background: #0f172a;
32+
color: #e5e7eb;
33+
}
34+
.frame {
35+
background: #111827;
36+
border-color: #374151;
37+
}
38+
}
39+
</style>
40+
<script src="https://cdn.jsdelivr.net/npm/handlebars@4.7.8/dist/handlebars.min.js"></script>
41+
</head>
42+
<body>
43+
<div id="app" class="frame"></div>
44+
<script>
45+
(function() {
46+
const sampleData = {"status": 0, "message": "Stub sample for /cmts/servingGroup/operations/get/ids", "data": {"ids": []}};
47+
const visualSource = "// Postman Visualizer: PyPNM-CMTS/ServingGroup/Opertions/Get/ids\n// Last Update: 2026-03-08 20:05:00 MST\n// Visual Constraints: Follow canonical visual rules in CODING_AGENTS.md.\n\n(function () {\n const response = pm.response.json();\n\n const template = `\n <style>\n body { background:#141821; color:#e7edf8; font-family:Arial,sans-serif; margin:0; padding:16px; }\n .wrap { max-width:1600px; margin:0 auto; }\n .card { background:#1b2332; border:1px solid rgba(255,255,255,0.09); border-radius:10px; padding:14px; }\n .title { margin:0 0 8px 0; color:#f3f6ff; text-align:center; font-size:20px; font-weight:700; }\n .meta { color:#dbe3ff; font-size:12px; margin-bottom:10px; text-align:center; }\n pre { margin:0; padding:10px; border-radius:6px; background:#1a1a1a; border:1px solid #4d4d4d; overflow:auto; font-size:12px; }\n </style>\n <div class=\"wrap\">\n <div class=\"card\">\n <h1 class=\"title\">Serving Group Operations Get IDs</h1>\n <div class=\"meta\">GET /cmts/servingGroup/operations/get/ids</div>\n <pre>{{raw}}</pre>\n </div>\n </div>\n `;\n\n pm.visualizer.set(template, { raw: JSON.stringify(response, null, 2) });\n})();\n";
48+
const app = document.getElementById("app");
49+
let visualizerData = sampleData;
50+
let lastTemplate = null;
51+
52+
function showError(prefix, err) {
53+
const msg = String(err && err.stack || err);
54+
app.innerHTML = '<div class="error">' + prefix + '\n' + msg + '</div>';
55+
}
56+
57+
async function executeRenderedScripts(root) {
58+
const scripts = Array.from(root.querySelectorAll("script"));
59+
for (const oldScript of scripts) {
60+
const newScript = document.createElement("script");
61+
for (const attr of oldScript.attributes) {
62+
newScript.setAttribute(attr.name, attr.value);
63+
}
64+
const parent = oldScript.parentNode;
65+
if (!parent) continue;
66+
67+
if (oldScript.src) {
68+
await new Promise((resolve, reject) => {
69+
newScript.onload = resolve;
70+
newScript.onerror = function() {
71+
reject(new Error('Failed to load script: ' + oldScript.src));
72+
};
73+
parent.replaceChild(newScript, oldScript);
74+
});
75+
continue;
76+
}
77+
78+
newScript.textContent = oldScript.textContent;
79+
parent.replaceChild(newScript, oldScript);
80+
}
81+
}
82+
83+
function renderTemplate(template, data) {
84+
lastTemplate = template;
85+
visualizerData = data == null ? sampleData : data;
86+
try {
87+
const looksLikeHandlebars =
88+
typeof template === "string" &&
89+
template.indexOf("{") !== -1 &&
90+
template.indexOf("}") !== -1;
91+
if (window.Handlebars && looksLikeHandlebars) {
92+
const compiled = window.Handlebars.compile(template);
93+
app.innerHTML = compiled(visualizerData);
94+
void executeRenderedScripts(app).catch((err) => showError('Rendered script execution error', err));
95+
} else if (typeof template === "string") {
96+
app.innerHTML = template;
97+
void executeRenderedScripts(app).catch((err) => showError('Rendered script execution error', err));
98+
} else {
99+
app.textContent = String(template);
100+
}
101+
} catch (err) {
102+
showError('Template render error', err);
103+
}
104+
}
105+
106+
function makeKVStore() {
107+
const store = Object.create(null);
108+
return {
109+
get: function(key) { return Object.prototype.hasOwnProperty.call(store, key) ? store[key] : undefined; },
110+
set: function(key, value) { store[key] = value; return value; },
111+
unset: function(key) { delete store[key]; }
112+
};
113+
}
114+
115+
window.pm = {
116+
response: {
117+
json: function() { return sampleData; },
118+
text: function() { return JSON.stringify(sampleData); }
119+
},
120+
request: {
121+
body: {
122+
raw: "{}"
123+
}
124+
},
125+
environment: makeKVStore(),
126+
globals: makeKVStore(),
127+
variables: makeKVStore(),
128+
getData: function(cb) {
129+
if (typeof cb === "function") cb(null, visualizerData);
130+
},
131+
visualizer: {
132+
set: function(template, data) {
133+
renderTemplate(template, data);
134+
}
135+
}
136+
};
137+
138+
window.console = window.console || { log(){}, warn(){}, error(){} };
139+
window.addEventListener('error', function(ev) {
140+
if (ev && ev.error) showError('Window error', ev.error);
141+
});
142+
window.addEventListener('unhandledrejection', function(ev) {
143+
showError('Unhandled promise rejection', ev && ev.reason);
144+
});
145+
146+
if (sampleData && typeof sampleData === 'object' && sampleData.__error__) {
147+
app.innerHTML = '<div class="error">Preview unavailable\nInvalid sample JSON fixture\n' + String(sampleData.__error__) + '</div>';
148+
return;
149+
}
150+
151+
try {
152+
const fn = new Function(visualSource);
153+
fn();
154+
if (!lastTemplate && !app.innerHTML.trim()) {
155+
app.innerHTML = '<div class="error">No visualizer output produced. The script may require unsupported Postman APIs.</div>';
156+
}
157+
} catch (err) {
158+
showError('Script execution error', err);
159+
}
160+
})();
161+
</script>
162+
</body>
163+
</html>

0 commit comments

Comments
 (0)