Skip to content

Commit 7efcd84

Browse files
authored
Merge pull request #10 from Lissy93/ref/test-and-ui-improvments
Ref/test and UI improvments
2 parents 7d592f7 + 611a7a0 commit 7efcd84

251 files changed

Lines changed: 17681 additions & 6362 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/README.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,23 @@ If you're new to GitHub or open source, take a look at [git-in.to](https://git-i
111111
---
112112

113113
### Features
114-
100+ networking and sysadmin tools, zero third-party dependencies, works ofline.
115114

115+
<h3 align="center">Make it your own</h3>
116+
<p align="center"><i>Custom layouts, theming, bookmarking, multi-language support and more</i></p>
116117
<p align="center">
117-
<img width="2761" height="1229" alt="networking-toolbox" src="https://github.com/user-attachments/assets/2a128ee2-9bcb-49f0-be41-f69a3b8f2474" />
118-
<br>
119-
<sup><i>We've got 100+ tools, covering all aspects of network engineering</i></sup>
118+
<img width="800" src="https://storage.googleapis.com/as93-screenshots/networking-toolbox/light-dark-mode-single.png" />
119+
</p>
120+
121+
<h3 align="center">Works anywhere</h3>
122+
<p align="center"><i>Offline-capable, mobile optimized, zero third-party dependencies</i></p>
123+
<p align="center">
124+
<img width="800" src="https://storage.googleapis.com/as93-screenshots/networking-toolbox/mobile-views.png" />
125+
</p>
126+
127+
<h3 align="center">100s of tools</h3>
128+
<p align="center"><i>Everything you need for converting, calculating, diagnosing and verifying server configs</i></p>
129+
<p align="center">
130+
<img width="800" src="https://github.com/user-attachments/assets/2dfe66b7-2325-4b41-b116-32eab74d3cf6" />
120131
</p>
121132

122133
---

.github/codeql-config.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: "CodeQL Config"
2+
3+
paths:
4+
- src/
5+
6+
paths-ignore:
7+
- "**/node_modules"
8+
- "**/.svelte-kit"
9+
- "**/build"
10+
- "**/dist"
11+
- "**/.next"
12+
- "**/coverage"
13+
- "**/*.config.js"
14+
- "**/*.config.ts"
15+
- "**/vite.config.*"
16+
- "**/vitest.config.*"
17+
- "**/playwright.config.*"
18+
- "**/tailwind.config.*"
19+
- "**/postcss.config.*"
20+
- "**/svelte.config.js"
21+
22+
queries:
23+
- uses: security-and-quality

