A Chrome extension that makes the Vantage timesheet app easier to use — freeze and hide columns, add task descriptions, and get autocomplete while entering daily activities.
- Frozen columns — Keep key columns like "Daily Activity" and "Event" pinned while you scroll horizontally.
- Hidden columns — Declutter your view by hiding columns you don't need.
- Description lookup column — Add a "Description" column that displays task descriptions fetched from ServiceNow.
- Daily Activity autocomplete — Get suggestions as you type in the Daily Activity field, sourced from your task data fetched from ServiceNow.
- New row focus — Adding a record on the Daily Activity tab scrolls the new row into view and focuses its Daily Activity input.
- Add-row keyboard shortcut — Press
Ctrl+Shift+.on Windows/Linux orCommand+Shift+.on macOS to add a Daily Activity record without leaving the keyboard. - Update Timesheet shortcut — On
Timesheet (TIMEI)in theDaily Activitytab, adds anUpdate Timesheetbutton next to the lower three-dot menu so you can trigger the native action in one click. - Automatic pagination upgrade — On the Daily Activity tab grid, the extension automatically selects the highest available visible page-size option only when the grid is in a verified fallback state at the default 20 rows, including after adding a new row when the grid resets.
- Quarter-hour warnings — Time cells that don't end in
:00,:15,:30, or:45are highlighted with an orange outline, helping you catch accidental decimal-style entries. - Missing Event warnings — An empty Event cell is highlighted with a red outline when its row contains entered hours.
- The production extension works on
vantage.utah.govandvantage.access.utah.gov(for non-state networks); local development and pre-release builds also supportvantage-ma1.utah.govfor testing.
Type-ahead search for tasks based on description:
Warnings for non-quarter-hour time entries or blank values in the Event column:
Install directly from the Chrome Web Store. Note that this extension is currently only available to State of Utah DTS employees.
The extension icon will appear in your Chrome toolbar. It is only active when you are on the Vantage site.
- Navigate to Vantage at
https://vantage.utah.gov/(orhttps://vantage.access.utah.gov/). - The extension activates automatically — columns are frozen and your saved visibility preferences are applied.
- Click the extension icon in your Chrome toolbar to open the popup, where you can:
- Show or hide individual columns.
- Show or hide the Scheduled Hours summary row.
- Fetch the current task descriptions from ServiceNow.
- On
Timesheet (TIMEI)with theDaily Activitygrid visible, use the addedUpdate Timesheetbutton beside the lower three-dot menu to run the same native update action without opening the menu first. - When you add a record on the Daily Activity tab, the new row is brought into view and its Daily Activity input receives focus.
- To change the add-row shortcut or resolve a shortcut conflict, open
chrome://extensions/shortcutsand edit the ad-vantage command. - When the Daily Activity tab grid shows inline pagination options such as
50or100, the extension automatically switches to the highest enabled option only after it detects a verified fallback to20, and it will not repeat that native click just because the page emitted more generic mutation noise.
Use Fetch from ServiceNow in the popup to sign in and load current task descriptions. The extension uses that information to populate the Description column and provide suggestions while entering Daily Activity codes. Your task data stays associated with your current browser profile and will need to be refreshed any time your ServiceNow tasks change. The extension does not store or transmit your ServiceNow credentials.
The sync request times out after 45 seconds. If the request fails, times out, or the background process does not respond, the popup shows an error and lets you try again.
There is also a DTS User Guide Doc.
- Node.js 24+
- pnpm (install with
npm install -g pnpmor via other methods)
-
Install dependencies:
pnpm install
-
Configure the local OAuth client ID:
cp .env.example .env.local
Replace the placeholder in
.env.localwith the public client ID from the ServiceNow OAuth application registration. -
Start the development server:
pnpm dev
This starts the Vite dev server with HMR via
@crxjs/vite-plugin. Extension files are written todist-devand requirehttp://localhost:5173to remain running. The generated manifest uses a Chrome-compatible numeric version, even when the source version includes an-rcsuffix. The development build supportsvantage-ma1.utah.govfor testing. Vite loads the development ServiceNow endpoint from.env.developmentand the public OAuth client ID from the ignored.env.localfile. -
Launch the dedicated debug browser:
pnpm chrome:dev
Opens Google Chrome Dev with remote debugging on
http://127.0.0.1:9223. Keep this browser open while using MCP-based browser inspection. -
In the Chrome Dev window, go to
chrome://extensions/, enable Developer mode, and load thedist-devfolder as an unpacked extension. -
Log in to Vantage in that same Chrome Dev window.
-
Reload VS Code after the browser is running so the MCP server in
.vscode/mcp.jsoncan connect.
You can verify the remote debugging endpoint with:
curl http://127.0.0.1:9223/json/versionIf Chrome Dev is already running without the remote debugging flag, macOS may reuse the existing instance and ignore the new launch arguments. Quit Chrome Dev and run
pnpm chrome:devagain.
pnpm buildBundles and minifies the extension into the dist folder using the ServiceNow endpoint from .env.production and the public OAuth client ID from .env.local or the VITE_SERVICE_NOW_CLIENT_ID environment variable. Load dist as an unpacked extension in chrome://extensions/ to test the production build.
pnpm build:pre-releaseBundles the separately publishable pre-release extension into dist-pre-release. It uses the pre-release ServiceNow endpoint from .env.pre-release, the ad-vantage (Pre-release) title, orange icons, and a warm popup theme. Its manifest deliberately has no key: Chrome Web Store assigns and maintains a distinct ID when the pre-release build is first submitted. A source version such as 1.3.14-rc.1 is normalized to the Chrome-compatible manifest version 1.3.14.1.
The pre-release version of ad-vantage has been published as a separate Chrome extension available only to members of this Google Group: ad-vantage-pre-release@utah.gov. The pre-release version's color scheme is set to orange to help eliminate confusion.
The pre-release extension can be installed alongside the production extension. To avoid both versions modifying the same Vantage page, keep only one enabled at a time:
- Install the pre-release extension from the Chrome Web Store.
- Open
chrome://extensions/, find ad-vantage, and turn its toggle off before testing the pre-release version. - Verify that ad-vantage (Pre-release) is enabled, then reload any open Vantage tabs before testing.
- To switch back to production, open
chrome://extensions/, turn ad-vantage (Pre-release) off, turn ad-vantage on, and reload Vantage tabs.
Do not uninstall either extension to switch versions. Turning off the version you are not testing preserves its settings and lets you move between production and pre-release builds quickly.
Note
The pre-release extension is pointed at the test ServiceNow instance. This means that task descriptions may be out-of-date from the production ServiceNow instance. I don't have any control over when they update SN data in test.
The popup uses OAuth 2.0 Authorization Code with PKCE to fetch tasks from the Utah ServiceNow instance. The extension is a public OAuth client and does not contain or store a client secret.
ServiceNow configuration is selected at build time through Vite modes:
pnpm devuses.env.developmentand.env.local.pnpm builduses.env.productionand.env.local, orVITE_SERVICE_NOW_CLIENT_IDfrom the environment.pnpm build:pre-releaseuses.env.pre-releaseand.env.local, orVITE_SERVICE_NOW_CLIENT_IDfrom the environment.- Tests use deterministic values from
.env.test.
The repository includes public ServiceNow endpoints but no OAuth client IDs. Release builds use the VITE_SERVICE_NOW_CLIENT_ID GitHub Actions secret. The generated extension manifest requests access only to the ServiceNow host selected for that build. Each ServiceNow OAuth Application Registry entry must allow the redirect URI returned by chrome.identity.getRedirectURL() for the corresponding extension ID.
The task request uses the sysparm_query filter defined in src/background/servicenow.ts.
The ServiceNow OAuth Application Registry entry must be configured as a public/external client with the Authorization Code grant and PKCE enabled. The user must have permission to read pm_project_task records.
Fetched lookup data is stored in the current Chrome profile's isolated chrome.storage.local area, while OAuth tokens are kept in chrome.storage.session (cleared when the browser restarts). Neither is synced to other devices. Tokens are refreshed automatically and cleared internally if ServiceNow rejects a refresh token.
Test local queries using the REST API Explorer in the dev instance.
Dev ServiceNow Instance: https://utahdev.servicenowservices.com/
pnpm testThe release workflow can publish new versions to the Chrome Web Store after the first manual submission.
The production and pre-release extensions are separate Chrome Web Store items with different IDs. The production build pins the existing production ID with VITE_EXTENSION_KEY; the pre-release build must remain without a key so its Chrome Web Store item retains its own assigned ID.
- Create a Chrome Web Store developer account and enable 2-step verification.
- Run
pnpm build. - Upload the
distcontents as a new item in the Chrome Web Store dashboard. - Complete the listing, privacy, and distribution sections, then submit so Google assigns a permanent extension ID.
The release workflow uses GitHub Actions OIDC with Google Workload Identity Federation (WIF) to impersonate a Google Cloud service account. It does not use long-lived OAuth refresh tokens or service account key files.
Add these repository secrets to enable automated publishing on release:
EXTENSION_IDPUBLISHER_ID- Chrome Web Store publisher ID from the Developer Dashboard's Publisher settings.GCP_WORKLOAD_IDENTITY_PROVIDER- full WIF provider resource name, in the formprojects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID.GCP_SERVICE_ACCOUNT_EMAIL- email address of the service account added to the Chrome Web Store publisher.VITE_SERVICE_NOW_CLIENT_ID- OAuth client ID for the environment's extension.
Set EXTENSION_ID and VITE_SERVICE_NOW_CLIENT_ID separately in the dev and prod GitHub environments. Make the shared publisher and WIF credentials available to both environments. The release workflow selects dev for prereleases and prod for stable releases.
Before publishing, enable the Chrome Web Store API in the Google Cloud project and add the service account in the Chrome Web Store Developer Dashboard under Account. A publisher can have one service account.
The existing WIF provider and IAM binding must allow this repository's release workflow to impersonate the service account. Restrict that trust condition to tags matching refs/tags/v*.
If any required secret or variable is missing, the release workflow still uploads the built zip to GitHub Releases and skips the Chrome Web Store step.
Once configured, a published prerelease from dev builds the orange pre-release extension, uploads its archive to GitHub Releases, and publishes it to the restricted pre-release Chrome Web Store item. A published stable release from main follows the same process for the blue production extension and production Store item.
Releases are managed with agrc/release-composite-action via GitHub Actions using conventional commits.
| Commit type | Release bump |
|---|---|
feat |
minor |
fix |
patch |
docs |
patch |
style |
patch |
deps |
patch |
- Pushes to
devcreate or update prerelease PRs and tags. - Pushes to
maincreate or update stable release PRs and tags. - Merging a release PR publishes the release and uploads the built extension archive.
Use squash merges so the PR title becomes the changelog entry. The workflow automatically bumps the version in package.json and manifest.json — do not edit those files manually to cut a release.
This project has a chrome-extensions skill installed from Google. You can update the skill with the following command:
pnpm dlx skills update chrome-extensions

