Skip to content

Add a Repository Status page and surface read-only status across the web UI - #1327

Merged
ikhoon merged 10 commits into
line:scoped-readonlyfrom
ikhoon:scoped-readonly-ui
Jul 13, 2026
Merged

Add a Repository Status page and surface read-only status across the web UI#1327
ikhoon merged 10 commits into
line:scoped-readonlyfrom
ikhoon:scoped-readonly-ui

Conversation

@ikhoon

@ikhoon ikhoon commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Motivation:

Central Dogma can put an individual repository or a whole project into read-only mode (#1305), but the web UI neither showed that status nor acted on it. Every write button stayed enabled, so a user discovered the read-only state only by having the server reject the write, and there was no way to see or change the status from the UI.

Modifications:

  • Add status to ProjectDto so that GET /api/v1/projects reports whether a project is read-only.
  • Show a Read-only / Writable tag on the project list, the project detail page, the repository list and the repository tree page.
  • Disable the write actions of a read-only project or repository, each with a tooltip that explains why: New Repository, New File, Edit, Delete (both a file and a repository), Revert, Project Settings and Repository Settings. A read-only project stays browsable.
  • Add a "Repository Status" settings tab (system administrator only) that lists the read-only projects and repositories and lets an administrator make one read-only or writable, guarded by re-typing the full project/repository name. Selecting the internal dogma repository changes the whole project, and the confirmation now says so.
  • Add GET /api/v1/status/repos/read-only, serialize RepositoryState.updatedAt as an ISO-8601 string, and expose repository.read.only.count and repository.read.only metrics.
  • Invalidate the project and repository caches on a status change, so the lists do not keep showing the previous status.

Result:

  • A user can see whether a project or a repository is read-only, and the write actions that would fail are disabled with an explanation of why.
  • A system administrator can view every read-only project and repository and toggle the status from the web UI, with a type-to-confirm safeguard and an explicit warning when the change is project-wide.

Motivation:

Central Dogma can put an individual repository or a whole project into
read-only mode (scoped replication-failure read-only, line#1305), but there was
no way to see which repositories or projects are currently read-only, nor to
set or clear that status, from the web UI.

Modifications:

- Add `GET /api/v1/status/repos/read-only` (system administrator only) that
  returns the projects and repositories that are currently read-only. A
  project-scoped entry uses `dogma` as its repository name.
- Serialize `RepositoryState.updatedAt` as an ISO-8601 string via `@JsonFormat`
  so clients render the real timestamp instead of an epoch number.
- Expose read-only scope metrics: a `repository.read.only.count` gauge and a
  `repository.read.only` multi-gauge tagged by project, repo and scope.
- Add a "Repository Status" settings tab (system administrator only) that
  - lists the read-only projects and repositories with their scope, status and
    last-updated time;
  - offers a form to make a repository read-only, with project and repository
    auto-complete; and
  - offers a per-row action to revert a repository or project to writable.
  Both changes require re-typing the full `project/repository` name to confirm,
  to guard against accidental clicks.
- Add the `updateRepositoryStatus` mutation and a `RepoStatus` cache tag so the
  list refreshes after a change.
- Add unit tests, a Playwright e2e test and a server test for the new endpoint.

Result:

- A system administrator can now view all read-only repositories and projects
  and toggle read-only status from the web UI, with a type-to-confirm safeguard
  against mistakes.
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: da32678d-27e1-4cf6-be27-008c3f72a655

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Motivation:

A project or a repository can be put into read-only mode, but the web UI
neither showed that status nor stopped a user from attempting a write that the
server would reject.

Modifications:

- Add `status` to `ProjectDto` so that `GET /api/v1/projects` reports the
  read-only status of a project, which is stored in its `dogma` repository.
- Add a `useReadOnly()` hook that resolves the effective read-only status of a
  project and a repository. It prefers the project-scoped hint when both are
  read-only, and reports writable while the status is still being fetched so
  that a write action is never disabled by a transient error.
- Show a `Read-only` / `Writable` tag on the project list, the project detail
  page, the repository list and the repository tree page.
- Disable the write actions of a read-only project or repository, each with a
  tooltip that explains why: New Repository, New File, Edit, Delete, Revert,
  Project Settings and Repository Settings. A disabled anchor is still
  clickable, so the link is dropped rather than disabled. `New Repository` is
  a `PopoverTrigger` child, which cannot be wrapped, so the popover is replaced
  with a tooltipped disabled button while the project is read-only.
- Warn in the confirmation modal that making the internal `dogma` repository
  read-only blocks writes to every repository in the project, and that
  reverting it leaves individually read-only repositories read-only.
- Invalidate the `Project` and `Repo` cache tags when a repository status
  changes. Both lists now carry the status, so they otherwise keep showing the
  previous one until the cache entry is dropped.
- Make a long error message scrollable inside the toast so that the close
  button stays reachable.
- Fix a checkstyle violation in `RepoStatusManager` and stabilize two tests.
  `RepoStatusManagerTest` awaits the status cache, because a commit notifies
  the status listener inline but the listener itself is registered
  asynchronously on the repository worker, so an update committed before the
  registration lands is only picked up by the initial snapshot.
  `ZooKeeperScopedReadonlyIntegrationTest` resets the server status with
  `Scope.ALL`, so that a replica which has not replayed the previous
  `REPLICATION_ONLY` entry cannot apply it in the middle of the test.

Result:

- A user can now see whether a project or a repository is read-only, and the
  write actions that would fail are disabled with an explanation of why.
@ikhoon ikhoon changed the title Add a Repository Status page to view and manage read-only repositories Add a Repository Status page and surface read-only status across the web UI Jul 9, 2026
Motivation:

The file list of the repository tree page offers a Delete button for every
file, and it stayed enabled while the repository or its project was read-only.
Pressing it opened the confirmation modal and the delete only failed once the
server rejected it.

Modifications:

- Disable the Delete button of `FileList` when the repository is read-only, and
  explain why on hover, like the other write actions.
- Keep the copy actions available, as they do not write.

Result:

- A read-only repository no longer offers a delete that is bound to fail.
ikhoon added 3 commits July 10, 2026 15:34
Motivation:

The `repository.read.only` gauge carried a `scope` tag that only restated its
`repo` tag: a project-scoped entry is exactly the one whose repository is the
internal `dogma` repository.

Modifications:

- Remove the `scope` tag from the `repository.read.only` multi-gauge.
- Assert the exact tag set in the test, so a stray tag fails it.

Result:

- The gauge is tagged by project and repository only. A project-wide read-only
  entry is still identified by its `dogma` repository.
Motivation:

The Repository Status page hid the repository name of a project-scoped entry
behind a dash and restated the same fact in a Scope column.

Modifications:

- Show the internal `dogma` repository name, linked like any other repository.
- Remove the Scope column, which the repository name already tells apart.

Result:

- A project-scoped read-only entry reads as `project` / `dogma`, and the table
  is one column narrower.
Motivation:

`webapp-e2e` failed: the confirm-form test still expected the row to contain the
Scope badge, which the previous commit removed.

Modifications:

- Assert the row names its project instead of the removed badge.

Result:

- The Repository Status e2e suite passes again.
@ikhoon

ikhoon commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author
05-confirm-project-writable 04-project-detail 03-projects-list 02-repo-status-list 01-confirm-project-read-only

Motivation:

A replica in `REPLICATION_ONLY` mode rejected replayed commands because the
server-level read-only check did not distinguish a replayed command from a
client request. A replay failure is treated as a poisoned log entry and
skipped, so a read-only replica silently dropped every replicated write,
permanently diverged from the cluster and escalated an unrelated read-only
status.

Modifications:

- Exempt a replayed command from the server-level read-only check in
  `AbstractCommandExecutor`, matching the existing repository-level exemption.
- Document the exemption on `ExecutionContext.isReplay()`.
- Add a unit test that a rejected client push is still applied when replayed
  under `REPLICATION_ONLY`.
- Add integration tests that a locally read-only replica keeps replaying
  pushes and project creations while the rest of the cluster stays writable.
- Assert in `afterEach()` that all replicas converge on the same `dogma/dogma`
  head revision, and wait for the seed commit replay in `injectFault()` to
  remove a race.

Result:

- A `REPLICATION_ONLY` replica keeps applying the replication log and no
  longer diverges from the cluster.
- Putting a single replica into `REPLICATION_ONLY` no longer risks a
  cluster-wide read-only escalation triggered by an unrelated write.
@ikhoon
ikhoon marked this pull request as ready for review July 10, 2026 16:18
@ikhoon
ikhoon requested review from jrhee17 and minwoox as code owners July 10, 2026 16:18

@jrhee17 jrhee17 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.

👍 👍

@minwoox minwoox 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.

👍 👍 👍

ikhoon added 3 commits July 13, 2026 10:55
Motivation:

READ_ONLY and REPLICATION_ONLY both reject client writes, but only the latter
keeps replaying the replication log. The distinction decides whether a replica
stays in sync with the cluster or must be re-synced manually, and it was
undocumented.

Modifications:

- Document each ServerStatus constant with its writable/replicating semantics
  and its operational consequence.

Result:

- Operators can tell which read-only status keeps a replica following the
  cluster. No functional change.
…startup

Motivation:

When a replicated server starts, the persisted server status was applied only
to the outer ZooKeeperCommandExecutor. A status update applied at runtime
reaches the inner delegate as well, so a replica restarted in a read-only
status came back with a writable delegate, unlike the state the runtime path
produces.

Modifications:

- Propagate the persisted `writable` flag to the delegate of
  `ZooKeeperCommandExecutor` in `CentralDogma.start()`.
- Add `ReplicationOnlyRestartTest`, which fails without the fix: after a
  cluster-wide `REPLICATION_ONLY` and a restart, every replica's delegate must
  come back read-only.

Result:

- A replica restarted in a read-only status now has the same executor state as
  one that entered it at runtime.
Motivation:

A REPLICATION_ONLY replica keeps replaying the replication log, but no test
covered that server-level gate overlapping with a repository-level READ_ONLY
on the same replica. A refactor merging the two read-only checks could
silently drop replayed entries again.

Modifications:

- Add an integration test that pushes to a writable sibling repository and
  asserts a replica replays it while both a repository-scope READ_ONLY and a
  local REPLICATION_ONLY are active, without flipping either status.
- Extract `enterReplicationOnly()` and `driveRepoIntoReadOnly()` helpers.
- Add a 1-based `serverById()` to `CentralDogmaReplicationExtension`, matching
  the 1-based `serverId` of `configureEach()` to remove the off-by-one against
  the 0-based `servers()`.

Result:

- Log replay under overlapping read-only scopes is guarded by a regression
  test. No functional change.
@ikhoon
ikhoon merged commit bec7f07 into line:scoped-readonly Jul 13, 2026
14 checks passed
@ikhoon
ikhoon deleted the scoped-readonly-ui branch July 13, 2026 06:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants