From 50252483c6ec479d7848a8f3a47769a774801824 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 18 Feb 2021 18:05:41 +0000 Subject: [PATCH 1/7] Remove stale unused components --- .../views/elements/RoomDirectoryButton.js | 41 ------------ .../views/elements/StartChatButton.js | 40 ------------ .../views/elements/TintableSvgButton.js | 63 ------------------- 3 files changed, 144 deletions(-) delete mode 100644 src/components/views/elements/RoomDirectoryButton.js delete mode 100644 src/components/views/elements/StartChatButton.js delete mode 100644 src/components/views/elements/TintableSvgButton.js diff --git a/src/components/views/elements/RoomDirectoryButton.js b/src/components/views/elements/RoomDirectoryButton.js deleted file mode 100644 index e9de6f8d15..0000000000 --- a/src/components/views/elements/RoomDirectoryButton.js +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import * as sdk from '../../../index'; -import PropTypes from 'prop-types'; -import { _t } from '../../../languageHandler'; -import {Action} from "../../../dispatcher/actions"; - -const RoomDirectoryButton = function(props) { - const ActionButton = sdk.getComponent('elements.ActionButton'); - return ( - - ); -}; - -RoomDirectoryButton.propTypes = { - size: PropTypes.string, - tooltip: PropTypes.bool, -}; - -export default RoomDirectoryButton; diff --git a/src/components/views/elements/StartChatButton.js b/src/components/views/elements/StartChatButton.js deleted file mode 100644 index f828f8ae4d..0000000000 --- a/src/components/views/elements/StartChatButton.js +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import * as sdk from '../../../index'; -import PropTypes from 'prop-types'; -import { _t } from '../../../languageHandler'; - -const StartChatButton = function(props) { - const ActionButton = sdk.getComponent('elements.ActionButton'); - return ( - - ); -}; - -StartChatButton.propTypes = { - size: PropTypes.string, - tooltip: PropTypes.bool, -}; - -export default StartChatButton; diff --git a/src/components/views/elements/TintableSvgButton.js b/src/components/views/elements/TintableSvgButton.js deleted file mode 100644 index a3f5b7db5d..0000000000 --- a/src/components/views/elements/TintableSvgButton.js +++ /dev/null @@ -1,63 +0,0 @@ -/* -Copyright 2017 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import PropTypes from 'prop-types'; -import TintableSvg from './TintableSvg'; -import AccessibleButton from './AccessibleButton'; - -export default class TintableSvgButton extends React.Component { - constructor(props) { - super(props); - } - - render() { - let classes = "mx_TintableSvgButton"; - if (this.props.className) { - classes += " " + this.props.className; - } - return ( - - - - - ); - } -} - -TintableSvgButton.propTypes = { - src: PropTypes.string, - title: PropTypes.string, - className: PropTypes.string, - width: PropTypes.string.isRequired, - height: PropTypes.string.isRequired, - onClick: PropTypes.func, -}; - -TintableSvgButton.defaultProps = { - onClick: function() {}, -}; From 8fc244452ce2f2d40643b2ddc1d22085d62bb9ea Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 18 Feb 2021 18:06:26 +0000 Subject: [PATCH 2/7] Prevent error being thrown so that we can throw our own better one --- src/stores/room-list/algorithms/Algorithm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stores/room-list/algorithms/Algorithm.ts b/src/stores/room-list/algorithms/Algorithm.ts index 25059aabe7..f709fc3ccb 100644 --- a/src/stores/room-list/algorithms/Algorithm.ts +++ b/src/stores/room-list/algorithms/Algorithm.ts @@ -211,7 +211,7 @@ export class Algorithm extends EventEmitter { } // When we do have a room though, we expect to be able to find it - let tag = this.roomIdsToTags[val.roomId][0]; + let tag = this.roomIdsToTags[val.roomId]?.[0]; if (!tag) throw new Error(`${val.roomId} does not belong to a tag and cannot be sticky`); // We specifically do NOT use the ordered rooms set as it contains the sticky room, which From 3ca5632f6a68f0b57c8c642d9b374d4bea6cd788 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 19 Feb 2021 00:00:10 +0000 Subject: [PATCH 3/7] Replace ObjectUtils.js with objects.ts --- src/ObjectUtils.js | 113 --------------------- src/components/structures/RoomView.tsx | 5 +- src/components/structures/TimelinePanel.js | 6 +- src/components/views/rooms/AuxPanel.tsx | 5 +- src/components/views/rooms/EventTile.js | 4 +- src/utils/objects.ts | 1 + 6 files changed, 10 insertions(+), 124 deletions(-) delete mode 100644 src/ObjectUtils.js diff --git a/src/ObjectUtils.js b/src/ObjectUtils.js deleted file mode 100644 index 24dfe61d68..0000000000 --- a/src/ObjectUtils.js +++ /dev/null @@ -1,113 +0,0 @@ -/* -Copyright 2016 OpenMarket Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/** - * For two objects of the form { key: [val1, val2, val3] }, work out the added/removed - * values. Entirely new keys will result in the entire value array being added. - * @param {Object} before - * @param {Object} after - * @return {Object[]} An array of objects with the form: - * { key: $KEY, val: $VALUE, place: "add|del" } - */ -export function getKeyValueArrayDiffs(before, after) { - const results = []; - const delta = {}; - Object.keys(before).forEach(function(beforeKey) { - delta[beforeKey] = delta[beforeKey] || 0; // init to 0 initially - delta[beforeKey]--; // keys present in the past have -ve values - }); - Object.keys(after).forEach(function(afterKey) { - delta[afterKey] = delta[afterKey] || 0; // init to 0 initially - delta[afterKey]++; // keys present in the future have +ve values - }); - - Object.keys(delta).forEach(function(muxedKey) { - switch (delta[muxedKey]) { - case 1: // A new key in after - after[muxedKey].forEach(function(afterVal) { - results.push({ place: "add", key: muxedKey, val: afterVal }); - }); - break; - case -1: // A before key was removed - before[muxedKey].forEach(function(beforeVal) { - results.push({ place: "del", key: muxedKey, val: beforeVal }); - }); - break; - case 0: {// A mix of added/removed keys - // compare old & new vals - const itemDelta = {}; - before[muxedKey].forEach(function(beforeVal) { - itemDelta[beforeVal] = itemDelta[beforeVal] || 0; - itemDelta[beforeVal]--; - }); - after[muxedKey].forEach(function(afterVal) { - itemDelta[afterVal] = itemDelta[afterVal] || 0; - itemDelta[afterVal]++; - }); - - Object.keys(itemDelta).forEach(function(item) { - if (itemDelta[item] === 1) { - results.push({ place: "add", key: muxedKey, val: item }); - } else if (itemDelta[item] === -1) { - results.push({ place: "del", key: muxedKey, val: item }); - } else { - // itemDelta of 0 means it was unchanged between before/after - } - }); - break; - } - default: - console.error("Calculated key delta of " + delta[muxedKey] + " - this should never happen!"); - break; - } - }); - - return results; -} - -/** - * Shallow-compare two objects for equality: each key and value must be identical - * @param {Object} objA First object to compare against the second - * @param {Object} objB Second object to compare against the first - * @return {boolean} whether the two objects have same key=values - */ -export function shallowEqual(objA, objB) { - if (objA === objB) { - return true; - } - - if (typeof objA !== 'object' || objA === null || - typeof objB !== 'object' || objB === null) { - return false; - } - - const keysA = Object.keys(objA); - const keysB = Object.keys(objB); - - if (keysA.length !== keysB.length) { - return false; - } - - for (let i = 0; i < keysA.length; i++) { - const key = keysA[i]; - if (!objB.hasOwnProperty(key) || objA[key] !== objB[key]) { - return false; - } - } - - return true; -} diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index ee50686123..68ab3c6e0c 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -38,7 +38,6 @@ import CallHandler from '../../CallHandler'; import dis from '../../dispatcher/dispatcher'; import Tinter from '../../Tinter'; import rateLimitedFunc from '../../ratelimitedfunc'; -import * as ObjectUtils from '../../ObjectUtils'; import * as Rooms from '../../Rooms'; import eventSearch, { searchPagination } from '../../Searching'; import { isOnlyCtrlOrCmdIgnoreShiftKeyEvent, Key } from '../../Keyboard'; @@ -80,6 +79,7 @@ import Notifier from "../../Notifier"; import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast"; import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore"; import { Container, WidgetLayoutStore } from "../../stores/widgets/WidgetLayoutStore"; +import { objectHasDiff } from "../../utils/objects"; const DEBUG = false; let debuglog = function(msg: string) {}; @@ -523,8 +523,7 @@ export default class RoomView extends React.Component { } shouldComponentUpdate(nextProps, nextState) { - return (!ObjectUtils.shallowEqual(this.props, nextProps) || - !ObjectUtils.shallowEqual(this.state, nextState)); + return (objectHasDiff(this.props, nextProps) || objectHasDiff(this.state, nextState)); } componentDidUpdate() { diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index e8da5c42d0..6bc1f70ba1 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -26,7 +26,6 @@ import {EventTimeline} from "matrix-js-sdk"; import * as Matrix from "matrix-js-sdk"; import { _t } from '../../languageHandler'; import {MatrixClientPeg} from "../../MatrixClientPeg"; -import * as ObjectUtils from "../../ObjectUtils"; import UserActivity from "../../UserActivity"; import Modal from "../../Modal"; import dis from "../../dispatcher/dispatcher"; @@ -37,6 +36,7 @@ import shouldHideEvent from '../../shouldHideEvent'; import EditorStateTransfer from '../../utils/EditorStateTransfer'; import {haveTileForEvent} from "../views/rooms/EventTile"; import {UIFeature} from "../../settings/UIFeature"; +import {objectHasDiff} from "../../utils/objects"; const PAGINATE_SIZE = 20; const INITIAL_SIZE = 20; @@ -261,7 +261,7 @@ class TimelinePanel extends React.Component { } shouldComponentUpdate(nextProps, nextState) { - if (!ObjectUtils.shallowEqual(this.props, nextProps)) { + if (objectHasDiff(this.props, nextProps)) { if (DEBUG) { console.group("Timeline.shouldComponentUpdate: props change"); console.log("props before:", this.props); @@ -271,7 +271,7 @@ class TimelinePanel extends React.Component { return true; } - if (!ObjectUtils.shallowEqual(this.state, nextState)) { + if (objectHasDiff(this.state, nextState)) { if (DEBUG) { console.group("Timeline.shouldComponentUpdate: state change"); console.log("state before:", this.state); diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index 7966643084..4ce31be410 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -19,7 +19,6 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg"; import { Room } from 'matrix-js-sdk/src/models/room' import * as sdk from '../../../index'; import dis from "../../../dispatcher/dispatcher"; -import * as ObjectUtils from '../../../ObjectUtils'; import AppsDrawer from './AppsDrawer'; import { _t } from '../../../languageHandler'; import classNames from 'classnames'; @@ -29,6 +28,7 @@ import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; import {UIFeature} from "../../../settings/UIFeature"; import { ResizeNotifier } from "../../../utils/ResizeNotifier"; import CallViewForRoom from '../voip/CallViewForRoom'; +import {objectHasDiff} from "../../../utils/objects"; interface IProps { // js-sdk room object @@ -89,8 +89,7 @@ export default class AuxPanel extends React.Component { } shouldComponentUpdate(nextProps, nextState) { - return (!ObjectUtils.shallowEqual(this.props, nextProps) || - !ObjectUtils.shallowEqual(this.state, nextState)); + return objectHasDiff(this.props, nextProps) || objectHasDiff(this.state, nextState); } componentDidUpdate(prevProps, prevState) { diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index c856919f5a..210f966d1e 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -32,13 +32,13 @@ import {EventStatus} from 'matrix-js-sdk'; import {formatTime} from "../../../DateUtils"; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {ALL_RULE_TYPES} from "../../../mjolnir/BanList"; -import * as ObjectUtils from "../../../ObjectUtils"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {E2E_STATE} from "./E2EIcon"; import {toRem} from "../../../utils/units"; import {WidgetType} from "../../../widgets/WidgetType"; import RoomAvatar from "../avatars/RoomAvatar"; import {WIDGET_LAYOUT_EVENT_TYPE} from "../../../stores/widgets/WidgetLayoutStore"; +import {objectHasDiff} from "../../../utils/objects"; const eventTileTypes = { 'm.room.message': 'messages.MessageEvent', @@ -294,7 +294,7 @@ export default class EventTile extends React.Component { } shouldComponentUpdate(nextProps, nextState) { - if (!ObjectUtils.shallowEqual(this.state, nextState)) { + if (objectHasDiff(this.state, nextState)) { return true; } diff --git a/src/utils/objects.ts b/src/utils/objects.ts index bc74ab9ee0..fe010df2b9 100644 --- a/src/utils/objects.ts +++ b/src/utils/objects.ts @@ -86,6 +86,7 @@ export function objectShallowClone(a: O, propertyCloner?: (k: keyo * @returns True if there's a difference between the objects, false otherwise */ export function objectHasDiff(a: O, b: O): boolean { + if (a === b) return false; const aKeys = Object.keys(a); const bKeys = Object.keys(b); if (arrayHasDiff(aKeys, bKeys)) return true; From 3c52446205e420689eab66af20e1f220c387dd5d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 19 Feb 2021 00:01:07 +0000 Subject: [PATCH 4/7] Remove redundant PhasedRollOut --- src/PhasedRollOut.js | 51 --------------------------- test/PhasedRollOut-test.js | 71 -------------------------------------- 2 files changed, 122 deletions(-) delete mode 100644 src/PhasedRollOut.js delete mode 100644 test/PhasedRollOut-test.js diff --git a/src/PhasedRollOut.js b/src/PhasedRollOut.js deleted file mode 100644 index b17ed37974..0000000000 --- a/src/PhasedRollOut.js +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright 2018 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import SdkConfig from './SdkConfig'; -import {hashCode} from './utils/FormattingUtils'; - -export function phasedRollOutExpiredForUser(username, feature, now, rollOutConfig = SdkConfig.get().phasedRollOut) { - if (!rollOutConfig) { - console.log(`no phased rollout configuration, so enabling ${feature}`); - return true; - } - const featureConfig = rollOutConfig[feature]; - if (!featureConfig) { - console.log(`${feature} doesn't have phased rollout configured, so enabling`); - return true; - } - if (!Number.isFinite(featureConfig.offset) || !Number.isFinite(featureConfig.period)) { - console.error(`phased rollout of ${feature} is misconfigured, ` + - `offset and/or period are not numbers, so disabling`, featureConfig); - return false; - } - - const hash = hashCode(username); - //ms -> min, enable users at minute granularity - const bucketRatio = 1000 * 60; - const bucketCount = featureConfig.period / bucketRatio; - const userBucket = hash % bucketCount; - const userMs = userBucket * bucketRatio; - const enableAt = featureConfig.offset + userMs; - const result = now >= enableAt; - const bucketStr = `(bucket ${userBucket}/${bucketCount})`; - if (result) { - console.log(`${feature} enabled for ${username} ${bucketStr}`); - } else { - console.log(`${feature} will be enabled for ${username} in ${Math.ceil((enableAt - now)/1000)}s ${bucketStr}`); - } - return result; -} diff --git a/test/PhasedRollOut-test.js b/test/PhasedRollOut-test.js deleted file mode 100644 index f02411d78d..0000000000 --- a/test/PhasedRollOut-test.js +++ /dev/null @@ -1,71 +0,0 @@ -/* -Copyright 2018 New Vector Ltd -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import {phasedRollOutExpiredForUser} from '../src/PhasedRollOut'; - -const OFFSET = 6000000; -// phasedRollOutExpiredForUser enables users in bucks of 1 minute -const MS_IN_MINUTE = 60 * 1000; - -describe('PhasedRollOut', function() { - it('should return true if phased rollout is not configured', function() { - expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", 0, null)).toBeTruthy(); - }); - - it('should return true if phased rollout feature is not configured', function() { - expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", 0, { - "feature_other": {offset: 0, period: 0}, - })).toBeTruthy(); - }); - - it('should return false if phased rollout for feature is misconfigured', function() { - expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", 0, { - "feature_test": {}, - })).toBeFalsy(); - }); - - it("should return false if phased rollout hasn't started yet", function() { - expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", 5000000, { - "feature_test": {offset: OFFSET, period: MS_IN_MINUTE}, - })).toBeFalsy(); - }); - - it("should start to return true in bucket 2/10 for '@user:hs'", function() { - expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", - OFFSET + (MS_IN_MINUTE * 2) - 1, { - "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, - })).toBeFalsy(); - expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", - OFFSET + (MS_IN_MINUTE * 2), { - "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, - })).toBeTruthy(); - }); - - it("should start to return true in bucket 4/10 for 'alice@other-hs'", function() { - expect(phasedRollOutExpiredForUser("alice@other-hs", "feature_test", - OFFSET + (MS_IN_MINUTE * 4) - 1, { - "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, - })).toBeFalsy(); - expect(phasedRollOutExpiredForUser("alice@other-hs", "feature_test", - OFFSET + (MS_IN_MINUTE * 4), { - "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, - })).toBeTruthy(); - }); - - it("should return true after complete rollout period'", function() { - expect(phasedRollOutExpiredForUser("user:hs", "feature_test", - OFFSET + (MS_IN_MINUTE * 20), { - "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, - })).toBeTruthy(); - }); -}); From d4df9e731d0053aa439f62d3e9dc0a67fa8128c4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 19 Feb 2021 00:10:47 +0000 Subject: [PATCH 5/7] i18n --- src/i18n/strings/en_EN.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 5bbbdf60b5..c3038fd9af 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1933,7 +1933,6 @@ "Please provide a room address": "Please provide a room address", "This address is available to use": "This address is available to use", "This address is already in use": "This address is already in use", - "Room directory": "Room directory", "Server Options": "Server Options", "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use Element with an existing Matrix account on a different homeserver.": "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use Element with an existing Matrix account on a different homeserver.", "Join millions for free on the largest public server": "Join millions for free on the largest public server", From 32cca0534c5ff7c7a86d854e6a00a4764652d20b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 19 Feb 2021 00:15:00 +0000 Subject: [PATCH 6/7] improve algo by skipping an O(n) operation --- src/utils/objects.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils/objects.ts b/src/utils/objects.ts index fe010df2b9..41e3f37d1b 100644 --- a/src/utils/objects.ts +++ b/src/utils/objects.ts @@ -89,9 +89,10 @@ export function objectHasDiff(a: O, b: O): boolean { if (a === b) return false; const aKeys = Object.keys(a); const bKeys = Object.keys(b); - if (arrayHasDiff(aKeys, bKeys)) return true; - const possibleChanges = arrayUnion(aKeys, bKeys); + // if the amalgamation of both sets of keys has the a different length to the inputs then there must be a change + if (possibleChanges.length !== aKeys.length) return true; + return possibleChanges.some(k => a[k] !== b[k]); } From 49f511bbab5a458f8be7e155f17ca317173d4a8e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 19 Feb 2021 00:26:52 +0000 Subject: [PATCH 7/7] delint --- src/utils/objects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/objects.ts b/src/utils/objects.ts index 41e3f37d1b..166c31c4c3 100644 --- a/src/utils/objects.ts +++ b/src/utils/objects.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { arrayDiff, arrayHasDiff, arrayMerge, arrayUnion } from "./arrays"; +import { arrayDiff, arrayMerge, arrayUnion } from "./arrays"; type ObjectExcluding = {[k in Exclude]: O[k]};