2024-02-08 09:35:26 +00:00
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
|
import Popover from 'react-bootstrap/Popover';
|
|
|
|
|
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
2024-05-08 08:17:11 +00:00
|
|
|
import DropDownSelect from '@/Editor/QueryManager/QueryEditors/TooljetDatabase/DropDownSelect';
|
2024-02-08 09:35:26 +00:00
|
|
|
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
|
2024-05-08 08:17:11 +00:00
|
|
|
import Information from '@/_ui/Icon/solidIcons/Information';
|
2024-02-08 09:35:26 +00:00
|
|
|
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
|
|
|
|
import LeftNav from '../../Icons/LeftNav.svg';
|
|
|
|
|
import RightNav from '../../Icons/RightNav.svg';
|
|
|
|
|
import cx from 'classnames';
|
|
|
|
|
import './styles.scss';
|
2024-05-30 11:06:12 +00:00
|
|
|
import styles from './styles.module.scss';
|
2024-05-28 07:36:04 +00:00
|
|
|
import Skeleton from 'react-loading-skeleton';
|
2024-02-08 09:35:26 +00:00
|
|
|
|
|
|
|
|
export const CellEditMenu = ({
|
|
|
|
|
darkMode = false,
|
|
|
|
|
children,
|
|
|
|
|
show,
|
|
|
|
|
close,
|
|
|
|
|
columnDetails,
|
|
|
|
|
saveFunction,
|
|
|
|
|
setCellValue,
|
|
|
|
|
cellValue,
|
|
|
|
|
previousCellValue,
|
|
|
|
|
setDefaultValue,
|
|
|
|
|
defaultValue,
|
|
|
|
|
setNullValue,
|
|
|
|
|
nullValue,
|
|
|
|
|
isBoolean,
|
2024-05-08 08:17:11 +00:00
|
|
|
referencedColumnDetails = [],
|
|
|
|
|
referenceColumnName = '',
|
|
|
|
|
isForeignKey = false,
|
2024-06-04 12:20:44 +00:00
|
|
|
scrollEventForColumnValues,
|
2024-05-08 08:17:11 +00:00
|
|
|
organizationId,
|
|
|
|
|
foreignKeys,
|
|
|
|
|
setReferencedColumnDetails,
|
|
|
|
|
cellHeader,
|
2024-06-04 12:20:44 +00:00
|
|
|
cachedOptions,
|
|
|
|
|
dataType = '',
|
2024-02-08 09:35:26 +00:00
|
|
|
}) => {
|
|
|
|
|
// below state is used only for boolean cell
|
|
|
|
|
const [selectedValue, setSelectedValue] = useState(cellValue);
|
2024-05-30 11:06:12 +00:00
|
|
|
const [shouldCloseFkMenu, setShouldCloseFKMenu] = useState(0);
|
2024-05-08 08:17:11 +00:00
|
|
|
const [selectedForeignKeyValue, setSelectedForeignKeyValue] = useState({
|
|
|
|
|
value: previousCellValue === 'Null' ? null : previousCellValue,
|
|
|
|
|
label: previousCellValue === 'Null' ? null : previousCellValue,
|
|
|
|
|
});
|
2024-02-08 09:35:26 +00:00
|
|
|
|
|
|
|
|
const handleDefaultChange = (defaultColumnValue, defaultBooleanValue) => {
|
|
|
|
|
if (defaultBooleanValue === true) {
|
|
|
|
|
setCellValue(defaultColumnValue);
|
2024-06-04 12:20:44 +00:00
|
|
|
setSelectedForeignKeyValue({
|
|
|
|
|
label: defaultColumnValue,
|
|
|
|
|
value: defaultColumnValue,
|
|
|
|
|
});
|
2024-02-08 09:35:26 +00:00
|
|
|
} else {
|
|
|
|
|
setCellValue(previousCellValue);
|
|
|
|
|
}
|
|
|
|
|
setDefaultValue(defaultBooleanValue);
|
|
|
|
|
setNullValue(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleNullChange = (nullVal) => {
|
|
|
|
|
if (nullVal === true) {
|
|
|
|
|
setCellValue(null);
|
2024-05-10 05:18:48 +00:00
|
|
|
setSelectedForeignKeyValue({
|
|
|
|
|
label: null,
|
|
|
|
|
value: null,
|
|
|
|
|
});
|
2024-02-08 09:35:26 +00:00
|
|
|
} else {
|
|
|
|
|
if (previousCellValue === null) {
|
|
|
|
|
setCellValue('');
|
2024-05-10 05:18:48 +00:00
|
|
|
setSelectedForeignKeyValue({
|
|
|
|
|
label: '',
|
|
|
|
|
value: '',
|
|
|
|
|
});
|
2024-02-08 09:35:26 +00:00
|
|
|
} else {
|
|
|
|
|
setCellValue(previousCellValue);
|
2024-05-10 05:18:48 +00:00
|
|
|
setSelectedForeignKeyValue({
|
|
|
|
|
label: previousCellValue,
|
|
|
|
|
value: previousCellValue,
|
|
|
|
|
});
|
2024-02-08 09:35:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setNullValue(nullVal);
|
|
|
|
|
setDefaultValue(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSelectedState = (value) => {
|
|
|
|
|
setSelectedValue(value);
|
|
|
|
|
setCellValue(value);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const closePopover = () => {
|
2024-05-08 08:17:11 +00:00
|
|
|
setReferencedColumnDetails([]);
|
2024-02-08 09:35:26 +00:00
|
|
|
setSelectedValue(previousCellValue);
|
|
|
|
|
close();
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-30 11:06:12 +00:00
|
|
|
const closeFKMenu = () => {
|
|
|
|
|
setShouldCloseFKMenu((prev) => prev + 1);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const saveFKValue = () => {
|
|
|
|
|
saveFunction(cellValue);
|
|
|
|
|
closeFKMenu();
|
|
|
|
|
};
|
|
|
|
|
|
2024-02-08 09:35:26 +00:00
|
|
|
const handleKeyDown = (e) => {
|
|
|
|
|
if (e.key === 'ArrowRight' && isBoolean) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
if (selectedValue === false) handleSelectedState(true);
|
|
|
|
|
if (selectedValue === true) handleSelectedState(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e.key === 'ArrowLeft' && isBoolean) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
if (selectedValue === null) handleSelectedState(true);
|
|
|
|
|
if (selectedValue === true) handleSelectedState(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e.key === 'Escape') {
|
|
|
|
|
closePopover();
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-05 13:01:16 +00:00
|
|
|
if (e.key === 'Enter' && cellValue != previousCellValue && show) {
|
2024-02-08 09:35:26 +00:00
|
|
|
saveFunction(cellValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e.key === 'Backspace') {
|
|
|
|
|
if (selectedValue === null) {
|
|
|
|
|
if (isBoolean) {
|
|
|
|
|
setSelectedValue(true);
|
|
|
|
|
setCellValue(true);
|
|
|
|
|
} else {
|
|
|
|
|
setSelectedValue('');
|
|
|
|
|
setCellValue('');
|
|
|
|
|
}
|
|
|
|
|
setNullValue(false);
|
|
|
|
|
setDefaultValue(false);
|
|
|
|
|
document.getElementById('edit-input-blur').focus();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-08 08:17:11 +00:00
|
|
|
const referencedFKDataList = referencedColumnDetails.map((item) => {
|
|
|
|
|
const [key, _value] = Object.entries(item);
|
|
|
|
|
return {
|
|
|
|
|
label: key[1] === null ? 'Null' : key[1],
|
|
|
|
|
value: key[1] === null ? 'Null' : key[1],
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
2024-02-08 09:35:26 +00:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (show) {
|
|
|
|
|
document.addEventListener('keydown', handleKeyDown);
|
|
|
|
|
return () => {
|
|
|
|
|
document.removeEventListener('keydown', handleKeyDown);
|
|
|
|
|
};
|
|
|
|
|
}
|
2024-05-08 08:17:11 +00:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2024-02-08 09:35:26 +00:00
|
|
|
}, [show, isBoolean, selectedValue, cellValue]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (selectedValue !== cellValue) setSelectedValue(cellValue);
|
2024-05-08 08:17:11 +00:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2024-02-08 09:35:26 +00:00
|
|
|
}, [cellValue]);
|
|
|
|
|
|
2024-05-30 11:06:12 +00:00
|
|
|
const SaveChangesSection = () => {
|
|
|
|
|
return (
|
|
|
|
|
<div className="d-flex justify-content-between align-items-center">
|
|
|
|
|
<div className="d-flex flex-column align-items-start gap-1">
|
|
|
|
|
<div className="d-flex align-items-center gap-1">
|
|
|
|
|
<div className={`fw-500 ${styles.tjdbCellMenuShortcutsInfo}`}>
|
|
|
|
|
<SolidIcon name="enterbutton" />
|
|
|
|
|
</div>
|
|
|
|
|
<div className={`fw-400 ${styles.tjdbCellMenuShortcutsText}`}>Save Changes</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="d-flex align-items-center gap-1">
|
|
|
|
|
<div className={`fw-500 ${styles.tjdbCellMenuShortcutsInfo}`}>Esc</div>
|
|
|
|
|
<div className={`fw-400 ${styles.tjdbCellMenuShortcutsText}`}>Discard Changes</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="d-flex flex-column align-items-end gap-1">
|
|
|
|
|
{columnDetails?.constraints_type.is_not_null === false && (
|
|
|
|
|
<div className="d-flex align-items-center gap-2">
|
|
|
|
|
<div className="d-flex flex-column">
|
|
|
|
|
<span className="fw-400 fs-12">Set to null</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className={`form-switch`}>
|
|
|
|
|
<input
|
|
|
|
|
className="form-check-input"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
checked={nullValue}
|
|
|
|
|
onChange={() => handleNullChange(!nullValue)}
|
|
|
|
|
/>
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{columnDetails?.column_default !== null && (
|
|
|
|
|
<div className="d-flex align-items-center gap-2">
|
|
|
|
|
<div className="d-flex flex-column">
|
|
|
|
|
<span className="fw-400 fs-12">Set to default</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className={`form-switch`}>
|
|
|
|
|
<input
|
|
|
|
|
className="form-check-input"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
checked={defaultValue}
|
|
|
|
|
onChange={() => handleDefaultChange(columnDetails?.column_default, !defaultValue)}
|
|
|
|
|
/>
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const SaveChangesFooter = ({ isForeignKeyInEditCell }) => {
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={cx('d-flex align-items-center gap-2', {
|
|
|
|
|
'justify-content-between': isBoolean,
|
|
|
|
|
'justify-content-end': !isBoolean,
|
|
|
|
|
})}
|
|
|
|
|
>
|
|
|
|
|
{isBoolean ? (
|
|
|
|
|
<div className="cell-editmenu-keyActions">
|
|
|
|
|
<div className="leftNav-parent-container">
|
|
|
|
|
<LeftNav style={{ verticalAlign: 'baseline' }} width={8} height={8} />
|
|
|
|
|
</div>
|
|
|
|
|
<div className="rightNav-parent-container">
|
|
|
|
|
<RightNav style={{ verticalAlign: 'baseline' }} width={8} height={8} />
|
|
|
|
|
</div>
|
|
|
|
|
<div className="navigate-title fs-10">Navigate</div>
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
|
|
|
|
<div className="d-flex" style={{ gap: '8px' }}>
|
|
|
|
|
<ButtonSolid
|
|
|
|
|
onClick={isForeignKeyInEditCell ? closeFKMenu : closePopover}
|
|
|
|
|
variant="tertiary"
|
|
|
|
|
size="sm"
|
2024-06-04 10:56:46 +00:00
|
|
|
className="fs-12 p-2"
|
2024-05-30 11:06:12 +00:00
|
|
|
>
|
|
|
|
|
Cancel
|
|
|
|
|
</ButtonSolid>
|
|
|
|
|
<ButtonSolid
|
|
|
|
|
onClick={isForeignKeyInEditCell ? saveFKValue : () => saveFunction(selectedValue)}
|
|
|
|
|
disabled={cellValue == previousCellValue ? true : false}
|
|
|
|
|
variant="primary"
|
|
|
|
|
size="sm"
|
2024-06-04 10:56:46 +00:00
|
|
|
className="fs-12 p-2"
|
2024-05-30 11:06:12 +00:00
|
|
|
>
|
|
|
|
|
Save
|
|
|
|
|
</ButtonSolid>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2024-02-08 09:35:26 +00:00
|
|
|
const popover = (
|
2024-05-08 08:17:11 +00:00
|
|
|
<Popover
|
|
|
|
|
className={`${darkMode && 'dark-theme'} tjdb-table-cell-edit-popover`}
|
|
|
|
|
onClick={(event) => {
|
|
|
|
|
if (event.target.closest('.react-select-container')) {
|
|
|
|
|
event.preventDefault(); // Prevent the Popover from closing
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
2024-02-08 09:35:26 +00:00
|
|
|
<Popover.Body className={`${darkMode && 'dark-theme'}`}>
|
|
|
|
|
<div className={`d-flex flex-column ${isBoolean ? 'gap-4' : 'gap-3'}`}>
|
|
|
|
|
{/* Boolean View */}
|
|
|
|
|
{isBoolean && (
|
|
|
|
|
<div className="d-flex align-items-start gap-2">
|
|
|
|
|
<span
|
|
|
|
|
className={`boolean-state-${
|
|
|
|
|
selectedValue === false ? 'selected' : ''
|
|
|
|
|
} d-flex align-items-center gap-2 fw-500 tjdb-bool-cell-menu-badge-default`}
|
|
|
|
|
tabIndex="0"
|
|
|
|
|
onClick={() => handleSelectedState(false)}
|
|
|
|
|
>
|
|
|
|
|
False
|
|
|
|
|
</span>
|
|
|
|
|
<span
|
|
|
|
|
className={`boolean-state-${
|
|
|
|
|
selectedValue === true ? 'selected' : ''
|
|
|
|
|
} d-flex align-items-center gap-2 fw-500 tjdb-bool-cell-menu-badge-default`}
|
|
|
|
|
tabIndex="1"
|
|
|
|
|
onClick={() => handleSelectedState(true)}
|
|
|
|
|
>
|
|
|
|
|
True
|
|
|
|
|
</span>
|
|
|
|
|
{columnDetails?.constraints_type.is_not_null === false && (
|
|
|
|
|
<span
|
|
|
|
|
className={`boolean-state-${
|
|
|
|
|
selectedValue === null ? 'selected' : ''
|
|
|
|
|
} d-flex align-items-center gap-2 fw-500 tjdb-bool-cell-menu-badge-default`}
|
|
|
|
|
tabIndex="2"
|
|
|
|
|
onClick={() => handleSelectedState(null)}
|
|
|
|
|
>
|
|
|
|
|
Null
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2024-05-30 11:06:12 +00:00
|
|
|
{!isBoolean && <SaveChangesSection />}
|
2024-02-08 09:35:26 +00:00
|
|
|
|
|
|
|
|
{/* Footer */}
|
2024-05-30 11:06:12 +00:00
|
|
|
<SaveChangesFooter />
|
2024-02-08 09:35:26 +00:00
|
|
|
</div>
|
|
|
|
|
</Popover.Body>
|
|
|
|
|
</Popover>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<OverlayTrigger show={show} trigger="click" placement="bottom-start" rootclose overlay={popover} defaultShow>
|
2024-05-30 11:06:12 +00:00
|
|
|
{isForeignKey ? (
|
|
|
|
|
<DropDownSelect
|
|
|
|
|
buttonClasses="border border-end-1 foreignKeyAcces-container"
|
|
|
|
|
showPlaceHolder={true}
|
|
|
|
|
loader={
|
2024-06-06 08:35:03 +00:00
|
|
|
<div className="tjdb-cellmenu-loader mx-2">
|
2024-05-30 11:06:12 +00:00
|
|
|
<Skeleton height={18} width={176} className="skeleton" style={{ margin: '15px 50px 7px 7px' }} />
|
|
|
|
|
<Skeleton height={18} width={212} className="skeleton" style={{ margin: '7px 14px 7px 7px' }} />
|
|
|
|
|
<Skeleton height={18} width={176} className="skeleton" style={{ margin: '7px 50px 15px 7px' }} />
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
isLoading={true}
|
|
|
|
|
options={referencedFKDataList}
|
|
|
|
|
darkMode={darkMode}
|
|
|
|
|
emptyError={
|
2024-06-06 08:35:03 +00:00
|
|
|
<div className="tjdb-cellmenu-error">
|
|
|
|
|
<div className="dd-select-alert-error m-2 d-flex align-items-center">
|
|
|
|
|
<Information />
|
|
|
|
|
No data found
|
|
|
|
|
</div>
|
2024-05-30 11:06:12 +00:00
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
value={selectedForeignKeyValue}
|
|
|
|
|
onChange={(value) => {
|
|
|
|
|
setSelectedForeignKeyValue({
|
|
|
|
|
label: value.value === 'Null' ? null : value.value,
|
|
|
|
|
value: value.value === 'Null' ? null : value.value,
|
|
|
|
|
});
|
|
|
|
|
setCellValue(value.value === 'Null' ? null : value.value);
|
|
|
|
|
setNullValue(value.value === 'Null' ? true : false);
|
|
|
|
|
}}
|
|
|
|
|
onAdd={true}
|
|
|
|
|
closeFKMenu={closeFKMenu}
|
|
|
|
|
saveFKValue={saveFKValue}
|
|
|
|
|
addBtnLabel={'Open referenced table'}
|
|
|
|
|
isCellEdit={true}
|
2024-06-04 12:20:44 +00:00
|
|
|
scrollEventForColumnValues={scrollEventForColumnValues}
|
2024-05-30 11:06:12 +00:00
|
|
|
organizationId={organizationId}
|
|
|
|
|
foreignKeys={foreignKeys}
|
|
|
|
|
setReferencedColumnDetails={setReferencedColumnDetails}
|
|
|
|
|
cellColumnName={cellHeader}
|
|
|
|
|
customChildren={
|
|
|
|
|
<div className={`d-flex flex-column gap-3`} style={{ padding: '10px' }}>
|
|
|
|
|
<SaveChangesSection />
|
|
|
|
|
<SaveChangesFooter isForeignKeyInEditCell={true} />
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
isForeignKeyInEditCell={true}
|
|
|
|
|
shouldCloseFkMenu={shouldCloseFkMenu}
|
2024-06-04 12:20:44 +00:00
|
|
|
cachedOptions={cachedOptions}
|
|
|
|
|
columnDataType={dataType}
|
2024-05-30 11:06:12 +00:00
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
children
|
|
|
|
|
)}
|
2024-02-08 09:35:26 +00:00
|
|
|
</OverlayTrigger>
|
|
|
|
|
);
|
|
|
|
|
};
|