Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
8d369f8
feat: align whats new page typography with admin shell
imantsk Jul 14, 2026
8fd7723
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
316d700
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
b885327
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
2bf0253
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
9e54bb2
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
d1c37d7
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
0d6ad76
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
54d6058
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
50a8398
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
657582b
feat: extract snippet priority input into common component
imantsk Jul 15, 2026
721ec5d
feat: add snippet actions footer to preview modal
imantsk Jul 15, 2026
224d47a
feat: style preview modal as pinned code viewport with actions footer
imantsk Jul 15, 2026
fee463e
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
8ba2cac
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
2071028
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
df08a10
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
26afd5f
fix: keep preview modal footer pinned by flexing the modal wrapper
imantsk Jul 15, 2026
dc1b6b2
fix: lead preview modal actions with edit and show read-only priority
imantsk Jul 15, 2026
85224a3
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
1524da6
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
994837d
fix: squeeze toolbar components instead of wrapping above mobile widths
imantsk Jul 15, 2026
3a479a1
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
c951a60
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
bf2ae92
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
6bc61a3
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
1005aea
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
0963e4c
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
b6a7f0a
fix: keep snippet type tabs on a single scrolling row
imantsk Jul 15, 2026
7995af7
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
3ae49eb
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
02760e3
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
24e5dad
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
7596cb5
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
78ae295
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
1bc40ce
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 15, 2026
32209cb
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 15, 2026
d82d431
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
098f43b
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
94bfa1b
feat: localize snippet type counts for instant tab rendering
imantsk Jul 16, 2026
93468a7
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
ab1abbd
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
d7ba51e
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
fd23f87
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
1111a45
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
4156eb1
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
465d51c
fix: only save snippet priority when the value has changed
imantsk Jul 16, 2026
14d98c0
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
731e45f
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
461e8e6
fix: correct docblock indentation in Manage_Menu
imantsk Jul 16, 2026
e14d5de
fix: hide modifying actions in preview modal for read-only snippets
imantsk Jul 16, 2026
947035d
fix: degrade snippet preview gracefully when the code editor is unava…
imantsk Jul 16, 2026
3686e06
fix: correct preview modal title prop type mismatch
imantsk Jul 16, 2026
a9b0690
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
a457349
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
c5eaa3d
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
69ce038
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
6ee2b46
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
4f859a4
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
7d97f91
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
30027e5
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
2c72537
fix: lead snippet type options with the language badge
imantsk Jul 16, 2026
a83e5fc
fix: match location selector height to the conditions button
imantsk Jul 16, 2026
a11268b
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
6111905
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
faeeb6d
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
80eb38f
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
c9e1d14
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
86beb07
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
db9ba34
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
21df82c
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
4ef85fd
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
004bee7
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
c6801dd
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
1e596e8
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
2b6c784
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
2109d1b
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
a78ded0
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
8165564
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
7684d10
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
85109f7
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
9cd436c
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
6a0374b
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
0937c43
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
f3995b8
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
b9a2132
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
df9cedf
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
5ed45f9
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
ca82ddc
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
b253519
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
422d083
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
80d18d7
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
73202d1
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
8199c4f
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
44b45d4
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
490a8df
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
f995cb4
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
9279bcf
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
7f96208
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
941a76b
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
69bf7b4
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
ccb2cc8
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 16, 2026
ef7b299
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 16, 2026
5157aca
fix: merge snippet card fixes
imantsk Jul 16, 2026
fc683c0
fix: merge typography branch fixes
imantsk Jul 16, 2026
a6c9623
fix: harden preview modal interactions
imantsk Jul 16, 2026
b093545
fix: cover grouped snippet type counts
imantsk Jul 16, 2026
3979a45
fix: cover preview modal mutation paths
imantsk Jul 16, 2026
6c516be
fix: cap cloud pagination before REST validation
imantsk Jul 16, 2026
47d8f75
fix: confirm dirty history navigation
imantsk Jul 16, 2026
c7c0f21
fix: simplify kebab menu focus handling
imantsk Jul 16, 2026
c63a033
fix: improve shared text contrast
imantsk Jul 16, 2026
3c81e3b
fix: translate cloud author attribution
imantsk Jul 16, 2026
fdc1171
fix: expose the inline snippets limit
imantsk Jul 16, 2026
1043756
fix: cover manage menu review behavior
imantsk Jul 16, 2026
eaddcf5
fix: cover Add New notice filtering
imantsk Jul 16, 2026
6479b1e
fix: cover snippet description sanitization
imantsk Jul 16, 2026
2f33ee8
fix: cover card pagination URL state
imantsk Jul 16, 2026
fa9dc55
fix: cover post-save history navigation
imantsk Jul 16, 2026
56ea7b9
fix: target the visible location control
imantsk Jul 16, 2026
4ae22c1
fix: target the visible type control
imantsk Jul 16, 2026
9c70419
fix: match both WordPress REST URL forms
imantsk Jul 16, 2026
04e2225
chore: drop a narrating stylesheet comment
imantsk Jul 17, 2026
2216010
fix: assert the post-save back destination correctly
imantsk Jul 17, 2026
aec2f13
feat: allow extra actions in the preview modal footer
imantsk Jul 17, 2026
cbfee34
Merge branch 'feat/169-snippet-cards' into feat/whats-new-typography
imantsk Jul 17, 2026
c9bff55
Merge branch 'feat/whats-new-typography' into feat/preview-modal-actions
imantsk Jul 17, 2026
e96ed9c
fix: share the preview working state with slotted footer actions
imantsk Jul 17, 2026
4457f44
fix: preserve keyboard access to snippet previews
imantsk Jul 17, 2026
9cea676
fix: replace add history after creating a snippet
imantsk Jul 17, 2026
5488de3
chore: extract manage menu data concerns
imantsk Jul 17, 2026
d48ac2d
fix: confirm dirty history navigation
imantsk Jul 17, 2026
8982bad
chore: merge snippet card fixes
imantsk Jul 17, 2026
b17c2d3
fix: make snippet preview focus accessible
imantsk Jul 17, 2026
fb4bc4e
fix: avoid duplicate dirty navigation prompts
imantsk Jul 17, 2026
b062ad4
chore: merge snippet card updates
imantsk Jul 17, 2026
80ee496
chore: merge snippet card cleanup
imantsk Jul 17, 2026
c70b0fd
chore: enforce preview source limits
imantsk Jul 17, 2026
c2a6abe
chore: merge source limit cleanup
imantsk Jul 17, 2026
953e061
chore: wrap preview support source lines
imantsk Jul 17, 2026
a5e745a
chore: isolate snippet draft comparison
imantsk Jul 17, 2026
313be7d
chore: merge snippet card standards
imantsk Jul 17, 2026
74277c9
chore: merge final Core standards
imantsk Jul 17, 2026
6aa193e
chore: remove preview implementation narration
imantsk Jul 18, 2026
804550f
chore: merge snippet card updates
Jul 19, 2026
a73954e
chore: merge whats new typography
Jul 19, 2026
e203956
fix: remove duplicate preview test constant
Jul 19, 2026
6b645f7
fix: scope preview editor locator
Jul 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 88 additions & 11 deletions src/css/common/_modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@
.components-modal__frame.code-snippets-preview-modal {
min-inline-size: 520px;
min-block-size: 240px;
max-inline-size: 80vw;
max-block-size: 80vh;
inline-size: min(900px, 90vw);
max-block-size: 85vh;

@media (width <= 600px) {
min-inline-size: 90vw;
}

.components-modal__content {
overflow: auto;
.components-modal__header {
border-block-end-color: #ddd;
}

// The badge lives in the modal content because the minimum-supported
Expand All @@ -75,12 +75,89 @@
inset-inline-end: 56px;
}

// Shown when the code editor is unavailable (syntax highlighting preference
// off): the raw read-only textarea is the functional fallback.
textarea {
inline-size: 100%;
min-block-size: 360px;
resize: none;
font-family: monospace;
// Header and footer stay pinned; the CodeMirror editor is the only
// scroll region, scrolling long code both vertically and horizontally.
.components-modal__content {
display: flex;
flex-flow: column;
min-block-size: 0;
padding: 0;
overflow: hidden;
}

// The modal component wraps its children in an unstyled focus container;
// it must join the flex chain or the editor grows to its content height.
.components-modal__header + div {
display: flex;
flex-flow: column;
flex: 1;
min-block-size: 0;
overflow: hidden;
}

.code-snippets-preview-modal__editor {
display: flex;
flex-flow: column;
flex: 1;
min-block-size: 0;

.CodeMirror {
flex: 1;
min-block-size: 0;
block-size: 100%;
}

textarea {
flex: 1;
min-block-size: 0;
inline-size: 100%;
resize: none;
font-family: monospace;
}
}

.code-snippets-preview-modal__footer {
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
gap: 16px;
padding: 11px 19px;
border-block-start: 1px solid #e2e2e4;
background: #f6f7f7;
}

.code-snippets-preview-modal__priority {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: #646970;

.code-snippets-preview-modal__priority-value {
font-weight: 600;
color: #2c3337;
}
}

.code-snippets-preview-modal__buttons {
display: flex;
align-items: center;
gap: 8px;

.button {
border-radius: 5px;
font-size: 14px;
}

.button-link.code-snippets-preview-modal__trash {
color: #b32d2e;
text-decoration: none;

&:hover,
&:focus {
color: #d63638;
}
}
}
}
3 changes: 1 addition & 2 deletions src/css/common/_subnav.scss
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,7 @@
font-size: 14px;
font-weight: 600;
line-height: 1.5;
color: #2c3337;
opacity: 0.4;
color: #646970;
}

