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

fix: release dateTime picker bugs #8403

Closed
wants to merge 43 commits into from

Conversation

jordanl17
Copy link
Member

@jordanl17 jordanl17 commented Jan 24, 2025

Description

Fixes a number of issues:

  • Prevents scheduled publish time of dates in past from being selected
  • Warning messages when the scheduled publish time is in the past
  • Positioning of dateTime calendar selects across studio
  • Minor refactor of ReleaseForm, CopyToNewRelease and CreateReleaseDialog
  • All publish date selects allow for textinput use to type the date
  • Selected schedule dates will always have 0 seconds
Scenario Demo
Create release newReleaseDatePastPR
Copy to Release copyToReleaseDatePastPR
Edit release type typePickerDatePastPR
Confirm Schedule confirmScheduleDatePastPR

What to review

  • Sensible ways of handling and showing that dates need to be in the future?
  • Updated ui component's Dialog to use the ui component's Buttons (so we can use tooltips on these buttons). Think there could be any issues here?

Testing

Adjusted existing tests; will fast-follow new tests for date in the past scenarios

Notes for release

N/A

Copy link

vercel bot commented Jan 24, 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 30, 2025 0:39am
performance-studio ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 30, 2025 0:39am
test-studio ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 30, 2025 0:39am
2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
studio-workshop ⬜️ Ignored (Inspect) Visit Preview Jan 30, 2025 0:39am
test-next-studio ⬜️ Ignored (Inspect) Jan 30, 2025 0:39am

Copy link
Contributor

No changes to documentation

Copy link
Contributor

github-actions bot commented Jan 24, 2025

Component Testing Report Updated Jan 30, 2025 12:43 PM (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) 13s 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) 51s 11 7 0
formBuilder/inputs/PortableText/copyPaste/CopyPasteFields.spec.tsx ✅ Passed (Inspect) 0s 0 12 0
formBuilder/inputs/PortableText/Decorators.spec.tsx ✅ Passed (Inspect) 26s 6 0 0
formBuilder/inputs/PortableText/DisableFocusAndUnset.spec.tsx ✅ Passed (Inspect) 14s 3 0 0
formBuilder/inputs/PortableText/DragAndDrop.spec.tsx ✅ Passed (Inspect) 27s 6 0 0
formBuilder/inputs/PortableText/FocusTracking.spec.tsx ✅ Passed (Inspect) 1m 7s 15 0 0
formBuilder/inputs/PortableText/Input.spec.tsx ✅ Passed (Inspect) 1m 35s 21 0 0
formBuilder/inputs/PortableText/ObjectBlock.spec.tsx ✅ Passed (Inspect) 2m 3s 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 24, 2025

⚡️ Editor Performance Report

Updated Thu, 30 Jan 2025 12:44:35 GMT

Benchmark reference
latency of sanity@latest
experiment
latency of this branch
Δ (%)
latency difference
article (title) 23.3 efps (43ms) 21.7 efps (46ms) +3ms (+7.0%)
article (body) 65.6 efps (15ms) 63.3 efps (16ms) +1ms (-/-%)
article (string inside object) 26.0 efps (39ms) 25.3 efps (40ms) +1ms (+2.6%)
article (string inside array) 22.7 efps (44ms) 20.8 efps (48ms) +4ms (+9.1%)
recipe (name) 55.6 efps (18ms) 50.0 efps (20ms) +2ms (+11.1%)
recipe (description) 62.5 efps (16ms) 55.6 efps (18ms) +2ms (+12.5%)
recipe (instructions) 99.9+ efps (5ms) 99.9+ efps (5ms) +0ms (-/-%)
synthetic (title) 19.2 efps (52ms) 19.6 efps (51ms) -1ms (-1.9%)
synthetic (string inside object) 20.4 efps (49ms) 18.9 efps (53ms) +4ms (+8.2%)

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) 43ms 51ms 88ms 459ms 844ms 12.2s
article (body) 15ms 19ms 37ms 314ms 403ms 6.0s
article (string inside object) 39ms 40ms 47ms 175ms 287ms 7.0s
article (string inside array) 44ms 47ms 54ms 235ms 351ms 7.4s
recipe (name) 18ms 20ms 21ms 49ms 0ms 7.0s
recipe (description) 16ms 17ms 18ms 30ms 0ms 4.3s
recipe (instructions) 5ms 7ms 8ms 23ms 0ms 3.1s
synthetic (title) 52ms 55ms 61ms 77ms 817ms 13.6s
synthetic (string inside object) 49ms 53ms 66ms 496ms 1175ms 8.6s

🧪 Experiment result

The performance result of this branch

Benchmark latency p75 p90 p99 blocking time test duration
article (title) 46ms 70ms 84ms 500ms 779ms 11.8s
article (body) 16ms 18ms 20ms 89ms 131ms 5.2s
article (string inside object) 40ms 42ms 45ms 75ms 140ms 7.3s
article (string inside array) 48ms 50ms 56ms 83ms 486ms 7.8s
recipe (name) 20ms 21ms 26ms 45ms 0ms 7.1s
recipe (description) 18ms 20ms 23ms 35ms 0ms 4.4s
recipe (instructions) 5ms 7ms 8ms 9ms 0ms 3.1s
synthetic (title) 51ms 53ms 56ms 91ms 355ms 12.8s
synthetic (string inside object) 53ms 55ms 76ms 343ms 847ms 8.4s

📚 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.

