Skip to content

Commit 041ef5b

Browse files
committed
Improve demo application
1 parent fc91241 commit 041ef5b

File tree

4 files changed

+352
-32
lines changed

4 files changed

+352
-32
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ node_modules/
33
npm-debug.log
44
.build*
55
.idea
6-
index.html
76
dist/
7+
test/coverage/lcov-report/index.html

docs/client-demo.html

Lines changed: 289 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,293 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
4-
<meta charset="UTF-8">
5-
<title>Labs64 NetLicensing JavaScript Client Demo</title>
6-
<script src="../dist/index.global.js"></script>
7-
<script src="client-demo.js"></script>
8-
<style>
9-
.console-log-div {
10-
border: 1px solid gray;
11-
padding: 5px 10px;
12-
border-radius: 5px;
13-
width: 95% !important;
14-
background-color: #efefef;
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Labs64 NetLicensing JavaScript Client Demo</title>
7+
8+
<!-- Load Tailwind CSS for modern styling -->
9+
<script src="https://cdn.tailwindcss.com"></script>
10+
11+
<!-- Configure Tailwind theme for Labs64 Brand Color -->
12+
<script>
13+
tailwind.config = {
14+
theme: {
15+
extend: {
16+
colors: {
17+
brand: {
18+
DEFAULT: '#E14817',
19+
hover: '#C23E14'
20+
},
21+
terminal: {
22+
text: '#F2951C' /* Custom console font color */
23+
}
24+
}
25+
}
26+
}
27+
}
28+
</script>
29+
30+
<!-- Load latest NetLicensing Client from unpkg -->
31+
<script src="https://unpkg.com/netlicensing-client@latest/dist/index.global.js"></script>
32+
33+
<!-- Load your demo logic (Ensure this matches your local file name) -->
34+
<script src="client-demo.js"></script>
35+
36+
<style>
37+
/* Custom scrollbar for the console output */
38+
#console-log-text::-webkit-scrollbar {
39+
width: 10px;
40+
}
41+
#console-log-text::-webkit-scrollbar-track {
42+
background: #111827;
43+
border-left: 1px solid #374151;
44+
}
45+
#console-log-text::-webkit-scrollbar-thumb {
46+
background: #4b5563;
47+
border-radius: 5px;
48+
border: 2px solid #111827;
49+
}
50+
#console-log-text::-webkit-scrollbar-thumb:hover {
51+
background: #6b7280;
52+
}
53+
54+
/* Flex layout setup */
55+
body {
56+
display: flex;
57+
flex-direction: column;
58+
height: 100vh;
59+
margin: 0;
60+
overflow: hidden;
61+
}
62+
63+
.main-container {
64+
flex: 1;
65+
display: flex;
66+
flex-direction: column;
67+
padding-bottom: 2rem;
68+
min-height: 0;
69+
}
70+
71+
.terminal-container {
72+
flex: 1;
73+
display: flex;
74+
flex-direction: column;
75+
min-height: 0;
76+
}
77+
78+
#console-log-text {
79+
flex: 1;
80+
overflow-y: auto;
81+
word-wrap: break-word;
82+
}
83+
84+
/* Prevent layout shift during auto-scroll */
85+
.log-entry {
86+
margin-bottom: 0.5rem;
87+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
88+
}
89+
90+
/* Hide the default triangle marker for summary */
91+
summary::-webkit-details-marker {
92+
display: none;
93+
}
94+
summary {
95+
list-style: none;
96+
}
97+
</style>
98+
</head>
99+
<body class="bg-gray-50 font-sans text-gray-800">
100+
101+
<div class="main-container w-[1024px] max-w-[1024px] mx-auto pt-6 px-4">
102+
103+
<!-- Header Section -->
104+
<div class="text-center mb-4 shrink-0">
105+
<h1 class="text-4xl font-extrabold text-gray-900 tracking-tight mb-2">
106+
<a class="block text-brand" href="https://netlicensing.io/" target="_blank" class="hover:text-brand-hover transition-colors">
107+
Labs64 NetLicensing
108+
</a>
109+
<span class="block">JavaScript Client</span>
110+
</h1>
111+
<p class="mt-1 text-base text-gray-500 max-w-2xl mx-auto">
112+
Interactive demo showcasing <a href="https://netlicensing.io/wiki/restful-api" target="_blank" class="text-brand hover:underline">RESTful API</a> access.
113+
</p>
114+
</div>
115+
116+
<!-- Controls Section -->
117+
<div class="flex justify-center gap-3 mb-4 shrink-0 flex-wrap">
118+
<button
119+
onclick="NetLicensingDemo()"
120+
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-brand hover:bg-brand-hover focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brand transition-colors duration-200">
121+
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
122+
Execute Demo
123+
</button>
124+
125+
<button
126+
onclick="clearBox('console-log-text')"
127+
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none transition-colors duration-200 shadow-sm">
128+
<svg class="w-4 h-4 mr-2 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg>
129+
Clear Console
130+
</button>
131+
132+
<!-- New Navigability Buttons -->
133+
<button
134+
onclick="toggleAllLogs(true)"
135+
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none transition-colors duration-200 shadow-sm">
136+
<svg class="w-4 h-4 mr-2 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
137+
Expand All
138+
</button>
139+
140+
<button
141+
onclick="toggleAllLogs(false)"
142+
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none transition-colors duration-200 shadow-sm">
143+
<svg class="w-4 h-4 mr-2 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"></path></svg>
144+
Collapse All
145+
</button>
146+
</div>
147+
148+
<!-- Terminal Output Section -->
149+
<div class="terminal-container bg-gray-900 rounded-lg shadow-xl overflow-hidden border border-gray-700 w-full relative">
150+
<!-- Mac-style window header -->
151+
<div class="bg-gray-800 px-4 py-2 border-b border-gray-700 flex items-center shrink-0 z-10">
152+
<div class="flex space-x-2">
153+
<div class="w-3 h-3 rounded-full bg-red-500"></div>
154+
<div class="w-3 h-3 rounded-full bg-yellow-500"></div>
155+
<div class="w-3 h-3 rounded-full bg-green-500"></div>
156+
</div>
157+
<div class="mx-auto text-gray-400 text-xs font-mono">demo-output.log</div>
158+
</div>
159+
160+
<!-- Output container -->
161+
<div class="p-4 text-sm w-full" id="console-log-text">
162+
<div class="text-gray-500 mb-2 font-mono">Ready. Click 'Execute Demo' to start the NetLicensing API simulation...</div>
163+
</div>
164+
</div>
165+
</div>
166+
167+
<!-- Intercept Console Output -->
168+
<script>
169+
// Helper function for the Expand/Collapse buttons
170+
function toggleAllLogs(expand) {
171+
const details = document.querySelectorAll('#console-log-text details');
172+
details.forEach(detail => {
173+
if (expand) {
174+
detail.setAttribute('open', '');
175+
} else {
176+
detail.removeAttribute('open');
177+
}
178+
});
179+
}
180+
181+
(function() {
182+
const oldLog = console.log;
183+
const oldError = console.error;
184+
const oldWarn = console.warn;
185+
const logger = document.getElementById('console-log-text');
186+
187+
function formatArgs(args) {
188+
return Array.from(args).map(arg => {
189+
if (arg instanceof Error) {
190+
return arg.stack || arg.message;
191+
}
192+
if (typeof arg === 'object' && arg !== null) {
193+
try {
194+
return JSON.stringify(arg, null, 2);
195+
} catch (e) {
196+
return String(arg);
197+
}
198+
}
199+
return String(arg);
200+
}).join(' ');
15201
}
16-
</style>
17-
</head>
18-
19-
<body>
20-
<h1><p align="center"><strong>Labs64 <a href="https://netlicensing.io">NetLicensing</a><br/>JavaScript Client
21-
Demo</strong></p></h1>
22-
<p align="center">This demo showcases <a href="https://netlicensing.io/wiki/restful-api">RESTful API</a> access
23-
to NetLicensing’s core features.</p>
24-
<p align="center">
25-
<input type="button" value="Execute" onclick="NetLicensingDemo();"/>
26-
<input type="button" value="Clear" onclick="clearBox('console-log-text')"/>
27-
</p>
28-
29-
<script src="https://cdn.jsdelivr.net/npm/console-log-div@0.6.3/console-log-div.min.js"></script>
30-
</body>
202+
203+
function appendLog(args, colorClass, prefixChar = '>') {
204+
const msg = formatArgs(args);
205+
const lines = msg.split('\n');
206+
207+
// If it's a multi-line output (like an API JSON response), make it foldable
208+
if (lines.length > 1) {
209+
const details = document.createElement('details');
210+
details.className = `log-entry ${colorClass} group`;
211+
212+
const summary = document.createElement('summary');
213+
summary.className = 'cursor-pointer hover:opacity-80 transition-opacity outline-none flex items-start select-none';
214+
215+
// Arrow indicator that rotates when expanded
216+
const arrow = document.createElement('span');
217+
arrow.className = 'text-[#E14817] mr-2 font-bold transform transition-transform group-open:rotate-90 inline-block w-3 flex-shrink-0 text-center';
218+
arrow.textContent = prefixChar;
219+
220+
const summaryText = document.createElement('span');
221+
// Show the first line with an ellipsis, so the user knows there is hidden data
222+
summaryText.textContent = lines[0] + ' ...';
223+
summaryText.className = 'truncate';
224+
225+
summary.appendChild(arrow);
226+
summary.appendChild(summaryText);
227+
228+
const content = document.createElement('div');
229+
// Indent the expanded JSON, add a subtle border on the left
230+
content.className = 'pl-4 ml-[0.35rem] border-l-2 border-gray-700 mt-1 whitespace-pre-wrap break-all opacity-90';
231+
content.textContent = lines.slice(1).join('\n');
232+
233+
details.appendChild(summary);
234+
details.appendChild(content);
235+
logger.appendChild(details);
236+
}
237+
// Single line output (like a basic string log)
238+
else {
239+
const div = document.createElement('div');
240+
div.className = `log-entry ${colorClass} flex items-start`;
241+
242+
const prefix = document.createElement('span');
243+
prefix.className = 'text-[#E14817] mr-2 select-none font-bold inline-block w-3 flex-shrink-0 text-center';
244+
prefix.textContent = prefixChar;
245+
246+
const text = document.createElement('span');
247+
text.className = 'whitespace-pre-wrap break-all';
248+
text.textContent = msg;
249+
250+
div.appendChild(prefix);
251+
div.appendChild(text);
252+
logger.appendChild(div);
253+
}
254+
255+
requestAnimationFrame(() => {
256+
logger.scrollTop = logger.scrollHeight;
257+
});
258+
}
259+
260+
console.log = function() {
261+
oldLog.apply(console, arguments);
262+
appendLog(arguments, 'text-terminal-text');
263+
};
264+
265+
console.error = function() {
266+
oldError.apply(console, arguments);
267+
appendLog(arguments, 'text-red-400', '✖');
268+
};
269+
270+
console.warn = function() {
271+
oldWarn.apply(console, arguments);
272+
appendLog(arguments, 'text-yellow-400', '⚠');
273+
};
274+
275+
window.onerror = function(message, source, lineno, colno, error) {
276+
console.error("Uncaught Error: " + message);
277+
return false;
278+
};
279+
280+
window.addEventListener("unhandledrejection", function(event) {
281+
console.error("Unhandled Promise Rejection: " + (event.reason ? event.reason.stack || event.reason : event));
282+
});
283+
284+
window.clearBox = function(elementID) {
285+
const el = document.getElementById(elementID);
286+
if (el) {
287+
el.innerHTML = '<div class="text-gray-500 mb-2 font-mono">Console cleared. Ready.</div>';
288+
}
289+
};
290+
})();
291+
</script>
292+
</body>
31293
</html>

