Compare commits

..

6 Commits

Author SHA1 Message Date
867a9c4e61 Refactor NotificationContext to Streamline Notification Fetching Logic
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Removed the useEffectEvent for fetching notifications and integrated the fetching logic directly into the useEffect hooks for improved clarity and performance.
- Updated dependency arrays to ensure notifications are fetched correctly based on authentication and connection status, enhancing responsiveness to state changes.
2026-08-21 11:09:49 +01:00
0225e229d8 Enhance MacOS Vibrancy Styles for Light and Dark Modes
- Updated CSS for MacOS vibrancy to include styles for the dashboard splitter in both light and dark modes, ensuring consistent background appearance across components.
- Improved specificity of styles for the ant-layout main content layout and splitter bar dragger to enhance visual clarity and user experience.
2026-08-21 11:09:38 +01:00
368e2ba9ef Refactor Tooltip Component to Improve Hover Target Management
- Introduced a variable for hovered targets in the Tooltip component to enhance clarity and maintainability of the hover state management.
- Updated the cleanup logic to directly reference the hovered targets variable, streamlining the event listener removal process.
2026-08-21 11:09:27 +01:00
8ff21a69a3 Remove unused 'lockResizeFor' prop from DashboardSidebarSplitter component to streamline code and improve clarity. 2026-08-21 11:09:13 +01:00
edf47b7c21 Update NotesPanel to Include 'type' in Dependency Array
- Modified the dependency array in the useEffect hook of the NotesPanel component to include 'type', ensuring that the effect re-runs when the type prop changes. This enhances the component's responsiveness to prop updates.
2026-08-21 11:08:59 +01:00
802de940ab Refactor CodeBlockEditor and Extract Utility Functions
- Moved the `toEditorCode` and `getCodeLanguageExtension` functions from CodeBlockEditor to a new utility file, `codeBlockEditorUtils.js`, for better code organization and reusability.
- Updated imports in CodeDiffViewer and DiffLabel components to reference the new utility file, ensuring consistent functionality across the application.
2026-08-21 11:08:42 +01:00
9 changed files with 102 additions and 93 deletions

View File

@ -143,11 +143,21 @@ html.macos-vibrancy .main-layout {
background: transparent !important; background: transparent !important;
} }
html.macos-vibrancy .light-mode .ant-layout.main-content-layout { html.macos-vibrancy .light-mode .ant-layout.main-content-layout,
html.macos-vibrancy
.light-mode
.dashboard-splitter.farmcontrol-splitter
> .ant-splitter-bar
.ant-splitter-bar-dragger:before {
background: rgba(255, 255, 255, 0.88) !important; background: rgba(255, 255, 255, 0.88) !important;
} }
html.macos-vibrancy .dark-mode .ant-layout.main-content-layout { html.macos-vibrancy .dark-mode .ant-layout.main-content-layout,
html.macos-vibrancy
.dark-mode
.dashboard-splitter.farmcontrol-splitter
> .ant-splitter-bar
.ant-splitter-bar-dragger:before {
background: rgba(0, 0, 0, 0.88) !important; background: rgba(0, 0, 0, 0.88) !important;
} }

View File

