mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 01:18:23 +00:00
fix: Fixed the multiselect issue on add new row and edit on validation onClick
This commit is contained in:
parent
e086ace613
commit
b8bb77e20c
5 changed files with 106 additions and 36 deletions
|
|
@ -1,11 +1,13 @@
|
|||
import React, { useState, useCallback, useMemo, useRef } from 'react';
|
||||
import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react';
|
||||
import Select from '@/_ui/Select';
|
||||
import { components } from 'react-select';
|
||||
import defaultStyles from '@/_ui/Select/styles';
|
||||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
import { Checkbox } from '@/_ui/CheckBox/CheckBox';
|
||||
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
||||
import { isArray, isString } from 'lodash';
|
||||
import { isArray } from 'lodash';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
const { MenuList } = components;
|
||||
|
||||
|
|
@ -132,11 +134,32 @@ export const CustomSelectColumn = ({
|
|||
optionsLoadingState = false,
|
||||
horizontalAlignment = 'left',
|
||||
isEditable,
|
||||
column,
|
||||
isNewRow,
|
||||
}) => {
|
||||
const validateWidget = useStore((state) => state.validateWidget, shallow);
|
||||
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const containerRef = useRef(null);
|
||||
const inputRef = useRef(null);
|
||||
|
||||
const validationData = validateWidget({
|
||||
validationObject: {
|
||||
customRule: { value: column.customRule },
|
||||
},
|
||||
widgetValue: value,
|
||||
customResolveObjects: { value },
|
||||
});
|
||||
const { isValid, validationError } = validationData;
|
||||
|
||||
useEffect(() => {
|
||||
const handleDocumentClick = (event) => {
|
||||
if ((isMulti || isNewRow) && !containerRef.current?.contains(event.target)) setIsFocused(false);
|
||||
};
|
||||
document.addEventListener('mousedown', handleDocumentClick);
|
||||
return () => document.removeEventListener('mousedown', handleDocumentClick);
|
||||
}, [isMulti, isNewRow]);
|
||||
|
||||
const customComponents = {
|
||||
MenuList: (props) => <CustomMenuList {...props} optionsLoadingState={optionsLoadingState} inputRef={inputRef} />,
|
||||
Option: CustomOption,
|
||||
|
|
@ -250,30 +273,52 @@ export const CustomSelectColumn = ({
|
|||
trigger={isMulti && !isFocused && isOverflowing() && ['hover', 'focus']}
|
||||
rootClose={true}
|
||||
>
|
||||
<div className="w-100 h-100 d-flex align-items-center" ref={containerRef}>
|
||||
<Select
|
||||
options={options}
|
||||
hasSearch={false}
|
||||
fuzzySearch={fuzzySearch}
|
||||
isDisabled={disabled}
|
||||
className={className}
|
||||
components={customComponents}
|
||||
value={selectedValue}
|
||||
onMenuInputFocus={() => setIsFocused(true)}
|
||||
onChange={handleChange}
|
||||
useCustomStyles={true}
|
||||
styles={customStyles}
|
||||
defaultValue={defaultValue}
|
||||
placeholder={placeholder}
|
||||
isMulti={isMulti}
|
||||
hideSelectedOptions={false}
|
||||
isClearable={false}
|
||||
clearIndicator={false}
|
||||
darkMode={darkMode}
|
||||
menuIsOpen={isFocused || undefined}
|
||||
isFocused={isFocused || undefined}
|
||||
/>
|
||||
</div>
|
||||
<>
|
||||
<div
|
||||
className="w-100 h-100 d-flex align-items-center"
|
||||
ref={containerRef}
|
||||
onClick={() => {
|
||||
if (isNewRow && isEditable) {
|
||||
setIsFocused((prev) => !prev);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Select
|
||||
options={options}
|
||||
hasSearch={false}
|
||||
fuzzySearch={fuzzySearch}
|
||||
isDisabled={disabled}
|
||||
className={className}
|
||||
components={customComponents}
|
||||
value={selectedValue}
|
||||
onMenuInputFocus={() => {
|
||||
setIsFocused(true);
|
||||
}}
|
||||
onChange={handleChange}
|
||||
useCustomStyles={true}
|
||||
styles={customStyles}
|
||||
defaultValue={defaultValue}
|
||||
placeholder={placeholder}
|
||||
isMulti={isMulti}
|
||||
hideSelectedOptions={false}
|
||||
isClearable={false}
|
||||
clearIndicator={false}
|
||||
darkMode={darkMode}
|
||||
menuIsOpen={isFocused || undefined}
|
||||
isFocused={isFocused || undefined}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
onClick={() => {
|
||||
if (!isValid) {
|
||||
setIsFocused(true); // Open the dropdown
|
||||
}
|
||||
}}
|
||||
className={` ${isValid ? 'd-none' : 'invalid-feedback d-block'}`}
|
||||
>
|
||||
{validationError}
|
||||
</div>
|
||||
</>
|
||||
</OverlayTrigger>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -70,6 +70,12 @@ export const StringColumn = ({
|
|||
(ref?.current?.clientWidth < ref?.current?.children[0]?.offsetWidth ||
|
||||
ref?.current?.clientHeight < ref?.current?.children[0]?.offsetHeight);
|
||||
|
||||
const focusInput = () => {
|
||||
if (ref.current) {
|
||||
ref.current.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const renderEditableContent = () => (
|
||||
<div className="h-100 d-flex flex-column justify-content-center position-relative">
|
||||
<div
|
||||
|
|
@ -106,11 +112,16 @@ export const StringColumn = ({
|
|||
setIsEditing(true);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
suppressContentEditableWarning={true}
|
||||
>
|
||||
<HighLightSearch text={String(cellValue)} searchTerm={searchText} />
|
||||
</div>
|
||||
</div>
|
||||
{!isValid && <div className="invalid-feedback text-truncate">{validationError}</div>}
|
||||
{!isValid && (
|
||||
<div className="invalid-feedback text-truncate" onClick={focusInput}>
|
||||
{validationError}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,12 @@ export const TextColumn = ({
|
|||
[cellTextColor, isMaxRowHeightAuto, maxRowHeightValue, cellHeight]
|
||||
);
|
||||
|
||||
const focusInput = () => {
|
||||
if (cellRef.current) {
|
||||
cellRef.current.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const renderContent = useCallback(() => {
|
||||
if (!isEditable) {
|
||||
return (
|
||||
|
|
@ -95,7 +101,7 @@ export const TextColumn = ({
|
|||
darkMode ? 'textarea-dark-theme' : ''
|
||||
}`}
|
||||
style={{
|
||||
...cellStyle,
|
||||
color: cellTextColor || 'inherit',
|
||||
maxWidth: containerWidth,
|
||||
outline: 'none',
|
||||
border: 'none',
|
||||
|
|
@ -112,22 +118,25 @@ export const TextColumn = ({
|
|||
handleContentChange(e.target.innerHTML);
|
||||
}
|
||||
}}
|
||||
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(cellValue) }}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={() => setIsEditing(true)}
|
||||
/>
|
||||
suppressContentEditableWarning={true}
|
||||
>
|
||||
<HighLightSearch text={String(cellValue)} searchTerm={searchText} />
|
||||
</div>
|
||||
);
|
||||
}, [
|
||||
isEditable,
|
||||
isValid,
|
||||
darkMode,
|
||||
cellStyle,
|
||||
cellTextColor,
|
||||
containerWidth,
|
||||
cellValue,
|
||||
handleKeyDown,
|
||||
handleContentChange,
|
||||
horizontalAlignment,
|
||||
cellValue,
|
||||
searchText,
|
||||
horizontalAlignment,
|
||||
cellStyle,
|
||||
handleContentChange,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
|
@ -166,7 +175,11 @@ export const TextColumn = ({
|
|||
>
|
||||
{renderContent()}
|
||||
</div>
|
||||
{isEditable && !isValid && <div className="invalid-feedback text-truncate">{validationError}</div>}
|
||||
{isEditable && !isValid && (
|
||||
<div className="invalid-feedback text-truncate" onClick={focusInput}>
|
||||
{validationError}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ export const TableRow = ({
|
|||
className={`td-container ${
|
||||
cell.column.columnDef?.meta?.columnType === 'image' && 'jet-table-image-column h-100'
|
||||
} ${cell.column.columnDef?.meta?.columnType !== 'image' && `w-100 h-100`}`}
|
||||
style={{ display: 'flex', alignItems: 'center' }}
|
||||
>
|
||||
{flexRender(cell.column?.columnDef?.cell, cell.getContext())}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -219,6 +219,8 @@ export default function generateColumnsData({
|
|||
isEditable={isEditable}
|
||||
isMulti={columnType === 'newMultiSelect'}
|
||||
className="select-search table-select-search"
|
||||
column={column}
|
||||
isNewRow={columnForAddNewRow}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue