Files
opportunities-extension/README.md

292 lines
18 KiB
Markdown

# Opportunities Extension 1.0.2
Browser extension that adds the "Opportunities Extension" shortcut to the permitted Oracle Fusion pages, retrieves opportunities, and displays them in a filterable table.
## Development Structure
- `src/content/`: page integration, modal shell, theme and content composition.
- `src/background/`: synchronous message registration and background composition.
- `src/features/`: opportunities, products, consumption, AI summaries, preferences and debug.
- `src/auth/`: credential-specific selection, reuse and session recovery.
- `src/services/`: Fusion/SPA operations and background HTTP/JSON transport.
- `src/platform/`: narrow browser messaging, cookies, tabs and storage adapters.
- `src/shared/messages.js`: names of the existing cross-context messages.
- `scripts/build.mjs`: generates browser-specific packages.
- `tests/`: isolated synthetic regression tests and a visual fixture.
- `docs/`: architecture/contracts and incremental refactoring record.
- `dist/chromium/`: output for Google Chrome and Microsoft Edge.
- `dist/firefox/`: output for Firefox.
## CRM Service Request Badges
The header's **Refresh all** button (between theme and Preferences) invalidates
persisted Products and activity caches and clears in-memory data views. It reloads
the selected Reference, fetching fresh products and then the permitted SR/Actions
queries. Customer details, rate cards, consumption charts and AI summaries are
requested again when opened. Preferences, cookies and authentication are preserved.
The button is disabled during invalidation and list reload; product/activity badges
continue to show subsequent background progress. Cache-clear failures are surfaced
instead of silently reusing cached data, and stale product responses cannot restore
an invalidated cache.
On the first Opportunities modal opening in a page session, `requestCurrentUser`
fetches SPA identity before tokenrelay or opportunity requests. Concurrent calls,
Reference changes and modal reopenings reuse that result. Users with `SALES_REP`
do not trigger CRM Service Request or Workload Actions queries or see their badges.
If identity or roles cannot be validated, only these two features stay disabled;
other opportunity features continue. Reload the page to refresh identity/roles.
The unused identity token is discarded and redacted from debug responses.
After a completed product-loading cycle with fresh API results, `resquestCrmServiceRequest` fetches all pages of
`CRMServiceRequest` records with `SVC_PENDING_DELIVERY` and `ORA_SVC_MY_SR_TEAM_SRS`,
using the existing general tokenrelay Bearer. It uses the Fusion `searchResources/latest`
query endpoint, independently of the opportunity query version. Calls appear in
the Service Requests debug category with masked credentials.
Records are linked by `OpportunityName_Id_c.OptyNumber`. A green SR badge indicates
one or more matches; its tooltip lists each SR number, title, reported hours, owner,
email and contact flags. A red badge indicates no match within that query's scope.
A failed lookup shows `SR ?`, not a false no-match result, and opportunities still load.
Badges follow Ramp Months. Successful SR and Actions responses are persisted in
extension local storage, isolated by tokenrelay principal. The cache uses the same
Preferences lifetime as Products (24 hours by default), anchored to the product
timestamp rather than the activity response time. Actions entries match each
product's update; the SR snapshot matches the latest product update in the cycle.
No credentials, request headers or debug envelopes are stored in this cache.
Products loaded from cache restore matching activity entries without network calls.
Missing, expired or mismatched entries are not treated as confirmed empty results;
they wait for a real product refresh before a new activity query is allowed.
Empty and entirely failed product cycles do not query activities. In mixed cycles,
only fresh products permit activity API calls on cache misses; SR refreshes once.
Activity lookups do not advance the existing Last update timestamp.
Closing and reopening the modal preserves results and does not
reload products or trigger these lookups. Already-running product requests may
finish in the background and update their related activities.
## Workload Actions
Workload Actions are queried in the background after the product cycle completes,
using only fresh API results. Each distinct `RevnId` uses `requestWlActions` with
the `WWB-TS` credential in `Wwb-Provider-Authorization`. The Act badge beside SR
aggregates all products: green means an action's `owner` matches the general
tokenrelay response's `principal`; red means no matching owner was found. `Act ?`
means ownership could not be confirmed (including a missing principal). Tooltips
retain all returned actions, regardless of owner. Credentials stay in memory only;
the principal is used to scope persisted activity entries.
Queries are shared per product cycle (up to four concurrently). Reference changes
that load products from cache do not refresh activities.
Only the first page is requested for now; `hasNext` is indicated in the tooltip.
The debug panel groups these requests under Actions, with credentials masked.
## Build
Use Node.js:
```bash
npm run build
```
The build updates `dist/chromium` and `dist/firefox` from the same source.
It preserves the output directories and unchanged files, replacing changed files
only after their complete contents have been written to a temporary file. Scripts
are published before the manifest, avoiding missing or partially written scripts
while an unpacked extension is loaded. Reload the extension and the Oracle page
after updating; clear historical extension errors to check for new failures.
Do not edit files under `dist` directly. Both targets use Manifest V3, with a
Chromium service worker and Firefox background scripts. The build composes classic
factory modules from `scripts/sources.cjs` into one isolated IIFE per execution
context. It serializes `src/content/styles/redwood.css` followed by the scoped
`src/features/debug/styles.css`, `src/features/opportunities/styles.css`,
`src/features/install-base/styles.css`, `src/features/service-requests/styles.css`
`src/features/consumption/plan-detail.css` and `src/features/ratecard/styles.css` at
build time. There is no
runtime module loader, browser-side eval, ES-module requirement or new dependency.
## Tests and Maintenance
Installed Base and Service Requests include a search input above their tables.
Search filters loaded records across every displayed column, including raw and
formatted numbers/dates, without additional API calls. Matching ignores case
and accents; all whitespace-separated terms must match somewhere in the row.
The result count updates as users type. Clearing the input restores all records;
reopening a dialog starts with an empty search. Search remains available during
loading and retains the entered terms when results arrive. Both themes are supported.
Each Cloud Consumption plan includes a **Rate card** button beside Contract ID.
It opens an animated right-side drawer with skeleton rows, an all-column search
and sortable headers. The drawer reuses the Cloud Consumption header component
with the title **Rate Card**, customer subtitle, and the active plan's Booking
Customer, Sold To Party Name, Contract ID, Header Status, Start Date and End Date.
There is no separate plan-number subtitle or nested Rate Card action; its Close button
dismisses only the drawer. `requestRatecardByPlan` sends the active plan's `subPlanNum`
as the payload's `planNumber`, with `recordsSize: 10000`, to the fixed SPA endpoint.
It uses the existing OCICONS-TS `uiaasHeader.value` in `G2m-Authorization` and is
logged in the Consumption debug category with the existing credential masking.
The eleven requested fields are displayed, including percentage discounts and
USD prices with at least four decimal places. Search includes raw and formatted
values; prices, quantities, percentages and dates sort by value. Only the drawer
table scrolls, horizontally when its available width is below 1100px.
Closing the drawer, changing plans or closing Cloud Consumption discards late UI
updates. Concurrent requests for the same plan are shared; reopening after completion
fetches again. Errors remain local. No new persisted cache, permissions, token
refresh or retries are added. The provided contract requests up to 10000 records;
the response's `searchAfter` is not used without a defined pagination contract.
`tests/ratecard.test.cjs` covers transport, formatting, filtering, sorting and
drawer lifecycle with synthetic responses and DOM, without launching browsers.
Cloud Consumption loads `requestConsumptionPlanDetail` for the active plan after
account plans arrive, independently of the chart. Selecting another plan loads
its `subPlanNum` on demand. The GET uses `active=true` and the raw OCICONS-TS
`uiaasHeader.value` in `G2m-Authorization`, through the existing consumer session.
Projection badges align with the chart container's left edge, while the
Quarterly/Monthly/Weekly/Daily controls stay on the right of the same header row:
red Forfeit, blue Overage.
Hover or keyboard focus reveals an interactive tooltip; clicking pins it for
access to the Order number links. Escape, Close, outside clicks, tab changes and
modal closure dismiss it. Each root line retains its nested `clines` details.
Only HTTPS order links on `accountdashboard.oracle.com` become clickable.
Amounts use the requested non-LC fields, formatted without inferring a local
currency. Details are kept only in the current modal, with in-flight deduplication
and local loading/empty/error states. Failed details do not block the chart.
The existing Consumption debug category includes this request.
The Service Requests action sits immediately after Installed Base below Customer.
Its dialog opens with skeleton rows and lists open SRs for the selected customer.
The background first calls `requestAccountSummary` with ACCP-TS, then uses its
`id` (not `registryId`) in the GET `requestCustomerServiceRequest` URL. The SR
credential is `uiaasHeader.value` from `SPA-ORANGE`, sent verbatim in
`custsr-auth`, without a Bearer prefix, regardless of `uiaasHeader.label`.
Pages of 40 are consolidated using `totalResults`, `count`
and `offset`. Concurrent clicks for the same customer share the in-flight query;
results are not cached, and closed/replaced dialogs ignore late responses.
The table maps Name/Registry ID from `customer`, Product Name from `component`,
and formats status as a badge and dates using the existing date formatter.
Debug contains a Service Requests category; credential headers are masked before
delivery to content. This feature adds no permissions or authentication retries.
The Installed Base action sits beside customer consumption below Customer. It
opens a skeleton dialog, then calls `requestAccountSummary` with ACCP-TS and uses
the returned `registryId` in `requestInstallBase`. The latter uses the SAIB-TS
`uiaasHeader.label` and `uiaasHeader.value`, and loads pages of 25 until `hasMore`
is false. Missing credentials, invalid collections and stalled pagination show
an error rather than partial results. These requests appear in debug; credential
headers in this flow are masked before delivery to the content script. No new
cache, permissions or session recovery logic is introduced. Amounts use two
decimal places without inferring a currency from the separate LC fields.
The opportunities table places product counts below Name and the customer
consumption action below Customer, without a separate Actions column. Compact
columns retain their values; Name and Customer share the remaining width while
Owner is fixed at 132px. Both text cells reserve at least two text lines, and
their controls stay anchored 10px above the row bottom, including while products
load. Longer text can grow the row without overlapping controls. Horizontal
scrolling is reserved for table containers below
1120px. The scoped table stylesheet does not change product-table column widths
or the existing light/dark colors.
Product HTTP requests appear in Debug Requests (Ctrl+D) as soon as they start.
Each entry identifies the opportunity and page offset, stays `running` while
waiting for headers or the response body, and updates with HTTP status, response,
duration or error. Cache hits do not create HTTP entries. Product diagnostics
mask authorization and sensitive response headers before messaging the source
tab/frame; this change adds no timeout, retry or authentication behavior.
Debug Requests opens as a full-page view inside the extension using Ctrl+D, without
opening a browser tab or entering native browser fullscreen. Close, Escape or Ctrl+D
returns to the underlying view. Header/category navigation remains above the
scrollable timeline; expanded details use two columns on wide screens and one on
narrow screens. Theme-specific colors distinguish success, failure, running,
HTTP methods/statuses, request/response sections and JSON tokens. Highlighting
uses safe text nodes only after the existing sensitive-value masking. Compact JSON,
supported protection prefixes and JSON documents wrapped in strings are normalized
and indented, including while sensitive values are visible. Large JSON responses
are captured as bounded, valid JSON previews with an explicit omission notice,
preserving indentation, highlighting and sensitive-field masking. Already incomplete
or invalid JSON remains plain text. The visibility toggle retains its existing
behavior. Focus, expansion and timeline scroll position survive log updates.
Debug tabs group Authentication, Opportunities, Products, AI, Consumption, Installed Base and Service Requests
requests; unknown request types appear under Other. Only categories with entries
are shown. All preserves the complete timeline. Every tab sorts by request start
time, retaining original request IDs and showing start times in collapsed rows.
Counts and running states update without changing the selected category or
collapsing expanded details. Use arrow keys, Home and End to navigate the tabs.
```bash
npm test
npm run check
```
Tests use built-in Node.js modules and synthetic credentials, without real Fusion
requests. The characterization suite verifies manifests, source/output equality,
fiscal dates, payloads, preferences, pagination, cache/progress and both browser API
styles. Architecture tests enforce source inclusion, explicit factory dependencies,
isolated state and unchanged CSS. These complement consumption, session recovery
and AI suites. `check` also fails if generated packages are stale.
There is no separate lint configuration or runtime dependency installation.
See [architecture and contracts](docs/architecture.md) and the
[incremental refactoring record](docs/refactoring.md) for execution boundaries,
authentication, storage, known risks and verification limits.
Mock-based tests do not replace testing the installed extension in each browser.
Without npm, run `node scripts/build.mjs`, `node scripts/test.cjs` and
`node scripts/build.mjs --check`. Development checks were run with Node 24.19.0.
For a local UI smoke test, run `node scripts/preview.mjs` and open the loopback URL
printed by the command. The fixture uses synthetic opportunities, tokens, products,
AI text and consumption; unexpected requests fail closed. It does not authenticate
against Fusion or read real extension storage. `/consumption-trend.html` provides
a focused chart fixture. Stop the server with Ctrl+C when finished.
## Release 1.0.0
- Paginated opportunity retrieval with filters for reference, customer, owner, status, stage, and text search.
- Column sorting, links to opportunities and accounts, opportunity number copying, and stage indicators.
- Opportunity type view preferences persisted in the browser.
- Background product retrieval with configurable caching, progress tracking, and expandable product details.
- Cloud consumption account-plan lookup from each opportunity, displayed in a tabbed detail modal.
- Light and dark themes based on Oracle Redwood.
- Separate outputs for Chromium/Edge and Firefox.
## Release 1.0.1
- Retries the consumer token service when it returns HTTP 200 with an HTML fallback.
- Opens the SPA session page in an inactive temporary tab and closes it as soon as valid JSON is received.
- Limits the recovery flow to five attempts and records the session bootstrap details in debug mode.
## Release 1.0.2
- Modularized the extension with regression tests and documented execution boundaries.
- Added AI opportunity summaries with a dedicated, reusable Sales Common access token.
- Added Installed Base and customer Service Requests tables with search and dark-mode support.
- Expanded Cloud Consumption with plan projections, interactive details and a searchable, sortable Rate Card drawer.
- Added Ramp Months, CRM Service Request and Workload Actions badges; SR details include direct links and copy controls.
- Added a one-time current-user lookup before the initial request flow. Users with `SALES_REP` do not query or display CRM SR/Actions.
- Improved debug request grouping, full-page viewing, response formatting and theme contrast.
- Improved compact layouts, customer actions, session recovery and completion-badge fade-out behavior.
- Regenerated Chromium/Edge and Firefox distributions. Validation uses automated, browser-independent tests; installed-browser smoke tests were not performed for this release.
## Loading in Development Mode
### Chrome or Microsoft Edge
1. Open `chrome://extensions` or `edge://extensions`.
2. Enable Developer mode.
3. Click **Load unpacked**.
4. Select the `dist/chromium` folder.
### Firefox
1. Open `about:debugging#/runtime/this-firefox`.
2. Click **Load Temporary Add-on**.
3. Select the `dist/firefox/manifest.json` file.
## Supported Pages
- `https://eeho.fa.us2.oraclecloud.com/hcmUI/faces/FuseWelcome`
- `https://eeho.fa.us2.oraclecloud.com/fscmUI/faces/FuseWelcome`
When it finds the `#yourapps_groupNode_sales` group, the extension adds the tile before the `.flat-grid-cell.flat-grid-cell-addicon` item. Clicking the tile opens the opportunities interface.