Rework patch visualizer with many fixes and improvements (#726)

- Reconciler now has precommit and postcommit hooks for patch applying
  - This is used to compute a patch tree snapshot precommit and update the
tree metadata postcommit
- PatchVisualizer can now display Removes that happened during sync
  - It was previously missing because the removed objects no longer
existed so it couldn't get any info on them (This is resolved because
the info is gotten in precommit, before the instance was removed)
- PatchVisualizer now shows Old and New values instead of just Incoming
during sync
  - (Still displays Current and Incoming during confirmation)
  - This is much more useful, since you now see what the changes were and
not just which things were changed
- PatchVisualizer displays clarifying message when initial sync has no
changes instead of just showing a blank box
- Objects in the tree UI no longer get stuck expanded when the next
patch has the same instance but different info on it
- Objects in the tree UI correctly become selectable after their
instance is added and unclickable when removed during sync
This commit is contained in:
boatbomber
2023-07-13 20:09:19 -07:00
committed by GitHub
parent 9d48af2b50
commit 6e40993199
9 changed files with 612 additions and 414 deletions

View File

@@ -3,6 +3,9 @@
and mutating the Roblox DOM.
]]
local Packages = script.Parent.Parent.Packages
local Log = require(Packages.Log)
local applyPatch = require(script.applyPatch)
local hydrate = require(script.hydrate)
local diff = require(script.diff)
@@ -14,13 +17,63 @@ function Reconciler.new(instanceMap)
local self = {
-- Tracks all of the instances known by the reconciler by ID.
__instanceMap = instanceMap,
__precommitCallbacks = {},
__postcommitCallbacks = {},
}
return setmetatable(self, Reconciler)
end
function Reconciler:hookPrecommit(callback: (patch: any, instanceMap: any) -> ()): () -> ()
table.insert(self.__precommitCallbacks, callback)
Log.trace("Added precommit callback: {}", callback)
return function()
-- Remove the callback from the list
for i, cb in self.__precommitCallbacks do
if cb == callback then
table.remove(self.__precommitCallbacks, i)
Log.trace("Removed precommit callback: {}", callback)
break
end
end
end
end
function Reconciler:hookPostcommit(callback: (patch: any, instanceMap: any, unappliedPatch: any) -> ()): () -> ()
table.insert(self.__postcommitCallbacks, callback)
Log.trace("Added postcommit callback: {}", callback)
return function()
-- Remove the callback from the list
for i, cb in self.__postcommitCallbacks do
if cb == callback then
table.remove(self.__postcommitCallbacks, i)
Log.trace("Removed postcommit callback: {}", callback)
break
end
end
end
end
function Reconciler:applyPatch(patch)
return applyPatch(self.__instanceMap, patch)
for _, callback in self.__precommitCallbacks do
local success, err = pcall(callback, patch, self.__instanceMap)
if not success then
Log.warn("Precommit hook errored: {}", err)
end
end
local unappliedPatch = applyPatch(self.__instanceMap, patch)
for _, callback in self.__postcommitCallbacks do
local success, err = pcall(callback, patch, self.__instanceMap, unappliedPatch)
if not success then
Log.warn("Postcommit hook errored: {}", err)
end
end
return unappliedPatch
end
function Reconciler:hydrate(virtualInstances, rootId, rootInstance)
@@ -31,4 +84,4 @@ function Reconciler:diff(virtualInstances, rootId)
return diff(self.__instanceMap, virtualInstances, rootId)
end
return Reconciler
return Reconciler