mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
* init kanban board widget * kanban board * reverts to beautifully * kanban UI updates and dnd fixes * bugfix: when dropped outside the col, should return back to it inital position * updates min-width of the column * container and widget styles * style fixes: column container onDrag * adds button for new group * fixes new card overflow * add btn for adding cards * groups and cards updated * add property definition * improves draggable card position while drag is active * handle delete group/col * handle col/group title updates * handles editing card title * style fixes for input cursor * cleanup * card popover with codehinter fields * minor card fixes * updates exposed variable * simplify boardData into cols and cards * adds width and min-width style definations * build board from queries * handle draggable rbd-id * removes add group card and delete group option * fixes typos * show empty state message * fixes typos * removes card extra border color * fixes column typi and cards updates issue * adds enableAddCard property defination * adds accent color options * default style accent color * accent color fix * revets popover with hinter * fixes card drag and drop * removes hook * fixes: state synced with property defination updates(col and cards data) * fixes: on re-arranging the card via dnd, update the card content * handles if card columnId is updated * adds card container layer * clean up * dark theme * fixes card onDrop issue * renamed the exposed variable data --> lists * adds custom resolvers to the popover * handle widget crash when non iterables are passed * updates default card and col value * fixes dnd issues for dynamic card values * refactor: cleanup * handles empty and undefined cardData * fixes Height of widget is changing when popover thing is displayed. * fixes: updating card data in widget inspector * fixes: updating column data in widget inspector * fixes adding cards for newly created groups/columns * clean up * Add kanban event onCardAdded and expose lastAddedCard * Add onCardRemoved action and expsed lastRemovedCard variable * Add events and variables for card movement and selection * Add card edit feature for kanban widget * Rename lastAddedRemoved to lastRemovedCard in kanban * Rename lists to columns on kanban board * Set max height of kanban column to respond to widget height * Have "Add description" link if there is no description for Kanban cards * kanban docs * Change text from "add +" to "Add card" on kanban * Validate card data before update * Add tip about card id type on kanban documentation * Add default min width and width for kanban Co-authored-by: Sherfin Shamsudeen <sherfin94@gmail.com> Co-authored-by: Shubhendra <withshubh@gmail.com>
157 lines
5.3 KiB
JavaScript
157 lines
5.3 KiB
JavaScript
import React, { useEffect, useRef, useState } from 'react';
|
|
|
|
export const CardEventPopover = function ({
|
|
show,
|
|
offset,
|
|
kanbanCardWidgetId,
|
|
popoverClosed,
|
|
card,
|
|
updateCardProperty,
|
|
index,
|
|
keyIndex,
|
|
}) {
|
|
const parentRef = useRef(null);
|
|
const [showPopover, setShow] = useState(show);
|
|
const [top, setTop] = useState(0);
|
|
const [left, setLeft] = useState(0);
|
|
|
|
const [titleInputBoxValue, setTitleInputBoxValue] = useState(card.title ?? '');
|
|
const [descriptionTextAreaValue, setDescriptionTextAreaValue] = useState(card.description ?? '');
|
|
const [titleHovered, setTitleHovered] = useState(false);
|
|
const [descriptionHovered, setDescriptionHovered] = useState(false);
|
|
const [titleEditMode, setTitleEditMode] = useState(false);
|
|
const [descriptionEditMode, setDescriptionEditMode] = useState(false);
|
|
|
|
const minHeight = 400;
|
|
let kanbanBounds;
|
|
|
|
const kanbanElement = document.getElementById(kanbanCardWidgetId);
|
|
|
|
const handleClickOutside = (event) => {
|
|
if (parentRef.current && !parentRef.current.contains(event.target)) {
|
|
popoverClosed();
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
document.addEventListener('click', handleClickOutside, true);
|
|
return () => {
|
|
document.removeEventListener('click', handleClickOutside, true);
|
|
};
|
|
});
|
|
|
|
useEffect(() => {
|
|
setShow(show);
|
|
}, [show]);
|
|
|
|
useEffect(() => {
|
|
if (offset?.top && showPopover) {
|
|
const _left = offset.left - kanbanBounds.x + offset.width;
|
|
const _top = ((offset.top - kanbanBounds.y) * 100) / kanbanBounds.height;
|
|
setTop(_top);
|
|
setLeft(_left);
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [offset?.top, showPopover]);
|
|
|
|
if (kanbanElement && showPopover) {
|
|
kanbanBounds = kanbanElement.getBoundingClientRect();
|
|
}
|
|
const darkMode = localStorage.getItem('darkMode') === 'true';
|
|
return (
|
|
<div
|
|
style={{
|
|
position: 'absolute',
|
|
zIndex: 100,
|
|
width: '300px',
|
|
maxWidth: '300px',
|
|
height: 300,
|
|
top: `${top}%`,
|
|
left,
|
|
display: showPopover ? 'block' : 'none',
|
|
}}
|
|
role="tooltip"
|
|
x-placement="left"
|
|
className={`popover bs-popover-left shadow-lg ${darkMode && 'popover-dark-themed theme-dark'}`}
|
|
ref={parentRef}
|
|
id={`${kanbanCardWidgetId}-popover`}
|
|
>
|
|
{parentRef.current && showPopover && (
|
|
<div className="popover-body" style={{ padding: 'unset', width: '100%', height: 100, zIndex: 11 }}>
|
|
<div className="rows p-2 overflow-auto">
|
|
<div
|
|
className="row overflow-auto"
|
|
onMouseEnter={() => setTitleHovered(true)}
|
|
onMouseLeave={() => setTitleHovered(false)}
|
|
>
|
|
{titleEditMode ? (
|
|
<div>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
defaultValue={titleInputBoxValue}
|
|
onChange={(event) => setTitleInputBoxValue(event.target.value)}
|
|
onBlur={() => {
|
|
updateCardProperty(keyIndex, index, 'title', titleInputBoxValue);
|
|
setTitleEditMode(false);
|
|
}}
|
|
/>
|
|
</div>
|
|
) : (
|
|
<h3>
|
|
{card?.title ?? ''}
|
|
<img
|
|
src="/assets/images/icons/editor/edit.svg"
|
|
style={{ visibility: titleHovered ? 'visible' : 'hidden', height: 15, width: 15, paddingLeft: 1 }}
|
|
onClick={() => setTitleEditMode(true)}
|
|
/>
|
|
</h3>
|
|
)}
|
|
</div>
|
|
<div
|
|
className="row overflow-auto d-flex align-items-center flex-column"
|
|
onMouseEnter={() => setDescriptionHovered(true)}
|
|
onMouseLeave={() => setDescriptionHovered(false)}
|
|
style={{ maxHeight: 250 }}
|
|
>
|
|
{descriptionEditMode ? (
|
|
<textarea
|
|
className="form-control"
|
|
style={{ width: '95%' }}
|
|
onChange={(event) => setDescriptionTextAreaValue(event.target.value)}
|
|
onBlur={() => {
|
|
updateCardProperty(keyIndex, index, 'description', descriptionTextAreaValue);
|
|
setDescriptionEditMode(false);
|
|
}}
|
|
rows={10}
|
|
>
|
|
{descriptionTextAreaValue}
|
|
</textarea>
|
|
) : (
|
|
<p>
|
|
{['', undefined].includes(card.description) ? (
|
|
<a style={{ color: 'grey' }} onClick={() => setDescriptionEditMode(true)}>
|
|
Add description
|
|
</a>
|
|
) : (
|
|
card.description
|
|
)}
|
|
<img
|
|
src="/assets/images/icons/editor/edit.svg"
|
|
style={{
|
|
visibility: descriptionHovered ? 'visible' : 'hidden',
|
|
height: 15,
|
|
width: 15,
|
|
paddingLeft: 1,
|
|
}}
|
|
onClick={() => setDescriptionEditMode(true)}
|
|
/>
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|