Skip to content

Latest commit

 

History

167 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ad-vantage

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.

Features

  • 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 or Command+Shift+. on macOS to add a Daily Activity record without leaving the keyboard.
  • Update Timesheet shortcut — On Timesheet (TIMEI) in the Daily Activity tab, adds an Update Timesheet button 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 :45 are 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.gov and vantage.access.utah.gov (for non-state networks); local development and pre-release builds also support vantage-ma1.utah.gov for testing.

ad-vantage popup screenshot

Type-ahead search for tasks based on description:

grid screenshot

Warnings for non-quarter-hour time entries or blank values in the Event column:

warnings screenshot

Installation

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.

Usage

  1. Navigate to Vantage at https://vantage.utah.gov/ (or https://vantage.access.utah.gov/).
  2. The extension activates automatically — columns are frozen and your saved visibility preferences are applied.
  3. 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.
  4. On Timesheet (TIMEI) with the Daily Activity grid visible, use the added Update Timesheet button beside the lower three-dot menu to run the same native update action without opening the menu first.
  5. When you add a record on the Daily Activity tab, the new row is brought into view and its Daily Activity input receives focus.
  6. To change the add-row shortcut or resolve a shortcut conflict, open chrome://extensions/shortcuts and edit the ad-vantage command.
  7. When the Daily Activity tab grid shows inline pagination options such as 50 or 100, the extension automatically switches to the highest enabled option only after it detects a verified fallback to 20, and it will not repeat that native click just because the page emitted more generic mutation noise.

ServiceNow Task Sync

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.

DTS Guide

There is also a DTS User Guide Doc.


Developer Guide

Prerequisites

Local Development

  1. Install dependencies:

    pnpm install
  2. Configure the local OAuth client ID:

    cp .env.example .env.local

    Replace the placeholder in .env.local with the public client ID from the ServiceNow OAuth application registration.

  3. Start the development server:

    pnpm dev

    This starts the Vite dev server with HMR via @crxjs/vite-plugin. Extension files are written to dist-dev and require http://localhost:5173 to remain running. The generated manifest uses a Chrome-compatible numeric version, even when the source version includes an -rc suffix. The development build supports vantage-ma1.utah.gov for testing. Vite loads the development ServiceNow endpoint from .env.development and the public OAuth client ID from the ignored .env.local file.

  4. 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.

  5. In the Chrome Dev window, go to chrome://extensions/, enable Developer mode, and load the dist-dev folder as an unpacked extension.

  6. Log in to Vantage in that same Chrome Dev window.

  7. Reload VS Code after the browser is running so the MCP server in .vscode/mcp.json can connect.

You can verify the remote debugging endpoint with:

curl http://127.0.0.1:9223/json/version

If 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:dev again.

Production Build

pnpm build

Bundles 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.

Pre-release Build

pnpm build:pre-release

Bundles 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.

Pre-release Tester Workflow

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:

  1. Install the pre-release extension from the Chrome Web Store.
  2. Open chrome://extensions/, find ad-vantage, and turn its toggle off before testing the pre-release version.
  3. Verify that ad-vantage (Pre-release) is enabled, then reload any open Vantage tabs before testing.
  4. 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.

ServiceNow Integration

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 dev uses .env.development and .env.local.
  • pnpm build uses .env.production and .env.local, or VITE_SERVICE_NOW_CLIENT_ID from the environment.
  • pnpm build:pre-release uses .env.pre-release and .env.local, or VITE_SERVICE_NOW_CLIENT_ID from 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/

Tests

pnpm test

Chrome Web Store

The 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.

First-Time Store Setup

  1. Create a Chrome Web Store developer account and enable 2-step verification.
  2. Run pnpm build.
  3. Upload the dist contents as a new item in the Chrome Web Store dashboard.
  4. Complete the listing, privacy, and distribution sections, then submit so Google assigns a permanent extension ID.

Automated Publishing via GitHub Actions

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_ID
  • PUBLISHER_ID - Chrome Web Store publisher ID from the Developer Dashboard's Publisher settings.
  • GCP_WORKLOAD_IDENTITY_PROVIDER - full WIF provider resource name, in the form projects/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

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 dev create or update prerelease PRs and tags.
  • Pushes to main create 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.

Skills

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

Releases

Used by

Contributors

Languages