Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: content releases #8454

Open
wants to merge 5 commits into
base: next
Choose a base branch
from
Open

feat: content releases #8454

wants to merge 5 commits into from

Conversation

bjoerge
Copy link
Member

@bjoerge bjoerge commented Jan 30, 2025

Description

This PR marks the public beta of the Content Releases feature. The content releases feature itself will be opt-in (for now), but these changes also introduces a few key improvements to the Studio UI, most notably the ability to switch between the published document and the current draft, and the ability to browse the Studio by only seeing what's currently published.

The Studio now supports a perspective search param, which is "sticky", meaning that it is preserved when navigating around in the studio. This param can take a comma-separated list of values (referred to as a "perspecive stack", which will then be forwarded to the perspective param used by list queries made by the Studio)

Terminology

With these changes we are introducing three new terms into the codebase, I'll cover them in brief here (there's more details to be found in internal documentation for the curious minded):

  • Version - This is comparable to a draft document but with a different prefix: instead of drafts.<publishedId> it will have versions.<releaseId>.<publishedId> . The versions. prefix is fixed, and no documents can have that as a prefix without following the versions.<string>.<id> structure.
  • Release – A release is represented by a system document that has an ID on the form _.release.<releaseId>. The <releaseId>-part here is what connects it with version documents. The <releaseId> part conventionally starts with r, and is followed by 8 random characters, e.g. rNe6H9RGZ.
  • Bundle - This is an internal, technical name used to connect documents in the release together. You can think of the releaseId as a type of bundle, but there could also be other types of bundles in the future.

There's no change to the semantics around draft documents, other than you can now think of them as version documents with special sematics applied to them.

What to review

This is a rather chonky one, when reviewing feel free to skp fast through things like tests and fixtures and focus on the more substantial stuff. Things in particular to watch out for are:

  • Changes to core APIs that could potentially be breaking
  • Changes to core that could affect data integrity in any way
  • Changes to datastores etc. that could pose performance issues

Note: we'll be using vX for various API calls if the feature is enabled, otherwise we'll stick with stable API versions. While it's not ideal to ship with vX, we have considered it to be an ok tradeoff in this case, given that the feature is opt-in and considered beta. Edit: Seems like this is not the case right now, we will be addressing this before merging, but adding a todo here:

  • Use vX only when opting-in to Content Releases

Testing

Most new code includes tests, but our coverage of existing code paths is still aspirational at best, so any manual testing is greatly appreciated.

Notes for release

tbd

Copy link

vercel bot commented Jan 30, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
page-building-studio ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 31, 2025 10:26am
performance-studio ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 31, 2025 10:26am
test-studio ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 31, 2025 10:26am
2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
studio-workshop ⬜️ Ignored (Inspect) Visit Preview Jan 31, 2025 10:26am
test-next-studio ⬜️ Ignored (Inspect) Jan 31, 2025 10:26am

Copy link
Contributor

No changes to documentation

Copy link
Contributor

github-actions bot commented Jan 30, 2025

Component Testing Report Updated Jan 31, 2025 10:25 AM (UTC)

❌ Failed Tests (1) -- expand for details
File Status Duration Passed Skipped Failed
comments/CommentInput.spec.tsx ✅ Passed (Inspect) 1m 4s 15 0 0
formBuilder/ArrayInput.spec.tsx ✅ Passed (Inspect) 12s 3 0 0
formBuilder/inputs/PortableText/Annotations.spec.tsx ❌ Failed (Inspect) 1m 21s 5 0 1
formBuilder/inputs/PortableText/copyPaste/CopyPaste.spec.tsx ✅ Passed (Inspect) 50s 11 7 0
formBuilder/inputs/PortableText/copyPaste/CopyPasteFields.spec.tsx ✅ Passed (Inspect) 0s 0 12 0
formBuilder/inputs/PortableText/Decorators.spec.tsx ✅ Passed (Inspect) 25s 6 0 0
formBuilder/inputs/PortableText/DisableFocusAndUnset.spec.tsx ✅ Passed (Inspect) 14s 3 0 0
formBuilder/inputs/PortableText/DragAndDrop.spec.tsx ✅ Passed (Inspect) 26s 6 0 0
formBuilder/inputs/PortableText/FocusTracking.spec.tsx ✅ Passed (Inspect) 1m 6s 15 0 0
formBuilder/inputs/PortableText/Input.spec.tsx ✅ Passed (Inspect) 1m 31s 21 0 0
formBuilder/inputs/PortableText/ObjectBlock.spec.tsx ✅ Passed (Inspect) 2m 4s 21 0 0
formBuilder/inputs/PortableText/PresenceCursors.spec.tsx ✅ Passed (Inspect) 13s 3 9 0
formBuilder/inputs/PortableText/Styles.spec.tsx ✅ Passed (Inspect) 27s 6 0 0
formBuilder/inputs/PortableText/Toolbar.spec.tsx ✅ Passed (Inspect) 1m 46s 21 0 0
formBuilder/tree-editing/TreeEditing.spec.tsx ✅ Passed (Inspect) 0s 0 3 0
formBuilder/tree-editing/TreeEditingNestedObjects.spec.tsx ✅ Passed (Inspect) 0s 0 3 0

