Skip to content

fix: send refetch on all rundown edits#2098

Open
alex-Arc wants to merge 6 commits into
masterfrom
pre-switch-refactor
Open

fix: send refetch on all rundown edits#2098
alex-Arc wants to merge 6 commits into
masterfrom
pre-switch-refactor

Conversation

@alex-Arc

@alex-Arc alex-Arc commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

ensures that all edits to rundown data result in a refetch event
this is done by refactoring all the routes to use the rundown.service instead of doing it inplace

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f94bf30d-ec7d-4f2f-8d0d-c93b441186a9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR refactors rundown management by moving duplication logic to the service layer and introducing two new operations (renameRundown, deleteRundown). The router now delegates to these service functions instead of inline operations, and DataProvider.setRundown returns the updated rundowns list to callers.

Changes

Rundown Management Service Refactor

Layer / File(s) Summary
DataProvider contract update
apps/server/src/classes/data-provider/DataProvider.ts
setRundown now returns ReadonlyPromise<ProjectRundowns> instead of Promise<void>, allowing callers to receive the updated rundowns list after persistence.
Service-layer rundown operations
apps/server/src/api-data/rundown/rundown.service.ts
Three new exports: duplicateRundown (clones rundown with new id, resets revision), renameRundown (updates title, re-initializes if loaded), deleteRundown (enforces constraints against deleting loaded or last rundown). All schedule sendRefetch(RefetchKey.ProjectRundowns).
Validation and router delegation
apps/server/src/api-data/rundown/rundown.validation.ts, apps/server/src/api-data/rundown/rundown.router.ts
Router service and validation imports updated; POST /:id/duplicate, PATCH /:id (with new rundownPatchValidator), and DELETE /:id endpoints now delegate to respective service functions instead of inline logic.
Test and utility cleanup
apps/server/src/api-data/rundown/rundown.utils.ts, apps/server/src/api-data/rundown/__tests__/rundown.utils.test.ts
Removed duplicateRundown test suite; replaced removed duplicateRundown utility with new IncrementNumber type and getIntegerAndFraction decimal parser.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • cpvalente/ontime#1913: The main PR's renameRundown calls initRundown, which is directly impacted by changes to initRundown's control flow in this PR.
  • cpvalente/ontime#1846: Implements the client-side counterpart to this PR's server-side duplicateRundown and renameRundown service operations with corresponding client API, hooks, and UI.
  • cpvalente/ontime#2005: The main PR's service operations trigger sendRefetch(RefetchKey.ProjectRundowns), which this PR adapts by switching client rundown cache invalidation to dynamic per-rundownId keys.

Suggested labels

priority

Suggested reviewers

  • cpvalente
  • jwetzell
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main objective of the PR—ensuring refetch events on all rundown edits through service-layer refactoring.
Description check ✅ Passed The description clearly explains the purpose (ensuring refetch on rundown edits) and the approach (refactoring routes to use rundown.service).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pre-switch-refactor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@alex-Arc alex-Arc force-pushed the pre-switch-refactor branch 3 times, most recently from 79797bb to eb37924 Compare June 13, 2026 10:11
@alex-Arc alex-Arc force-pushed the pre-switch-refactor branch from eb37924 to 4d079bd Compare June 13, 2026 10:24
@alex-Arc alex-Arc requested a review from cpvalente June 13, 2026 10:24
@alex-Arc

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
apps/server/src/api-data/rundown/rundown.router.ts (1)

123-135: 💤 Low value

Minor: Status code 201 is unconventional for PATCH.

Line 129 returns status 201 (Created) for a PATCH operation that updates an existing rundown's title. HTTP status 200 (OK) or 204 (No Content) would be more semantically appropriate for updates. While not incorrect, 201 is typically reserved for operations that create new resources.

♻️ Optional fix to use conventional status code
-      res.status(201).json({ loaded: getCurrentRundown().id, rundowns: normalisedToRundownArray(projectRundowns) });
+      res.status(200).json({ loaded: getCurrentRundown().id, rundowns: normalisedToRundownArray(projectRundowns) });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/api-data/rundown/rundown.router.ts` around lines 123 - 135,
The PATCH handler currently returns HTTP 201; change the response to a
conventional update status: replace res.status(201).json(...) in the
router.patch async callback with res.status(200).json(...) (or
res.status(204).send() if you prefer no body) so renameRundown and the handler
return a proper success code for updates; keep the existing body (loaded and
rundowns) when using 200.
apps/server/src/api-data/rundown/rundown.service.ts (2)

738-740: ⚖️ Poor tradeoff

Minor: Redundant refetch when renaming the loaded rundown.

When renaming the currently loaded rundown, initRundown (line 735) already schedules sendRefetch(RefetchKey.ProjectRundowns) at line 675, making the explicit call here at line 739 redundant. While harmless (refetch is idempotent), this could be optimized by conditionally scheduling the refetch only when not re-initializing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/api-data/rundown/rundown.service.ts` around lines 738 - 740,
The setImmediate call that always does sendRefetch(RefetchKey.ProjectRundowns)
is redundant when initRundown already scheduled the same refetch; update the
code around initRundown and the setImmediate block so you only schedule the
extra refetch when not re-initializing the currently loaded rundown — e.g.,
detect the re-initialization/rename case (use the same flag or condition used by
initRundown) and wrap the setImmediate(sendRefetch(RefetchKey.ProjectRundowns))
call in that conditional so it is skipped during initRundown-driven
re-initialization.

