diff --git a/plugin/src/App/StatusPages/Confirming.lua b/plugin/src/App/StatusPages/Confirming.lua index 7819ab54..75f5708c 100644 --- a/plugin/src/App/StatusPages/Confirming.lua +++ b/plugin/src/App/StatusPages/Confirming.lua @@ -153,15 +153,15 @@ function ConfirmingPage:render() onClick = self.props.onAbort, }), - PullAll = e(TextButton, { - text = "Pull All", - style = "Danger", - transparency = self.props.transparency, - layoutOrder = 2, - onClick = function() - self.setAllSelections("pull") - end, - }), + PullAll = e(TextButton, { + text = "Pull All", + style = "Danger", + transparency = self.props.transparency, + layoutOrder = 2, + onClick = function() + self.setAllSelections("pull") + end, + }), SkipAll = e(TextButton, { text = "Skip All", diff --git a/plugin/src/App/init.lua b/plugin/src/App/init.lua index 6583f71f..e368ad03 100644 --- a/plugin/src/App/init.lua +++ b/plugin/src/App/init.lua @@ -571,22 +571,25 @@ function App:useRunningConnectionInfo() end function App:startSession() - local claimedLock, priorOwner = self:claimSyncLock() - if not claimedLock then - local msg = string.format("Could not sync because user '%s' is already syncing", tostring(priorOwner)) + -- Skip session lock in one-shot mode since it's a quick sync-and-disconnect + if not Settings:get("oneShotSync") then + local claimedLock, priorOwner = self:claimSyncLock() + if not claimedLock then + local msg = string.format("Could not sync because user '%s' is already syncing", tostring(priorOwner)) - Log.warn(msg) - self:addNotification({ - text = msg, - timeout = 10, - }) - self:setState({ - appStatus = AppStatus.Error, - errorMessage = msg, - toolbarIcon = Assets.Images.PluginButtonWarning, - }) + Log.warn(msg) + self:addNotification({ + text = msg, + timeout = 10, + }) + self:setState({ + appStatus = AppStatus.Error, + errorMessage = msg, + toolbarIcon = Assets.Images.PluginButtonWarning, + }) - return + return + end end local host, port = self:getHostAndPort() @@ -671,7 +674,10 @@ function App:startSession() }) elseif status == ServeSession.Status.Disconnected then self.serveSession = nil - self:releaseSyncLock() + -- Only release lock if we claimed it (not in one-shot mode) + if not Settings:get("oneShotSync") then + self:releaseSyncLock() + end self:clearRunningConnectionInfo() self:setState({ patchData = { @@ -709,6 +715,10 @@ function App:startSession() end) serveSession:setConfirmCallback(function(instanceMap, patch, serverInfo) + -- Filter out the DataModel name change from the patch + -- The project name (DataModel.Name) is managed by Studio independently + PatchSet.removeDataModelName(patch, instanceMap) + local isOneShotMode = Settings:get("oneShotSync") -- ONE-SHOT MODE: Never auto-accept, always require explicit confirmation @@ -759,24 +769,6 @@ function App:startSession() return "Accept" end end - - -- The datamodel name gets overwritten by Studio, making confirmation of it intrusive - -- and unnecessary. This special case allows it to be accepted without confirmation. - if - PatchSet.hasAdditions(patch) == false - and PatchSet.hasRemoves(patch) == false - and PatchSet.containsOnlyInstance(patch, instanceMap, game) - then - local datamodelUpdates = PatchSet.getUpdateForInstance(patch, instanceMap, game) - if - datamodelUpdates ~= nil - and next(datamodelUpdates.changedProperties) == nil - and datamodelUpdates.changedClassName == nil - then - Log.trace("Accepting patch without confirmation because it only contains a datamodel name change") - return "Accept" - end - end else Log.info("One-shot mode: skipping all auto-accept paths, requiring explicit confirmation") end diff --git a/plugin/src/PatchSet.lua b/plugin/src/PatchSet.lua index 281f147a..7e516972 100644 --- a/plugin/src/PatchSet.lua +++ b/plugin/src/PatchSet.lua @@ -394,6 +394,34 @@ function PatchSet.updatedIdList(patchSet): { string } return table.freeze(idList) end +--[[ + Remove the Name property change from the DataModel update in the patch. + This prevents the project name from being synced, which is usually + unwanted as Studio manages the DataModel name independently. + Mutates the patch in place for efficiency. +]] +function PatchSet.removeDataModelName(patchSet, instanceMap) + local dataModelId = instanceMap.fromInstances[game] + if dataModelId == nil then + return + end + + for i, update in ipairs(patchSet.updated) do + if update.id == dataModelId and update.changedName ~= nil then + update.changedName = nil + -- Remove update entirely if no other changes remain + if + update.changedClassName == nil + and update.changedMetadata == nil + and next(update.changedProperties) == nil + then + table.remove(patchSet.updated, i) + end + return + end + end +end + --[[ Create a list of human-readable statements summarizing the contents of this patch, intended to be displayed to users.