Copy link
Contributor

github-actions bot commented Jan 30, 2025

⚡️ Editor Performance Report

Updated Fri, 31 Jan 2025 10:26:31 GMT

Benchmark reference
latency of sanity@latest
experiment
latency of this branch
Δ (%)
latency difference
article (title) 26.3 efps (38ms) 25.6 efps (39ms) +1ms (+2.6%)
article (body) 67.6 efps (15ms) 63.3 efps (16ms) +1ms (-/-%)
article (string inside object) 27.0 efps (37ms) 25.6 efps (39ms) +2ms (+5.4%)
article (string inside array) 25.0 efps (40ms) 22.2 efps (45ms) +5ms (+12.5%)
recipe (name) 52.6 efps (19ms) 52.6 efps (19ms) +0ms (-/-%)
recipe (description) 58.8 efps (17ms) 58.8 efps (17ms) +0ms (-/-%)
recipe (instructions) 99.9+ efps (5ms) 99.9+ efps (5ms) +0ms (-/-%)
synthetic (title) 18.9 efps (53ms) 19.6 efps (51ms) -2ms (-3.8%)
synthetic (string inside object) 20.8 efps (48ms) 19.2 efps (52ms) +4ms (+8.3%)

efps — editor "frames per second". The number of updates assumed to be possible within a second.

Derived from input latency. efps = 1000 / input_latency

Detailed information

🏠 Reference result

The performance result of sanity@latest

Benchmark latency p75 p90 p99 blocking time test duration
article (title) 38ms 42ms 49ms 372ms 147ms 10.1s
article (body) 15ms 19ms 22ms 224ms 250ms 5.2s
article (string inside object) 37ms 41ms 48ms 68ms 150ms 6.5s
article (string inside array) 40ms 44ms 50ms 220ms 404ms 7.2s
recipe (name) 19ms 20ms 23ms 36ms 0ms 6.9s
recipe (description) 17ms 18ms 21ms 42ms 0ms 4.4s
recipe (instructions) 5ms 6ms 7ms 9ms 0ms 3.0s
synthetic (title) 53ms 59ms 70ms 325ms 842ms 14.7s
synthetic (string inside object) 48ms 49ms 51ms 111ms 446ms 7.9s

🧪 Experiment result

The performance result of this branch

Benchmark latency p75 p90 p99 blocking time test duration
article (title) 39ms 46ms 67ms 520ms 812ms 10.8s
article (body) 16ms 18ms 23ms 86ms 191ms 5.5s
article (string inside object) 39ms 43ms 46ms 154ms 396ms 7.3s
article (string inside array) 45ms 49ms 57ms 243ms 289ms 7.5s
recipe (name) 19ms 22ms 26ms 43ms 3ms 6.8s
recipe (description) 17ms 19ms 21ms 34ms 0ms 4.5s
recipe (instructions) 5ms 7ms 8ms 22ms 0ms 3.1s
synthetic (title) 51ms 53ms 60ms 123ms 444ms 13.4s
synthetic (string inside object) 52ms 56ms 62ms 682ms 1594ms 8.8s

📚 Glossary