.github/docs/error-tracking.md

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Error Tracking and Handling
2+
3+
This app has a global error handling system that automatically catches and logs errors across both server and client side.
4+
5+
## How It Works
6+
7+
All errors are automatically captured by SvelteKit hooks and global listeners. You don't need to wrap everything in try-catch blocks.
8+
9+
**Key Files:**
10+
11+
- [`src/lib/types/error.ts`](https://github.com/Lissy93/networking-toolbox/blob/main/src/lib/types/error.ts) - Error types and custom error classes
12+
- [`src/lib/utils/logger.ts`](https://github.com/Lissy93/networking-toolbox/blob/main/src/lib/utils/logger.ts) - Environment-aware logger with styled console output
13+
- [`src/lib/utils/error-manager.ts`](https://github.com/Lissy93/networking-toolbox/blob/main/src/lib/utils/error-manager.ts) - Central error management with deduplication
14+
- [`src/hooks.server.ts`](https://github.com/Lissy93/networking-toolbox/blob/main/src/hooks.server.ts) - Server-side error hook
15+
- [`src/hooks.client.ts`](https://github.com/Lissy93/networking-toolbox/blob/main/src/hooks.client.ts) - Client-side error hook with global listeners
16+
- [`src/routes/+error.svelte`](https://github.com/Lissy93/networking-toolbox/blob/main/src/routes/+error.svelte) - Error page UI
17+
18+
**What Gets Caught Automatically:**
19+
20+
- Server errors (API routes, server load functions)
21+
- Client errors (component errors, runtime errors)
22+
- Unhandled promise rejections
23+
- Window errors (global `window.onerror`)
24+
25+
## For Developers
26+
27+
### Most of the time: Do nothing
28+
29+
The hooks catch everything. Just write your code normally.
30+
31+
### When you want custom context
32+
33+
Use the error manager to add specific context for debugging:
34+
35+
```typescript
36+
import { errorManager } from '$lib/utils/error-manager';
37+
38+
try {
39+
await saveUserData(data);
40+
} catch (error) {
41+
errorManager.captureException(error, 'error', {
42+
component: 'UserSettings',
43+
action: 'saveData',
44+
dataSize: data.length
45+
});
46+
throw error; // Re-throw so user sees it
47+
}
48+
```
49+
50+
### Custom error types
51+
52+
Use `AppError` for domain-specific errors with user-friendly messages:
53+
54+
```typescript
55+
import { AppError, NetworkError, ValidationError } from '$lib/types/error';
56+
57+
// Generic app error
58+
throw new AppError('Database query failed', 'Unable to save your changes');
59+
60+
// Specific error types
61+
throw new NetworkError('Connection timeout');
62+
throw new ValidationError('Invalid email format', 'Please enter a valid email');
63+
```
64+
65+
### Logging
66+
67+
Use the logger instead of `console.log`:
68+
69+
```typescript
70+
import { logger } from '$lib/utils/logger';
71+
72+
logger.debug('Cache hit', { key, size });
73+
logger.info('User action completed', { action: 'export', format: 'csv' });
74+
logger.warn('Rate limit approaching', { requests: 95, limit: 100 });
75+
logger.error('Operation failed', error, { component: 'DataExporter' });
76+
```
77+
78+
The logger automatically adjusts based on environment (more verbose in dev, quieter in prod) and provides styled, collapsible output in the browser.
79+
80+
## Configuration
81+
82+
Set the log level via environment variable:
83+
84+
```bash
85+
VITE_LOG_LEVEL=debug # Options: debug, info, warn, error
86+
```
87+
88+
Defaults to `debug` in development, `warn` in production.
89+
90+
## Expanding with External Services
91+
92+
The error manager uses a transport pattern, making it easy to add services like Sentry or GlitchTip.
93+
94+
### Adding Sentry
95+
96+
1. Install Sentry:
97+
```bash
98+
npm install @sentry/sveltekit
99+
```
100+
101+
2. Create a Sentry transport in [`src/lib/utils/error-manager.ts`](https://github.com/Lissy93/networking-toolbox/blob/main/src/lib/utils/error-manager.ts):
102+
103+
```typescript
104+
import * as Sentry from '@sentry/sveltekit';
105+
106+
class SentryTransport implements ErrorTransport {
107+
send(error: SerializedError): void {
108+
Sentry.captureException(new Error(error.message), {
109+
level: error.level,
110+
tags: { component: error.context.component },
111+
extra: error.context,
112+
});
113+
}
114+
}
115+
116+
// Add to error manager
117+
if (import.meta.env.VITE_SENTRY_DSN) {
118+
errorManager.addTransport(new SentryTransport());
119+
}
120+
```
121+
122+
3. Initialize Sentry in your hooks:
123+
124+
```typescript
125+
// src/hooks.client.ts
126+
import * as Sentry from '@sentry/sveltekit';
127+
128+
Sentry.init({
129+
dsn: import.meta.env.VITE_SENTRY_DSN,
130+
environment: import.meta.env.MODE,
131+
});
132+
```
133+
134+
### Adding GlitchTip
135+
136+
GlitchTip is Sentry-compatible, so use the same approach with a different DSN.
137+
138+
### Custom Transport
139+
140+
Create any transport that implements the `ErrorTransport` interface:
141+
142+
```typescript
143+
class CustomTransport implements ErrorTransport {
144+
async send(error: SerializedError): Promise<void> {
145+
await fetch('/api/log-error', {
146+
method: 'POST',
147+
body: JSON.stringify(error),
148+
});
149+
}
150+
}
151+
152+
errorManager.addTransport(new CustomTransport());
153+
```
154+
155+
## Error Deduplication
156+
157+
The error manager automatically deduplicates identical errors within a 5-second window. This prevents log spam when an error repeats rapidly.
158+
159+
## Testing
160+
161+
See [`tests/unit/utils/error-manager.test.ts`](https://github.com/Lissy93/networking-toolbox/blob/main/tests/unit/utils/error-manager.test.ts) for examples of testing error handling in your code.

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ jobs:
6969
- name: Create Release
7070
uses: softprops/action-gh-release@v2
7171
with:
72+
token: ${{ secrets.BOT_TOKEN }}
7273
tag_name: ${{ github.ref_name }}
7374
name: Networking Toolbox ${{ steps.version.outputs.version }}
7475
body: |

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ Thumbs.db
2525
/test-results
2626
e2e-results.xml
2727

28+
# Other generated results
29+
codeql-db/
30+
*.sarif
31+
2832
# AI Crap
2933
.claude/
3034
.playwright-mcp/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Alicia Sykes
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

codecov.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ coverage:
1111
status:
1212
project:
1313
default:
14-
target: 60%
15-
threshold: 0%
14+
target: 80%
15+
threshold: 5%
1616
informational: true
1717
if_ci_failed: success
1818
patch:
1919
default:
2020
target: 50%
21-
threshold: 0%
21+
threshold: 10%
2222
informational: true
2323
if_ci_failed: success
2424

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "networking-toolbox",
33
"private": true,
4-
"version": "1.2.0",
4+
"version": "1.3.0",
55
"type": "module",
66
"scripts": {
77
"dev": "vite dev",

src/app.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
declare global {
77
namespace App {
8-
// interface Error {}
8+
interface Error {
9+
message: string;
10+
errorId?: string;
11+
}
912
// interface Locals {}
1013
// interface PageData {}
1114
// interface PageState {}
@@ -14,6 +17,7 @@ declare global {
1417

1518
// Make version available globally
1619
const __APP_VERSION__: string;
20+
const __DEPLOY_ENV__: string;
1721
}
1822

1923
// SVG imports

src/app.html

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,63 @@
44
<meta charset="utf-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1" />
66

7+
<!-- Preload self-hosted fonts for default themes (Tokyo Night, Dark, Light) -->
8+
<link rel="preload" as="style" href="/fonts/fonts.css" />
9+
<link rel="stylesheet" href="/fonts/fonts.css" media="print" onload="this.media='all';this.onload=null;" />
10+
<noscript>
11+
<link rel="stylesheet" href="/fonts/fonts.css" />
12+
</noscript>
13+
14+
<!-- Preconnect to Google Fonts for other themes -->
15+
<link rel="preconnect" href="https://fonts.googleapis.com" />
16+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
17+
718
<!-- Prevent FOUC by applying theme before page renders -->
819
<script>
920
(function () {
1021
try {
11-
// Apply theme
12-
const theme = localStorage.getItem('theme') || 'dark';
22+
// Get saved theme from localStorage
23+
const savedTheme = localStorage.getItem('theme');
24+
25+
let theme;
26+
if (savedTheme) {
27+
// Use saved theme if it exists
28+
theme = savedTheme;
29+
} else {
30+
// No saved theme - check system preference
31+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
32+
const prefersLight = window.matchMedia('(prefers-color-scheme: light)').matches;
33+
if (prefersLight) {
34+
theme = 'light';
35+
} else if (prefersDark) {
36+
theme = 'dark';
37+
} else {
38+
theme = 'ocean';
39+
}
40+
}
41+
42+
// Apply theme class (dark theme doesn't need a class)
1343
if (theme !== 'dark') {
1444
document.documentElement.classList.add('theme-' + theme);
1545
}
1646
} catch (e) {
1747
// Ignore localStorage errors (private browsing, etc.)
48+
// Fall back to system preference or ocean
49+
try {
50+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
51+
const prefersLight = window.matchMedia('(prefers-color-scheme: light)').matches;
52+
53+
if (prefersLight) {
54+
document.documentElement.classList.add('theme-light');
55+
} else if (!prefersDark) {
56+
// Neither dark nor light preferred - use ocean
57+
document.documentElement.classList.add('theme-ocean');
58+
}
59+
// If prefersDark, no class needed (dark is default)
60+
} catch (e2) {
61+
// If all fails, use ocean
62+
document.documentElement.classList.add('theme-ocean');
63+
}
1864
}
1965
})();
2066
</script>

0 commit comments

Comments
 (0)