Commit graph

68 commits

Author SHA1 Message Date
2212bf9134
Make traffic graph header clickable and add dedicated graph page 2026-01-05 13:33:32 -06:00
3643700d73
Add overall traffic graph combining all interfaces 2026-01-05 13:32:07 -06:00
223434dd99
Make equipment list rows clickable 2026-01-05 13:29:23 -06:00
3629522d25
Auto-select site when only one is available for new equipment 2026-01-05 13:18:09 -06:00
46cfd86981
Add catch-all handler for unknown PubSub messages in PollerWorker 2026-01-05 12:49:56 -06:00
8f7ed19d34
Trigger immediate poll after SNMP discovery completes 2026-01-05 12:46:25 -06:00
fb0bf14b66
event pubsub 2026-01-05 12:23:15 -06:00
249c7d3560
Log initial interface discovery as events
- Detect when interface speed changes from null to a value
- Detect when MAC address changes from null to a value
- Log initial discoveries with "info" severity
- Differentiate between initial discovery and actual changes
- Show "detected" message for initial values
- Show "changed from X to Y" message for actual changes
2026-01-05 11:16:31 -06:00
06a31441f2
Change temperature and voltage display to table format
- Replace grid of sensor cards with table format matching device info
- Display sensor name on left, value on right
- Make sensor names clickable links to graph detail page
- Remove generic "Sensors" section from overview
- Cleaner, more scannable layout for temperature and voltage sensors
2026-01-05 11:14:59 -06:00
ddabb3f030
Add detailed graph view with date range selection
- Create GraphLive.Show for detailed sensor graph visualization
- Add route for /equipment/:id/graph/:sensor_type endpoint
- Make all chart headers clickable with navigation to detail view
- Implement date range selector (1h, 6h, 12h, 24h, 7d, 30d)
- Fix chart rendering by destroying and recreating on data updates
- Fix duplicate data loading in LiveView event handlers
- Fix MikroTik profile typing warning for entity sensor discovery
2026-01-05 11:09:21 -06:00
05f1aec227
Add sensor charts and improve equipment detail page
- Add Chart.js integration for interactive sensor graphs
- Add processor, memory, storage, temperature, and voltage charts showing 24 hours of data
- Fix device information box to use natural height instead of stretching
- Update MikroTik profile to discover ENTITY-SENSOR-MIB sensors
- Support multiple sensor types per chart (celsius/temperature, volts/voltage)
- Use 24-hour time format in chart tooltips and x-axis labels
- Support auto-scaling y-axis for non-percentage metrics
2026-01-05 11:01:21 -06:00
4ad4e3a673
cleanup 2026-01-05 10:44:21 -06:00
cac54b46a2
Implement event logging system and fix sensor display
- Add equipment_events table and Event schema for tracking device changes
- Implement automatic change detection for interface attributes during SNMP polling
  - Detects operational status changes (up/down)
  - Detects admin status changes
  - Detects speed changes with warning severity for speed drops
  - Detects MAC address changes
- Add Logs tab to equipment detail page with event display
- Fix temperature sensor display bug (was showing 4.3C instead of 43C due to double division)
- Remove response time tracking from monitoring checks and UI
- Move Rediscover Device button to equipment edit page
2026-01-05 10:42:34 -06:00
9eca2e7069
Fix database schema mismatches preventing SNMP and monitoring data collection
This fixes critical issues where SNMP sensor readings, interface stats, and
monitoring checks were not being saved to the database due to schema mismatches.

Database schema fixes:
- Recreate snmp_sensor_readings table with binary_id primary key
- Recreate snmp_interface_stats table with binary_id primary key
- Recreate monitoring_checks table with binary_id primary key

The original migrations used default integer primary keys, but the schemas
expected binary_id (UUID). This caused Ecto to generate UUID strings that
Postgrex tried to encode as binaries, resulting in silent insert failures.

SNMP interface stats fixes:
- Fix field name mismatch in get_interface_stats (if_in_octets vs in_octets)
- Remove unnecessary tuple handling code (Client already unwraps SNMPKit tuples)
- Clean up decode_snmp_value function and improve error messages

