Skip to content

Commit 27ea117

Browse files
fix: only allow save after form is modified (#6189)
1 parent 7ab156e commit 27ea117

File tree

6 files changed

+30
-18
lines changed

6 files changed

+30
-18
lines changed

packages/ui/src/elements/DocumentDrawer/DrawerContent.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { RenderTitle } from '../RenderTitle/index.js'
2121
import { baseClass } from './index.js'
2222

2323
export const DocumentDrawerContent: React.FC<DocumentDrawerProps> = ({
24-
id,
24+
id: existingDocID,
2525
Header,
2626
collectionSlug,
2727
drawerSlug,
@@ -39,7 +39,7 @@ export const DocumentDrawerContent: React.FC<DocumentDrawerProps> = ({
3939
const { closeModal, modalState, toggleModal } = useModal()
4040
const locale = useLocale()
4141
const { t } = useTranslation()
42-
const [createdID, setCreatedID] = useState()
42+
const [docID, setDocID] = useState(existingDocID)
4343
const [isOpen, setIsOpen] = useState(false)
4444
const [collectionConfig] = useRelatedCollections(collectionSlug)
4545
const { formQueryParams } = useFormQueryParams()
@@ -48,10 +48,12 @@ export const DocumentDrawerContent: React.FC<DocumentDrawerProps> = ({
4848
const { componentMap } = useComponentMap()
4949

5050
const { Edit } = componentMap[`${collectionSlug ? 'collections' : 'globals'}`][collectionSlug]
51-
const isEditing = Boolean(id)
52-
const apiURL = id ? `${serverURL}${apiRoute}/${collectionSlug}/${id}?locale=${locale.code}` : null
51+
const isEditing = Boolean(docID)
52+
const apiURL = docID
53+
? `${serverURL}${apiRoute}/${collectionSlug}/${docID}?locale=${locale.code}`
54+
: null
5355
const action = `${serverURL}${apiRoute}/${collectionSlug}${
54-
isEditing ? `/${id}` : ''
56+
isEditing ? `/${docID}` : ''
5557
}?${formattedQueryParams}`
5658

5759
useEffect(() => {
@@ -70,7 +72,7 @@ export const DocumentDrawerContent: React.FC<DocumentDrawerProps> = ({
7072

7173
const onSave = useCallback<DocumentDrawerProps['onSave']>(
7274
(args) => {
73-
setCreatedID(args.doc.id)
75+
setDocID(args.doc.id)
7476
if (typeof onSaveFromProps === 'function') {
7577
void onSaveFromProps({
7678
...args,
@@ -115,7 +117,7 @@ export const DocumentDrawerContent: React.FC<DocumentDrawerProps> = ({
115117
// Same reason as above. We need to fully-fetch the docPreferences from the server. This is done in DocumentInfoProvider if we set it to null here.
116118
hasSavePermission={null}
117119
// isLoading,
118-
id={id || createdID}
120+
id={docID}
119121
isEditing={isEditing}
120122
onLoadError={onLoadError}
121123
onSave={onSave}

packages/ui/src/elements/Save/index.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,27 @@
22

33
import React, { useRef } from 'react'
44

5-
import { useForm } from '../../forms/Form/context.js'
5+
import { useForm, useFormModified } from '../../forms/Form/context.js'
66
import { FormSubmit } from '../../forms/Submit/index.js'
77
import { useHotkey } from '../../hooks/useHotkey.js'
88
import { useEditDepth } from '../../providers/EditDepth/index.js'
9+
import { useOperation } from '../../providers/Operation/index.js'
910
import { useTranslation } from '../../providers/Translation/index.js'
1011

1112
export const DefaultSaveButton: React.FC<{ label?: string }> = ({ label: labelProp }) => {
1213
const { t } = useTranslation()
1314
const { submit } = useForm()
15+
const modified = useFormModified()
1416
const label = labelProp || t('general:save')
1517
const ref = useRef<HTMLButtonElement>(null)
1618
const editDepth = useEditDepth()
19+
const operation = useOperation()
20+
21+
const forceDisable = operation === 'update' && !modified
1722

1823
useHotkey({ cmdCtrlKey: true, editDepth, keyCodes: ['s'] }, (e) => {
24+
if (forceDisable) return
25+
1926
e.preventDefault()
2027
e.stopPropagation()
2128
if (ref?.current) {
@@ -26,6 +33,7 @@ export const DefaultSaveButton: React.FC<{ label?: string }> = ({ label: labelPr
2633
return (
2734
<FormSubmit
2835
buttonId="action-save"
36+
disabled={forceDisable}
2937
onClick={() => submit()}
3038
ref={ref}
3139
size="small"

packages/ui/src/elements/SaveDraft/index.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useConfig } from '../../providers/Config/index.js'
99
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
1010
import { useEditDepth } from '../../providers/EditDepth/index.js'
1111
import { useLocale } from '../../providers/Locale/index.js'
12+
import { useOperation } from '../../providers/Operation/index.js'
1213
import { useTranslation } from '../../providers/Translation/index.js'
1314

1415
const baseClass = 'save-draft'
@@ -25,8 +26,13 @@ const DefaultSaveDraftButton: React.FC = () => {
2526
const editDepth = useEditDepth()
2627
const { t } = useTranslation()
2728
const { submit } = useForm()
29+
const operation = useOperation()
30+
31+
const forceDisable = operation === 'update' && !modified
2832

2933
const saveDraft = useCallback(async () => {
34+
if (forceDisable) return
35+
3036
const search = `?locale=${locale}&depth=0&fallback-locale=null&draft=true`
3137
let action
3238
let method = 'POST'
@@ -48,12 +54,10 @@ const DefaultSaveDraftButton: React.FC = () => {
4854
},
4955
skipValidation: true,
5056
})
51-
}, [submit, collectionSlug, globalSlug, serverURL, api, locale, id])
57+
}, [submit, collectionSlug, globalSlug, serverURL, api, locale, id, forceDisable])
5258

5359
useHotkey({ cmdCtrlKey: true, editDepth, keyCodes: ['s'] }, (e) => {
54-
if (!modified) {
55-
return
56-
}
60+
if (forceDisable) return
5761

5862
e.preventDefault()
5963
e.stopPropagation()
@@ -67,7 +71,7 @@ const DefaultSaveDraftButton: React.FC = () => {
6771
buttonId="action-save-draft"
6872
buttonStyle="secondary"
6973
className={baseClass}
70-
disabled={!modified}
74+
disabled={forceDisable}
7175
onClick={saveDraft}
7276
ref={ref}
7377
size="small"

test/admin/e2e.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,6 @@ describe('admin', () => {
465465
await globalLabel.click()
466466
await checkPageTitle(page, label)
467467
await checkBreadcrumb(page, label)
468-
await saveDocAndAssert(page)
469468
})
470469

471470
test('global — should render slug in sentence case as fallback', async () => {
@@ -478,7 +477,6 @@ describe('admin', () => {
478477
await globalLabel.click()
479478
await checkPageTitle(page, label)
480479
await checkBreadcrumb(page, label)
481-
await saveDocAndAssert(page)
482480
})
483481
})
484482

test/fields-relationship/e2e.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,10 @@ describe('fields - relationship', () => {
438438
).toHaveCount(1)
439439

440440
// save the same document again to ensure the relationship field doesn't receive duplicative values
441+
await drawerField.fill('Updated document')
441442
await saveButton.click()
442-
await expect(page.locator('.Toastify')).toContainText('successfully')
443+
await expect(page.locator('.Toastify')).toContainText('Updated successfully')
444+
await page.locator('.doc-drawer__header-close').click()
443445
await expect(
444446
page.locator('#field-relationshipHasMany .value-container .rs__multi-value'),
445447
).toHaveCount(1)

test/localization/e2e.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ describe('Localization', () => {
116116

117117
await fillValues({ description, title })
118118
await saveDocAndAssert(page)
119-
await saveDocAndAssert(page)
120119

121120
await expect(page.locator('#field-title')).toHaveValue(title)
122121
await expect(page.locator('#field-description')).toHaveValue(description)
@@ -241,7 +240,6 @@ describe('Localization', () => {
241240
await openDocControls(page)
242241
await page.locator('#action-duplicate').click()
243242
await expect(page.locator('.id-label')).not.toContainText(originalID)
244-
await page.locator('#action-save').click()
245243

246244
// verify that the locale did copy
247245
await expect(page.locator('#field-title')).toHaveValue(englishTitle)

0 commit comments

Comments
 (0)