Skip to content

Commit 80c1f26

Browse files
Merge pull request #117 from chriscareycode/cc/2026-01-01-minimapmozilla
MiniMapMozilla
2 parents 6f566da + 090da56 commit 80c1f26

16 files changed

Lines changed: 594 additions & 133 deletions

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ Installing NagiosTV
4646
-------------
4747
- Download the latest NagiosTV tar.gz release from https://github.com/chriscareycode/nagiostv-react/releases or you can just copy and paste the command below to get it:
4848
```console
49-
wget https://github.com/chriscareycode/nagiostv-react/releases/download/v0.9.7/nagiostv-0.9.7.tar.gz
49+
wget https://github.com/chriscareycode/nagiostv-react/releases/download/v0.9.8/nagiostv-0.9.8.tar.gz
5050
```
5151
- Extract the NagiosTV release using tar. This will create a nagiostv/ folder.
5252
```console
53-
tar xvfz nagiostv-0.9.7.tar.gz
53+
tar xvfz nagiostv-0.9.8.tar.gz
5454
```
5555
- We're going to host the NagiosTV folder from the built-in Nagios web ui. Copy/Move the nagiostv/ folder into your Nagios web ui folder. For Nagios Core 4 the Nagios web ui folder might be at `/usr/local/nagios/share/` or `/usr/nagios/share/`. Nagios XI might be at `/var/www/html/` or `/usr/local/nagiosxi/html/`.
5656

@@ -104,8 +104,8 @@ Then pretty much the same process as above. Download and overwrite the nagiostv
104104
Remember your web ui destination folder `/usr/local/nagios/share/nagiostv/` may vary depending on your Nagios install.
105105
You can do it on the box with:
106106
```console
107-
wget https://github.com/chriscareycode/nagiostv-react/releases/download/v0.9.7/nagiostv-0.9.7.tar.gz
108-
tar xvfz nagiostv-0.9.7.tar.gz
107+
wget https://github.com/chriscareycode/nagiostv-react/releases/download/v0.9.8/nagiostv-0.9.8.tar.gz
108+
tar xvfz nagiostv-0.9.8.tar.gz
109109
sudo cp -r nagiostv/* /usr/local/nagios/share/nagiostv/
110110
```
111111

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nagiostv",
3-
"version": "0.9.7",
3+
"version": "0.9.8",
44
"type": "module",
55
"private": true,
66
"homepage": "./",

src/atoms/settingsState.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ const useFakeSampleData = urlParams.get('fakedata') === 'true' || urlParams.get(
2626

2727
const bigStateInitial: BigState = {
2828

29-
currentVersion: 85, // This gets incremented with each new release (manually)
30-
currentVersionString: '0.9.7', // This gets incremented with each new release (manually)
29+
currentVersion: 86, // This gets incremented with each new release (manually)
30+
currentVersionString: '0.9.8', // This gets incremented with each new release (manually)
3131

3232
latestVersion: 0,
3333
latestVersionString: '',
@@ -67,10 +67,13 @@ export const clientSettingsInitial: ClientSettings = {
6767
alertMaxItems: 1000,
6868

6969
hostsAndServicesSideBySide: false,
70-
hideSummarySection: true,
70+
71+
hideSummarySection: false,
7172
hideMostRecentAlertSection: true,
7273
hideLocalLLMSection: true,
74+
7375
hideServiceSection: false,
76+
7477
hideServicePending: false,
7578
hideServiceOk: true,
7679
hideServiceWarning: false,
@@ -84,6 +87,7 @@ export const clientSettingsInitial: ClientSettings = {
8487
serviceSortOrder: 'newest',
8588

8689
hideHostSection: false,
90+
8791
hideHostPending: false,
8892
hideHostUp: true,
8993
hideHostDown: false,
@@ -138,28 +142,26 @@ export const clientSettingsInitial: ClientSettings = {
138142
miniMapWidth: 120,
139143

140144
// LLM integration
141-
llmServerHost: 'localhost',
142-
llmServerPort: 1234,
145+
llmServerBaseUrl: 'http://localhost:1234',
143146
llmModel: 'openai/gpt-oss-20b',
144147
llmApiKey: '',
145148
llmSpeakResponse: false,
149+
llmSystemPrompt: `
150+
You are a helpful assistant analyzing Nagios monitoring data. Provide concise insights about the current infrastructure health, identify critical issues, and suggest priorities for resolution. Today's date is {{DATE}}. The time is {{TIME}}. Day of the week is {{DAY_OF_WEEK}}. If you mention "flapping", capitalize it as "FLAPPING". Always add an emoji in the first position at the beginning of the response; it will be displayed as a "large icon" next to the response.
151+
`,
146152
llmPromptAllOk: `
147-
You are an expert IT and Networking admin and know how to diagnose issues.
148-
149153
All systems are operating normally with no detected issues.
150154
151155
Please start by announcing the time in plain language, and saying the following:
152156
"All systems OK".
153157
154-
If the current day is significant, like a major holiday, mention it.
155-
156-
Optionally append a single happy or network or server related emoji on the end of the response, be creative with your choice.
158+
If the current day is significant, like a major holiday, mention it. If it is not, don't mention it and be more brief.
157159
`,
158160
llmPromptNotOk: `
159-
You are an expert IT and Networking admin and know how to diagnose issues.
160-
161161
Provide a brief summary of the current situation.
162162
163+
Alerts are always in the past, and I like to measure how long since the last alert. If it happened recently then it's worth mentioning. If it happened > 1 hour ago then not as interesting.
164+
163165
- If you mention a host name, service name, or check name, put backticks around the name so it will emphasize in the markup.
164166
165167
- If there are no host issues, then do not mention there are no host issues; only focus on the service issues.
@@ -176,6 +178,9 @@ RECOMMENDATIONS if the service is not in OK state:
176178
======================================
177179
178180
`,
181+
182+
// Server settings
183+
serverSettingsTakePrecedence: false,
179184
};
180185

181186
export const bigStateAtom = atom(bigStateInitial);

src/components/Settings.tsx

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -939,34 +939,21 @@ const Settings = () => {
939939
</td>
940940
</tr>
941941
<tr>
942-
<th>LLM Server Host:</th>
942+
<th>LLM Server Base URL:</th>
943943
<td>
944944
<input
945945
type="text"
946-
value={clientSettingsTemp.llmServerHost}
947-
onChange={handleChange('llmServerHost', 'string')}
948-
placeholder="localhost or 10.0.0.1"
946+
value={clientSettingsTemp.llmServerBaseUrl}
947+
onChange={handleChange('llmServerBaseUrl', 'string')}
948+
placeholder="http://localhost:1234"
949949
/>
950950
<br />
951951
<span style={{ fontSize: '0.9em', color: '#888' }}>
952-
Hostname or IP address of your OpenAI-compatible LLM server (e.g., Ollama, LM Studio, LocalAI)
953-
</span>
954-
</td>
955-
</tr>
956-
<tr>
957-
<th>LLM Server Port:</th>
958-
<td>
959-
<input
960-
type="number"
961-
min="1"
962-
max="65535"
963-
value={clientSettingsTemp.llmServerPort}
964-
onChange={handleChange('llmServerPort', 'number')}
965-
placeholder="11434"
966-
/>
967-
<br />
968-
<span style={{ fontSize: '0.9em', color: '#888' }}>
969-
Port number (Ollama: 11434, LM Studio: 1234, LocalAI: 8080)
952+
Base URL to your OpenAI-compatible LLM server (the path /v1/chat/completions is added automatically)<br />
953+
Examples:<br />
954+
• Ollama: <code>http://localhost:11434</code><br />
955+
• LM Studio: <code>http://localhost:1234</code><br />
956+
• LocalAI: <code>http://localhost:8080</code>
970957
</span>
971958
</td>
972959
</tr>
@@ -1013,6 +1000,25 @@ const Settings = () => {
10131000
</span>
10141001
</td>
10151002
</tr>
1003+
<tr>
1004+
<th>System Prompt:</th>
1005+
<td>
1006+
<div className="text-[0.9em] text-[#888]">
1007+
The system prompt sent to the LLM. Available variables:<br />
1008+
<code className="bg-[#1e1e1e] px-1.5 py-0.5 rounded">{`{{DATE}}`}</code> - Current date (e.g., 2026-01-01)<br />
1009+
<code className="bg-[#1e1e1e] px-1.5 py-0.5 rounded">{`{{TIME}}`}</code> - Current time (e.g., 14:30:45)<br />
1010+
<code className="bg-[#1e1e1e] px-1.5 py-0.5 rounded">{`{{DAY_OF_WEEK}}`}</code> - Day of the week (e.g., Thursday)
1011+
</div>
1012+
<textarea
1013+
value={clientSettingsTemp.llmSystemPrompt}
1014+
onChange={handleChange('llmSystemPrompt', 'string')}
1015+
placeholder="System prompt for the LLM"
1016+
rows={8}
1017+
className="w-full font-mono text-[0.9em]"
1018+
style={{ fontFamily: 'monospace', fontSize: '0.9em' }}
1019+
/>
1020+
</td>
1021+
</tr>
10161022
<tr>
10171023
<th>Prompt (All OK):</th>
10181024
<td>
@@ -1052,14 +1058,17 @@ const Settings = () => {
10521058
<ul style={{ marginTop: '10px', marginBottom: '5px', paddingLeft: '20px' }}>
10531059
<li style={{ marginBottom: '5px' }}>
10541060
<strong>Ollama:</strong> Install from <a href="https://ollama.com" target="_blank" rel="noopener noreferrer" style={{ color: '#4a90e2' }}>ollama.com</a>,
1055-
run <code style={{ backgroundColor: '#1e1e1e', padding: '2px 6px', borderRadius: '3px' }}>ollama serve</code> (default port: 11434)
1061+
run <code style={{ backgroundColor: '#1e1e1e', padding: '2px 6px', borderRadius: '3px' }}>ollama serve</code>
1062+
<br />Base URL: <code style={{ backgroundColor: '#1e1e1e', padding: '2px 6px', borderRadius: '3px' }}>http://localhost:11434</code>
10561063
</li>
10571064
<li style={{ marginBottom: '5px' }}>
10581065
<strong>LM Studio:</strong> Download from <a href="https://lmstudio.ai" target="_blank" rel="noopener noreferrer" style={{ color: '#4a90e2' }}>lmstudio.ai</a>,
1059-
load a model, and start the local server (default port: 1234)
1066+
load a model, and start the local server
1067+
<br />Base URL: <code style={{ backgroundColor: '#1e1e1e', padding: '2px 6px', borderRadius: '3px' }}>http://localhost:1234</code>
10601068
</li>
10611069
<li style={{ marginBottom: '5px' }}>
10621070
<strong>LocalAI:</strong> Run via Docker: <code style={{ backgroundColor: '#1e1e1e', padding: '2px 6px', borderRadius: '3px' }}>docker run -p 8080:8080 localai/localai:latest</code>
1071+
<br />Base URL: <code style={{ backgroundColor: '#1e1e1e', padding: '2px 6px', borderRadius: '3px' }}>http://localhost:8080</code>
10631072
</li>
10641073
</ul>
10651074
<div style={{ marginTop: '10px', fontSize: '0.9em', color: '#999' }}>
@@ -1090,6 +1099,22 @@ const Settings = () => {
10901099
Local client settings are applied AFTER loading settings from the server, so you can think of server settings as a way to set defaults
10911100
for all clients, but they can still be customized individually with settings saved in client settings. Delete the client settings and refresh the page to fetch server setting defaults again.
10921101
</div>
1102+
<br />
1103+
<div>
1104+
<label>
1105+
<input
1106+
type="checkbox"
1107+
checked={clientSettingsTemp.serverSettingsTakePrecedence}
1108+
onChange={(e: ChangeEvent<HTMLInputElement>) => {
1109+
setClientSettingsTemp(curr => ({ ...curr, serverSettingsTakePrecedence: e.target.checked }));
1110+
setIsDirty(true);
1111+
}}
1112+
/>
1113+
{' '}Server settings take precedence (when enabled, local settings will not override server settings)
1114+
</label>
1115+
</div>
1116+
1117+
<br />
10931118

10941119
<h4>Option 1: If you have PHP enabled on your server</h4>
10951120

src/components/SettingsLoad.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,18 @@ const SettingsLoad = () => {
242242
// Now that we have loaded server settings, set the document.title from the title setting
243243
if (response.data.titleString) { document.title = response.data.titleString; }
244244

245+
// If serverSettingsTakePrecedence is true, skip loading local settings
246+
// This means server settings will not be overwritten by local settings
247+
if (response.data.serverSettingsTakePrecedence) {
248+
console.log('serverSettingsTakePrecedence is true - skipping local settings');
249+
setBigState(curr => ({
250+
...curr,
251+
isDoneLoading: true
252+
}));
253+
loadSettingsFromUrl();
254+
return;
255+
}
256+
245257
// Now that we have loaded remote settings, load the cookie and overwrite settings with cookie
246258
// getLocalSettings() is then going to call loadSettingsFromUrl()
247259
getLocalSettings();

src/components/llm/LLMMarkup.css

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
.llm-markup {
22
color: #e0e0e0;
3-
line-height: 1.0;
3+
line-height: 130%;
44
font-size: 0.95em;
55
}
66

77
/* Headings */
88
.llm-heading {
99
margin: 0.8em 0 0.5em 0;
1010
font-weight: 600;
11-
line-height: 1.0;
1211
}
1312

1413
.llm-heading:first-child {
@@ -52,7 +51,6 @@
5251
/* Paragraphs */
5352
.llm-paragraph {
5453
margin: 0.5em 0;
55-
line-height: 1.3;
5654
}
5755

5856
.llm-first-paragraph {
@@ -78,7 +76,6 @@
7876

7977
.llm-list-item {
8078
margin: 0.3em 0;
81-
line-height: 1.0;
8279
}
8380

8481
.llm-list-item::marker {
@@ -123,7 +120,6 @@
123120
font-family: 'Monaco', 'Courier New', monospace;
124121
font-size: 0.9em;
125122
color: #d4d4d4;
126-
line-height: 1.0;
127123
display: block;
128124
}
129125

src/components/llm/LLMMarkup.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ export default function LLMMarkup({ content }: LLMMarkupProps) {
220220
const highlightStatusWords = (text: string, startIndex: number): (string | JSX.Element)[] => {
221221
const parts: (string | JSX.Element)[] = [];
222222

223-
// Match DOWN, CRITICAL, WARNING, UNKNOWN, or FLAPPING as whole words (case-insensitive)
224-
const statusRegex = /\b(DOWN|CRITICAL|WARNING|UNKNOWN|FLAPPING)\b/gi;
223+
// Match OK, DOWN, CRITICAL, WARNING, UNKNOWN, or FLAPPING as whole words (case-insensitive)
224+
const statusRegex = /\b(OK|DOWN|CRITICAL|WARNING|UNKNOWN|FLAPPING)\b/gi;
225225
let lastIndex = 0;
226226
let match;
227227
let partIndex = startIndex;
@@ -235,7 +235,9 @@ export default function LLMMarkup({ content }: LLMMarkupProps) {
235235
// Determine the color class based on the status word (case-insensitive)
236236
let colorClass = '';
237237
const word = match[1];
238-
if (word === 'DOWN' || word === 'CRITICAL') {
238+
if (word === 'OK') {
239+
colorClass = 'color-green';
240+
} else if (word === 'DOWN' || word === 'CRITICAL') {
239241
colorClass = 'color-red';
240242
} else if (word === 'WARNING' || word === 'Warning') {
241243
colorClass = 'color-yellow';

src/components/llm/LocalLLM.README.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ import LocalLLM from './summary/LocalLLM';
2626
### 2. Configure LLM Server
2727
The component uses the following settings from `clientSettings`:
2828

29-
- `llmServerHost`: Hostname of the LLM server (default: 'localhost')
30-
- `llmServerPort`: Port number of the LLM server (default: 11434)
29+
- `llmServerBaseUrl`: Base URL to the OpenAI-compatible LLM server (default: 'http://localhost:1234'). The path /v1/chat/completions is added automatically.
3130
- `llmModel`: Model name to use (default: 'gpt-3.5-turbo')
3231
- `llmApiKey`: Optional API key for authentication (default: '')
3332

@@ -46,8 +45,7 @@ ollama serve
4645
```
4746

4847
Configure in NagiosTV:
49-
- Host: `localhost`
50-
- Port: `11434`
48+
- Base URL: `http://localhost:11434`
5149
- Model: `llama2`
5250

5351
#### Using LM Studio
@@ -56,8 +54,7 @@ Configure in NagiosTV:
5654
3. Start the local server (typically on port 1234)
5755

5856
Configure in NagiosTV:
59-
- Host: `localhost`
60-
- Port: `1234`
57+
- Base URL: `http://localhost:1234`
6158
- Model: Name of the loaded model
6259

6360
#### Using LocalAI
@@ -66,8 +63,7 @@ docker run -p 8080:8080 localai/localai:latest
6663
```
6764

6865
Configure in NagiosTV:
69-
- Host: `localhost`
70-
- Port: `8080`
66+
- Base URL: `http://localhost:8080`
7167
- Model: Available model name
7268

7369
## API Compatibility

0 commit comments

Comments
 (0)