### What?
Fixed two bugs with readonly state for server-rendered components (like
richtext fields and custom server fields):
1. Server components remained readonly after a user took over a locked
document
2. Server components were not readonly when viewing in "read only" mode
until page refresh
### Why?
Both issues stemmed from server-rendered components using their initial
readonly state that was baked in during server-side rendering, rather
than respecting dynamic readonly state changes:
1. **Takeover bug**: When a user took over a locked document,
client-side readonly state was updated but server components continued
using their initial readonly state because the server-side state wasn't
refreshed properly.
2. **Read-only view bug**: When entering "read only" mode, server
components weren't immediately updated to reflect the new readonly state
without a page refresh.
The root cause was that server-side `buildFormState` was called with
`readOnly: isLocked` during initial render, and individual field
components used this initial state rather than respecting dynamic
document-level readonly changes.
### How?
1. **Fixed race condition in `handleTakeOver`**: Made the function async
and await the `updateDocumentEditor` call before calling
`clearRouteCache()` to ensure the database is updated before page reload
2. **Improved editor comparison in `getIsLocked`**: Used `extractID()`
helper to properly compare editor IDs when the editor might be a
reference object
3. **Ensured cache clearing for all takeover scenarios**: Call
`clearRouteCache()` for both DocumentLocked modal and DocumentControls
takeovers to refresh server-side state
4. **Added Form key to force re-render**: Added `key={isLocked}` to the
Form component so it re-renders when the lock state changes, ensuring
all child components get fresh readonly state for both takeover and
read-only view scenarios
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1211373627247885
40 lines
1.2 KiB
TypeScript
40 lines
1.2 KiB
TypeScript
import { fileURLToPath } from 'node:url'
|
|
import path from 'path'
|
|
|
|
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
|
import { PagesCollection } from './collections/Pages/index.js'
|
|
import { PostsCollection } from './collections/Posts/index.js'
|
|
import { ServerComponentsCollection } from './collections/ServerComponents/index.js'
|
|
import { TestsCollection } from './collections/Tests/index.js'
|
|
import { Users } from './collections/Users/index.js'
|
|
import { AdminGlobal } from './globals/Admin/index.js'
|
|
import { MenuGlobal } from './globals/Menu/index.js'
|
|
import { seed } from './seed.js'
|
|
|
|
const filename = fileURLToPath(import.meta.url)
|
|
const dirname = path.dirname(filename)
|
|
|
|
export default buildConfigWithDefaults({
|
|
admin: {
|
|
importMap: {
|
|
baseDir: path.resolve(dirname),
|
|
},
|
|
},
|
|
collections: [
|
|
PagesCollection,
|
|
PostsCollection,
|
|
ServerComponentsCollection,
|
|
TestsCollection,
|
|
Users,
|
|
],
|
|
globals: [AdminGlobal, MenuGlobal],
|
|
onInit: async (payload) => {
|
|
if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') {
|
|
await seed(payload)
|
|
}
|
|
},
|
|
typescript: {
|
|
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
|
},
|
|
})
|