@ -3,25 +3,14 @@ import PropTypes from 'prop-types'
import CodeMirror from '@uiw/react-codemirror' import CodeMirror from '@uiw/react-codemirror'
import { EditorView, Decoration, ViewPlugin } from '@codemirror/view' import { EditorView, Decoration, ViewPlugin } from '@codemirror/view'
import { StateField } from '@codemirror/state' import { StateField } from '@codemirror/state'
import { python } from '@codemirror/lang-python'
import { javascriptLang } from '../../../codemirror/javascriptLang'
import { json } from '@codemirror/lang-json'
import { css } from '@codemirror/lang-css'
import { html } from '@codemirror/lang-html'
import { markdown } from '@codemirror/lang-markdown'
import { sql } from '@codemirror/lang-sql'
import { java } from '@codemirror/lang-java'
import { cpp } from '@codemirror/lang-cpp'
import { rust } from '@codemirror/lang-rust'
import { go } from '@codemirror/lang-go'
import { php } from '@codemirror/lang-php'
import { yaml } from '@codemirror/lang-yaml'
import { xml } from '@codemirror/lang-xml'
import { import {
farmControlDark, farmControlDark,
farmControlLight farmControlLight
} from '../../../codemirror/farmControlTheme' } from '../../../codemirror/farmControlTheme'
import { fcTemplateLang } from '../../../codemirror/fcTemplateLang' import {
getCodeLanguageExtension,
toEditorCode
} from './codeBlockEditorUtils'
import { useThemeContext } from '../context/ThemeContext' import { useThemeContext } from '../context/ThemeContext'
import ScrollBox from './ScrollBox' import ScrollBox from './ScrollBox'
import { Button, Modal, Typography, Card } from 'antd' import { Button, Modal, Typography, Card } from 'antd'
@ -99,64 +88,6 @@ function createScrollBoxSyncExtension() {
) )
} }
export function toEditorCode(code, language = 'javascript') {
if (code == null) return ''
if (typeof code === 'object' && language === 'json') {
return JSON.stringify(code, null, 2)
}
return String(code)
}
export function getCodeLanguageExtension(
language = 'javascript',
autoCompleteObject = null
) {
const lang = Array.isArray(language) ? language[0] : language
switch (String(lang || 'javascript').toLowerCase()) {
case 'javascript':
case 'js':
return javascriptLang({ autoCompleteObject })
case 'python':
case 'py':
return python()
case 'json':
return json()
case 'xml':
return xml()
case 'fctemplatelang':
case 'ejs':
return fcTemplateLang({ autoCompleteObject })
case 'html':
return html()
case 'css':
return css()
case 'markdown':
case 'md':
return markdown()
case 'sql':
return sql()
case 'java':
return java()
case 'cpp':
case 'c++':
case 'c':
return cpp()
case 'rust':
case 'rs':
return rust()
case 'go':
return go()
case 'php':
return php()
case 'yaml':
case 'yml':
return yaml()
default:
return javascriptLang({ autoCompleteObject })
}
}
function buildErrorLineDecorations(state, errorLineSet) { function buildErrorLineDecorations(state, errorLineSet) {
if (!errorLineSet.size) { if (!errorLineSet.size) {
return Decoration.none return Decoration.none

View File

@ -12,7 +12,7 @@ import { useThemeContext } from '../context/ThemeContext'
import { import {
getCodeLanguageExtension, getCodeLanguageExtension,
toEditorCode toEditorCode
} from './CodeBlockEditor' } from './codeBlockEditorUtils'
export default function CodeDiffViewer({ export default function CodeDiffViewer({
oldCode = '', oldCode = '',

View File

@ -268,7 +268,6 @@ const DashboardSidebarSplitter = ({ sidebar, children }) => {
collapseSidebar, collapseSidebar,
collapsedWidth, collapsedWidth,
expandSidebar, expandSidebar,
lockResizeFor,
lockResizeUntilPointerUp lockResizeUntilPointerUp
] ]
) )

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import { Button, Modal, Typography, theme, Flex } from 'antd' import { Button, Modal, Typography, theme, Flex } from 'antd'
import { presentableDiff } from '@codemirror/merge' import { presentableDiff } from '@codemirror/merge'
import CodeDiffViewer from './CodeDiffViewer' import CodeDiffViewer from './CodeDiffViewer'
import { toEditorCode } from './CodeBlockEditor' import { toEditorCode } from './codeBlockEditorUtils'
const { Link, Text } = Typography const { Link, Text } = Typography

View File

@ -109,7 +109,7 @@ const NotesPanel = ({ _id, type }) => {
subscribeToObjectTypeUpdatesRef.current = null subscribeToObjectTypeUpdatesRef.current = null
} }
} }
}, [_id, subscribeToObjectTypeUpdates, connected, handleReloadData]) }, [_id, type, subscribeToObjectTypeUpdates, connected, handleReloadData])
useEffect(() => { useEffect(() => {
if ( if (

View File

@ -55,6 +55,8 @@ const Tooltip = ({ children, title, content, listenParents = 0 }) => {
const span = spanRef.current const span = spanRef.current
if (!span || listenParents < 1) return if (!span || listenParents < 1) return
const hoveredTargets = hoveredTargetsRef.current
const handleEnter = (event) => onMouseEnterRef.current(event) const handleEnter = (event) => onMouseEnterRef.current(event)
const handleLeave = (event) => onMouseLeaveRef.current(event) const handleLeave = (event) => onMouseLeaveRef.current(event)
@ -75,7 +77,7 @@ const Tooltip = ({ children, title, content, listenParents = 0 }) => {
parent.removeEventListener('mouseenter', handleEnter) parent.removeEventListener('mouseenter', handleEnter)
parent.removeEventListener('mouseleave', handleLeave) parent.removeEventListener('mouseleave', handleLeave)
}) })
hoveredTargetsRef.current.clear() hoveredTargets.clear()
} }
}, [listenParents]) }, [listenParents])

