- Formatted tab: grouped sections (Overview, Parties, Classification, Dates, System)
- ID-to-label resolution for status, priority, source, queue, company type
- Elegant bordered table layout with muted label column
- Clickable phone/URL fields, monospace IDs, formatted dates
- Description rendered in its own block for tickets
- Raw tab: all fields with monospace keys, copy-on-hover
- Auto-detects ticket vs company data for appropriate grouping
- Shadcn Tabs, Separator, Badge used throughout
- Removed sm:max-w-lg default that was overriding max-w-7xl in DetailModal
- DialogContent now respects whatever max-w class is passed via className
- Fixes data browser detail modal not widening as expected
- Restructured ticker to show ticket number and title on first line
- Company name now displays on second line below ticket
- Adjusted ticker speed slider range: 8s-120s (was 10s-120s)
- Changed step from 5s to 2s for finer speed control
- Allows 25% faster speed adjustment (down to 8s)
- Better two-line layout for improved readability
- Added translate3d(0,0,0) for hardware acceleration
- Added font smoothing for better rendering
- Reduced default ticker speed from 60s to 30s (2x faster)
- Improved animation smoothness to reduce jitter
- Better GPU acceleration with backface-visibility and willChange
- Changed from max-w-6xl to container mx-auto
- Restored left-4 and right-4 positioning for logo and theme toggle
- Navigation edges now align perfectly with dashboard card edges
- Matches the same container padding used throughout the app
- Removed container class, using max-w-6xl with px-4 directly
- Changed absolute positioning from left-4/right-4 to left-0/right-0
- Navigation edges now align perfectly with card edges
- Logo lines up with Dashboard text on left
- Theme toggle aligns with card edge on right
- Added max-w-6xl to navigation container
- Navigation now aligns with KPI cards on wide screens
- Prevents navigation from stretching too wide
- Maintains consistent layout alignment
- Replaced favicon.ico with Wulf logo PNG
- Removed old icon.svg (triangle icon)
- Added icon.png with Wulf logo
- All favicon formats now use Wulf logo
- Should fix persistent triangle icon issue
- Added favicon.png copy of Wulf logo
- Updated metadata to use PNG favicon with multiple size options
- Should fix triangle icon issue in browser tab
- Favicon now properly displays Wulf logo
- Replaced Pulse icon with Wulf logo on left side of navbar
- Removed duplicate logo from right side
- Corrected alt text from 'Wulff' to 'Wulf'
- Logo now appears next to Pulse branding on left
- Added Wulff logo (W_RGB.png) to public directory
- Updated favicon to use Wulff logo
- Added logo to upper right of navigation bar (h-10)
- Logo appears next to theme toggle
- Links to home page when clicked
- Autotask REST API doesn't expose ClassificationIcons endpoint
- Created migration to populate 17 standard classification icons
- Removed sync button from UI (classifications are pre-loaded)
- Includes: Tools Only, Co-Managed, Wulf 365 Essentials, Partner, etc.
- Users can now select any classification to exclude from kiosk
- Created company_classifications table to store Autotask classification icons
- Added getClassificationIcons() method to AutotaskClient
- Created /api/sync/classifications endpoint (GET/POST)
- Updated kiosk settings UI to dynamically load classifications
- Added 'Sync from Autotask' button to pull latest classifications
- Removed hardcoded classification list
- Display classification name and description in checkboxes
- Allow excluding any classification synced from Autotask
- Fixed settings API to parse excluded_classifications as array
- Fixed companies API response handling (returns {companies: []} not array)
- Resolves TypeError: excluded_classifications.filter is not a function
- Resolves TypeError: s.sort is not a function
- Added classification column to companies table
- Created excluded_classifications setting (default: Tools Only)
- Updated kiosk stats and activity APIs to filter by classification
- Added comprehensive classification filtering UI with checkboxes
- Support for common classifications (Tools Only, Wulff Consulting Client, Customer)
- Allow custom classification entry
- Fixed company name display in settings (convert string IDs properly)
- Classification filtering works alongside company ID exclusions
- Increased ticket number font from text-lg to text-2xl
- Increased company name font from text-sm to text-lg
- Increased ticket title font from text-xs to text-base
- Increased padding on ticket cards for better spacing
- Fixed company ID to name conversion in settings page
- Ensure excluded_company_ids are parsed as numbers for proper lookup
- Created kiosk_settings table for configuration storage
- Added API endpoints for kiosk settings (GET/POST)
- Filter out co-managed clients (configurable company exclusions)
- Built comprehensive settings UI at /kiosk/settings
- Allow excluding specific companies from kiosk display
- Configurable cycle interval, refresh interval, and RMM alert toggle
- Updated dashboard link to point to settings page
- Applied company exclusion filter to all ticket queries and activity feed
- Default excludes Thrasher Group (ID: 29861361)
- Show company name and ticket title for top 3 tickets per category
- Critical tickets sorted by priority then create date
- Waiting tickets sorted by oldest activity
- Stale tickets sorted by oldest activity
- Overdue tickets sorted by most overdue
- Closed tickets sorted by most recent
- Adjusted card layout to accommodate ticket list
- Created /kiosk route with full-screen display
- Added API endpoints for stats and activity feed
- Built cycling KPI display with 12 metrics
- Added scrolling ticker for ticket activity
- Implemented UI-configurable cycle interval (3-15s, default 7s)
- Focus on critical tickets and business metrics
- Added navigation link from dashboard
- Dark theme optimized for TV viewing
When includeUnmapped=true, the mapping APIs now populate the
auvik_tenants and rmm_sites tables with all fetched data.
This ensures accurate mapped/unmapped counts on the dashboard.
- Created auvik_tenants and rmm_sites tables
- Added /api/sync/tenants-sites endpoint to sync all tenants from Auvik
and all sites from Datto RMM for accurate mapped/unmapped counts
Added tables to store all tenants/sites from external APIs.
Populated with existing mapped data. Full sync of all tenants/sites
needed for accurate unmapped counts.
The companies were being returned with database column names (snake_case)
but the TypeScript Company interface expects camelCase. Added transform
function to convert column names, fixing the localeCompare error in
mapping pages.
- Added tableExists helper to check if tables exist before querying
- Gracefully handle missing auvik_tenants, rmm_sites, and quotes tables
- Return partial data when some tables are missing
- Created /api/dashboard/stats endpoint that queries local PostgreSQL only
- Updated companies API to use cached database instead of Autotask API
- Dashboard now loads instantly from cached data instead of waiting for external APIs
- Scheduled syncs keep data fresh throughout the day
Created SVG icon that matches the Activity/pulse icon used in the app:
- Blue gradient background matching the app theme
- White pulse/activity line icon
- Updated layout.tsx to use the new SVG icon
Changed navigation layout from spread (justify-between) to centered:
- Logo positioned absolutely on the left
- Navigation menu centered with mx-auto
- Right actions positioned absolutely on the right
- Container uses justify-center for proper centering
The scheduled sync was using AUTOTASK_INTEGRATION_CODE but the actual
environment variable is AUTOTASK_API_INTEGRATION_CODE. This caused
scheduled syncs to fail with 'IntegrationCode is invalid' while
manual syncs worked fine.
Changed:
- AUTOTASK_INTEGRATION_CODE -> AUTOTASK_API_INTEGRATION_CODE
This aligns the scheduler with autotask-factory.ts which was already
using the correct variable name.
Fixed critical logic bug where Companies and Resources were not getting
proper filters applied when falling back from incremental to full sync.
Root Cause:
- During scheduled incremental sync, Companies and Resources correctly
identify they don't support incremental sync
- However, the filter-building logic was in an else block that only
executed for non-incremental syncs
- This caused Companies and Resources to sync with NO filters at all
- Autotask API now rejects queries without filters, returning:
'Value cannot be null. Parameter name: filters'
Fix:
- Restructured logic so filter building happens for BOTH:
1. Non-incremental (full) syncs
2. Incremental syncs that fall back to full sync
- Companies and Resources now get active filters applied even during
scheduled incremental syncs
This resolves the scheduled sync failures for Companies, Resources,
and all other entities that were failing due to the cascading effect
of early failures.
Added 10 critical missing fields to Tickets entity:
Database Migration (016):
- billing_code_id: Billing code assignment
- configuration_item_id: Primary asset/CI
- creator_resource_id: Ticket creator
- creator_type: Creator type (resource/contact)
- problem_ticket_id: Link to problem ticket
- rma_status: RMA status tracking
- rma_type: RMA type classification
- service_level_agreement_paused_next_event_hours: SLA pause tracking
- is_assigned_to_comanaged: Co-managed assignment flag
- is_visible_to_comanaged: Co-managed visibility flag
Entity Mapper Updates:
- Added all new fields with correct camelCase mapping
- Ensures all Autotask Tickets API fields are captured
This completes the Tickets entity to match the full Autotask API
specification and should resolve issues with missing ticket data.
Fixed field names to use proper camelCase from Autotask API instead of
snake_case. This should resolve the issue where assigned_resource_id
was NULL because the mapper was looking for incorrect field names.
Changed mappings:
- firstResponseDateTime (was first_response_date_time)
- resolutionPlanDateTime (was resolution_plan_date_time)
- resolvedDateTime (was resolved_date_time)
- firstResponseAssignedResourceID (was first_response_assigned_resource_id)
- firstResponseInitiatingResourceID (was first_response_initiating_resource_id)
- projectID, opportunityID, contractID, monitorID (were snake_case)
- All change approval and ticket fields converted to camelCase
- All service thermometer fields converted to camelCase
This fix should populate assigned_resource_id and other fields correctly
on the next ticket sync.
Updated Resources data browser page to display all 40+ fields in the
detail modal including:
- Name fields (prefix, middle initial, suffix)
- All contact information (3 email addresses, home phone)
- Employment details (payroll, accounting, internal cost)
- Location and availability
- System preferences (date/time/number formats)
- Demographics and security (gender, license, security level)
- Survey ratings
Fields are organized into logical groups with comments for clarity.
Autotask API returns string values like 'PRIMARY' for some integer
fields (e.g., emailTypeCode). Added safeInt() helper function to:
- Parse numeric values correctly
- Return null for non-numeric strings
- Handle null/undefined/empty values
This prevents database errors when syncing Resources with non-standard
field values from Autotask API.