# Spark + -- Instruction Manual

**Version:** 2.1.0
**Author:** Linus Olofsson - Iver
**Last Updated:** 2026-03-18

---

## Table of Contents

- [1. Introduction](#1-introduction)
- [2. Installation](#2-installation)
- [3. Authentication](#3-authentication)
- [4. User Interface](#4-user-interface)
  - [4.1 Standard View](#41-standard-view)
  - [4.2 Minimal View](#42-minimal-view)
  - [4.3 Toolbar Buttons](#43-toolbar-buttons)
  - [4.4 Ticket List](#44-ticket-list)
  - [4.5 Ticket Detail Modal](#45-ticket-detail-modal)
- [5. Features](#5-features)
  - [5.1 Automatic Updates](#51-automatic-updates)
  - [5.2 Timer](#52-timer)
  - [5.3 Notifications](#53-notifications)
  - [5.4 Status Change Detection](#54-status-change-detection)
  - [5.5 Time Report Article Validation](#55-time-report-article-validation)
  - [5.6 Microsoft Teams Integration](#56-microsoft-teams-integration)
- [6. Configuration](#6-configuration)
  - [6.1 Sorting](#61-sorting)
  - [6.2 Appearance](#62-appearance)
  - [6.3 Notification Settings](#63-notification-settings)
  - [6.4 Status Filters](#64-status-filters)
- [7. File Structure and Architecture](#7-file-structure-and-architecture)
  - [7.1 manifest.json](#71-manifestjson)
  - [7.2 HTML Files](#72-html-files)
  - [7.3 CSS](#73-css)
  - [7.4 JavaScript -- Entry Point](#74-javascript----entry-point)
  - [7.5 JavaScript -- API Layer](#75-javascript----api-layer)
  - [7.6 JavaScript -- Background](#76-javascript----background)
  - [7.7 JavaScript -- Common Utilities](#77-javascript----common-utilities)
  - [7.8 JavaScript -- Components](#78-javascript----components)
  - [7.9 JavaScript -- Content Scripts](#79-javascript----content-scripts)
  - [7.10 JavaScript -- Handlers](#710-javascript----handlers)
- [8. Data Flow](#8-data-flow)
- [9. Troubleshooting](#9-troubleshooting)
- [10. Changelog](#10-changelog)

---

## 1. Introduction

Spark + is a Chromium browser extension developed for Iver employees. It connects to the Spark ticketing system at `spark.iver.com` and provides the following capabilities:

- List all tickets assigned to the logged-in user.
- Monitor ticket status changes in real-time with desktop notifications.
- Track SLA deadlines with visual indicators.
- Set a configurable timer for periodic automatic updates.
- View ticket descriptions and latest updates (status changes, posts, emails) directly in the popup.
- Validate time report article classifications.
- Integrate with Microsoft Teams for channel notifications.

The extension operates entirely within the browser and requires no external server or backend beyond the existing Spark API.

---

## 2. Installation

1. Open a Chromium-based browser (Chrome, Edge, or Brave).
2. Navigate to the extensions management page:
   - **Chrome:** `chrome://extensions/`
   - **Edge:** `edge://extensions/`
   - **Brave:** `brave://extensions/`
3. Enable **Developer mode** using the toggle in the top-right corner.
4. Click **Load unpacked**.
5. In the file dialog, select the `PROD-READY-SETUP` folder.
6. The Spark + extension will appear in the extensions list.
7. Click the puzzle piece icon in the browser toolbar and pin the Spark + icon for quick access.

---

## 3. Authentication

Spark + uses a **passive token extraction** approach. It does not require the user to enter credentials within the extension.

**How it works:**

1. The user logs in to [spark.iver.com](https://spark.iver.com) normally in the browser.
2. A content script (`sparkTokenReader.js`) reads the JWT access token from the Spark site's `localStorage`.
3. The service worker caches this token and uses it for all API requests.
4. When the token expires, the extension prompts the user to revisit `spark.iver.com` to renew the session.

**Important:** The user must have an active Spark session (i.e., be logged in to `spark.iver.com` in at least one tab) for the extension to function. The extension never opens new tabs or redirects the user automatically.

---

## 4. User Interface

### 4.1 Standard View

The standard popup view (420x600 pixels) displays the following elements from top to bottom:

1. **User Info Bar** -- Displays the logged-in user's name, title, and total ticket count.
2. **Spark + Logo** -- The extension branding image.
3. **Toolbar Buttons** -- Five action buttons (Timer, Teams, Notifications, Update, Clear).
4. **Ticket List** -- A scrollable list of all assigned tickets with columns for ID, Status, SLA, and Link.
5. **Config Button** -- Opens the configuration modal.

### 4.2 Minimal View

When enabled via the configuration modal, minimal view provides a compact layout:

- The user info bar and logo are placed side by side on the same row.
- Toolbar buttons display as icon-only (no text labels).
- The ticket list is given more vertical space.
- The CSS Grid layout uses explicit row sizing (`auto auto 1fr auto`) to ensure that the header, buttons, and config button maintain their natural height. Only the ticket list row expands to fill remaining space. This prevents visual distortion when the ticket list is empty.

### 4.3 Toolbar Buttons

| Button              | Icon | Function                                                    |
|---------------------|------|-------------------------------------------------------------|
| **Timer**           | ⏱   | Opens the timer settings modal. Displays countdown when active. |
| **Anslut Teams**    | T    | Initiates Microsoft Teams channel connection.                |
| **Notifikationer**  | 🔔   | Toggles desktop notifications on or off.                    |
| **Uppdatera nu**    | ↻    | Triggers an immediate ticket list refresh from the Spark API.|
| **Tom lista**       | 🗑   | Clears all tickets from the local list.                     |

### 4.4 Ticket List

Each ticket row displays:

- **Remove Button** -- A small icon to remove the individual ticket from the list.
- **ID** -- The numeric ticket identifier (clickable to open detail modal).
- **Status** -- Current ticket status with a color-coded badge.
- **SLA** -- Remaining SLA time. Displays `UTGATT` (expired) in red when overdue.
- **Link** -- A direct link to the ticket in the Spark web interface.

A gold bullet point appears next to the ticket row the user is currently hovering over.

Tickets with recent status changes display a blinking animation on the ID number until the user clicks to view the detail modal.

### 4.5 Ticket Detail Modal

Clicking on a ticket's ID, status, or SLA column opens a detail modal containing:

- **Title** -- The ticket's display name (e.g., `7658853 - Ticket Description`).
- **Detail Rows** -- Status, Assignee, Priority, Ticket Type, Customer, and SLA information.
- **Beskrivning (Description)** -- The full ticket description text (`descriptionPlain`), truncated to 100 characters. Clicking the truncated text opens a full-screen popup with the complete text.
- **Senaste uppdatering (Latest Update)** -- Always shows the most recent status change in the format:
  `OldStatus -> NewStatus by User at Date, Time`
  Below the status change, the latest post or email is displayed:
  - **Post:** Author, date, and text content (truncated to 100 characters with click-to-expand).
  - **Mail:** Sender, recipient, subject, and date (displayed when the latest status change is "Updated by customer" by "System").
- **Action Buttons** -- "Oppna i Spark" (opens in Spark) and "Stang" (close modal).

---

## 5. Features

### 5.1 Automatic Updates

When the timer is active, the extension periodically fetches the latest ticket data from the Spark API. The update cycle:

1. The service worker alarm fires at the configured interval.
2. The extension retrieves the user's assigned tickets via the Spark API.
3. Ticket statuses are compared with the locally stored previous state.
4. If any status has changed, a desktop notification is displayed and the affected tickets are visually highlighted.

An offscreen document keeps the service worker alive between alarm intervals to ensure reliable operation.

### 5.2 Timer

The timer controls the automatic update interval.

- Open the timer settings by clicking the Timer button.
- Set the desired interval in hours, minutes, and seconds (minimum 30 seconds).
- Click **Spara** to save and activate the timer.
- Click **Avbryt** to close the modal without making changes.
- The Timer button displays a live countdown when active.
- The timer persists across popup open/close cycles using Chrome storage.

### 5.3 Notifications

Desktop notifications are shown for the following events:

- Ticket status changes detected during automatic updates.
- Token expiration warnings.
- Time report article mismatches.
- API errors.

Notifications can be toggled on or off using the Notifications button in the toolbar.

All notifications that direct the user to a specific destination include action buttons:

| Notification Type | Button | Action |
|-------------------|--------|--------|
| Status change (per ticket) | **Öppna ärende** | Opens the specific ticket in Spark |
| Token missing / expired | **Öppna Spark** | Opens `spark.iver.com` for re-authentication |
| API error | **Öppna Spark** | Opens `spark.iver.com` |
| Article mismatch | **Ignorera** / **Fixa** | Suppresses future alerts or opens the ticket |
| Background update fallback | **Visa ärenden** | Opens the extension popup |

Clicking the notification body (outside the button) also navigates to the appropriate destination.

### 5.4 Status Change Detection

The extension tracks status changes by comparing the current ticket status with the previously stored status. When a change is detected:

1. The ticket row's ID number begins a blinking animation (gold to red).
2. A separate desktop notification is created for each affected ticket, displaying the old and new status. Each notification includes an **"Öppna ärende"** button that links directly to the ticket in the Spark web interface.
3. Clicking the affected ticket in the popup clears the animation and resets the change flag.

### 5.5 Time Report Article Validation

When enabled in the configuration, the extension validates time report article classifications against the expected article for the logged-in user's role. This check runs independently of the ticket list display and covers **all** tickets assigned to the user within the last seven days, regardless of ticket status. This ensures that tickets which have been moved to a closed or resolved status are still validated.

The validation flow:

1. A separate API call retrieves all tickets assigned to the user from the last seven days (no status filter).
2. For each ticket, the extension fetches timesheet entries and filters for the current user's entries within the same period.
3. Each timesheet entry's article ID is compared against the expected article for the user's title.
4. Overtime articles are excluded from validation.
5. If a mismatch is detected, a desktop notification is created with two action buttons:
   - **Ignore** -- Adds the ticket to a persistent ignore list. The ticket will be skipped in all future validation cycles until the ignore list is cleared.
   - **Fix** -- Opens the ticket directly in the Spark web interface (`spark.iver.com/tickets/detail/{ticketGuid}`) so the user can correct the time report.

Ignored tickets are stored in Chrome local storage under the key `articleMismatchIgnored`.

### 5.6 Microsoft Teams Integration

The Teams button initiates a connection to a Microsoft Teams channel for sending ticket-related notifications. This feature uses the Microsoft Graph API and requires appropriate Azure AD permissions.

---

## 6. Configuration

The configuration modal is accessed by clicking the **Config** button at the bottom of the popup.

### 6.1 Sorting

The ticket list can be sorted by one of three criteria:

| Option            | Behavior                                              |
|-------------------|-------------------------------------------------------|
| **Latest change** | Tickets with the most recent `changedDate` appear first. |
| **SLA tid**       | Tickets with the shortest remaining SLA time appear first. |
| **Status**        | Tickets are grouped alphabetically by status.          |

### 6.2 Appearance

- **Minimal** -- A toggle switch that enables or disables the compact minimal view layout.

### 6.3 Notification Settings

- **Tidrapport artikel-kontroll** -- Enables or disables the time report article validation feature.

### 6.4 Status Filters

A list of checkboxes allows the user to select which ticket statuses are visible. Unchecked statuses are hidden from the ticket list. The available statuses are fetched dynamically from the Spark API.

---

## 7. File Structure and Architecture

### 7.1 manifest.json

The extension manifest defines all metadata, permissions, icons, and entry points. It uses **Manifest V3** format.

- **`action.default_popup`** -- Points to `html/PopupUI.html` as the popup interface.
- **`background.service_worker`** -- Points to `javascript/background/serviceWorker.js`.
- **`content_scripts`** -- Injects `sparkTokenReader.js` on `spark.iver.com` pages.
- **`host_permissions`** -- Grants API access to `spark.iver.com`, `api.apps.iver.com`, `login.microsoftonline.com`, and `graph.microsoft.com`.

### 7.2 HTML Files

**`html/PopupUI.html`**
The main popup document. Contains the static HTML structure for the user info bar, logo, toolbar buttons, ticket list, and modals (Config and Timer). Loads `popup.js` as a module script.

**`html/offscreen.html`**
A minimal HTML document used by the offscreen API to keep the service worker active via heartbeat messages.

### 7.3 CSS

**`css/popup.css`**
All styles for the extension are defined in this single file. It uses CSS custom properties (variables) for theming and includes styles for:

- Base layout and typography.
- User info bar and logo.
- Toolbar buttons (standard and minimal mode).
- Ticket list, header row, and individual ticket rows.
- Status badges and SLA indicators.
- Modals (config, timer, detail).
- Full-screen text popups.
- Scrollbar customization.
- Animations (status change blink).
- Minimal mode overrides (CSS Grid layout with explicit `grid-template-rows`).

### 7.4 JavaScript -- Entry Point

**`javascript/popup.js`**
The main script loaded by `PopupUI.html`. Responsibilities:

- Imports and initializes all handler and component modules.
- Sets up global error handling.
- Calls `displayItems()` to render the ticket list on popup open.
- Initializes all button handlers (timer, teams, notifications, update, clear, config).
- Restores the timer display state from storage.
- Loads user info from the service worker cache.

### 7.5 JavaScript -- API Layer

**`javascript/api/auth.js`**
Manages authentication with the Spark API.

- `getSparkToken()` -- Retrieves the JWT token from `spark.iver.com` localStorage via the content script.
- `hasValidSparkToken()` -- Checks if the cached token is still valid.
- `makeAuthenticatedRequest(url, options)` -- Wraps `fetch()` calls with the Bearer token header.
- `getLoggedInUserId()` -- Extracts the user ID from the JWT token payload.
- Exports `SPARK_API_BASE` (`https://spark.iver.com/api`).

**`javascript/api/ssoAuth.js`**
Handles SSO authentication flows using Microsoft Azure AD for Teams integration.

**`javascript/api/ticketApi.js`**
Provides higher-level API functions for ticket-related operations.

- `getTicketTimeSheets(ticketGuid)` -- Fetches time sheet entries for a ticket.
- `getExpectedArticleGuid(ticket)` -- Determines the expected time report article based on ticket type.
- `getArticleNameByGuid(guid)` -- Resolves an article GUID to its display name.
- Exports `OVERTIME_ARTICLE_GUIDS` for overtime article validation.

### 7.6 JavaScript -- Background

**`javascript/background/serviceWorker.js`**
The core background process. Responsibilities:

- **Message Handling:** Listens for messages from the popup (e.g., `getTicketAuditLogs`, `getTicketPosts`, `getTicketTexts`, `getTicketFullEmail`, `startTimer`, `stopTimer`, `scanNow`, `testNotification`).
- **Timer Management:** Starts and stops `chrome.alarms` for periodic updates.
- **Ticket Fetching:** Calls the Spark API to retrieve assigned tickets, maps them to an internal format, and stores them in Chrome storage.
- **Status Comparison:** Detects status changes between the current and previous ticket states.
- **Notifications:** Creates desktop notifications for status changes, errors, and alerts.
- **Offscreen Document:** Creates and manages an offscreen document to keep the service worker alive via heartbeat messages.
- **Article Validation:** Runs an independent article validation cycle via `checkArticleTimesheets()`, checking all user-assigned tickets from the last seven days regardless of status. Creates notifications with Ignore/Fix action buttons on mismatch.

**`javascript/background/offscreen.js`**
Runs inside the offscreen document. Sends periodic heartbeat messages to the service worker to prevent it from being terminated by the browser.

### 7.7 JavaScript -- Common Utilities

**`javascript/common/storage.js`**
Abstracts Chrome's `chrome.storage.local` API.

- `saveItems(items)` -- Stores the ticket list.
- `getItems()` -- Retrieves the ticket list.

**`javascript/common/utils.js`**
General-purpose utility functions.

- `formatDate(date)` -- Formats dates for display.
- `shuffleArray(array)` -- Randomizes array order.
- `generateId()` -- Creates unique identifiers.
- `calculateSlaRemaining(completeDueDate)` -- Computes remaining SLA time and returns a formatted string with an expiration flag.

### 7.8 JavaScript -- Components

**`javascript/components/itemList.js`**
Renders the ticket list and handles ticket detail modals.

- `displayItems()` -- Reads tickets from storage, sorts them, and renders each row with ID, status, SLA, and link columns.
- `showItemDetailModal(item)` -- Opens a detail modal for a specific ticket, fetching description and latest update data asynchronously.
- `fetchDescription(ticketGuid)` -- Retrieves `descriptionPlain` from the `/Tickets/{guid}/Texts` endpoint.
- `fetchLatestUpdate(ticketGuid, customerId)` -- Fetches audit logs and posts, then determines the latest update type (status change, post, or email).
- `showFullTextPopup(title, text)` -- Displays a full-screen overlay for reading long text content.

**`javascript/components/modal.js`**
Generic modal management.

- `showModal(modalId)` -- Displays a modal by removing the `hidden` class.
- `hideModal(modalId)` -- Hides a modal by adding the `hidden` class.
- Handles outside-click and Escape key dismissal.

**`javascript/components/timer.js`**
Timer logic for the automatic update cycle.

- `startTimer(duration)` -- Starts the countdown timer and sends a message to the service worker.
- `stopTimer()` -- Stops the timer and clears the interval.
- Persists timer state to Chrome storage for continuity across popup sessions.

### 7.9 JavaScript -- Content Scripts

**`javascript/contentScripts/sparkTokenReader.js`**
Injected into pages matching `https://spark.iver.com/*`. Reads the JWT access token from the page's `localStorage` and sends it to the service worker via `chrome.runtime.sendMessage`.

### 7.10 JavaScript -- Handlers

Each handler module manages one toolbar button or UI interaction.

**`clearButton.js`** -- Clears the ticket list from storage and refreshes the display.

**`configButton.js`** -- Opens the configuration modal, loads saved preferences, handles saving sort order, minimal mode toggle, notification settings, and status filter checkboxes.

**`notificationsButton.js`** -- Toggles desktop notifications on/off and updates the button icon state.

**`teamsButton.js`** -- Initiates Microsoft Teams channel connection via Microsoft Graph API.

**`timerButton.js`** -- Opens the timer settings modal. The **Spara** button saves the new interval and starts the timer. The **Avbryt** button closes the modal without changes.

**`updateButton.js`** -- Triggers an immediate ticket list refresh by sending a `scanNow` message to the service worker.

---

## 8. Data Flow

```
[spark.iver.com]
       |
       | (1) User logs in normally
       v
[sparkTokenReader.js]  -- reads JWT from localStorage
       |
       | (2) Token sent to service worker
       v
[serviceWorker.js]  -- caches token, schedules alarms
       |
       | (3) Alarm fires / manual update triggered
       v
[Spark API]  -- GET /Tickets, /AuditLogs, /Posts, /Texts
       |
       | (4) Response mapped to internal ticket format
       v
[Chrome Storage]  -- tickets, settings, timer state
       |
       | (5) Popup reads from storage on open
       v
[popup.js -> itemList.js]  -- renders ticket list and modals
```

---

## 9. Troubleshooting

| Symptom                                      | Likely Cause                              | Resolution                                                    |
|----------------------------------------------|-------------------------------------------|---------------------------------------------------------------|
| "Inga statusandringar hittades" in detail modal | Missing `customerId` in API call         | Ensure the ticket object includes `customerId`. Reload the extension. |
| No tickets displayed                         | Token expired or user not logged in       | Navigate to `spark.iver.com` and log in. Click **Uppdatera nu**. |
| Timer does not count down                    | Service worker was terminated             | Reopen the popup. The offscreen document will restart automatically. |
| Notifications not appearing                  | Notifications are toggled off             | Click the Notifications button to re-enable.                   |
| Extension icon is blank                      | Icon files missing or path incorrect      | Verify that the `icons/` folder contains all required image files. |
| "Kunde inte hamta data" in detail modal      | Network error or API rate limiting        | Wait a moment and try again. Check browser console for details. |
| Buttons stretch vertically in minimal mode   | Empty ticket list with old CSS Grid rows  | Update to version 2.0.1 or later. The fix uses explicit `grid-template-rows`. |

---

## 10. Changelog

### 2.1.0 (2026-03-18)

- **Timer Minimum Reduced:** The minimum timer duration has been lowered from 5 minutes to 30 seconds. A new "Sekunder" (seconds) input field has been added to the timer settings modal, allowing precise sub-minute intervals.

### 2.0.9 (2026-03-18)

- **Custom Queue:** A new "Custom Queue" toggle under "Appearance" in the Configuration panel allows users to select specific SavedViews (queues) from Spark to monitor. When enabled, only tickets from the selected queues are displayed, replacing the default "My Tickets" search. Notifications and manual refresh work identically for custom queue tickets.

### 2.0.8 (2026-03-16)

- **Title Override for Article Check:** A new dropdown in the Configuration panel under "Notifications" allows manual selection of the job title used for time report article validation. Overrides the JWT token title when set. A "Current Title" label shows the effective title. The setting is persisted in local storage.

### 2.0.7 (2026-03-10)

- **Minimal Mode -- Button Text Overflow Fix:** The "Kontrollera min kö" button now correctly uses icon/text span elements instead of overwriting the entire button content, preventing text overflow in minimal mode.
- **Configuration Panel -- English Translation:** All configuration modal text translated to English.
- **Configuration Panel -- Dark Theme:** Modal background changed from white to the same dark gray as the main popup, with adjusted text colors.
- **Minimal Mode -- Timer Countdown:** The timer button displays a live MM:SS countdown in its icon slot when in minimal mode.
- **Spark + Logo -- Linked:** The logo is now clickable and links to `https://sparkplus.se/`.

### 2.0.6 (2026-03-09)

- **Bugfix -- Empty Queue Not Clearing List:** Resolved an issue where the last ticket in the list would persist in the popup even after the API confirmed zero active tickets. The `scrapedItems` storage is now explicitly cleared when the API returns an empty result set.
- **Timer Minimum Reduced:** The minimum timer duration has been lowered from 15 minutes to 5 minutes, allowing shorter recurring update intervals.
- **Improved Error Messages:** API errors caused by invalid or expired tokens (including `Unexpected token` JSON parse failures) now display a user-friendly message -- "Öppna Spark för att verifiera ditt token" -- instead of raw error text, with an **"Öppna Spark"** button for quick re-authentication.

### 2.0.4 (2026-03-06)

- **Actionable Notification Buttons:** All notifications that direct the user to a specific destination now include action buttons. Status change notifications are created per ticket with an **"Öppna ärende"** button linking directly to the affected ticket. Token and API error notifications include an **"Öppna Spark"** button. The background update fallback notification includes a **"Visa ärenden"** button. Both notification body clicks and button clicks route to the correct destination.
- **Per-Ticket Status Change Notifications:** The single summary notification for status changes has been replaced with individual notifications per affected ticket, each displaying the specific status transition and a direct link.

### 2.0.3 (2026-03-05)

- **Time Report Article Validation -- Architectural Overhaul:** Extracted article validation into a standalone function (`checkArticleTimesheets`) with its own API call that retrieves all tickets assigned to the user from the last seven days, regardless of ticket status. This resolves an issue where tickets moved to Resolved, Closed, or other excluded statuses were skipped before the user could correct the time report.
- **Notification Buttons -- Ignore and Fix:** Article mismatch notifications now include two action buttons. **Ignore** persists the ticket ID in local storage to suppress future notifications. **Fix** opens the ticket in the Spark web interface for immediate correction.

### 2.0.1 (2026-03-04)

- **Minimal View -- Cosmetic Fix:** Resolved an issue where toolbar buttons would stretch vertically to fill the available space when the ticket list was empty in minimal mode. The `.container.minimal` CSS Grid now declares `grid-template-rows: auto auto 1fr auto`, assigning a fixed natural height to the header row, button row, and config button row. Only the ticket list row (`1fr`) expands to occupy remaining vertical space.

### 2.0.0 (2026-03-04)

- Initial production release with Spark API integration, ticket monitoring, SLA tracking, status change notifications, timer, minimal view, ticket detail modal with latest updates, and time report article validation.