View File

@ -0,0 +1,73 @@
import { python } from '@codemirror/lang-python'
import { javascriptLang } from '../../../codemirror/javascriptLang'
import { json } from '@codemirror/lang-json'
import { css } from '@codemirror/lang-css'
import { html } from '@codemirror/lang-html'
import { markdown } from '@codemirror/lang-markdown'
import { sql } from '@codemirror/lang-sql'
import { java } from '@codemirror/lang-java'
import { cpp } from '@codemirror/lang-cpp'
import { rust } from '@codemirror/lang-rust'
import { go } from '@codemirror/lang-go'
import { php } from '@codemirror/lang-php'
import { yaml } from '@codemirror/lang-yaml'
import { xml } from '@codemirror/lang-xml'
import { fcTemplateLang } from '../../../codemirror/fcTemplateLang'
export function toEditorCode(code, language = 'javascript') {
if (code == null) return ''
if (typeof code === 'object' && language === 'json') {
return JSON.stringify(code, null, 2)
}
return String(code)
}
export function getCodeLanguageExtension(
language = 'javascript',
autoCompleteObject = null
) {
const lang = Array.isArray(language) ? language[0] : language
switch (String(lang || 'javascript').toLowerCase()) {
case 'javascript':
case 'js':
return javascriptLang({ autoCompleteObject })
case 'python':
case 'py':
return python()
case 'json':
return json()
case 'xml':
return xml()
case 'fctemplatelang':
case 'ejs':
return fcTemplateLang({ autoCompleteObject })
case 'html':
return html()
case 'css':
return css()
case 'markdown':
case 'md':
return markdown()
case 'sql':
return sql()
case 'java':
return java()
case 'cpp':
case 'c++':
case 'c':
return cpp()
case 'rust':
case 'rs':
return rust()
case 'go':
return go()
case 'php':
return php()
case 'yaml':
case 'yml':
return yaml()
default:
return javascriptLang({ autoCompleteObject })
}
}

View File

@ -3,8 +3,7 @@ import {
useState, useState,
useContext, useContext,
useCallback, useCallback,
useEffect, useEffect
useEffectEvent
} from 'react' } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { notification, Drawer } from 'antd' import { notification, Drawer } from 'antd'
@ -60,11 +59,6 @@ const NotificationProvider = ({ children }) => {
} }
}, [authenticated, fetchNotificationsApi, showError]) }, [authenticated, fetchNotificationsApi, showError])
const onFetchNotifications = useEffectEvent(() => {
if (!authenticated || !connected) return
fetchNotifications()
})
const markNotificationAsRead = useCallback( const markNotificationAsRead = useCallback(
async (notificationId) => { async (notificationId) => {
try { try {
@ -121,15 +115,15 @@ const NotificationProvider = ({ children }) => {
// Initial load / when we become authenticated and connected // Initial load / when we become authenticated and connected
useEffect(() => { useEffect(() => {
onFetchNotifications() if (!authenticated || !connected) return
}, [authenticated, connected]) fetchNotifications()
}, [authenticated, connected, fetchNotifications])
// Refresh when the notification center opens // Refresh when the notification center opens
useEffect(() => { useEffect(() => {
if (notificationCenterVisible) { if (!notificationCenterVisible || !authenticated || !connected) return
onFetchNotifications() fetchNotifications()
} }, [notificationCenterVisible, authenticated, connected, fetchNotifications])
}, [notificationCenterVisible])
useEffect(() => { useEffect(() => {
setNotificationCenterVisible(false) setNotificationCenterVisible(false)