diff --git a/CHANGELOG.md b/CHANGELOG.md index 204cea8d..83c1ebeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,14 @@ * Added support for optional paths in project files. ([#472]) * Added support for the new Open Cloud API when uploading. ([#504]) * Added `sourcemap` command for generating sourcemaps to feed into other tools. ([#530]) +* Added PluginActions for connecting/disconnecting a session ([#537]) * Added changing toolbar icon to indicate state ([#538]) [#472]: https://github.com/rojo-rbx/rojo/pull/472 [#504]: https://github.com/rojo-rbx/rojo/pull/504 [#507]: https://github.com/rojo-rbx/rojo/pull/507 [#530]: https://github.com/rojo-rbx/rojo/pull/530 +[#537]: https://github.com/rojo-rbx/rojo/pull/537 [#538]: https://github.com/rojo-rbx/rojo/pull/538 ## [7.0.0] - December 10, 2021 diff --git a/plugin/src/App/Components/Studio/StudioPluginAction.lua b/plugin/src/App/Components/Studio/StudioPluginAction.lua new file mode 100644 index 00000000..458bd4fc --- /dev/null +++ b/plugin/src/App/Components/Studio/StudioPluginAction.lua @@ -0,0 +1,40 @@ +local Rojo = script:FindFirstAncestor("Rojo") +local Plugin = Rojo.Plugin + +local Roact = require(Rojo.Roact) + +local Dictionary = require(Plugin.Dictionary) + +local StudioPluginContext = require(script.Parent.StudioPluginContext) + +local e = Roact.createElement + +local StudioPluginAction = Roact.Component:extend("StudioPluginAction") + +function StudioPluginAction:init() + self.pluginAction = self.props.plugin:CreatePluginAction( + self.props.name, self.props.title, self.props.description, self.props.icon, self.props.bindable + ) + + self.pluginAction.Triggered:Connect(self.props.onTriggered) +end + +function StudioPluginAction:render() + return nil +end + +function StudioPluginAction:willUnmount() + self.pluginAction:Destroy() +end + +local function StudioPluginActionWrapper(props) + return e(StudioPluginContext.Consumer, { + render = function(plugin) + return e(StudioPluginAction, Dictionary.merge(props, { + plugin = plugin, + })) + end, + }) +end + +return StudioPluginActionWrapper diff --git a/plugin/src/App/StatusPages/NotConnected.lua b/plugin/src/App/StatusPages/NotConnected.lua index 083f22c2..fb9434fc 100644 --- a/plugin/src/App/StatusPages/NotConnected.lua +++ b/plugin/src/App/StatusPages/NotConnected.lua @@ -82,11 +82,6 @@ end local NotConnectedPage = Roact.Component:extend("NotConnectedPage") -function NotConnectedPage:init() - self.hostRef = Roact.createRef() - self.portRef = Roact.createRef() -end - function NotConnectedPage:render() return Roact.createFragment({ Header = e(Header, { @@ -95,8 +90,8 @@ function NotConnectedPage:render() }), AddressEntry = e(AddressEntry, { - hostRef = self.hostRef, - portRef = self.portRef, + hostRef = self.props.hostRef, + portRef = self.props.portRef, transparency = self.props.transparency, layoutOrder = 2, }), @@ -119,18 +114,7 @@ function NotConnectedPage:render() style = "Solid", transparency = self.props.transparency, layoutOrder = 2, - onClick = function() - local hostText = self.hostRef.current.Text - local portText = self.portRef.current.Text - - lastHost = hostText - lastPort = portText - - self.props.onConnect( - #hostText > 0 and hostText or Config.defaultHost, - #portText > 0 and portText or Config.defaultPort - ) - end, + onClick = self.props.onConnect, }), Layout = e("UIListLayout", { @@ -156,4 +140,4 @@ function NotConnectedPage:render() }) end -return NotConnectedPage \ No newline at end of file +return NotConnectedPage diff --git a/plugin/src/App/init.lua b/plugin/src/App/init.lua index 78c94015..e6dd50c7 100644 --- a/plugin/src/App/init.lua +++ b/plugin/src/App/init.lua @@ -16,6 +16,7 @@ local Theme = require(script.Theme) local PluginSettings = require(script.PluginSettings) local Page = require(script.Page) +local StudioPluginAction = require(script.Components.Studio.StudioPluginAction) local StudioToolbar = require(script.Components.Studio.StudioToolbar) local StudioToggleButton = require(script.Components.Studio.StudioToggleButton) local StudioPluginGui = require(script.Components.Studio.StudioPluginGui) @@ -37,6 +38,9 @@ local App = Roact.Component:extend("App") function App:init() preloadAssets() + self.hostRef = Roact.createRef() + self.portRef = Roact.createRef() + self:setState({ appStatus = AppStatus.NotConnected, guiEnabled = false, @@ -44,7 +48,17 @@ function App:init() }) end -function App:startSession(host, port, sessionOptions) +function App:startSession() + local hostText = self.hostRef.current.Text + local portText = self.portRef.current.Text + + local host = if #hostText > 0 then hostText else Config.defaultHost + local port = if #portText > 0 then portText else Config.defaultPort + local sessionOptions = { + openScriptsExternally = self.props.settings:get("openScriptsExternally"), + twoWaySync = self.props.settings:get("twoWaySync"), + } + local baseUrl = ("http://%s:%s"):format(host, port) local apiContext = ApiContext.new(baseUrl) @@ -68,6 +82,8 @@ function App:startSession(host, port, sessionOptions) address = address, toolbarIcon = Assets.Images.PluginButtonConnected, }) + + Log.info("Connected to session '{}' at {}", details, address) elseif status == ServeSession.Status.Disconnected then self.serveSession = nil @@ -86,6 +102,8 @@ function App:startSession(host, port, sessionOptions) appStatus = AppStatus.NotConnected, toolbarIcon = Assets.Images.PluginButton, }) + + Log.info("Disconnected session") end end end) @@ -95,6 +113,22 @@ function App:startSession(host, port, sessionOptions) self.serveSession = serveSession end +function App:endSession() + if self.serveSession == nil then + return + end + + Log.trace("Disconnecting session") + + self.serveSession:stop() + self.serveSession = nil + self:setState({ + appStatus = AppStatus.NotConnected, + }) + + Log.trace("Session terminated by user") +end + function App:render() local pluginName = "Rojo " .. Version.display(Config.version) @@ -141,22 +175,20 @@ function App:render() }) end, }, { - NotConnectedPage = PluginSettings.with(function(settings) - return createPageElement(AppStatus.NotConnected, { - onConnect = function(host, port) - self:startSession(host, port, { - openScriptsExternally = settings:get("openScriptsExternally"), - twoWaySync = settings:get("twoWaySync"), - }) - end, + NotConnectedPage = createPageElement(AppStatus.NotConnected, { + hostRef = self.hostRef, + portRef = self.portRef, - onNavigateSettings = function() - self:setState({ - appStatus = AppStatus.Settings, - }) - end, - }) - end), + onConnect = function() + self:startSession() + end, + + onNavigateSettings = function() + self:setState({ + appStatus = AppStatus.Settings, + }) + end, + }), Connecting = createPageElement(AppStatus.Connecting), @@ -165,15 +197,7 @@ function App:render() address = self.state.address, onDisconnect = function() - Log.trace("Disconnecting session") - - self.serveSession:stop() - self.serveSession = nil - self:setState({ - appStatus = AppStatus.NotConnected, - }) - - Log.trace("Session terminated by user") + self:endSession() end, }), @@ -206,6 +230,51 @@ function App:render() end), }), + toggleAction = e(StudioPluginAction, { + name = "RojoConnection", + title = "Rojo: Connect/Disconnect", + description = "Toggles the server for a Rojo sync session", + icon = Assets.Images.PluginButton, + bindable = true, + onTriggered = function() + if self.serveSession then + self:endSession() + else + self:startSession() + end + end, + }), + + connectAction = e(StudioPluginAction, { + name = "RojoConnect", + title = "Rojo: Connect", + description = "Connects the server for a Rojo sync session", + icon = Assets.Images.PluginButton, + bindable = true, + onTriggered = function() + if self.serveSession then + return + end + + self:startSession() + end, + }), + + disconnectAction = e(StudioPluginAction, { + name = "RojoDisconnect", + title = "Rojo: Disconnect", + description = "Disconnects the server for a Rojo sync session", + icon = Assets.Images.PluginButton, + bindable = true, + onTriggered = function() + if not self.serveSession then + return + end + + self:endSession() + end, + }), + toolbar = e(StudioToolbar, { name = pluginName, }, { @@ -229,4 +298,15 @@ function App:render() }) end -return App +return function(props) + return e(PluginSettings.StudioProvider, { + plugin = props.plugin, + }, { + App = PluginSettings.with(function(settings) + local settingsProps = Dictionary.merge(props, { + settings = settings, + }) + return e(App, settingsProps) + end), + }) +end \ No newline at end of file