fix(admin): add publish-date editing#2201
Conversation
🦋 Changeset detectedLatest commit: 37afcff The changes in this PR will be included in the next version bump. This PR includes changesets to release 17 packages
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 |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
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.
| onUnschedule={handleUnschedule} | ||
| isScheduling={scheduleMutation.isPending} | ||
| onPublishedAtChange={handlePublishedAtChange} | ||
| isUpdatingPublishedAt={ |
There was a problem hiding this comment.
[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.
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
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
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges except in translation PRs — a workflow extracts catalogs on merge tomain.AI-generated code disclosure
Screenshots / test output
pnpm --filter @emdash-cms/admin exec vitest run tests/components/ContentSettingsPanel.test.tsx tests/router.test.tsx— 32 tests passedpnpm --filter @emdash-cms/admin test— 1,240 tests passedpnpm typecheckpnpm lintpnpm formatThe coverage includes Arabic/RTL rendering, editor authorization, the exact update payload, and concurrent auxiliary updates while a publish-date request remains pending.