Merge pull request #12252 from ToolJet/fix/ui-code-hinter-issues

Fix/UI code hinter issues
This commit is contained in:
Johnson Cherian 2025-03-21 14:03:33 +05:30 committed by GitHub
commit 62d381e5c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 110 additions and 52 deletions

View file

@ -294,13 +294,9 @@ const PreviewContainer = ({
...restProps
}) => {
const { validationSchema, isWorkspaceVariable, errorStateActive, previewPlacement, validationFn } = restProps;
const [errorMessage, setErrorMessage] = useState('');
const typeofError = getCurrentNodeType(errorMessage);
const errorMsg = typeofError === 'Array' ? errorMessage[0] : errorMessage;
const darkMode = localStorage.getItem('darkMode') === 'true';
const popover = (
<Popover
@ -423,10 +419,12 @@ const PreviewContainer = ({
<>
{!isPortalOpen && (
<Overlay
placement="left"
placement={previewPlacement || 'left'}
{...(previewRef?.current ? { target: previewRef.current } : {})}
show={showPreview}
rootClose
shouldUpdatePosition={true}
container={document.body}
popperConfig={{
modifiers: [
{
@ -441,6 +439,7 @@ const PreviewContainer = ({
{
name: 'preventOverflow',
options: {
enabled: true,
boundary: 'viewport',
altAxis: true,
tether: false,
@ -449,10 +448,17 @@ const PreviewContainer = ({
{
name: 'offset',
options: {
offset: [33, 15],
offset: [0, 3],
},
},
],
onFirstUpdate: (state) => {
// Force position update on first render
// This is done to avoid scroll issue
if (state.elements.popper) {
state.elements.popper.style.position = 'fixed';
}
},
}}
>
{(props) => React.cloneElement(popover, props)}

View file

@ -1,5 +1,5 @@
/* eslint-disable import/no-unresolved */
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { PreviewBox } from './PreviewBox';
import { ToolTip } from '@/Editor/Inspector/Elements/Components/ToolTip';
import { useTranslation } from 'react-i18next';
@ -31,6 +31,7 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r
const [currentValue, setCurrentValue] = useState('');
const [errorStateActive, setErrorStateActive] = useState(false);
const [cursorInsidePreview, setCursorInsidePreview] = useState(false);
const [showSuggestions, setShowSuggestions] = useState(true);
const validationFn = restProps?.validationFn;
const componentDefinition = useStore((state) => state.getComponentDefinition(componentId), shallow);
const parentId = componentDefinition?.component?.parent;
@ -38,6 +39,30 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r
const customVariables = customResolvables?.[parentId]?.[0] || {};
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.intersectionRatio < 1) {
setShowPreview(false);
setShowSuggestions(false);
} else {
setShowSuggestions(true);
}
},
{ root: null, threshold: [1] } // Fires when any part of the element is out of view
);
if (wrapperRef.current) {
observer.observe(wrapperRef.current);
}
return () => {
if (wrapperRef.current) {
observer.unobserve(wrapperRef.current);
}
};
}, []);
const isPreviewFocused = useRef(false);
const wrapperRef = useRef(null);
@ -136,6 +161,7 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r
componentName={componentName}
setShowPreview={setShowPreview}
showPreview={showPreview}
showSuggestions={showSuggestions}
{...restProps}
/>
</div>
@ -168,6 +194,7 @@ const EditorInput = ({
previewRef,
setShowPreview,
onInputChange,
showSuggestions,
}) => {
const getSuggestions = useStore((state) => state.getSuggestions, shallow);
function autoCompleteExtensionConfig(context) {
@ -223,7 +250,7 @@ const EditorInput = ({
defaultKeymap: true,
positionInfo: () => {
return {
class: 'cm-completionInfo-top cm-custom-completion-info',
class: 'cm-completionInfo-top cm-custom-completion-info cm-custom-singleline-completion-info',
};
},
maxRenderedOptions: 10,
@ -286,7 +313,7 @@ const EditorInput = ({
const isInsideQueryPane = !!currentEditorHeightRef?.current?.closest('.query-details');
const showLineNumbers = lang == 'jsx' || type === 'extendedSingleLine' || false;
const customClassNames = cx('codehinter-input', {
const customClassNames = cx('codehinter-input single-line-codehinter-input', {
'border-danger': error,
focused: isFocused,
'focus-box-shadow-active': firstTimeFocus,
@ -339,15 +366,6 @@ const EditorInput = ({
data-cy={`${cyLabel.replace(/_/g, '-')}-input-field`}
>
{/* sticky element to position the preview box correctly on top without flowing out of container */}
<div
style={{
position: 'sticky',
top: 0,
left: 0,
zIndex: 1000,
}}
ref={previewRef}
></div>
{usePortalEditor && (
<CodeHinter.PopupIcon
callback={handleTogglePopupExapand}
@ -372,39 +390,55 @@ const EditorInput = ({
callgpt={null}
>
<ErrorBoundary>
<CodeMirror
value={currentValue}
placeholder={placeholder}
height={isInsideQueryPane ? '100%' : showLineNumbers ? '400px' : '100%'}
width="100%"
extensions={[
javascript({ jsx: lang === 'jsx' }),
autoCompleteConfig,
keymap.of([...customKeyMaps]),
customTabKeymap,
]}
onChange={(val) => {
setFirstTimeFocus(false);
handleOnChange(val);
onInputChange && onInputChange(val);
<div
style={{
position: 'relative',
top: 0,
left: 0,
width: '100%',
height: '100%',
}}
basicSetup={{
lineNumbers: showLineNumbers,
syntaxHighlighting: true,
bracketMatching: true,
foldGutter: false,
highlightActiveLine: false,
autocompletion: true,
completionKeymap: true,
searchKeymap: false,
}}
onMouseDown={() => handleFocus()}
onBlur={() => handleOnBlur()}
className={customClassNames}
theme={theme}
indentWithTab={false}
readOnly={disabled}
/>
className="check-here"
ref={previewRef}
>
<CodeMirror
value={currentValue}
placeholder={placeholder}
height={isInsideQueryPane ? '100%' : showLineNumbers ? '400px' : '100%'}
width="100%"
extensions={
showSuggestions
? [
javascript({ jsx: lang === 'jsx' }),
autoCompleteConfig,
keymap.of([...customKeyMaps]),
customTabKeymap,
]
: [javascript({ jsx: lang === 'jsx' })]
}
onChange={(val) => {
setFirstTimeFocus(false);
handleOnChange(val);
onInputChange && onInputChange(val);
}}
basicSetup={{
lineNumbers: showLineNumbers,
syntaxHighlighting: true,
bracketMatching: true,
foldGutter: false,
highlightActiveLine: false,
autocompletion: showSuggestions,
completionKeymap: true,
searchKeymap: false,
}}
onMouseDown={() => handleFocus()}
onBlur={() => handleOnBlur()}
className={customClassNames}
theme={theme}
indentWithTab={false}
readOnly={disabled}
/>
</div>
</ErrorBoundary>
</CodeHinter.Portal>
</div>

View file

@ -655,6 +655,11 @@
background-color: #F28F2D !important;
}
.cm-custom-singleline-completion-info {
display: none;
}
.tjdb-hinter-portal{
.cm-theme{
height: 100% ;

View file

@ -177,7 +177,7 @@ class TableComponent extends React.Component {
style={{
width: '280px',
maxHeight: resolveReferences(column.isEditable) ? '100vh' : 'inherit',
overflowY: 'auto',
// overflowY: 'auto',
zIndex: '9999',
}}
>

View file

@ -1543,7 +1543,7 @@ button {
.tab-content {
overflow-y: auto;
// TAB HEADER HEIGHT + FOOTER HEIGHT + Extra padding = 120px
height: calc(100vh - 7.5rem);
height: calc(100vh - 10.4rem);
// Hide scrollbar
-ms-overflow-style: none;
/* IE and Edge */
@ -18577,6 +18577,12 @@ section.ai-message-prompt-input-wrapper {
flex-grow: 1;
}
}
.cm-tooltip {
z-index: 9999 !important;
}
.workspace-constant-value {
position: relative;
@ -18625,3 +18631,10 @@ section.ai-message-prompt-input-wrapper {
}
}
}
.single-line-codehinter-input {
.cm-editor {
max-height: 100px !important;
}
}