mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
* initial commit * redesign column manager * redesign string column type in the table * setting the color of the input field for string column type * setting bg of popover body * design the style tab of string column type * adjusted spaces in the properties and style elements in the column manager * fixed typo error * removed unwanted line * redesign the validation section of number column type manager * added the placeholder value for string column type min and max length in the validation section * replace text with icons for horizontal alignment in the style tab * show delete icon outside of the menu actions for each column in the table inspector * Revert "redesign string column type in the table" This reverts commita440f3fc23, which made changes for string column type in the table component on the canvas * making flex fill for horizontal alignment icon buttons in the style tab of column manager in the table * Bug fixed: event manager is not working in toggle column type * added decimalPlaces prop to number column manager * added text color and cell background props to style tab of number column manager * added few validations for number * created boolean column type consisting input checkbox working as toggle switch * allow user to select boolean column type from the component manager and display boolean column in the table on the canvas * making boolean component content consistent with the horizontal alignment * making Boolean column type functional adding editable and non-editale content to display on table * fixed horizonta alignment issue for boolean column * Revert "fixed horizonta alignment issue for boolean column" This reverts commitd41499a1ed. * making input elment vertically aligned * added generalised cell interaction * added props for boolean column types in column manager of table * added feature to provide custom bg to toggle switch * removed default value to toggleOnBg and toggleOffBg * conditionally displaying hardcoded value if toggleBg is not available * change the file and component name of existing customSelect to customDropdown * change component name * remove unwanted code * added select option to the column type dropdown field * Created component for select column type * rendering custom select component for select column type * adding border danger for invalid value * redesign column manager for select column type * bug fixed : disabling control to select column type when editable is off * changing the name key to label for select column type options * partially implemented make default option feature * Implemented default option for select column type * added text color prop in a styles tab to select column type * adding indigo color to selected option to select column type menu list * avoid breaking table if array is not provided for dynamicOption field * Organize the column manager and related files * Added validation fields in text column manager * Added text color to text area column type * Added validation to text column type * Avoiding bg to persisit for few column tupes, who dont have background field * bug fixed : other valdiation are not rendering for string column type * bug fixed: on hover always danger border is displayed for each cell * Cell density enhancement * Returning empty array for validationList for few column types * handling validation list by merging organizing-column-manager * Changed the select component in the properties tab of column popover * Changed the UI of validation according to new design also few column popover and action popover UI changes * Adding fx code block in style tab for text color and cell bg color * fixing UI of select column type column manager according to new UI * creating multiselect column and its UI wrt option list * added overlay trigger to multiselect * feat : added design theme new colors * fix : adding new color swatch to input components * fix : colors, number input with height less than 16px and number input arrow in padding none mdode * fix : icon color * few color fixes * overlay trigger for multi-select column type * color picker bug fixed * color changes * column type input text is not consistent with the dark theme- fixed * custom select single value container bug * manking add new row, hide column and download popover background consistent with the dark theme * Making add new row consistent with the updated UI changes * feat : link column type table * fix: default underline color * fix : sentence casing * added missing transformation field * fixes * fixing tab opening condition * fix : backward compatibility * supported multiple badges , tags for cell density propety * added feature to duplicate column * made td container overflow hidden * provided 100% width to Image fit prop in styles tab * oveflow hidden prop changes * revert unwanted change * change the gap between columns in column lists inside table inspector * Deprecate few column types in table * Fix * Fixes * change the functionality of cell density feature * Fix msg * Revamp date picker in table * Fix * fix : darkmode colors * revert * Supported cell density feature for multiple badges * making badges aligned center * madde tags column consistent with cell density feature * Remove imports * enhancing the code density feature * Making radio column consistent with the cell density feature * Fix unixtimestamp * Fix CSS issues * making tags and badges overlay appear only when content is overflowed * CSS fixes * Fix * Fix dark mode issues * making background transparent for deprecating columns making overlay visible on horizontal overflow * New revamped styles * fix box shadow * Migrations to move visibility and disabled states from styles to properties * undo change * refactored custom select component * patch fixes * bug fixed action popover was inconsistent with dark theme * testing * update custom select column type * fixes * Avoided options being populated in columns * removed consoles * making custom select align center vertically * on focus , we used to see on hover effect, avoiding it * Design review changes * Made text and string text-container according to design * vertical positioning of select and multiselect * overlay for deprecated columns * regex placeholder * Icons for number column type * Design feedback changes * Design fixes * box shadow on select menu list in canvas * added missing feature of decimal places and make increment and decrement icon vertically aligned * Fix design issues * Solve lint issues * Design theme revert changes * color of column list on hover and active is updated * fixes * changing the font weight of labels in styles tab of column manager * fix * Revert design theme * label change * horizontal alignment of select and datepicker columns * Reverted back to textarea for text column type * sync package-lock.json * fix import * UI fixes * Css changes * feat: Update default table data (#9312) * updated default table data * fix : table breaking * fix : datepikcer crashing table * fix : data * fix :: table image height (#9307) * fix : Table datepicker UI fixes (#9324) * fix : datepicker ui * update * fix * refactor: removed unused codes * add overlay * add overlay * Fix datepicker when date and time both are disabled * Fix paddings and margins * fix : default states in datepicker in table (#9335) * feat : update default data with images (#9338) * Design feedback * fix multiselect column type issues * Fix datepicker header width * Fix dropdown * Fix options loading state * Fix select issues * Fix multiselect default option * fix overlay trigger multiselect * fix: fixed issue with overlay display and cell content alignment for text * fix: Multiselect popover (#9394) * fix: popover only needed when content overflows * fix * fix: update zindex of edited text column * fix: show overlay when text in string overlay overflows * Fix multiselect default options * fix: show error message for editable string cloumn * Fix date issues * Fix date fixes * fix: more info popup close on mouse leave * Fix unix timestamp issue * Migration: set default demo data for older data (#9423) * fix: backfill old default data if user did not add a data * fix: backfill old default data if user did not add a data * Table column redeisgn demo string fix (#9415) * fix: show error message on table input validations * fix: error message alignments * Fix import issue for datepicker * wrapping the contant of multiselect selected options (#9429) * Fix popover in multiselect * Add multiselect popover only when content wrap is false or max row height is custom * Fix : String column types bug fixes (#9431) * Bug fixed: Hiding max row height field when content wrap is disabled * Removed border bottom when striped table style is applied * removed unwanted code * Apply hover effect on non-editable cell * fix : Max column hight is not working in table * Fixed width applied to multiselect popover * fix : Remove height and width from table image column / backward compatibility (#9425) * fix : table column image , remove width and height * optimise * adding default object fit * fix : text is overlaping issue * fix : non editable string column text alignment * remove logs * fix : text overflow * fix : text padding --------- Co-authored-by: manishkushare <kushare.manish9@gmail.com> Co-authored-by: Nakul Nagargade <nakul@tooljet.com> Co-authored-by: Nakul Nagargade <133095394+nakulnagargade@users.noreply.github.com> Co-authored-by: Johnson Cherian <johnsonc.dev@gmail.com> Co-authored-by: Manish Kushare <37823141+manishkushare@users.noreply.github.com>
345 lines
9.9 KiB
JavaScript
345 lines
9.9 KiB
JavaScript
import React, { useRef, useState, useEffect, useMemo } 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';
|
|
const { MenuList } = components;
|
|
|
|
const SCALING_FACTOR = 0.6;
|
|
const FONT_SIZE = 12;
|
|
const PADDING = 12;
|
|
const MARGIN = 10; // including left and right side
|
|
|
|
export const CustomSelect = ({
|
|
options,
|
|
value,
|
|
onChange,
|
|
fuzzySearch = false,
|
|
placeholder,
|
|
disabled,
|
|
className,
|
|
darkMode,
|
|
defaultOptionsList,
|
|
textColor = '',
|
|
isMulti,
|
|
containerWidth,
|
|
optionsLoadingState = false,
|
|
horizontalAlignment = 'left',
|
|
isEditable,
|
|
showPopoverIfOverflow,
|
|
isMaxRowHeightAuto,
|
|
}) => {
|
|
const containerRef = useRef(null);
|
|
const inputRef = useRef(null); // Ref for the input search box
|
|
const [isFocused, setIsFocused] = useState(false);
|
|
useEffect(() => {
|
|
const handleDocumentClick = (event) => {
|
|
if (isMulti && !containerRef.current?.contains(event.target)) {
|
|
setIsFocused(false);
|
|
}
|
|
};
|
|
|
|
document.addEventListener('mousedown', handleDocumentClick);
|
|
|
|
return () => {
|
|
document.removeEventListener('mousedown', handleDocumentClick);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
// Focus the input search box when the menu list is open and the component is focused
|
|
if (isFocused && inputRef.current) {
|
|
inputRef.current.focus();
|
|
}
|
|
}, [isFocused]);
|
|
|
|
const customStyles = {
|
|
...defaultStyles(darkMode, '100%'),
|
|
...(isMulti && {
|
|
multiValue: (provided) => ({
|
|
...provided,
|
|
display: 'inline-block', // Display selected options inline
|
|
marginRight: '4px', // Add some space between options
|
|
}),
|
|
}),
|
|
valueContainer: (provided) => ({
|
|
...provided,
|
|
...(isMulti && {
|
|
marginBottom: '0',
|
|
display: 'flex',
|
|
flexWrap: 'no-wrap',
|
|
overflow: 'hidden',
|
|
flexDirection: 'row',
|
|
}),
|
|
justifyContent: horizontalAlignment,
|
|
}),
|
|
menuList: (base) => ({
|
|
...base,
|
|
backgroundColor: 'var(--surfaces-surface-01) ',
|
|
color: 'var(--text-primary)',
|
|
cursor: 'pointer',
|
|
overflow: 'auto',
|
|
}),
|
|
multiValueLabel: (provided) => ({
|
|
...provided,
|
|
padding: '2px 6px',
|
|
background: 'var(--surfaces-surface-03)',
|
|
margin: '0 5px',
|
|
borderRadius: '6px',
|
|
color: textColor || 'var(--text-primary)',
|
|
fontSize: '12px',
|
|
}),
|
|
singleValue: (provided) => ({
|
|
...provided,
|
|
padding: '2px 6px',
|
|
background: 'var(--surfaces-surface-03)',
|
|
margin: '0 5px',
|
|
borderRadius: '6px',
|
|
color: textColor || 'var(--text-primary)',
|
|
fontSize: '12px',
|
|
}),
|
|
};
|
|
const customComponents = {
|
|
MenuList: (props) => <CustomMenuList {...props} optionsLoadingState={optionsLoadingState} inputRef={inputRef} />,
|
|
Option: CustomMultiSelectOption,
|
|
DropdownIndicator: isEditable ? DropdownIndicator : null,
|
|
...(isMulti && {
|
|
MultiValueRemove,
|
|
MultiValueContainer: CustomMultiValueContainer,
|
|
}),
|
|
};
|
|
const defaultValue = useMemo(() => {
|
|
if (defaultOptionsList.length >= 1) {
|
|
return !isMulti ? defaultOptionsList[defaultOptionsList.length - 1] : defaultOptionsList;
|
|
}
|
|
}, [isMulti, defaultOptionsList]);
|
|
|
|
const _value = useMemo(() => {
|
|
// Return null to show default value
|
|
if (!value) {
|
|
return null;
|
|
}
|
|
if (isMulti && value?.length) {
|
|
if (isArray(value)) {
|
|
return options?.filter((option) =>
|
|
value?.find((val) => {
|
|
if (val.hasOwnProperty('value')) {
|
|
return option.value === val.value;
|
|
} else return option.value === val;
|
|
})
|
|
);
|
|
} else {
|
|
return []; // Return empty array to not show default value in case of wrong value to be set
|
|
}
|
|
} else {
|
|
// Condition for single select
|
|
return options?.find((option) => option.value === value) || [];
|
|
}
|
|
}, [options, value, isMulti]);
|
|
|
|
const calculateIfPopoverRequired = (value, containerWidth) => {
|
|
let totalWidth = 0;
|
|
|
|
// // Calculate total width of all span elements
|
|
for (const option of value) {
|
|
const valueWidth = option.label.length * FONT_SIZE * SCALING_FACTOR + PADDING + MARGIN;
|
|
// Check if max row height is auto and then if any of the options width exceeds container width, return true
|
|
if (isMaxRowHeightAuto) {
|
|
if (valueWidth > containerWidth) {
|
|
return true;
|
|
}
|
|
} else {
|
|
totalWidth += valueWidth + 4; // Adding 4px to be safe
|
|
}
|
|
}
|
|
return totalWidth > containerWidth; // Return based on total width comparison
|
|
};
|
|
|
|
return (
|
|
<OverlayTrigger
|
|
placement="bottom"
|
|
overlay={
|
|
isMulti && showPopoverIfOverflow && (_value?.length || defaultValue?.length) && !isFocused ? (
|
|
getOverlay(_value ? _value : defaultValue, containerWidth, darkMode)
|
|
) : (
|
|
<div></div>
|
|
)
|
|
}
|
|
trigger={
|
|
isMulti &&
|
|
!isFocused &&
|
|
showPopoverIfOverflow &&
|
|
calculateIfPopoverRequired(_value ? _value : defaultValue, containerWidth - 40) && ['hover', 'focus']
|
|
} //container width -24 -16 gives that select container size
|
|
rootClose={true}
|
|
>
|
|
<div className="w-100 h-100 d-flex align-items-center">
|
|
<Select
|
|
options={options}
|
|
hasSearch={false}
|
|
fuzzySearch={fuzzySearch}
|
|
isDisabled={disabled}
|
|
className={className}
|
|
components={customComponents}
|
|
value={_value}
|
|
onMenuInputFocus={() => setIsFocused(true)}
|
|
onChange={(value) => {
|
|
setIsFocused(false);
|
|
onChange(value);
|
|
}}
|
|
useCustomStyles={true}
|
|
styles={customStyles}
|
|
defaultValue={defaultValue}
|
|
placeholder={placeholder}
|
|
isMulti={isMulti}
|
|
hideSelectedOptions={false}
|
|
isClearable={false}
|
|
clearIndicator={false}
|
|
{...{
|
|
menuIsOpen: isFocused || undefined,
|
|
isFocused: isFocused || undefined,
|
|
}}
|
|
/>
|
|
</div>
|
|
</OverlayTrigger>
|
|
);
|
|
};
|
|
|
|
const CustomMenuList = ({ optionsLoadingState, children, selectProps, inputRef, ...props }) => {
|
|
const { onInputChange, inputValue, onMenuInputFocus } = selectProps;
|
|
|
|
return (
|
|
<div className="table-select-custom-menu-list" onClick={(e) => e.stopPropagation()}>
|
|
<div className="table-select-column-type-search-box-wrapper ">
|
|
{!inputValue && (
|
|
<span className="">
|
|
<SolidIcon name="search" width="14" />
|
|
</span>
|
|
)}
|
|
<input
|
|
autoCorrect="off"
|
|
autoComplete="off"
|
|
spellCheck="false"
|
|
type="text"
|
|
value={inputValue}
|
|
onChange={(e) =>
|
|
onInputChange(e.currentTarget.value, {
|
|
action: 'input-change',
|
|
})
|
|
}
|
|
onMouseDown={(e) => {
|
|
e.stopPropagation();
|
|
e.target.focus();
|
|
}}
|
|
onTouchEnd={(e) => {
|
|
e.stopPropagation();
|
|
e.target.focus();
|
|
}}
|
|
onFocus={onMenuInputFocus}
|
|
placeholder="Search..."
|
|
className="table-select-column-type-search-box"
|
|
ref={inputRef} // Assign the ref to the input search box
|
|
/>
|
|
</div>
|
|
<MenuList {...props} selectProps={selectProps}>
|
|
{optionsLoadingState ? (
|
|
<div class="text-center py-4">
|
|
<div class="spinner-border text-primary" role="status">
|
|
<span class="sr-only"></span>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
children
|
|
)}
|
|
</MenuList>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const CustomMultiSelectOption = ({ innerRef, innerProps, children, isSelected, ...props }) => {
|
|
return (
|
|
<div ref={innerRef} {...innerProps} className="option-wrapper d-flex">
|
|
{props.isMulti ? (
|
|
<Checkbox label="" isChecked={isSelected} onChange={(e) => e.stopPropagation()} key="" value={children} />
|
|
) : (
|
|
<div style={{ visibility: isSelected ? 'visible' : 'hidden' }}>
|
|
<Checkbox label="" isChecked={isSelected} onChange={(e) => e.stopPropagation()} key="" value={children} />
|
|
</div>
|
|
)}
|
|
{children}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const MultiValueRemove = (props) => {
|
|
const { innerProps } = props;
|
|
return <div {...innerProps} />;
|
|
};
|
|
const CustomMultiValueContainer = (props) => {
|
|
return (
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
flexWrap: 'wrap',
|
|
alignItems: 'center',
|
|
gap: '4px',
|
|
}}
|
|
>
|
|
{props.children}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const getOverlay = (value, containerWidth, darkMode) => {
|
|
const getLabel = (option) => {
|
|
if (option?.hasOwnProperty('label')) {
|
|
return option.label;
|
|
} else if (isString(option)) {
|
|
return option;
|
|
} else return '';
|
|
};
|
|
|
|
return Array.isArray(value) ? (
|
|
<div
|
|
style={{
|
|
maxWidth: '266px',
|
|
}}
|
|
className={`overlay-cell-table overlay-multiselect-table ${darkMode && 'dark-theme'}`}
|
|
>
|
|
{value?.map((option) => {
|
|
return (
|
|
<span
|
|
style={{
|
|
padding: '2px 6px',
|
|
background: 'var(--surfaces-surface-03)',
|
|
borderRadius: '6px',
|
|
color: 'var(--text-primary)',
|
|
fontSize: '12px',
|
|
}}
|
|
key={getLabel(option)}
|
|
>
|
|
{getLabel(option)}
|
|
</span>
|
|
);
|
|
})}
|
|
</div>
|
|
) : (
|
|
<div></div>
|
|
);
|
|
};
|
|
|
|
const DropdownIndicator = (props) => {
|
|
return (
|
|
<div {...props} className="cell-icon-display">
|
|
{/* Your custom SVG */}
|
|
{props.selectProps.menuIsOpen ? (
|
|
<SolidIcon name="arrowUpTriangle" width="16" height="16" fill={'#6A727C'} />
|
|
) : (
|
|
<SolidIcon name="arrowDownTriangle" width="16" height="16" fill={'#6A727C'} />
|
|
)}
|
|
</div>
|
|
);
|
|
};
|