Skip to content

fix(admin): add publish-date editing#2201

Open
masonjames wants to merge 2 commits into
emdash-cms:mainfrom
masonjames:codex/edit-published-date
Open

fix(admin): add publish-date editing#2201
masonjames wants to merge 2 commits into
emdash-cms:mainfrom
masonjames:codex/edit-published-date

Conversation

@masonjames

@masonjames masonjames commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a publish-date field to the content settings panel for published entries. Editors and administrators can update the date, while authors retain the existing read-only permissions. The value is normalized to an ISO timestamp and sent through the existing content update endpoint.

Closes #2178

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable). Do not include messages.po changes except in translation PRs — a workflow extracts catalogs on merge to main.
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: https://github.com/emdash-cms/emdash/discussions/... (N/A: bug fix)

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: OpenAI Codex (GPT-5)

Screenshots / test output

  • pnpm --filter @emdash-cms/admin exec vitest run tests/components/ContentSettingsPanel.test.tsx tests/router.test.tsx — 32 tests passed
  • pnpm --filter @emdash-cms/admin test — 1,240 tests passed
  • pnpm typecheck
  • pnpm lint
  • pnpm format

The coverage includes Arabic/RTL rendering, editor authorization, the exact update payload, and concurrent auxiliary updates while a publish-date request remains pending.

@changeset-bot

changeset-bot Bot commented Jul 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 37afcff

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 17 packages
Name Type
@emdash-cms/admin Patch
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/plugin-mcp-smoke Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@2201

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@2201

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@2201

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@2201

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@2201

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@2201

emdash

npm i https://pkg.pr.new/emdash@2201

create-emdash

npm i https://pkg.pr.new/create-emdash@2201

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@2201

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@2201

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@2201

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@2201

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@2201

@emdash-cms/registry-verification

npm i https://pkg.pr.new/@emdash-cms/registry-verification@2201

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@2201

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@2201

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@2201

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@2201

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@2201

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@2201

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@2201

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@2201

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@2201

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@2201

commit: 37afcff

@masonjames
masonjames marked this pull request as ready for review July 22, 2026 14:36
@github-actions github-actions Bot added the review/needs-review No maintainer or bot review yet label Jul 22, 2026

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

This is the right change, in the right place. The publish-date field plugs into the existing auxiliary-update path for content metadata, and the backend already has schema and authorization support (publishedAt on contentUpdateBody, gated by content:publish_any in the update route). The frontend correctly limits the control to editor+ users and already-published items, the strings are wrapped for Lingui, the new UI uses logical Tailwind classes, and the added tests cover role gating and the update payload.

I checked the full diff, the backend route (packages/core/src/astro/routes/api/content/[collection]/[id].ts), the content update handler/repository, the Zod schema, the role/permission mapping, and the admin tests. Only one real issue stood out: the isUpdatingPublishedAt flag is derived from the latest variables of a shared updateMutation, so it can flip to false while a publish-date update is still in flight. That clears the input/button disabled state too early and allows duplicate/conflicting submissions when other auxiliary writes (SEO, author, or even a save) happen concurrently.

Comment thread packages/admin/src/router.tsx Outdated
onUnschedule={handleUnschedule}
isScheduling={scheduleMutation.isPending}
onPublishedAtChange={handlePublishedAtChange}
isUpdatingPublishedAt={

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.

[needs fixing] isUpdatingPublishedAt is computed from updateMutation.variables?.changes.publishedAt, but updateMutation is shared across all auxiliary content writes (SEO, author, publish date, and the main editor save). variables is always the latest mutate call, and isPending stays true until every in-flight request settles. If an editor clicks Update publish date and then changes SEO or saves while the date request is still running, the newest variables will no longer contain publishedAt, so isUpdatingPublishedAt becomes false even though the date update is still pending. That re-enables the date input and button prematurely and allows a second, conflicting publish-date submission.

Track publish-date pending state independently of the shared mutation's latest variables. For example, keep a ref counter keyed to this operation and pass the resulting boolean into ContentEditor:

const publishedAtPendingRef = React.useRef(0);
const [publishedAtPendingCount, setPublishedAtPendingCount] = React.useState(0);

const handlePublishedAtChange = React.useCallback(
  (publishedAt: string) => {
    setPublishedAtPendingCount((c) => c + 1);
    publishedAtPendingRef.current += 1;
    updateMutation.mutate(
      {
        targetId: id,
        targetLocale: rawItem?.locale ?? activeLocale,
        source: "auxiliary",
        changes: { publishedAt },
      },
      {
        onSettled: () => {
          publishedAtPendingRef.current = Math.max(0, publishedAtPendingRef.current - 1);
          setPublishedAtPendingCount(publishedAtPendingRef.current);
        },
      },
    );
  },
  [activeLocale, id, rawItem?.locale, updateMutation.mutate],
);

Then pass isUpdatingPublishedAt={publishedAtPendingCount > 0} instead of the updateMutation.variables check.

@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review size/L overlap and removed size/M review/needs-review No maintainer or bot review yet labels Jul 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/admin overlap review/needs-rereview Author pushed changes since the last review size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Content publishing - Configurable publish date

1 participant