Monitoring check fixes:
- Fix response_time type from float to integer in Poller.check_device
- Add error logging to catch and report check creation failures

These changes enable:
- SNMP sensor readings to be collected and stored (disk usage, memory, CPU, etc.)
- Interface statistics to be collected (Counter64 octets, errors, discards)
- Equipment availability metrics to update on the dashboard
2026-01-05 08:26:16 -06:00
2e650c2be8
Add UTC timestamp tooltip to Last Check time
Shows the full UTC timestamp when hovering over the relative 'time ago'
text on the equipment detail page.

Changes:
- Wrapped time_ago display in a span with title attribute
- Title shows full datetime in UTC format
- Added cursor-help class for visual hint that tooltip is available

Users can now see both the easy-to-read relative time ('5m ago') and
the precise UTC timestamp (2026-01-04 19:30:15Z) by hovering.
2026-01-04 13:39:50 -06:00
1253230639
format 2026-01-04 13:35:54 -06:00
40a329ea78
Add back navigation links to edit pages
Added back navigation links at the top of all edit/new pages to
improve UX and make it easier to navigate back to previous pages.

Changes:
- Added back link to equipment edit/new pages
  - Edit: goes back to equipment detail page
  - New: goes back to equipment list
- Added back link to site edit/new pages
  - Edit: goes back to site detail page
  - New: goes back to sites list
- Links styled with arrow icon and subtle hover effect
- Added error handling to Counter64 decoder with try/rescue

The back links appear above the page header and provide clear
navigation context for users.
2026-01-04 13:35:31 -06:00
d209b3295a
Add danger variant for delete buttons
Added a new 'danger' button variant to the button component for
destructive actions like deleting equipment or sites.

Changes:
- Added 'danger' variant to button component (red background/hover)
- Updated equipment delete button to use variant="danger"
- Updated site delete button to use variant="danger"
- Removed custom red color classes in favor of standardized variant

This provides consistent styling for all delete/destructive actions
across the application while maintaining proper button base styles
(padding, rounded corners, shadow, focus ring, etc).
2026-01-04 13:34:02 -06:00
3fe3a01726
Remove 'Check Now' button and clean up equipment detail page
Removed the manual 'Check Now' functionality since polling happens
automatically on a schedule with distributed coordination. Manual
triggers would interfere with the coordinated polling system.

Changes:
- Removed 'Check Now' button from equipment detail page
- Removed trigger_check event handler
- Simplified Discover and Edit buttons to use standard button styling
- Removed custom classes in favor of default button component styling

The equipment is now polled automatically based on its configured
check_interval_seconds, coordinated across all pods.
2026-01-04 13:31:14 -06:00
38bd9828f7
Improve Counter64 decoder to handle 16-byte values
Some SNMP implementations return 16-byte binaries for Counter64 values
instead of the standard 8 bytes. Updated decoder to:
- Handle 8-byte standard Counter64
- Handle 16-byte values by reading last 8 bytes
- Handle any size > 8 bytes by reading last 8 bytes
- Add debug/warning logging for non-standard sizes

This fixes DBConnection.EncodeError when polling interface statistics
from devices that return non-standard Counter64 encodings.
2026-01-04 13:28:53 -06:00
20f6a9171d
Add distributed coordination for SNMP polling
Prevents duplicate polling when multiple pods are running by using
database-based coordination.

Changes:
- Added last_snmp_poll_at timestamp to equipment table
- Added Equipment.update_snmp_poll_time/1 function
- Updated PollerWorker to check last_snmp_poll_at before polling
- Polls are skipped if equipment was polled within (interval - 5s)
- Updates timestamp before polling (optimistic locking)

This ensures that when K8s scales up/down or pods restart, only one
pod polls each piece of equipment at a time, preventing wasteful
duplicate SNMP queries and database writes.

The 5-second grace period accounts for clock drift and processing delays
between pods.
2026-01-04 13:28:06 -06:00
91759ac16c
Add error handling and logging to monitoring supervisor
Improved startup reliability and debugging for SNMP pollers:
- Added try/rescue blocks around monitor and poller startup
- Added logging for successful startup and errors
- Added error logging to PollerWorker's perform_poll
- Added debug logging for successful sensor/interface polls

This will help identify issues when pollers fail to start or
encounter errors during polling, which was causing silent failures
where sensors weren't being collected.
2026-01-04 13:24:33 -06:00
bd91e2a7c3
Add metadata support for storage sensors
Storage sensors (disk/memory usage) need to fetch two OIDs to calculate
percentages: the 'used' value and the 'size' value. Previously, only the
'used' OID was stored and polled, resulting in meaningless raw values.

Changes:
- Added metadata JSONB field to snmp_sensors table
- Updated Sensor schema to include metadata field
- Updated MikroTik profile to store size_oid in metadata for storage sensors
- Updated PollerWorker to handle percentage calculation sensors:
  - poll_simple_sensor: Standard OID fetch with divisor
  - poll_percentage_sensor: Fetches both used and size OIDs, calculates percentage

Storage sensors now properly calculate and store percentage values during polling.

NOTE: Existing MikroTik devices need to re-run SNMP discovery to populate
the metadata field for storage sensors.
2026-01-04 13:09:47 -06:00
9918f1633c
Handle SNMP Counter64 binary values in poller
SNMP Counter64 values (used for interface byte counters) are returned
as 8-byte binary data by SNMPKit and need to be decoded to integers
before database insertion.

Added decode_snmp_value/1 helper that:
- Passes through numeric values unchanged
- Decodes 8-byte binaries as 64-bit unsigned big-endian integers
- Returns nil for unknown formats

Updated both sensor and interface polling to use this decoder,
preventing DBConnection.EncodeError when trying to insert binary
values into integer columns.
2026-01-04 13:02:01 -06:00
3544d117a8
Implement SNMP polling for continuous data collection
Add background workers to regularly poll SNMP sensors and interfaces:

- Create PollerWorker GenServer to poll SNMP devices
- Poll all sensors for temperature, voltage, CPU, memory, etc.
- Poll all interfaces for bandwidth, errors, and discards
- Save time-series data to snmp_sensor_readings and snmp_interface_stats
- Integrate with monitoring supervisor to auto-start pollers
- Use same interval as connectivity checks (minimum 30 seconds)
- Add list_snmp_enabled_equipment function to Equipment context

Pollers start automatically on app boot for all SNMP-enabled equipment
and run independently of connectivity monitoring.
2026-01-04 12:56:51 -06:00
52f8af382c
Move delete buttons to edit pages for sites and equipment
- Remove delete buttons from show pages
- Add 'Danger Zone' section to edit pages with delete functionality
- Improves UX by keeping destructive actions on edit pages
- Add clear warnings about deletion consequences
2026-01-04 12:25:31 -06:00
50e7fa13af
Improve onboarding: redirect to site page after creation
- After creating a site, redirect to site detail page instead of list
- Show helpful empty state on site page with instructions to add equipment
- Flash message guides user to add their first device
2026-01-04 12:22:50 -06:00
d09d64f7bd
add more things to dashboard 2026-01-04 12:13:20 -06:00
ef06170c0d
Make site cards fully clickable and remove View button 2026-01-04 11:53:32 -06:00
e3c3056aca
Add onboarding wizard to guide users through site creation
- Dashboard shows welcome wizard when no sites exist
- Equipment page redirects to site creation when no sites exist
- Equipment form redirects users to create a site if none exist
- Equipment list hides "New Equipment" button when no sites exist
- Update layouts to accept nil current_organization for org-less pages
2026-01-04 11:47:25 -06:00
6bc802b22a
Add global header to new organization page
All authenticated pages now have consistent navigation header.
Login/registration pages keep simple layout as they're for
unauthenticated users.
2026-01-04 11:41:26 -06:00
6fbdf9a9b8
Add global header to user settings page
Use Layouts.authenticated instead of Layouts.app for consistent
navigation across the application.
2026-01-04 11:38:07 -06:00
5fdb0e81fd
Add main menubar to /orgs page
- Change /orgs to use Layouts.authenticated instead of Layouts.app
- Update authenticated layout to show user menu without organization
- Menu button shows org name when in org, 'Menu' on org list page
- Always show Settings and Log out options
2026-01-04 11:34:21 -06:00
c87630f472
Make org boxes clickable and add global layout
- Wrap /orgs page in Layouts.app to include header/footer
- Make entire org box clickable by using .link component
- Remove 'Open' button - entire card is now the link
- Add cursor-pointer for better UX
2026-01-04 11:27:36 -06:00
9a721191fe
Set default email sender to hi@towerops.net
Configure mailer_from in runtime config and update UserNotifier
and AlertNotifier to use the configured from address.
2026-01-04 11:16:12 -06:00
72c260e122
Add /health endpoint for Kubernetes probes
Create HealthController that returns 200 OK for health checks.
Route is outside browser pipeline to avoid SSL redirect and
authentication requirements.
2026-01-04 10:56:03 -06:00
25b82848d6
Run migrations on app start instead of separate job
- Migrations now run in Application.start/2 before starting services
- Ecto's advisory locks prevent concurrent migrations in clustered setup
- Simplified deployment - no separate migration job needed
- Removed migrate-job.yaml manifest
2026-01-03 16:09:31 -06:00
f050fb0eea
Enable LiveDashboard at /dashboard with authentication
LiveDashboard is now available at /dashboard in all environments
and requires user authentication to access
2026-01-03 15:53:18 -06:00
d6a9bb11d7
Redesign equipment view with compact LibreNMS-style dashboard
- Add real-time updates with 10-second refresh and PubSub integration
- Implement pure SVG charts: response time sparkline and uptime gauge
- Create compact dashboard layout with status cards, metrics, and graphs
- Add relative time display (e.g., '5s ago') for last check
- Redesign SNMP data display: compact device info, sensors grid, interfaces table
- Calculate and display uptime percentage and average response time
- Update tests to match new compact layout
2026-01-03 15:11:47 -06:00
7772ff9a4a
fix a few bits 2026-01-03 14:58:06 -06:00
8cbca259fc
snmp bits 2026-01-03 14:41:28 -06:00
0f9266027f
fix dialyzer things 2026-01-03 12:56:40 -06:00
5ae974d7aa
Fix Dialyzer unmatched return warning in trigger_check handler
- Explicitly discard return value from trigger_check call
- The return value is not needed for this fire-and-forget operation
- Resolves unmatched_return warning at line 58
2026-01-03 12:43:05 -06:00
ba75c7313d
Fix Dialyzer unmatched return warning in log_out_user
- Explicitly discard return value from Endpoint.broadcast call
- Broadcast is fire-and-forget, return value not needed
- Resolves unmatched_return warning at line 54
2026-01-03 12:42:21 -06:00
7cdb93ef31
Fix Dialyzer opaque type warning in register_user_with_organization
- Create changeset before Multi pipeline for better type inference
- Pass changeset directly to Multi.insert instead of using function form
- Resolves call_without_opaque warning at line 97
2026-01-03 12:41:28 -06:00
d345d7df30
Fix Dialyzer pattern match coverage warning
- Replace catch-all pattern with explicit :unknown status handling
- Makes status transitions more explicit and type-safe
- Resolves pattern_match_cov warning at line 174
2026-01-03 12:40:32 -06:00
5d9ebb14f9
Change organization slugs to random IDs independent of name
- Organization names can now be freely duplicated
- Slugs are generated as random 8-character lowercase alphanumeric IDs
- Provides ~218 trillion possible combinations
- Updated tests to not rely on name-based slug patterns
2026-01-03 12:33:11 -06:00
7d4f7dd7d4
Add active page navigation highlighting
- Add active_page attribute to authenticated layout
- Update nav_link component to show active state with border and text styling
- Update all LiveView templates to pass active_page parameter
- Fix datetime truncation issues in tests and schemas for :utc_datetime fields
- Fix dashboard test assertions for equipment status text
2026-01-03 12:28:26 -06:00
d283f4ac6c
Fix dropdown menu position to appear below button 2026-01-03 12:18:56 -06:00
424b82ca4c
Add z-index to dropdown menu to appear above page content 2026-01-03 12:18:03 -06:00