From 55e7c94b91a05581b45ed8b675866524ef8ad7e4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 5 Jul 2026 17:16:22 +1000 Subject: [PATCH] fix: render Cloud Config Date params as dates after refresh (#2566) --- src/dashboard/Data/Config/Config.react.js | 11 ++----- src/lib/decodeConfigValue.js | 23 +++++++++++++ src/lib/tests/decodeConfigValue.test.js | 39 +++++++++++++++++++++++ 3 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 src/lib/decodeConfigValue.js create mode 100644 src/lib/tests/decodeConfigValue.test.js diff --git a/src/dashboard/Data/Config/Config.react.js b/src/dashboard/Data/Config/Config.react.js index 7daf827fb5..91016f26ec 100644 --- a/src/dashboard/Data/Config/Config.react.js +++ b/src/dashboard/Data/Config/Config.react.js @@ -13,6 +13,7 @@ import AddArrayEntryDialog from 'dashboard/Data/Config/AddArrayEntryDialog.react import RemoveArrayEntryDialog from 'dashboard/Data/Config/RemoveArrayEntryDialog.react'; import EmptyState from 'components/EmptyState/EmptyState.react'; import Icon from 'components/Icon/Icon.react'; +import decodeConfigValue from 'lib/decodeConfigValue'; import { isDate } from 'lib/DateUtils'; import Parse from 'parse'; import React from 'react'; @@ -365,7 +366,7 @@ class Config extends TableView { // Get latest param values const fetchedParams = this.props.config.data.get('params'); - const fetchedValue = fetchedParams.get(this.state.modalParam); + const fetchedValue = decodeConfigValue(fetchedParams.get(this.state.modalParam)); const fetchedMasterKeyOnly = this.props.config.data.get('masterKeyOnly')?.get(this.state.modalParam) || false; @@ -482,15 +483,9 @@ class Config extends TableView { data = []; params.forEach((value, param) => { const masterKeyOnly = masterKeyOnlyParams.get(param) || false; - const type = typeof value; - if (type === 'object' && value.__type == 'File') { - value = Parse.File.fromJSON(value); - } else if (type === 'object' && value.__type == 'GeoPoint') { - value = new Parse.GeoPoint(value); - } data.push({ param: param, - value: value, + value: decodeConfigValue(value), masterKeyOnly: masterKeyOnly, }); }); diff --git a/src/lib/decodeConfigValue.js b/src/lib/decodeConfigValue.js new file mode 100644 index 0000000000..442446fead --- /dev/null +++ b/src/lib/decodeConfigValue.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016-present, Parse, LLC + * All rights reserved. + * + * This source code is licensed under the license found in the LICENSE file in + * the root directory of this source tree. + */ +import Parse from 'parse'; + +export default function decodeConfigValue(value) { + if (value && typeof value === 'object') { + if (value.__type === 'File') { + return Parse.File.fromJSON(value); + } + if (value.__type === 'GeoPoint') { + return new Parse.GeoPoint(value); + } + if (value.__type === 'Date') { + return new Date(value.iso); + } + } + return value; +} diff --git a/src/lib/tests/decodeConfigValue.test.js b/src/lib/tests/decodeConfigValue.test.js new file mode 100644 index 0000000000..0b509e559f --- /dev/null +++ b/src/lib/tests/decodeConfigValue.test.js @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016-present, Parse, LLC + * All rights reserved. + * + * This source code is licensed under the license found in the LICENSE file in + * the root directory of this source tree. + */ +jest.dontMock('../decodeConfigValue'); + +const decodeConfigValue = require('../decodeConfigValue').default; +const Parse = require('parse'); + +describe('decodeConfigValue', () => { + it('rehydrates a wire-format Date into a Date instance', () => { + const result = decodeConfigValue({ __type: 'Date', iso: '2024-05-05T00:36:00.000Z' }); + expect(result instanceof Date).toBe(true); + expect(result.toISOString()).toBe('2024-05-05T00:36:00.000Z'); + }); + + it('passes a real Date through unchanged', () => { + const d = new Date('2024-05-05T00:36:00.000Z'); + expect(decodeConfigValue(d)).toBe(d); + }); + + it('rehydrates a File wire object', () => { + const result = decodeConfigValue({ __type: 'File', name: 'f.png', url: 'https://x/f.png' }); + expect(result instanceof Parse.File).toBe(true); + }); + + it('rehydrates a GeoPoint wire object', () => { + const result = decodeConfigValue({ __type: 'GeoPoint', latitude: 1, longitude: 2 }); + expect(result instanceof Parse.GeoPoint).toBe(true); + }); + + it('passes primitives through', () => { + expect(decodeConfigValue('x')).toBe('x'); + expect(decodeConfigValue(42)).toBe(42); + }); +});