docs/client-demo.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const NetLicensingDemo = async () => {
2+
try {
23
const {
34
Context,
45
LicenseType,
@@ -38,8 +39,8 @@ const NetLicensingDemo = async () => {
3839

3940
console.log('UtilityService.listLicenseTypes() :', await UtilityService.listLicenseTypes(context));
4041
console.log('UtilityService.listLicensingModels() :', await UtilityService.listLicensingModels(context));
41-
console.log('UtilityService.listCountries() :', await UtilityService.listCountries(context));
42-
console.log((await UtilityService.listCountries(context)).getContent());
42+
//console.log('UtilityService.listCountries() :', await UtilityService.listCountries(context));
43+
//console.log((await UtilityService.listCountries(context)).getContent());
4344
// endregion
4445

4546
// region ********* Product
@@ -300,9 +301,22 @@ const NetLicensingDemo = async () => {
300301

301302
// region ********* CleanUp
302303

303-
console.log('All done.');
304-
await ProductService.delete(context, productNumber, true);
304+
console.log('All done');
305+
await ProductService.delete(context, productNumber, true);
305306
// endregion
307+
308+
} catch (error) {
309+
console.error('❌ NetLicensing API Error:');
310+
311+
// Check if it's an Axios/API response error
312+
if (error.response && error.response.data) {
313+
console.error('Status Code:', error.response.status);
314+
console.error(JSON.stringify(error.response.data, null, 2));
315+
} else {
316+
// Standard JS/Network error
317+
console.error(error.message || error);
318+
}
319+
}
306320
};
307321

308322
function numberWithPrefix(prefix, number) {

0 commit comments

Comments
 (0)