column definitions

  • benchmark — the name of the test, e.g. "article", followed by the label of the field being measured, e.g. "(title)".
  • latency — the time between when a key was pressed and when it was rendered. derived from a set of samples. the median (p50) is shown to show the most common latency.
  • p75 — the 75th percentile of the input latency in the test run. 75% of the sampled inputs in this benchmark were processed faster than this value. this provides insight into the upper range of typical performance.
  • p90 — the 90th percentile of the input latency in the test run. 90% of the sampled inputs were faster than this. this metric helps identify slower interactions that occurred less frequently during the benchmark.
  • p99 — the 99th percentile of the input latency in the test run. only 1% of sampled inputs were slower than this. this represents the worst-case scenarios encountered during the benchmark, useful for identifying potential performance outliers.
  • blocking time — the total time during which the main thread was blocked, preventing user input and UI updates. this metric helps identify performance bottlenecks that may cause the interface to feel unresponsive.
  • test duration — how long the test run took to complete.

@@ -35,39 +48,57 @@ export function getReferenceInfo(
documentPreviewStore: DocumentPreviewStore,
id: string,
referenceType: ReferenceSchemaType,
{version}: {version?: string} = {},
perspective: {bundleIds: string[]; bundleStack: PerspectiveStack} = {
Copy link
Member Author

Choose a reason for hiding this comment

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

we should consider renaming this to perspective: {ids: string[], stack: PerspectiveStack}

} else if (releaseId === 'published' || releaseId.startsWith('r')) {
perspectiveParam = releaseId
} else {
throw new Error(`Invalid releaseId: ${releaseId}`)
Copy link
Member Author

Choose a reason for hiding this comment

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

making a note for us to verify whether we can keep this hard validation of release ids, or whether we should rather consider it a convention

/**
* An array of all existing bundle ids.
*/
bundleIds: string[]
Copy link
Member Author

Choose a reason for hiding this comment

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

should we rename this to ids?

* An array of release ids ordered chronologically to represent the state of documents at the
* given point in time.
*/
bundleStack: PerspectiveStack
Copy link
Member Author

Choose a reason for hiding this comment

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

should we rename this to just stack? not sure if perspective.bundleStack makes sense anymore?

* document readability for the version document
*/
version?: DocumentAvailability
// TODO: validate versions availability?
Copy link
Member Author

Choose a reason for hiding this comment

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

is this still relevant?


const QUERY_FILTER = `_type=="${RELEASE_DOCUMENT_TYPE}" && _id in path("${RELEASE_DOCUMENTS_PATH}.*")`

// TODO: Extend the projection with the fields needed
Copy link
Member Author

Choose a reason for hiding this comment

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

is this still relevant?

*/
export interface ReleaseStore {
state$: Observable<ReleasesReducerState>
getMetadataStateForSlugs$: (slugs: string[]) => Observable<MetadataWrapper>
Copy link
Member Author

Choose a reason for hiding this comment

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

it's probably fine to skip the $-suffix here and above (feels like a less valuable pattern combined with types)

/**
* @internal
*/
export function useReleaseOperations() {
Copy link
Member Author

Choose a reason for hiding this comment

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

instead of creating a separate store per component it would be better if we moved this to a context and kept a single instance to it (the store is stateless, so it's probably not critical for merge)

* Gets all the releases ids
* @internal
*/
export function useReleasesIds(releases: ReleaseDocument[]): {
Copy link
Member Author

Choose a reason for hiding this comment

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

The double plural reads a bit awkward, better to rename it to useReleaseIds?

Copy link
Member Author

Choose a reason for hiding this comment

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

We could also consider whether we need it at all, seems to have somewhat limited value?

Copy link
Member Author

Choose a reason for hiding this comment

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

The naming of this file seems a bit off to me. I think it's one of very few places we use "variant" as the common term for published, draft and versions. It might not be a 100% correct name, but could we consider renaming to getDocumentVersionType instead? At least that's closer to the name I would look for if I needed to know.

bjoerge and others added 3 commits January 30, 2025 23:01
Co-Authored-By: Jordan Lawrence <[email protected]>
Co-Authored-By: Bjørge Næss <[email protected]>
Co-Authored-By: Rita <[email protected]>
Co-Authored-By: pedrobonamin <[email protected]>
Co-Authored-By: Ash <[email protected]>
Co-Authored-By: Cody Olsen <[email protected]>
Co-Authored-By: Robin Neatherway <[email protected]>
Comment on lines +1 to +2
export * from '../store/_legacy'
export * from '../store/user'
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should remove this two exports from here

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.

5 participants