551 lines
33 KiB
Markdown
551 lines
33 KiB
Markdown
# Opportunities Extension
|
|
|
|
Browser extension that adds the "Opportunities Extension" shortcut to the permitted Oracle Fusion pages, retrieves opportunities, and displays them in a filterable table or calendar.
|
|
|
|
See [Release Notes](RELEASE_NOTES.md) for version history and
|
|
[Architecture](docs/architecture.md) for execution, authentication and storage contracts.
|
|
|
|
## OpenSpec Workflow
|
|
|
|
The [twelve durable capability specifications](openspec/specs/) define the reviewed
|
|
behavioral baseline for this checkout. The initial
|
|
[`document-project-baseline` change](openspec/changes/archive/2026-10-31-document-project-baseline/proposal.md)
|
|
was completed and archived on 2026-10-31. Its
|
|
[design and evidence map](openspec/changes/archive/2026-10-31-document-project-baseline/design.md)
|
|
connect the baseline to source and tests, and its
|
|
[tracked tasks](openspec/changes/archive/2026-10-31-document-project-baseline/tasks.md)
|
|
record the completed application work. Use the durable specifications as the
|
|
starting point for subsequent capability changes.
|
|
|
|
For subsequent work, explore the problem, propose a change with the affected
|
|
capabilities, apply its tasks, verify the outcome, then archive. In Codex these
|
|
steps use `$openspec-explore`, `$openspec-propose`, `$openspec-apply-change` and
|
|
`$openspec-archive-change`. Application and archival are separate actions.
|
|
|
|
```bash
|
|
openspec list --json
|
|
openspec list --specs --json
|
|
openspec validate --specs --strict
|
|
```
|
|
|
|
Keep setup/usage guidance here, behavioral requirements in OpenSpec, execution
|
|
details in the architecture document and historical releases in RELEASE_NOTES.md.
|
|
|
|
## Opportunity Views
|
|
|
|
**Overview** is the default table view. It gives Name and Customer greater width
|
|
priority, uses customer `PartyName`, and labels win probability **Prob.**. Monetary
|
|
values and headers align right; other headers align left. Counts and stage amounts
|
|
follow the filtered opportunities.
|
|
|
|
Overview and **Calendar** share Reference, search, Customer, Owner, Status, Stage,
|
|
Booking/Workload and eligible SR/Action filters. Selecting Customers narrows the
|
|
available Owners, and selecting Owners narrows Customers, using loaded data.
|
|
Clicking one choice while all choices are selected isolates that choice; subsequent
|
|
clicks can add others. This also applies to Booking/Workload badges. The SR below
|
|
4h option has its own exclusive behavior, described under Workload Actions.
|
|
|
|
Calendar displays Close Date (`EffectiveDate`) in vertically scrolling months
|
|
restricted to Reference. There are no previous/next buttons or month/week switch.
|
|
Every matching opportunity has a card; crowded days scroll internally instead of
|
|
using a hidden-event overflow link. Switching views and filtering loaded records
|
|
do not send new opportunity requests. When today is inside Reference, the view
|
|
positions around its week with one preceding and one following week where the
|
|
Reference allows; otherwise it starts at the beginning of the range.
|
|
|
|
Cards preserve the API calendar day without timezone shifts and use stage colors.
|
|
Clicking opens read-only details with an opportunity link and copy action. Invalid
|
|
or missing close dates remain accessible in a separate collapsible list. Fiscal
|
|
labels use `FY27-Q2-W19`: June-May fiscal years, Sunday-Saturday weeks, and W1 for
|
|
the week containing June 1. The week's Sunday determines its quarter, except W1
|
|
belongs to Q1.
|
|
|
|
Table sorting remembers the last column and direction independently for Overview,
|
|
Installed Base, Service Requests, Rate Card, Consumption projection, contact
|
|
opportunities and Manage Time. Preferences survive reopening and page reloads in
|
|
the same browser profile. Opportunity product tables retain their original order.
|
|
|
|
FullCalendar Standard 6.1.19 is bundled locally under `src/vendor/fullcalendar/`
|
|
with its MIT license. It is initialized only on first use, without a runtime CDN.
|
|
|
|
## Products, Workloads and Projections
|
|
|
|
Product counts and details load in the background after opportunities are shown.
|
|
Workloads are retrieved per distinct customer account, paginated and matched to
|
|
products by `RevnId`. Valid workload cache entries are reused across modal openings
|
|
and token renewals according to Cache duration.
|
|
|
|
When a nonempty product list contains only blank or `-` Workload names, the ramp
|
|
badge becomes **Booking**, with its own color. If any product has a Workload name,
|
|
the ramp behavior remains. Booking and Workload badges beside the view tabs filter
|
|
these categories.
|
|
|
|
Clicking a ramp badge opens **Consumption projection** even when there is no
|
|
forecast discrepancy. Difference alerts sit between the ramp and SR badges;
|
|
products without a workload record show an unavailable alert in a disabled color.
|
|
Projection calculates monthly amounts from adjusted ACR and ramp months, including
|
|
first-month proration, and compares `forecast - calculated` at cent precision.
|
|
|
|
**Update estimates** asks for confirmation before sending the Calculated values
|
|
to SPA. It prevents duplicate submission, reports success or failure, refreshes
|
|
the comparison after success and invalidates the affected workload cache.
|
|
|
|
## Customer Organization Charts
|
|
|
|
The organization-chart icon beside **View customer service requests** opens a
|
|
builder shared by opportunities for the same customer. Add people and direct
|
|
reports, change their manager using **Reports to**, or click a person to edit
|
|
name and notes, and view contact details. **Name** uses the shared searchable select, populated by
|
|
`requestQueryAccountContact` after a 350 ms pause in typing, using the Token Relay
|
|
Bearer token and filtering by the customer's `PartyId`. Each POST returns up to
|
|
15 relevance-ranked results; empty queries and chart opening do not send searches.
|
|
Superseded responses are ignored. Contact names are keyed by `PartyId`;
|
|
options display only the person's name and job title. **Job Title** and **Email address**
|
|
are read-only and fetched afresh using the person's name as `keywords` whenever
|
|
Person details opens. The stored contact `PartyId` identifies the correct result.
|
|
Job Title is saved with the chart and shown immediately on the node. A fresh
|
|
response updates the matching person's name and Job Title automatically, preserving
|
|
notes and reporting relationships; **Save chart** persists those changes.
|
|
Email remains in memory only; existing persisted emails are removed by migration. Existing
|
|
saved people remain available even if absent from the contact list. Notes appear on hover or
|
|
keyboard focus. Branches can be expanded/collapsed; zoom, fit and canvas panning
|
|
help navigate larger trees. Deleting a person promotes their direct reports to
|
|
that person's manager without deleting those reports.
|
|
|
|
**Apply changes** updates the working tree; **Save chart** persists it. Unsaved
|
|
changes require confirmation before closing. The extension background stores
|
|
JSON-compatible records in IndexedDB, scoped by current user and customer ID in
|
|
the current browser profile. Records include schema version, revision, update
|
|
timestamp and a flat node array (`id`, `parentId`, `name`, `jobTitle`, `notes`,
|
|
`collapsed`, and optional `contactPartyId` and `PartyNumber`). PartyNumber is
|
|
preserved as an identifier, including alphanumeric values such as `A4KCS2P`.
|
|
Person details persists a returned PartyNumber so it can be reused by subsequent
|
|
opportunity lookups. Concurrent stale saves are rejected. Saving the hierarchy
|
|
does not write it to Oracle or synchronize it between devices. Charts support up
|
|
to 500 people and 60 reporting levels, with required name and optional notes.
|
|
|
|
The opportunities icon beside the person's delete action opens
|
|
**Opportunities | <name>**. It uses that person's stored PartyNumber in
|
|
`OpportunityContact.ContactPartyNumber`, resolving it through contact lookup when
|
|
missing. It loads all pages while `hasMore=true`, shows a loading skeleton and
|
|
provides sortable results. Clicking an opportunity Name opens its corresponding
|
|
Fusion opportunity in a new tab. Unresolved identifiers produce an explicit error
|
|
instead of an unfiltered opportunity query.
|
|
|
|
The Create Contact button at the right of **Name** opens an Oracle contact form.
|
|
First Name, Last Name and Email Address are required. Job Title and Work/Mobile
|
|
Phone are optional; supplied country codes and numbers are combined as
|
|
`55-99999999999`. Email and phone consent selections map to the corresponding
|
|
Do/DoNot flags. Account identifiers come from the current customer, and absent
|
|
optional values are omitted. Save submits directly to the contact API, without a
|
|
payload preview. Contact creation is a separate Oracle write from local chart
|
|
persistence.
|
|
|
|
The interaction is inspired by [OrgChart](https://github.com/dabeng/OrgChart).
|
|
Layout uses bundled [D3 Hierarchy 3.1.2](https://d3js.org/d3-hierarchy/tree), with
|
|
the extension's existing modal, theme and autocomplete patterns. D3 and icon
|
|
licenses are in `src/vendor/d3-hierarchy/` and `src/vendor/lucide/`. There is no
|
|
runtime CDN dependency or new browser permission.
|
|
|
|
For synthetic browser checks, install Playwright separately (or provide it through
|
|
`NODE_PATH`) and run `node scripts/verify-org-chart.cjs`. `TEST_BROWSER_CHANNEL`
|
|
can select an installed `msedge` or `chrome`. This exercises real IndexedDB in a
|
|
local fixture and writes light/dark/mobile screenshots to a temporary folder;
|
|
native extension storage and Oracle integration still require the browser smoke
|
|
check below.
|
|
|
|
## 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, customer tables, organization charts, Manage Time, 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.
|
|
|
|
## Authentication and Access
|
|
|
|
Before dependent data requests, the extension establishes a valid SPA identity.
|
|
Concurrent consumers share acquisition; Reference changes and modal reopenings
|
|
reuse success. Identity also has a background browser-session cache, partitioned
|
|
by Firefox cookie store and private-browsing context, so a page reload does not
|
|
necessarily fetch identity again. The validated API response must contain user
|
|
id, name, roles and a token; the reusable identity stores only id, name and roles.
|
|
Failures keep dependent requests waiting and retry with backoff.
|
|
|
|
Users with **SALES_REP** do not load CRM SR or Workload Actions data or see their
|
|
badges. **Manage Time** is also hidden and its data request entry points are
|
|
blocked. Independent SR session bootstrap may still run; readiness does not grant
|
|
access to restricted activity data.
|
|
|
|
When identity requires session recovery, the extension opens
|
|
`https://spa.oracle.com/oalcrm/web/api/g2m-consumer-application/ui/index.html?ojr=whitespace`
|
|
in an inactive auxiliary tab. SPA inspection rejects error documents, SAML/login
|
|
forms and OAuth callbacks before an identity probe. HTTP 200, cookies or elapsed
|
|
time alone do not prove readiness. Rejected callbacks restart at this bootstrap
|
|
URL. Recovery preserves the originating browser context and cleans up its owned
|
|
tab; its bounded cycle can be retried by the waiting identity gate.
|
|
|
|
Consumer-token recovery uses the same SPA bootstrap URL for invalid JSON and
|
|
HTTP 401/403, with up to five HTTP attempts. Token Relay uses the Fusion XSRF
|
|
cookie, has a 30-second request timeout and bounded cookie recovery; it cannot
|
|
remain indefinitely pending when the timeout fires.
|
|
|
|
SR session preparation can run concurrently with SPA preparation through
|
|
`https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live/webApps/external/`.
|
|
It reports **SR session ready** on success, waits up to 70 seconds, and offers
|
|
Retry after failure. Eligible users' resource data is consumed after both identity
|
|
and SR preparation finish. See the architecture document for service-specific
|
|
credentials and the distinction between session navigation and API requests.
|
|
|
|
## CRM Service Request Badges
|
|
|
|
The header's **Refresh all** button invalidates persisted Products and activity
|
|
caches and clears related in-memory data views. It reloads the selected Reference,
|
|
displays opportunities first, then starts permitted SR and product enrichment.
|
|
Actions follow their SR/product prerequisites. Customer details, rate cards and consumption charts 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.
|
|
|
|
Opportunity retrieval first calls `requestOpportunitiesSavedSearch` and requires
|
|
exactly one valid `isDefault=true` item. Its `savedSearchNumber` becomes
|
|
`copiedFrom: queries/<savedSearchNumber>` for every opportunity page. A missing or
|
|
ambiguous default blocks the dependent query instead of using a hard-coded value.
|
|
|
|
After all opportunity pages are displayed, SR and product enrichment start in the
|
|
background. Before the first `resquestCrmServiceRequest` page,
|
|
`requestSRSearchResources` retrieves CRMServiceRequest searches with the general
|
|
Token Relay Bearer. The first item's `savedSearchNumber` supplies SR `copiedFrom`;
|
|
this is independent of Opportunity's default-search selection.
|
|
SR fetches all pages of `SVC_PENDING_DELIVERY` / `ORA_SVC_MY_SR_TEAM_SRS` records
|
|
through Fusion `searchResources/latest`. Each page can update badges while the
|
|
remaining pages load. These requests appear in the Service Requests debug category.
|
|
After a complete successful SR query (HTTP 200 with valid responses on all pages),
|
|
its result is reused for subsequent Reference/product cycles in the current page
|
|
session. Refresh all explicitly clears it. Failed pages are retried up to five
|
|
total attempts each; completed pages are not requested again. Resetting the query
|
|
stops further retries from the previous run.
|
|
|
|
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.
|
|
SR snapshots are stored separately by update timestamp so changing Reference does
|
|
not overwrite a previous period's snapshot. Expired snapshots are removed on
|
|
subsequent SR cache writes; Refresh all invalidates every snapshot.
|
|
No credentials, request headers or debug envelopes are stored in this cache.
|
|
Matching activity entries can be restored without network calls. Missing, expired
|
|
or mismatched entries remain unknown until queried, and cache-miss activity
|
|
lookups are allowed even when the products came from cache. A completed SR result
|
|
is reused and can be associated with the current product update. Empty or entirely
|
|
failed product cycles do not start product-dependent Actions; independently started
|
|
SR loading does not depend on a successful product cycle.
|
|
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
|
|
|
|
The missing Act badge includes a separate plus control that opens an Action form
|
|
with Owner, Role, Action, Team, Start date, End Date, Status, Complexity and Notes.
|
|
Opening the form loads team members and action lookups using the WWB-TS token.
|
|
Team members use the product RevnId; when multiple workloads are available, the
|
|
user selects one before its members are requested. Owner options use email for
|
|
both label and value; lookup options display name and submit code.
|
|
All Action selects support local autocomplete by label or code, arrow-key
|
|
navigation and Enter selection. Escape or leaving the field restores the last
|
|
selected option; typed search text is never submitted as an option value.
|
|
Fields are enabled only after both metadata requests return HTTP 200. Loading,
|
|
errors and manual retry are supported, and debug logs mask the credential.
|
|
Save validates all required fields and the date range before posting to the WWB
|
|
actions endpoint. Dates are sent at midnight UTC in ISO format; notes are an
|
|
array of strings (empty when omitted). The current user.id supplies createdBy
|
|
and updatedBy. While saving, editing and dismissal are locked to prevent duplicate
|
|
submissions. Success closes the form and displays a toast; failure preserves the
|
|
form and displays an error toast without automatically retrying the POST.
|
|
Cancel or Escape dismisses an idle form. The form is unavailable to SALES_REP
|
|
users, like the other Action features.
|
|
|
|
SR and Action filter badges appear before Status for users allowed to view these
|
|
activities. They filter the loaded data without issuing requests and combine with
|
|
the existing opportunity filters. The SR below 4h option replaces the other SR
|
|
selections and matches at least one linked SR with a numeric `ReportedHours_c < 4`
|
|
(including zero, excluding missing values). Action matches use the same ownership
|
|
rule as the row badge. Loading/failed lookups are not treated as missing records;
|
|
with both positive and negative options selected, all activity states remain
|
|
visible. These selections are kept in memory, not persisted.
|
|
|
|
Workload Actions are queried in the background after the product cycle completes,
|
|
and only after SR has completed successfully (or was restored/reused). If SR is
|
|
unavailable, Actions are not requested and remain unknown rather than absent.
|
|
Each failed workload lookup gets up to five total attempts, stopping on success
|
|
or when its session is superseded. Valid activity cache entries are reused;
|
|
cache misses can trigger lookups for cached products. 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. The principal scopes persisted
|
|
activity entries; this data cache excludes credentials and debug envelopes.
|
|
Queries are shared per product cycle (up to four concurrently). Reference changes
|
|
reuse matching activity data or load missing data as needed.
|
|
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.
|
|
|
|
## Manage Time
|
|
|
|
Eligible users can open **Manage Time** once the SR session is ready. It restores
|
|
the selected reference date, moves by seven days and preserves local week drafts
|
|
while navigating within the modal. Service Request, Activity and Task Type use
|
|
searchable dependent selections; Service and Non Service rows use their respective
|
|
task types. Duplicate SR selections are rejected with row feedback.
|
|
|
|
Daily hours must be numeric and between 0 and 24 inclusive. Save creates new
|
|
entries, updates changed saved entries and applies queued deletions. Deleting an
|
|
unsaved row is local; deleting a saved row waits for Save. Partial failures retain
|
|
unfinished work without repeating confirmed writes. Loading uses skeletons and
|
|
errors expose retry. The feature is unavailable for SALES_REP.
|
|
|
|
## 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. CSS is serialized at build time in the order defined by
|
|
`scripts/compose.cjs`, including feature styles followed by shared table and modal
|
|
overrides in `src/content/styles/tables.css` and `dialogs.css`. There is no
|
|
runtime module loader, browser-side eval, ES-module requirement or new dependency.
|
|
|
|
## Customer Insights
|
|
|
|
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. An **Order Number**
|
|
multiselect beside Search groups distinct order numbers and supports selecting all
|
|
or several orders. Clicking one order while all are selected isolates that order.
|
|
Order selections and text search combine locally.
|
|
Shared table styles remove the old fixed minimum width, tighten cell spacing and
|
|
allow multiword headers to wrap at word boundaries so the table fits the drawer.
|
|
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. The
|
|
customer appears in its modal header rather than a repeated Customer column. 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 and badges below Name and customer
|
|
actions below Customer. Their spacing is coordinated; longer names can grow the
|
|
row without overlapping controls. Shared table and modal styles provide consistent
|
|
titles, typography, borders, padding and loading skeletons in both themes.
|
|
|
|
## Debug Requests
|
|
|
|
Request records are persisted in page localStorage under a tab-specific namespace.
|
|
Closing the main modal preserves them. The reset occurs immediately before the
|
|
first `requestOpportunities` page of a new query; subsequent pages preserve that
|
|
query's history. Requests logged before that reset, including its saved-search
|
|
lookup, are removed by the same boundary.
|
|
|
|
The hidden debug panel does not prebuild request details. Opening it loads the
|
|
summaries and expanding an entry constructs its details. Storage is updated in
|
|
batches of changed records; quota or access failures retain the session's records
|
|
in memory with explanatory feedback rather than interrupting API requests.
|
|
|
|
Product HTTP requests appear in Debug Requests (Ctrl+Shift+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+Shift+D, without
|
|
opening a browser tab or entering native browser fullscreen. Close, Escape or Ctrl+Shift+D
|
|
returns to the underlying view. Debug stays above other extension modals.
|
|
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 in full, preserving indentation, highlighting and sensitive-field
|
|
masking. Original sensitive values are retained for explicit reveal, including
|
|
identity, tokenrelay and catalog tokens. Already incomplete
|
|
or invalid JSON remains plain text. The visibility toggle retains its existing
|
|
behavior. This is display masking, not encryption or guaranteed redaction at rest:
|
|
captured records can retain original sensitive values in localStorage. Focus,
|
|
expansion and timeline scroll position survive log updates.
|
|
|
|
Debug tabs group Authentication, Opportunities, Contacts, Products, Consumption,
|
|
Installed Base, Service Requests and Actions
|
|
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.
|
|
|
|
## Tests and Maintenance
|
|
|
|
```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,
|
|
organization-chart and Manage Time 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.
|
|
Calendar week positioning, responsive tables, modal dragging and print pagination
|
|
still need visual checks in installed browsers; synthetic tests alone do not
|
|
certify those layouts or live Oracle authentication.
|
|
|
|
Without npm, run `node scripts/build.mjs`, `node scripts/test.cjs` and
|
|
`node scripts/build.mjs --check`. The documentation-baseline checks use Node 22.15.0;
|
|
the build has no runtime dependency installation step.
|
|
|
|
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,
|
|
and consumption data; 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.
|
|
|
|
## 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.
|
|
|
|
Opening the saved shortcut ending in `#opportunities-extension` also opens the
|
|
modal without clicking the Sales group. Its intent is captured before Fusion can
|
|
rewrite the URL, then consumed once when the extension is ready.
|
|
|
|
## Favorites, Modal Interaction and Printing
|
|
|
|
With the main modal open, **Ctrl+Shift+F** opens a searchable browser bookmark
|
|
folder picker. Choose the destination and Save; the extension uses the bookmarks
|
|
API rather than the browser's native Add Favorite dialog. If the shortcut is not
|
|
bookmarked, a prominent hint appears for 20 seconds and disappears immediately
|
|
after saving. **Last update** remains the first header badge.
|
|
|
|
Non-full-page modals can be dragged from any noninteractive area of their title
|
|
bar. Up to 70% of their width and height can move beyond the viewport; title-bar
|
|
buttons keep their normal actions. Full-page views remain fixed.
|
|
|
|
The print icon beside **Booking** and **Workload** opens a report containing the
|
|
current filters, counts, stage amounts and opportunity list. Unrestricted Customer
|
|
and Owner selections are labeled **All customers** and **All owners**. The report
|
|
requests A4 landscape with page margins and supports the browser's Print / Save PDF
|
|
dialog. Browser print settings can override the requested orientation and paper.
|