@jordanl17 jordanl17 force-pushed the fix/corel-disabled-time-picker branch from 69fc97c to 6ed6816 Compare January 24, 2025 13:20
@jordanl17 jordanl17 force-pushed the fix/corel-disabled-time-picker branch from 76a8c95 to f817f57 Compare January 24, 2025 19:40
@jordanl17 jordanl17 changed the title Fix/corel disabled time picker fix: release dateTime picker bugs Jan 25, 2025
@jordanl17 jordanl17 closed this Jan 25, 2025
@jordanl17 jordanl17 reopened this Jan 25, 2025
@RitaDias
Copy link
Contributor

RitaDias commented Jan 30, 2025

I haven't reviewed the code itself, but how does this play with timezones? Was this something you double checked? (specifically related to putting a date for earlier than the current time)
(given that we just use the Date() object it should be fine I was just thinking about it)

Copy link
Contributor

@RitaDias RitaDias left a comment

Choose a reason for hiding this comment

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

A thought I also had was if we should have e2e / component tests around the dialogs for the dates blocking the "create" action. probably something we can create a story for.

Copy link
Contributor

@RitaDias RitaDias left a comment

Choose a reason for hiding this comment

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

A few questions, let mw know if you want to have a call we can but there are some parts that I'm not quite understanding why we needed to do it this way (specifically about the re-renders)

useImperativeHandle<HTMLInputElement | null, HTMLInputElement | null>(
forwardedRef,
() => ref.current,
)

useEffect(() => setReferenceElement(ref.current), [])
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need this? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

So this was something new I learned doing this:

Do not write or read ref.current during rendering, except for initialization. This makes your component’s behavior unpredictable.
From here

This is I think symptomatic that the sanity UI Popover should accept a react ref as referenceElement rather than a HTML element.

But by putting this into state and setting in the useEffect, it's ensured that the updates to the referenceElement happen after the initial render cycle, so that the ref.current value is accurate and aligned with the react state model

Copy link
Member Author

@jordanl17 jordanl17 Jan 30, 2025

Choose a reason for hiding this comment

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

  • Add why the useEffect is there as a code comment

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, might need to add a task to improve this at some, it just feels bad that we need to add a useeffect where the only thing we are doing is this. Which might be fine but since useEffects tend to tank performance I'm aways just 👁️ when I see them

Copy link
Contributor

Choose a reason for hiding this comment

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

Speaking with Jordan, we should create a story for updating the popover to work as intended instead of having us rely on workarounds from the studio side. This fine for now we adding a code comment there.

portal
content={
<Box overflow="auto">
<FocusLock onDeactivation={handleDeactivation}>
{inputValue && isPastDisabled && isPast(new Date(inputValue)) && (
Copy link
Contributor

Choose a reason for hiding this comment

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

could we move this outside to not have it in the render? use a useMemo / etc?

Copy link
Member Author

@jordanl17 jordanl17 Jan 30, 2025

Choose a reason for hiding this comment

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

  • Memoize in DateTimeInput

status: 'warning',
title: tRelease('schedule-dialog.publish-date-in-past-warning'),
})
setRerenderDialog((cur) => cur + 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

ooh, do we need this? This feels like something of a hack 😬
I don't understand why we need it, but I don't quite like it 🥲


const handleConfirmSchedule = useCallback(async () => {
if (!publishAt) return

if (isScheduledDateInPast()) {
// rerender dialog to recalculate isScheduledDateInPast
setRerenderDialog((cur) => cur + 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as this comment 🙏
I don't know if this is the best way of going about it? What is the use case, sorry I don't understand why we are doing it and it might be obvious 😅

Copy link
Member Author

Choose a reason for hiding this comment

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

So this is for the edge case that you select a time that is in the future, say 1 min in the future, but you take 1 minute to complete the dialog before submitting. The handleSubmit callbacks check again against the current time, if they see that you are now in the past, there needs to be a way of getting the component to rerender so that the submit button now shows as disabled and has a warning or tooltip. Since no actual existing state has changed, I added this state, to flush a rerender of the component and cause isScheduledDateInPast to be rerun and repainted. Does this make sense - happy to sync

Copy link
Contributor

Choose a reason for hiding this comment

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

Speaking with Jordan, we should add a comment about the scenarios and edge cases that rely on this and why and if we find a better solution in the future but otherwise let's keep this as is :)

Comment on lines 38 to 39
cancelButton?: Omit<ComponentProps<typeof Button>, 'fontSize' | 'padding'>
confirmButton?: Omit<ComponentProps<typeof Button>, 'fontSize' | 'padding'>
Copy link
Contributor

Choose a reason for hiding this comment

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

Concerned about this change because it will impact other things and other parts of the studio. Should we be making this change now? On Corel?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeh this was also my concern. Perhaps to avoid fallout from this with COREL I can just render a warning elsewhere in the dialog and we can come back to this once opt in-out is completed

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 that might be wiser, or at least pluck this from here and put it directly into a next improvement (which we would update on our dialog once that came back around)

@jordanl17
Copy link
Member Author

I haven't reviewed the code itself, but how does this play with timezones? Was this something you double checked? (specifically related to putting a date for earlier than the current time) (given that we just use the Date() object it should be fine I was just thinking about it)

Good callout - I've got a followup PR that resolves the timezone issues that builds on this one

Copy link
Contributor

@RitaDias RitaDias left a comment

Choose a reason for hiding this comment

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

🚀
Thank you for going through this!

@jordanl17 jordanl17 changed the base branch from corel to feat/content-releases January 30, 2025 13:45
@jordanl17 jordanl17 requested review from a team as code owners January 30, 2025 13:45
@jordanl17 jordanl17 changed the base branch from feat/content-releases to corel January 30, 2025 13:46
@jordanl17 jordanl17 closed this Jan 30, 2025
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.

2 participants