From f33b6ac0223d021a3fb2c81e5d18337bbbcf3ad2 Mon Sep 17 00:00:00 2001 From: sadakchap Date: Mon, 20 Apr 2026 16:48:36 +0530 Subject: [PATCH 1/2] migration cards --- .../Modals/editParseVersionModal.react.js | 48 ++++++++++++++- .../Modals/editParseVersionModal.scss | 59 +++++++++++++++++++ src/lib/ParseApp.js | 5 ++ 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/dashboard/Settings/Modals/editParseVersionModal.react.js b/src/dashboard/Settings/Modals/editParseVersionModal.react.js index 9e76e957ed..bd9a025b91 100644 --- a/src/dashboard/Settings/Modals/editParseVersionModal.react.js +++ b/src/dashboard/Settings/Modals/editParseVersionModal.react.js @@ -16,6 +16,9 @@ export const EditParseVersionModal = ({ context, setParentState, currentParseVer const [dropdownOpen, setDropdownOpen] = useState(false); const [note, setNote] = useState(''); const [noteColor, setNoteColor] = useState('red'); + const [migrationLinks, setMigrationLinks] = useState([]); + + const isGDPR = !!(context && context.custom && context.custom.isGDPR); const parseDependencies = (deps) => { if (!deps) { @@ -66,7 +69,7 @@ export const EditParseVersionModal = ({ context, setParentState, currentParseVer useEffect(() => { setProcessing(true); - context.supportedParseServerVersionsForApp() + const versionsPromise = context.supportedParseServerVersionsForApp() .then((data) => { const versions = Array.isArray(data) ? data : (data.results || []); setParseVersions(versions); @@ -77,13 +80,28 @@ export const EditParseVersionModal = ({ context, setParentState, currentParseVer setNote(e.error || 'Failed to load versions'); console.log('e', e); setNoteColor('red'); + }); + + // Migration links are best-effort: if they fail we still show the version picker. + const linksPromise = context.parseServerMigrationLinks() + .then((data) => { + const links = Array.isArray(data) ? data : (data?.results || []); + setMigrationLinks(links); }) - .finally(() => setProcessing(false)); + .catch(() => { + setMigrationLinks([]); + }); + + Promise.all([versionsPromise, linksPromise]).finally(() => setProcessing(false)); }, []); const npmModules = parseDependencies(selectedVersion?.dependencies ?? selectedVersion?.npmModules); const hasSelectedVersion = !!selectedVersion?.version; + const visibleMigrations = isGDPR + ? [] + : (migrationLinks || []).filter((m) => m && m.link && m.version !== selectedVersion?.version); + const close = () => setParentState({ showEditParseVersionModal: false }); const save = async () => { @@ -126,6 +144,32 @@ export const EditParseVersionModal = ({ context, setParentState, currentParseVer
+ {visibleMigrations.length > 0 && ( +
+ {visibleMigrations.map((m) => ( +
+
+ + Upgrade to the latest Parse Server + + + + +
+ {m.description && ( +

{m.description}

+ )} +
+ ))} +
+ )}
diff --git a/src/dashboard/Settings/Modals/editParseVersionModal.scss b/src/dashboard/Settings/Modals/editParseVersionModal.scss index 5b30321785..bd041d4c4d 100644 --- a/src/dashboard/Settings/Modals/editParseVersionModal.scss +++ b/src/dashboard/Settings/Modals/editParseVersionModal.scss @@ -227,3 +227,62 @@ font-size: 14px; } +/* Migration scheduling callouts */ +.migrationCard { + display: flex; + flex-direction: column; + gap: 8px; + margin-bottom: 12px; +} + +.migrationItem { + background: $white; + border: 1px solid rgba($dark, 0.15); + border-radius: 8px; + padding: 12px 16px; +} + +.migrationHead { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.migrationTitle { + @include InterFont; + font-size: 14px; + font-weight: 500; + color: $dark; + line-height: 1.3; +} + +.migrationLink { + display: inline-flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 24px; + height: 24px; + border-radius: 50%; + transition: background 0.15s ease; + transform: rotate(45deg); + background: rgba($cta-green, 0.1); + + &:hover { + cursor: pointer; + } + + &:focus { + outline: none; + } +} + +.migrationDescription { + @include InterFont; + font-size: 10px; + color: rgba($dark, 0.65); + margin: 6px 0 0; + line-height: 1.45; +} + diff --git a/src/lib/ParseApp.js b/src/lib/ParseApp.js index 7a64a239dd..9443288c8b 100644 --- a/src/lib/ParseApp.js +++ b/src/lib/ParseApp.js @@ -451,6 +451,11 @@ export default class ParseApp { return AJAX.get(path); } + parseServerMigrationLinks() { + const path = `/parse-version/links/${this.slug}`; + return AJAX.get(path); + } + changeParseServerVersion(parseVersion) { const path = `/parse-version/${this.slug}/`; return AJAX.post(path, { parseVersion }); From ad1160d0f5974b7cb2d61ab6688ef1b0890f842f Mon Sep 17 00:00:00 2001 From: sadakchap Date: Mon, 20 Apr 2026 17:49:03 +0530 Subject: [PATCH 2/2] change to calendar icon --- .../Settings/Modals/editParseVersionModal.react.js | 14 +++++++++++++- .../Settings/Modals/editParseVersionModal.scss | 3 --- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/dashboard/Settings/Modals/editParseVersionModal.react.js b/src/dashboard/Settings/Modals/editParseVersionModal.react.js index bd9a025b91..23a776f45b 100644 --- a/src/dashboard/Settings/Modals/editParseVersionModal.react.js +++ b/src/dashboard/Settings/Modals/editParseVersionModal.react.js @@ -160,7 +160,19 @@ export const EditParseVersionModal = ({ context, setParentState, currentParseVer aria-label='Schedule migration' title='Schedule migration' > - +
{m.description && ( diff --git a/src/dashboard/Settings/Modals/editParseVersionModal.scss b/src/dashboard/Settings/Modals/editParseVersionModal.scss index bd041d4c4d..a5b2d7a63f 100644 --- a/src/dashboard/Settings/Modals/editParseVersionModal.scss +++ b/src/dashboard/Settings/Modals/editParseVersionModal.scss @@ -265,9 +265,6 @@ width: 24px; height: 24px; border-radius: 50%; - transition: background 0.15s ease; - transform: rotate(45deg); - background: rgba($cta-green, 0.1); &:hover { cursor: pointer;