sdp-request-watcher/README.md

118 lines
6.5 KiB
Markdown

# sdp-request-watcher
A local Node.js dashboard for ManageEngine ServiceDesk Plus (SDP) Cloud. It shows each technician's open tickets by status, plays a sound when a ticket is closed, tracks the unassigned queue, and shows local weather.
![Dashboard](images/4.png)
## Setup
### 1. Zoho API client
Create a **Non-Browser Application** at <https://api-console.zoho.com/add>. That gives you the client ID and secret. The app only asks for the `SDPOnDemand.requests.READ` scope, so it can read requests but never change them.
### 2. `.env` file
Copy `src/env.example` to a file named `.env` and fill it in. dotenv reads `.env` from the folder you start the server in, so keep `.env` in the project root and start the server from there (see step 3).
| Setting | Required | What it does |
| --- | --- | --- |
| `CLIENT_ID`, `CLIENT_SECRET` | Yes | The Zoho Non-Browser Application credentials. |
| `TECHNICIAN_NAMES` | No | Comma-separated technician names, spelled as they appear in SDP. One table row per name. Leave it empty to include every technician. |
| `STATUS_NAMES` | No | Statuses that count as "closed" for the ding and the Closed today count. Everything else counts as open. Defaults to `Closed,Resolved,Canceled`. |
| `SITE_NAMES` | No | Only include requests from these sites (the region). Leave it empty for all sites. |
| `GROUP_NAMES` | No | Only include requests in these support groups, e.g. `Customer Support`. Leave it empty for all groups. |
| `UNASSIGNED_EXCLUDED_STATUSES` | No | Statuses the Unassigned requests counter leaves out. Defaults to `STATUS_NAMES`. |
| `WORKLOAD_MINUTES` | No | How often the status table and unassigned count refresh, in minutes. Defaults to 5. |
| `OWM_API_KEY`, `OWM_ZIP_CODE` | No | OpenWeatherMap key and zip code for the weather card. Leave either one empty to hide the card. A free key from <https://openweathermap.org/api> is enough. New keys can take a couple of hours to start working. |
Spaces around commas are fine in every list.
The central region settings currently in use:
```text
SITE_NAMES=Base Site,ASSIGN,CMCC,CMCC-Damariscotta,EMCC,KVCC,KVCC-Alfond,MCCS
GROUP_NAMES=Customer Support
UNASSIGNED_EXCLUDED_STATUSES=Canceled,Closed,Need Information,On Hold,Resolved
```
These match the "Central Region Unassigned" custom view in ManageEngine. The Unassigned requests count was checked against that view and matched.
### 3. Run it
```text
npm install
npm run app
```
`npm run app` runs `node src/server.js` from the project root. Then open <http://localhost:3000>. Set `PORT` in `.env` to use a different port.
## Connecting to Zoho
The token is kept in memory only, so you connect each time the server starts.
1. Click **Connect**.
![Connect screen](images/1.png)
2. Once Zoho sends back a device code, the code and an **Open authorization page** button appear. The Zoho page opens in a new tab.
![Approve screen](images/2.png)
3. Check that the code matches, tick the box and click **Accept**, then close that tab.
![Zoho consent page](images/3.png)
4. Return to the dashboard tab. Zoho can't redirect back to a local app, but the dashboard checks the server every few seconds and goes live by itself once you approve.
## The dashboard
- **Stat tiles**: unassigned requests, total open requests, closed today, closed in the last hour, and the technician with the most open tickets.
- **Tickets by technician**: each technician's open tickets by status. **Total open** and **Closed today** come first, so they stay visible on narrow screens while the status columns scroll sideways. Darker cells mean more tickets. A row flashes when that technician closes a ticket.
- **Weather**: current conditions and a 5-day forecast for `OWM_ZIP_CODE`, refreshed every 10 minutes.
- **Recently closed**: the live closed-ticket feed, checked every minute. A ding plays for each new close. The sound is on by default, and the **Sound on close** toggle mutes it in that browser.
- **Refresh now** reruns every check immediately.
If a query fails, a red error box shows what SDP returned, and the other sections keep working. If the table ever shows **partial**, a query matched more tickets than it can page through (2,000). The server console then logs the details, including SDP's total count. A very large total usually means SDP ignored the search criteria.
### Unassigned verification list
`src/public/index.html` still has a hidden table listing every unassigned request by ID and subject. It was used to confirm the count matches the ManageEngine view. To show it again, set `SHOW_UNASSIGNED_LIST = true`.
## How it works
| File | Role |
| --- | --- |
| `src/server.js` | Reads `.env`, then starts Express and the services. |
| `src/auth.js` | Zoho device-code sign-in. |
| `src/boardService.js` | Holds the token and state, and runs the refresh timers. |
| `src/tickets.js` | SDP API queries for the closed feed, the status table, closed today and unassigned requests. |
| `src/weather.js` | OpenWeatherMap current weather and forecast, cached for 10 minutes. |
| `src/routes.js` | `/api/state`, `/api/connect`, `/api/check` and `/api/weather`. |
| `src/public/index.html` | The dashboard page. |
Every SDP query is limited to the configured sites, groups and technicians. Results are also re-checked locally, so a ticket from outside the region is never counted even if the API returns one.
## Requirements
Node.js 18 or newer. Dependencies are `axios`, `dotenv` and `express`, all installed by `npm install`.
## Credits
- **Skylar Grant**: project owner and author.
- **Isaac Godin**: original page design.
- **Claude** (Anthropic, via Claude Code): dashboard, region scoping, unassigned counter, weather card and SDP query fixes, built with Skylar.
## Reference materials (provided by Skylar)
- [Non-Browser Apps - Overview](https://www.zoho.com/accounts/protocol/oauth/limited-input-devices.html)
- [Non-Browser Apps - Initiation Request](https://www.zoho.com/accounts/protocol/oauth/devices/initiation-request.html)
- [Non-Browser Apps - Polling Request](https://www.zoho.com/accounts/protocol/oauth/devices/polling-request.html)
- [Get List Request](https://www.manageengine.com/products/service-desk/sdpod-v3-api/requests/request.html#get-list-request)
- [Input Data](https://www.manageengine.com/products/service-desk/sdpod-v3-api/getting-started/input-data.html)
- [Search Criteria](https://www.manageengine.com/products/service-desk/sdpod-v3-api/getting-started/search-criteria.html)
- [OpenWeatherMap Current Weather](https://openweathermap.org/current) and [5 Day Forecast](https://openweathermap.org/forecast5)
## License
MIT. See [LICENSE](LICENSE).