// The active tab's count adopts the accent alongside its label.
Expand Down
2 changes: 1 addition & 1 deletion src/css/manage/_snippets-table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@
}

.snippet-card-modified {
color: #6c7e7e;
color: #646970;
margin-inline-start: auto;
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/css/welcome.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ $breakpoint: 1060px;

.code-snippets-welcome {
h2 {
font-size: 1.5rem;
font-weight: 400;
line-height: 1.3;
font-size: 32px;
font-weight: 510;
line-height: 1.25;
color: #2c3337;
padding: 0;
margin-block: 50px 1rem;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ import { TooltipButton } from '../../../common/TooltipButton'
import { useSnippetForm } from '../../SnippetForm/WithSnippetFormContext'

export const LockControl: React.FC = () => {
const { snippet, setSnippet, isWorking, setIsWorking, setCurrentNotice } = useSnippetForm()
const {
acceptSnippet,
snippet,
setSnippet,
isWorking,
setIsWorking,
setCurrentNotice
} = useSnippetForm()
const { update } = useSnippetsAPI()

const handleToggle = () => {
Expand All @@ -15,7 +22,7 @@ export const LockControl: React.FC = () => {

update({ id: snippet.id, network: snippet.network, locked: !snippet.locked })
.then(result => {
setSnippet(result)
acceptSnippet(result)

setCurrentNotice(['updated', result.locked
? __('Snippet <strong>locked</strong>.', 'code-snippets')
Expand Down
74 changes: 62 additions & 12 deletions src/js/components/EditMenu/SnippetForm/SnippetForm.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import classnames from 'classnames'
import { __ } from '@wordpress/i18n'
import { WithRestAPIContext } from '../../../hooks/useRestAPI'
import { WithSnippetsAPIContext } from '../../../hooks/useSnippetsAPI'
import { WithSnippetsListContext, useSnippetsList } from '../../../hooks/useSnippetsList'
import { SubmitSnippetAction, useSubmitSnippet } from '../../../hooks/useSubmitSnippet'
import { handleUnknownError } from '../../../utils/errors'
import { createSnippetObject, getSnippetType, isCondition, validateSnippet } from '../../../utils/snippets/snippets'
import {
createSnippetObject,
getSnippetType,
isCondition,
validateSnippet
} from '../../../utils/snippets/snippets'
import { buildUrl } from '../../../utils/urls'
import { ConfirmDialog } from '../../common/ConfirmDialog'
import { Toolbar } from '../../common/Toolbar'
Expand Down Expand Up @@ -96,7 +101,7 @@ const EditForm: React.FC<EditFormProps> = ({ children, className }) => {
.replace(__('Create New Condition', 'code-snippets'), __('Edit Condition', 'code-snippets'))

const newUrl = buildUrl(window.CODE_SNIPPETS.urls.edit, { id: response.id })
window.history.pushState({}, document.title, newUrl)
window.history.replaceState({}, document.title, newUrl)
}
}
})
Expand Down Expand Up @@ -126,7 +131,9 @@ const EditForm: React.FC<EditFormProps> = ({ children, className }) => {
{children}
</form>

<ConfirmSubmitDialog {...{ doSubmit, submitAction, setSubmitAction, validationWarning, setValidationWarning }} />
<ConfirmSubmitDialog
{...{ doSubmit, submitAction, setSubmitAction, validationWarning, setValidationWarning }}
/>
</>
)
}
Expand All @@ -141,17 +148,58 @@ const ConditionsEditor: React.FC = () => {
: null
}

const EditFormWrap: React.FC = () => {
const { snippet, isReadOnly } = useSnippetForm()
const [isExpanded, setIsExpanded] = useState(false)
const [isUpgradeDialogOpen, setIsUpgradeDialogOpen] = useState(false)
const useReloadOnPopState = (isDirty: boolean) => {
const currentUrl = useRef(window.location.href)
const skipNextUnloadPrompt = useRef(false)

useEffect(() => {
currentUrl.current = window.location.href
})

// Restoring history after pushState requires a reload to render the matching snippet.
useEffect(() => {
const handlePopState = () => window.location.reload()
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
if (skipNextUnloadPrompt.current) {
skipNextUnloadPrompt.current = false
return
}

event.preventDefault()
// Required by Chrome and Edge versions before 119.
// eslint-disable-next-line @typescript-eslint/no-deprecated
event.returnValue = true
}

if (isDirty) {
window.addEventListener('beforeunload', handleBeforeUnload)
}

return () => window.removeEventListener('beforeunload', handleBeforeUnload)
}, [isDirty])

useEffect(() => {
const handlePopState = () => {
if (isDirty && !window.confirm(
__('You have unsaved changes. Leave this page and discard them?', 'code-snippets')
)) {
window.history.pushState({}, document.title, currentUrl.current)
return
}

skipNextUnloadPrompt.current = isDirty
window.location.reload()
}

window.addEventListener('popstate', handlePopState)
return () => window.removeEventListener('popstate', handlePopState)
}, [])
}, [isDirty])
}

const EditFormWrap: React.FC = () => {
const { snippet, isReadOnly, isDirty } = useSnippetForm()
const [isExpanded, setIsExpanded] = useState(false)
const [isUpgradeDialogOpen, setIsUpgradeDialogOpen] = useState(false)

useReloadOnPopState(isDirty)

return (
<>
Expand Down Expand Up @@ -187,7 +235,9 @@ export const SnippetForm: React.FC = () =>
<WithRestAPIContext>
<WithSnippetsAPIContext>
<WithSnippetsListContext>
<WithSnippetFormContext initialSnippet={() => createSnippetObject(window.CODE_SNIPPETS_EDIT?.snippet)}>
<WithSnippetFormContext
initialSnippet={() => createSnippetObject(window.CODE_SNIPPETS_EDIT?.snippet)}
>
<Toolbar />
<EditFormWrap />
</WithSnippetFormContext>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ export interface SnippetFormContext {
snippet: Snippet
isWorking: boolean
isReadOnly: boolean
isDirty: boolean
setSnippet: Dispatch<SetStateAction<Snippet>>
acceptSnippet: (snippet: Snippet) => void
updateSnippet: Dispatch<SetStateAction<Snippet>>
setIsWorking: Dispatch<SetStateAction<boolean>>
currentNotice: ScreenNotice | undefined
Expand All @@ -28,8 +30,30 @@ export interface WithSnippetFormContextProps extends PropsWithChildren {
initialSnippet: () => Snippet
}

const getSnippetDraftState = (snippet: Snippet) => ({
name: snippet.name,
desc: snippet.desc,
code: snippet.code,
tags: snippet.tags,
scope: snippet.scope,
priority: snippet.priority,
active: snippet.active,
locked: snippet.locked,
network: snippet.network,
sharedNetwork: snippet.shared_network,
conditionId: snippet.conditionId
})

const isSnippetDraftDirty = (snippet: Snippet, savedSnippet: Snippet): boolean => {
const draftState = JSON.stringify(getSnippetDraftState(snippet))
const savedDraftState = JSON.stringify(getSnippetDraftState(savedSnippet))
return draftState !== savedDraftState
}

export const WithSnippetFormContext: React.FC<WithSnippetFormContextProps> = ({ children, initialSnippet }) => {
const [snippet, setSnippet] = useState<Snippet>(initialSnippet)
const [initialValue] = useState<Snippet>(initialSnippet)
const [snippet, setSnippet] = useState<Snippet>(initialValue)
const [savedSnippet, setSavedSnippet] = useState<Snippet>(initialValue)
const [isWorking, setIsWorking] = useState(false)
const [currentNotice, setCurrentNotice] = useState<ScreenNotice>()
const [codeEditorInstance, setCodeEditorInstance] = useState<CodeEditorInstance>()
Expand All @@ -38,6 +62,14 @@ export const WithSnippetFormContext: React.FC<WithSnippetFormContextProps> = ({
() => snippet.locked || !isLicensed() && isProSnippet({ scope: snippet.scope }),
[snippet.locked, snippet.scope]
)
const isDirty = useMemo(
() => isSnippetDraftDirty(snippet, savedSnippet),
[snippet, savedSnippet]
)
const acceptSnippet = useCallback((value: Snippet) => {
setSnippet(value)
setSavedSnippet(value)
}, [])

const handleRequestError = useCallback((error: unknown, message?: string) => {
console.error('Request failed', error)
Expand All @@ -58,7 +90,9 @@ export const WithSnippetFormContext: React.FC<WithSnippetFormContextProps> = ({
snippet,
isWorking,
isReadOnly,
isDirty,
setSnippet,
acceptSnippet,
setIsWorking,
updateSnippet,
currentNotice,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const CardPreviewButton: React.FC<SnippetCardActionsProps> = ({ snippet }) => {
type={getSnippetType(snippet)}
isOpen={isPreviewOpen}
setIsOpen={setIsPreviewOpen}
snippet={snippet}
/>
</>
)
Expand Down
1 change: 1 addition & 0 deletions src/js/components/ManageMenu/SnippetsTable/RowActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const PreviewLink: React.FC<RowActionsProps> = ({ snippet }) => {
type={getSnippetType(snippet)}
isOpen={isPreviewOpen}
setIsOpen={setIsPreviewOpen}
snippet={snippet}
/>
</>
)
Expand Down
Loading
Loading