Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion docs/_docs/developer-guide/cueweb-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ loads at runtime are copies under `cueweb/public/`.
- **`AppSessionProvider`** (`app/providers/session-provider.tsx`): Thin client wrapper around `next-auth/react`'s `SessionProvider` so `useSession()` works inside the header and any other client component.
- **`CueWebIcon`** (`components/ui/cuewebicon.tsx`): OpenCue icon + **CueWeb** wordmark, sized off a single `height` prop. Used by the login page, LDAP login page, frame log page, and comments page. Reads the brand assets from `cueweb/public/opencue-icon-{black,white}.png`.
- **`JobsTable`** (`app/jobs/data-table.tsx`): Main jobs dashboard table (no longer renders its own inline header - the global `AppHeader` owns that chrome). Each `TableRow` left-click dispatches `setAttributeSelection(...)` so the Attributes panel updates as the user inspects rows and also surfaces the inline Layers + Frames panel below the grid via `JobDetailsInline`. Destructive toolbar actions (Eat / Retry / Pause / Unpause / Kill) consume `useDisableJobInteraction()` and dim themselves when the safety flag is on. Wires TanStack's `columnVisibility`, `columnOrder`, and `globalFilter` state into the reducer State so each is persisted to `localStorage` (`columnVisibility`, `columnOrder`); the per-table substring filter is purely component-state.
- **`JobDetailsInline`** (`components/ui/job-details-inline.tsx`): Inline Layers + Frames panel rendered below the Jobs table when a row is selected. Polls layers and frames every 5s with cancellation guards. Layer-row clicks toggle a frames-table filter to that layer and push the layer's attributes into the docked Attributes panel.
- **`JobDetailsInline`** (`components/ui/job-details-inline.tsx`): Inline Layers + Frames panel rendered below the Jobs table when a row is selected. Polls layers and frames every 5s with cancellation guards. Layer-row clicks toggle a frames-table filter to that layer and push the layer's attributes into the docked Attributes panel. When `useShowDependencyGraph()` is on, it also mounts `JobDependencyGraph` as a third stacked panel (`id="job-dependency-graph-panel"`) below Frames, with a header naming the focus job plus show/hide and close controls.
- **`JobDependencyGraph`** (`components/ui/job-dependency-graph.tsx`): Read-only, interactive node graph of a job's dependency tree, built with React Flow (`@xyflow/react`) + dagre. Mirrors CueGUI's `JobMonitorGraph`. A breadth-first walk from the focus job follows both `GetDepends` (downstream) and `GetWhatDependsOnThis` (upstream, active-only), bounded by `maxDepth` (default 4) and a visited-set to break cycles. Each hop resolves a job name to its UUID via `/api/job/getjobs` anchored-regex (Cuebot rejects name-only depend lookups), memoized in a `Map` so the whole walk costs ~one lookup per distinct job. All BFS fetches go through a `silentPost` helper that bypasses `accessGetApi`, so jobs in other shows / unmonitored + pruned don't cascade into red toasts. The custom `DependencyNode` renderer truncates long names (full name in a `title` tooltip), color-codes the left border by kind (JOB/LAYER/FRAME), rings the focus job, and shows hierarchical labels for layer/frame nodes. dagre lays out fresh per call (no module-level singleton); the data fetch is keyed on `job.id` so flipping the theme doesn't re-walk the tree, and the crosshair-cursor SVG is scoped per instance via a `data-graph-id` attribute. Clicking a node calls `onNodeNavigate(jobName)` if supplied, else `router.push("/jobs/<jobName>?tab=overview")`.
- **`JobDetailsPage`** (`app/jobs/[job-name]/page.tsx`): Standalone tabbed job-details route reached via the **View Job Details** right-click entry (or the row's `⋮` Actions button). Resolves the job by name through `findJobByName(...)`, polls layers + frames every 5s with cancellation guards, and exposes five tabs - **Overview**, **Layers**, **Frames**, **Comments**, **Dependencies**. The active tab is mirrored to the URL as `?tab=<key>` and read back through `useSearchParams()` + `router.replace(...)` so the page is bookmarkable and browser back/forward walks between tabs. `isTabKey(value)` rejects unknown query values so the URL can never select a missing tab. The Comments tab embeds a read-only preview of `getJobComments(...)` with a link out to the full `/jobs/<jobName>/comments` editor; Dependencies is currently a placeholder. The standard `Breadcrumbs` + `EmptyState` (`FileX` icon, "Job not found") wrappers cover loading and missing-job paths.
- **`SimpleDataTable`** (`components/ui/simple-data-table.tsx`): Shared TanStack-table wrapper used by Layers and Frames (and the standalone log-viewer / per-job detail page). Owns the per-table substring filter (`globalFilter` + `getFilteredRowModel`), column-visibility persistence (`columnVisibilityStorageKey`), and column-order persistence (a parallel `cueweb.<table>.columnOrder` key derived from the visibility key). Renders the Columns dropdown that holds the `←` / `→` reorder buttons and the **Reset to Default** action.
- **`JobProgressBar` / `LayerProgressBar`** (`components/ui/{job,layer}-progress-bar.tsx`): Stacked progress bars with a hover tooltip showing per-state counts and percentages. Both delegate to the shared `<ProgressBar/>` renderer in `components/ui/progressbar.tsx`. Segment colors and ordering come from `app/utils/{job,layer}_progress_utils.ts`.
Expand Down Expand Up @@ -243,6 +244,15 @@ provider tree.
- Helper: `getShortcutNotificationsEnabled()` reads the pref
imperatively at fire time, so flipping the toggle takes effect on
the very next keypress without remounting the listener.
- **`useShowDependencyGraph`** (`app/utils/use_show_dependency_graph.ts`)
&mdash; `{ show, set, toggle }`. Drives the inline Dependency Graph
panel and the checkable **Cuetopia &rarr; View Job Graph** menu entry.
- Key: `cueweb.jobs.showDependencyGraph` (`"1"`/`"0"`, defaults off).
- Event: `cueweb:show-dependency-graph-changed` (same-tab) plus the
standard `storage` event for cross-tab sync. Exported as
`SHOW_DEP_GRAPH_CHANGED_EVENT`.
- Hydrates to `false` on first render so SSR and the first client
paint agree, then upgrades from `localStorage` in an effect.

The header and sidebar share their NAV data via
`app/utils/menus.ts` (exports `NAV_MENUS`, `NavMenu`, `NavItem`). The Help
Expand All @@ -267,6 +277,7 @@ on `window` instead of prop-drilling shared state. Existing events:
| `cueweb:attribute-selection-changed` | `setAttributeSelection()` | `useAttributeSelection` listeners | Same-tab sync of the selected entity |
| `cueweb:disable-job-interaction-changed` | `useDisableJobInteraction().toggle` | `useDisableJobInteraction` listeners | Same-tab sync of the safety flag |
| `cueweb:open-mobile-nav` | `AppHeader` hamburger button (`md:hidden`) | `MobileNavSheet` | Open the mobile nav drawer |
| `cueweb:show-dependency-graph-changed` | `useShowDependencyGraph().set` (Cuetopia ▸ View Job Graph, panel toggle) | `useShowDependencyGraph` listeners | Same-tab sync of the inline Dependency Graph panel visibility |

The browser's built-in `storage` event handles cross-tab sync for every
pref that lives in `localStorage`, so the `CustomEvent`s only need to
Expand Down Expand Up @@ -813,6 +824,51 @@ Data flow:
14px`; otherwise it falls back to the default centered layout, so
the column stays decoupled from the grouping mode.

### Dependency graph panel

The inline **Job Dependency Graph** (`JobDependencyGraph`,
`components/ui/job-dependency-graph.tsx`) is the read-only, visual
counterpart to the Group-By Dependent tree - it mirrors CueGUI's
`JobMonitorGraph` Monitor-Jobs dock rather than the tree view.

- **New dependencies.** The component pulls in three new npm packages:
`@xyflow/react` (React Flow, `^12`) for the canvas, `dagre`
(`^0.8.5`) for directed-graph layout, and `@types/dagre` (dev).
- **Toggle + mount.** Visibility is owned by the shared
`useShowDependencyGraph()` hook (see *Application state hooks*),
flipped from the **Cuetopia &rarr; View Job Graph** menu entry and the
panel header. `JobDetailsInline` mounts it as a third stacked panel
under Layers + Frames when the hook is on.
- **Tree walk.** `walkDependencyTree(focus, maxDepth)` runs a BFS from
the focus job over both directions - `silentGetDepends` (downstream,
`GetDepends`) and `silentGetWhatDependsOnThis` (upstream,
`GetWhatDependsOnThis`, filtered to `active !== false`) - bounded by
`maxDepth` (default 4) and a `visited` job-name set to break cycles.
Mirrors `JobMonitorGraph.getRecursiveDependentJobs`.
- **Name &rarr; UUID resolution.** Each hop calls
`resolveJobIdByName(name, cache)`, which posts an anchored
`^escapeRegex(name)$` query to `/api/job/getjobs` (Cuebot rejects
name-only depend lookups). Results are memoized in a `Map` seeded
with the focus job, so the walk costs ~one `GetJobs` per distinct job.
- **Silent fetches.** `silentPost(endpoint, body)` deliberately bypasses
`accessGetApi`; non-OK responses and `{ error }` bodies return `null`
so jobs in other shows / unmonitored + pruned don't fire
`handleError()` red toasts.
- **Layout + rendering.** `layoutNodes` builds a fresh
`dagre.graphlib.Graph` per call (no module-level singleton) with
`rankdir: "TB"`. `describeEndpoint` derives a stable node id, kind
(JOB / LAYER / FRAME), and a hierarchical label per endpoint;
`ingestDepend` merges each `Depend` into node/edge `Map`s and returns
the er/on job names to expand the frontier. The custom
`DependencyNode` truncates the label (full name in `title`),
color-codes the left border by kind, and rings the focus job.
- **Decoupled effects.** The data fetch is keyed on `[job.id, job.name,
maxDepth]` so flipping the theme doesn't re-walk the tree; the
crosshair-cursor SVG is memoized on `resolvedTheme` and scoped to the
instance via a `data-graph-id` attribute. Node clicks call
`onNodeNavigate(jobName)` when supplied, else
`router.push("/jobs/<jobName>?tab=overview")`.

---

## Pause / Unpause Toggle (Job Context Menu)
Expand Down
16 changes: 16 additions & 0 deletions docs/_docs/other-guides/cueweb.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ CueWeb replicates the core functionality of [CueGUI](https://www.opencue.io/docs
- The same image works whether the browser reaches CueWeb at `localhost` on the dev machine or at a LAN IP from another device on the same network - no rebuild needed when you want to test on a phone. The build-time `NEXT_PUBLIC_URL` setting defaults to empty for this reason; only set it to an absolute URL if your deployment serves the API on a different origin than the UI.
- Copy actions (Copy Job / Layer / Frame Name, Copy Log Path) work even when CueWeb is reached over plain HTTP at a LAN IP, including on iOS Safari.

27. **Job dependency graph (Cuetopia &rarr; View Job Graph):**
- A read-only, interactive node graph of a job's dependency tree, mirroring CueGUI's Monitor-Jobs dependency-graph dock.
- Toggled from the checkable **Cuetopia &rarr; View Job Graph** entry (header dropdown and sidebar); the choice is persisted and synced across tabs.
- When on, selecting a job in Monitor Jobs mounts the graph as a third panel under the inline Layers and Frames panels. It walks the depends in both directions (what the job depends on and what depends on the job), color-codes nodes by kind (JOB / LAYER / FRAME), rings the focus job, truncates long names with a full-name tooltip, and lets you click a node to open that job's detail page. Pan / zoom / fit controls and a "No dependencies found" empty state are included.


## CueWeb's user interface

Expand Down Expand Up @@ -519,6 +524,17 @@ After **Apply**, a toast confirms the new value and the **Priority** column in t
**Figure 69: Toast confirming the priority change and immediate column update**
![Toast confirming the priority change](/assets/images/cueweb/cueweb_cuetopia_monitor_jobs_set_priority_confirmation.png)

The checkable **Cuetopia &rarr; View Job Graph** entry (Figure 70) toggles a read-only dependency-graph panel. With it on, selecting a job in Monitor Jobs mounts an interactive node graph of the job's dependency tree as a third panel under the inline Layers and Frames panels (Figure 71). The graph walks the depends in both directions, color-codes nodes by kind (JOB / LAYER / FRAME), rings the focus job, and lets you click a node to open that job's detail page (Figure 72).

**Figure 70: View Job Graph entry in the Cuetopia menu**
![View Job Graph entry in the Cuetopia menu](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_menu.png)

**Figure 71: Dependency graph panel below the inline Layers and Frames panels**
![Dependency graph panel below Layers and Frames](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_monitor_jobs_dependency_graph.png)

**Figure 72: The dependency graph panel on its own**
![The dependency graph panel on its own](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_monitor_jobs_dependency_graph_only.png)


## Conclusion

Expand Down
3 changes: 3 additions & 0 deletions docs/_docs/quick-starts/quick-start-cueweb.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ Click a job row to reveal the inline Layers and Frames panels below the jobs tab
- **Kill Jobs**: Use the stop button to terminate jobs
- **Job Details (inline)**: Click on a job row to reveal the inline Layers + Frames panel below the Jobs table.
- **Job Details (tabbed page)**: Right-click a job and choose **View Job Details** to open the tabbed `/jobs/<jobName>` page with Overview / Layers / Frames / Comments / Dependencies tabs. The active tab is stored in the URL so the page is bookmarkable.
- **Job Dependency Graph**: Toggle **Cuetopia &rarr; View Job Graph**, then click a job to mount a read-only, interactive node graph of its dependency tree below the inline Layers + Frames panels. Nodes are color-coded by kind (JOB / LAYER / FRAME), the focus job is ringed, and clicking a node opens that job's detail page.

![Dependency graph panel below Layers and Frames](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_monitor_jobs_dependency_graph_only.png)
- **Job Comments**: Right-click a job and choose **Comments**, or click the sticky-note icon in the Jobs table's **Comments** column (sortable, sits right after Name), to open the Comments page where you can list / add / edit / delete comments and manage predefined-comment macros.

The job right-click menu, and the tabbed Job Details page it can open:
Expand Down
27 changes: 27 additions & 0 deletions docs/_docs/reference/cueweb.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,33 @@ Clicking a row in the Jobs table populates `JobDetailsInline` (`cueweb/component
| **Refresh** | Both panels poll every 5 seconds, with cancellation guards so a stale response cannot overwrite a fresh selection. |
| **Log viewer** | Double-clicking any frame row opens the log viewer (`/frames/<frameName>?frameId=...&frameLogDir=...`). |

### Job dependency graph panel

A read-only, interactive node graph of a job's dependency tree, rendered with [React Flow](https://reactflow.dev/) (`@xyflow/react`) and laid out with [dagre](https://github.com/dagrejs/dagre). It mirrors CueGUI's `JobMonitorGraph` Monitor-Jobs dock. Lives in `JobDependencyGraph` (`cueweb/components/ui/job-dependency-graph.tsx`).

**Toggle.** The checkable **Cuetopia &rarr; View Job Graph** entry (header dropdown in `app-header.tsx`, sidebar in `app-sidebar.tsx`, both expanded and collapsed) drives a shared `useShowDependencyGraph()` hook. The hook persists to `localStorage["cueweb.jobs.showDependencyGraph"]` and syncs in-tab via the `cueweb:show-dependency-graph-changed` CustomEvent and cross-tab via the `storage` event, so the menu items, the panel header toggle, and the panel itself stay in lockstep without prop drilling.

![View Job Graph entry in the Cuetopia menu](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_menu.png)

**Mounting.** When the toggle is on, `JobDetailsInline` (`cueweb/components/ui/job-details-inline.tsx`) renders the graph as a third stacked panel (`id="job-dependency-graph-panel"`) under Layers and Frames, with a header naming the focus job and a close button.

![Dependency graph panel below the inline Layers and Frames panels](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_monitor_jobs_dependency_graph.png)

![Dependency graph panel below the inline Layers and Frames panels (dark mode)](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_monitor_jobs_dependency_graph_dark.png)

| Behavior | Description |
|----------|-------------|
| **Tree walk** | Breadth-first search from the focus job over both directions - `GetDepends` (downstream) and `GetWhatDependsOnThis` (upstream, active depends only) - bounded by `maxDepth` (default 4) and a visited-job set to break cycles. Mirrors CueGUI's `JobMonitorGraph.getRecursiveDependentJobs`. |
| **Name resolution** | Each BFS hop first resolves a job name to its UUID via `/api/job/getjobs` with an anchored `^name$` regex (Cuebot rejects name-only depend lookups). Resolved IDs are memoized in a `Map`, so a 12-job chain costs ~12 lookups across the whole walk, not 12 per hop. |
| **Silent fetches** | All BFS requests go through a `silentPost` helper that bypasses `accessGetApi`. Partial failures (jobs in other shows, unmonitored/finished + pruned) return `null` instead of cascading red "Resource not found" toasts. |
| **Nodes** | Custom `DependencyNode` renderer: monospace, truncated label with the full name in a `title` tooltip, a kind label and color-coded left border (JOB = blue, LAYER = amber, FRAME = emerald), and a stronger ring on the focus job. Layer / frame nodes carry a hierarchical label so their parent job/layer is visible. |
| **Edges** | Directed upstream &rarr; downstream (top-to-bottom); animated when the depend is active. |
| **Navigation** | Clicking a node calls `onNodeNavigate(jobName)` if supplied, else `router.push("/jobs/<jobName>?tab=overview")`. |
| **Theme-aware** | dagre lays out fresh per call (no module-level singleton); the data fetch is keyed on `job.id` so toggling dark/light does not re-walk the tree. The crosshair-cursor SVG is scoped per instance via a `data-graph-id` attribute so two graphs on a page do not collide. |
| **Empty / loading states** | `Loading dependency graph...` while walking; `No dependencies found for this job.` when only the focus node remains. |

![The dependency graph panel on its own](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_monitor_jobs_dependency_graph_only.png)

### Job-finished notifications

| Behavior | Description |
Expand Down
16 changes: 16 additions & 0 deletions docs/_docs/tutorials/cueweb-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,22 @@ The job context menu groups four dependency actions so you can audit, create, or

![Drop Internal Dependencies success toast](/assets/images/cueweb/cueweb_cuetopia_monitor_jobs_drop_internal_dependencies_confirmation.png)

### Visualizing the dependency graph

When you want to *see* a render chain rather than read a table of depends, turn on the **Job Dependency Graph** - a read-only node graph mirroring CueGUI's Monitor-Jobs dependency-graph dock.

1. **Enable the graph.** Open the **Cuetopia** menu (header dropdown or sidebar) and click **View Job Graph**. The entry is a checkable toggle - a check mark appears when it is on, and the choice is remembered across pages, tabs, and reloads.

![View Job Graph entry in the Cuetopia menu](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_menu.png)

2. **Open a job.** Click a job row in Monitor Jobs. The graph mounts as a third panel under the inline Layers and Frames panels. It walks the job's depends in both directions - what the job depends on and what depends on the job - and lays the result out top-to-bottom.

![Dependency graph panel below the inline Layers and Frames panels](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_monitor_jobs_dependency_graph.png)

3. **Read and navigate the graph.** Each node carries a kind label (JOB / LAYER / FRAME) and a color-coded left border; the job you opened the panel for is ringed. Hover a node to see its full name, and click a node to open that job's detail page. Use the corner controls to pan, zoom, and fit. Collapse or close the panel from the **Dependency Graph** button above Layers or the panel's **&times;** button. A job with no depends shows **No dependencies found for this job.**

![The dependency graph panel on its own](/assets/images/cueweb/cueweb_cuetopia_view_job_graph_monitor_jobs_dependency_graph_only.png)

---

## Job Details and Frame Management
Expand Down
Loading
Loading