Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 72 additions & 69 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,69 +1,72 @@
.vscode
jsconfig.json

# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache

# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
yarn-error.log

# OSX
.DS_Store

# flow-typed
flow-typed/npm/*
!flow-typed/npm/module_vx.x.x.js

# App packaged
release
src/main.prod.js
src/main.prod.js.map
src/renderer.prod.js
src/renderer.prod.js.map
src/style.css
src/style.css.map
dist
dll
main.js
main.js.map

.idea
npm-debug.log.*

TODO

.npmrc
*.p12

# Yarn 3
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.nx/cache
.vscode
jsconfig.json

# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache

# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
yarn-error.log

# OSX
.DS_Store

# flow-typed
flow-typed/npm/*
!flow-typed/npm/module_vx.x.x.js

# App packaged
release
src/main.prod.js
src/main.prod.js.map
src/renderer.prod.js
src/renderer.prod.js.map
src/style.css
src/style.css.map
dist
dll
main.js
main.js.map

.idea
npm-debug.log.*

TODO

.npmrc
*.p12

# Yarn 3
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.nx/cache
temp_auto_push.bat
temp_interactive_push.bat
config.bat
37 changes: 19 additions & 18 deletions apps/example-app/babel.config.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo } from "react"
import styled from "styled-components"
import { MdCheckCircle as Checkmark } from "react-icons/md"
import { MdCheckCircle as Checkmark, MdClose as CloseIcon } from "react-icons/md"

import {
getIcon,
Expand All @@ -10,13 +10,18 @@ import {
} from "../../util/connectionHelpers"
import { Connection } from "../../contexts/Standalone/useStandalone"

const Container = styled.div`
interface ContainerProps {
$isConnected: boolean
}

const Container = styled.div<ContainerProps>`
display: flex;
flex-direction: row;
flex: 0 0 auto;
cursor: pointer;
margin-right: 20px;
align-items: center;
opacity: ${(props) => (props.$isConnected ? 1 : 0.5)};
`

const IconContainer = styled.div`
Expand All @@ -30,22 +35,57 @@ const CheckmarkContainer = styled.div`
color: green;
`

interface StatusDotProps {
$isConnected: boolean
}

const StatusDot = styled.div<StatusDotProps>`
position: absolute;
top: -2px;
left: -2px;
width: 10px;
height: 10px;
border-radius: 50%;
background-color: ${(props) => (props.$isConnected ? "#50c878" : "#ff6b6b")};
border: 2px solid ${(props) => props.theme.subtleLine};
`

const InfoContainer = styled.div`
margin-left: 10px;
`

const DeleteButton = styled.div`
margin-left: 8px;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #ff6b6b;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
flex-shrink: 0;

&:hover {
background-color: #ff4444;
}
`

interface ConnectionSelectorProps {
selectedConnection: Connection | null
connection: Connection
onClick: () => void
onDelete?: (clientId: string) => void
}

export default function ConnectionSelector({
selectedConnection,
connection,
onClick,
onDelete,
}: ConnectionSelectorProps) {
const isSelected = selectedConnection && selectedConnection.clientId === connection.clientId
const isConnected = connection.connected

const [ConnectionIcon, platformName, platformDetails, connectionName] = useMemo(() => {
return [
Expand All @@ -56,10 +96,18 @@ export default function ConnectionSelector({
]
}, [connection])

const handleDelete = (e: React.MouseEvent) => {
e.stopPropagation()
if (onDelete && !isConnected) {
onDelete(connection.clientId)
}
}

return (
<Container onClick={onClick}>
<Container onClick={onClick} $isConnected={isConnected}>
<IconContainer>
<ConnectionIcon size={32} />
<StatusDot $isConnected={isConnected} title={isConnected ? "Connected" : "Disconnected"} />
{isSelected && (
<CheckmarkContainer>
<Checkmark />
Expand All @@ -72,6 +120,11 @@ export default function ConnectionSelector({
{platformName} {platformDetails}
</div>
</InfoContainer>
{!isConnected && onDelete && (
<DeleteButton onClick={handleDelete} title="Remove disconnected connection">
<CloseIcon size={12} color="white" />
</DeleteButton>
)}
</Container>
)
}
19 changes: 15 additions & 4 deletions apps/reactotron-app/src/renderer/components/Footer/Stateless.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ function renderExpanded(
serverStatus: ServerStatus,
connections: Connection[],
selectedConnection: Connection | null,
onChangeConnection: (clientId: string | null) => void
onChangeConnection: (clientId: string | null) => void,
onDeleteConnection?: (clientId: string) => void
) {
return (
<ConnectionContainer>
Expand All @@ -92,6 +93,7 @@ function renderExpanded(
selectedConnection={selectedConnection}
connection={c}
onClick={() => onChangeConnection(c.clientId)}
onDelete={onDeleteConnection}
/>
))}
</ConnectionContainer>
Expand All @@ -111,10 +113,12 @@ function renderCollapsed(
connections: Connection[],
selectedConnection: Connection | null
) {
const activeConnections = connections.filter((c) => c.connected).length
const totalConnections = connections.length
return (
<>
<ConnectionInfo>
port {config.get("serverPort")} | {connections.length} connections
port {config.get("serverPort")} | {activeConnections}/{totalConnections} connections
</ConnectionInfo>
{serverStatus === "portUnavailable" && (
<ConnectionInfo>Port 9090 unavailable.</ConnectionInfo>
Expand All @@ -134,6 +138,7 @@ interface Props {
isOpen: boolean
setIsOpen: (isOpen: boolean) => void
onChangeConnection: (clientId: string | null) => void
onDeleteConnection?: (clientId: string) => void
mcpStatus: McpStatus
mcpPort: number | null
onToggleMcp: () => void
Expand All @@ -146,16 +151,22 @@ function Header({
isOpen,
setIsOpen,
onChangeConnection,
onDeleteConnection,
mcpStatus,
mcpPort,
onToggleMcp,
}: Props) {
const renderMethod = isOpen ? renderExpanded : renderCollapsed
const renderContent = () => {
if (isOpen) {
return renderExpanded(serverStatus, connections, selectedConnection, onChangeConnection, onDeleteConnection)
}
return renderCollapsed(serverStatus, connections, selectedConnection)
}

return (
<Container>
<ContentContainer onClick={() => !isOpen && setIsOpen(true)} $isOpen={isOpen}>
{renderMethod(serverStatus, connections, selectedConnection, onChangeConnection)}
{renderContent()}
<McpButton
$active={mcpStatus === "started"}
onClick={(e) => { e.stopPropagation(); onToggleMcp() }}
Expand Down
3 changes: 2 additions & 1 deletion apps/reactotron-app/src/renderer/components/Footer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import StandaloneContext from "../../contexts/Standalone"
import Footer from "./Stateless"

export default function ConnectedFooter() {
const { serverStatus, connections, selectedConnection, selectConnection, mcpStatus, mcpPort, toggleMcp } =
const { serverStatus, connections, selectedConnection, selectConnection, deleteConnection, mcpStatus, mcpPort, toggleMcp } =
useContext(StandaloneContext)
const [isOpen, setIsOpen] = useState(false)

Expand All @@ -15,6 +15,7 @@ export default function ConnectedFooter() {
connections={connections}
selectedConnection={selectedConnection}
onChangeConnection={selectConnection}
onDeleteConnection={deleteConnection}
isOpen={isOpen}
setIsOpen={setIsOpen}
mcpStatus={mcpStatus}
Expand Down
Loading