732-735: 💤 Low value

Minor: Variable shadowing reduces clarity.

At line 733, rundown is re-declared, shadowing the variable from line 725. While this works correctly (the second declaration fetches the persisted updated rundown), consider using a distinct name like updatedRundown to improve readability.

♻️ Optional refactor for clarity
   if (isCurrentRundown(id)) {
-    const rundown = dataProvider.getRundown(id);
+    const updatedRundown = dataProvider.getRundown(id);
     const customField = dataProvider.getCustomFields();
-    await initRundown(rundown, customField);
+    await initRundown(updatedRundown, customField);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/api-data/rundown/rundown.service.ts` around lines 732 - 735,
The variable declared at the second retrieval shadows the earlier "rundown";
rename the second variable to a distinct name (e.g., updatedRundown) so the code
reads: const updatedRundown = dataProvider.getRundown(id); const customField =
dataProvider.getCustomFields(); await initRundown(updatedRundown, customField);
keep the surrounding logic (isCurrentRundown check and use of
dataProvider.getCustomFields and initRundown) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/server/src/api-data/rundown/rundown.router.ts`:
- Around line 123-135: The PATCH handler currently returns HTTP 201; change the
response to a conventional update status: replace res.status(201).json(...) in
the router.patch async callback with res.status(200).json(...) (or
res.status(204).send() if you prefer no body) so renameRundown and the handler
return a proper success code for updates; keep the existing body (loaded and
rundowns) when using 200.

In `@apps/server/src/api-data/rundown/rundown.service.ts`:
- Around line 738-740: The setImmediate call that always does
sendRefetch(RefetchKey.ProjectRundowns) is redundant when initRundown already
scheduled the same refetch; update the code around initRundown and the
setImmediate block so you only schedule the extra refetch when not
re-initializing the currently loaded rundown — e.g., detect the
re-initialization/rename case (use the same flag or condition used by
initRundown) and wrap the setImmediate(sendRefetch(RefetchKey.ProjectRundowns))
call in that conditional so it is skipped during initRundown-driven
re-initialization.
- Around line 732-735: The variable declared at the second retrieval shadows the
earlier "rundown"; rename the second variable to a distinct name (e.g.,
updatedRundown) so the code reads: const updatedRundown =
dataProvider.getRundown(id); const customField = dataProvider.getCustomFields();
await initRundown(updatedRundown, customField); keep the surrounding logic
(isCurrentRundown check and use of dataProvider.getCustomFields and initRundown)
unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8f0b5014-f87e-43dd-99b1-38a81ec89555

📥 Commits

Reviewing files that changed from the base of the PR and between c238147 and 4d079bd.

⛔ Files ignored due to path filters (1)
  • e2e/tests/features/202-cuesheet.spec.ts is excluded by none and included by none
📒 Files selected for processing (6)
  • apps/server/src/api-data/rundown/__tests__/rundown.utils.test.ts
  • apps/server/src/api-data/rundown/rundown.router.ts
  • apps/server/src/api-data/rundown/rundown.service.ts
  • apps/server/src/api-data/rundown/rundown.utils.ts
  • apps/server/src/api-data/rundown/rundown.validation.ts
  • apps/server/src/classes/data-provider/DataProvider.ts
💤 Files with no reviewable changes (2)
  • apps/server/src/api-data/rundown/tests/rundown.utils.test.ts
  • apps/server/src/api-data/rundown/rundown.utils.ts

@alex-Arc alex-Arc force-pushed the pre-switch-refactor branch from 56312d5 to 1f98635 Compare June 13, 2026 10:53
newRundown.title = `Copy of ${rundown.title}`;
newRundown.revision = 0;

const newProjectRundowns = await dataProvider.setRundown(newRundownId, newRundown);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: would we benefit from a thin abstraction like addRundown

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the dataProvider?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking in the service. that would keep the logic of the service functions at a higher level

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm what would be it's responsibility?
we have makeNewRundown for blank ones

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be to clarify that we are adding a rundown to the project, doesn't matter if it is empty or not

Right now, all the methods need to know how to add a rundown to the projects
This could make maintenance a bit tricky, like if we ever want to kick off side effects we need to change many things

initRundown(rundown, customField);
} else {
setImmediate(() => {
sendRefetch(RefetchKey.ProjectRundowns);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: should we not refetch if the rundown is renamed?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes either it is done as part of initRundown
or we do it manually if it is a background rundown

Comment thread e2e/tests/features/202-cuesheet.spec.ts Outdated
alex-Arc and others added 2 commits June 16, 2026 20:03
Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants