diff --git a/client/src/components/production-list-columns/production-list-columns.alert.component.jsx b/client/src/components/production-list-columns/production-list-columns.alert.component.jsx
index 55a3207ac..218d6295a 100644
--- a/client/src/components/production-list-columns/production-list-columns.alert.component.jsx
+++ b/client/src/components/production-list-columns/production-list-columns.alert.component.jsx
@@ -1,7 +1,7 @@
import { ExclamationCircleFilled } from "@ant-design/icons";
import { useMutation } from "@apollo/client";
-import { Dropdown } from "antd";
-import React, { useCallback, useMemo } from "react";
+import { Button } from "antd";
+import React, { useCallback } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -16,58 +16,45 @@ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type }))
});
-export function ProductionListColumnAlert({ record, insertAuditTrail }) {
+const ProductionListColumnAlert = ({ record, insertAuditTrail }) => {
const { t } = useTranslation();
-
const [updateAlert] = useMutation(UPDATE_JOB);
const handleAlertToggle = useCallback(() => {
logImEXEvent("production_toggle_alert");
+
+ const newAlertState = !!record.production_vars?.alert ? !record.production_vars.alert : true;
+
updateAlert({
variables: {
jobId: record.id,
job: {
production_vars: {
...record.production_vars,
- alert: !!record.production_vars && !!record.production_vars.alert ? !record.production_vars.alert : true
+ alert: newAlertState
}
}
}
+ }).catch((err) => {
+ console.error(`Something went wrong updating production note: ${err.message || ""}`);
});
+
insertAuditTrail({
jobid: record.id,
- operation: AuditTrailMapping.alertToggle(
- !!record.production_vars && !!record.production_vars.alert ? !record.production_vars.alert : true
- ),
+ operation: AuditTrailMapping.alertToggle(newAlertState),
type: "alertToggle"
}).then(() => {
if (record.refetch) record.refetch();
});
}, [updateAlert, insertAuditTrail, record]);
- const menuItems = useMemo(
- () => [
- {
- key: "toggleAlert",
- label:
- record.production_vars && record.production_vars.alert
- ? t("production.labels.alertoff")
- : t("production.labels.alerton"),
- onClick: handleAlertToggle
- }
- ],
- [record.production_vars, t, handleAlertToggle]
- );
-
return (
-
-
- {record.production_vars && record.production_vars.alert ? (
-
- ) : null}
-
-
+
+ {record.production_vars?.alert && (
+ } onClick={handleAlertToggle} />
+ )}
+
);
-}
+};
export default connect(mapStateToProps, mapDispatchToProps)(ProductionListColumnAlert);
diff --git a/client/src/components/trello-board/components/AddCardLink.jsx b/client/src/components/trello-board/components/AddCardLink.jsx
deleted file mode 100644
index df259a9d9..000000000
--- a/client/src/components/trello-board/components/AddCardLink.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from "react";
-import { AddCardLink } from "../styles/Base";
-import { useTranslation } from "react-i18next";
-
-const AddCardLinkComponent = ({ onClick, laneId }) => {
- const { t } = useTranslation();
-
- return {t("trello.labels.add_card")};
-};
-
-export default AddCardLinkComponent;
diff --git a/client/src/components/trello-board/components/Card/Tag.jsx b/client/src/components/trello-board/components/Card/Tag.jsx
deleted file mode 100644
index 78bd78063..000000000
--- a/client/src/components/trello-board/components/Card/Tag.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from "react";
-import PropTypes from "prop-types";
-import { TagSpan } from "../../styles/Base";
-
-const Tag = ({ title, color, bgcolor, tagStyle, ...otherProps }) => {
- const style = { color: color || "white", backgroundColor: bgcolor || "orange", ...tagStyle };
- return (
-
- {title}
-
- );
-};
-
-Tag.propTypes = {
- title: PropTypes.string.isRequired,
- color: PropTypes.string,
- bgcolor: PropTypes.string,
- tagStyle: PropTypes.object
-};
-
-export default Tag;
diff --git a/client/src/components/trello-board/components/Lane/LaneHeader.jsx b/client/src/components/trello-board/components/Lane/LaneHeader.jsx
deleted file mode 100644
index d849bb0a6..000000000
--- a/client/src/components/trello-board/components/Lane/LaneHeader.jsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import React from "react";
-import PropTypes from "prop-types";
-import InlineInput from "../../widgets/InlineInput.jsx";
-import { LaneHeader, RightContent, Title } from "../../styles/Base";
-import LaneMenu from "./LaneHeader/LaneMenu.jsx";
-import { useTranslation } from "react-i18next";
-
-const LaneHeaderComponent = ({
- updateTitle,
- canAddLanes,
- onDelete,
- onDoubleClick,
- editLaneTitle,
- label,
- title,
- titleStyle,
- labelStyle
-}) => {
- const { t } = useTranslation();
-
- return (
-
-
- {editLaneTitle ? (
-
- ) : (
- title
- )}
-
- {label && (
-
- {label}
-
- )}
- {canAddLanes && }
-
- );
-};
-
-LaneHeaderComponent.propTypes = {
- updateTitle: PropTypes.func,
- editLaneTitle: PropTypes.bool,
- canAddLanes: PropTypes.bool,
- label: PropTypes.string,
- title: PropTypes.string,
- onDelete: PropTypes.func,
- onDoubleClick: PropTypes.func
-};
-
-LaneHeaderComponent.defaultProps = {
- updateTitle: () => {},
- editLaneTitle: false,
- canAddLanes: false
-};
-
-export default LaneHeaderComponent;
diff --git a/client/src/components/trello-board/components/Lane/LaneHeader/LaneMenu.jsx b/client/src/components/trello-board/components/Lane/LaneHeader/LaneMenu.jsx
deleted file mode 100644
index 0dc6610bd..000000000
--- a/client/src/components/trello-board/components/Lane/LaneHeader/LaneMenu.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from "react";
-
-import { Popover } from "react-popopo";
-
-import { CustomPopoverContainer, CustomPopoverContent } from "../../../styles/Base";
-
-import {
- DeleteWrapper,
- GenDelButton,
- LaneMenuContent,
- LaneMenuHeader,
- LaneMenuItem,
- LaneMenuTitle,
- MenuButton
-} from "../../../styles/Elements";
-import { useTranslation } from "react-i18next";
-
-const LaneMenu = ({ onDelete }) => {
- const { t } = useTranslation();
-
- return (
- ⋮}
- >
-
- {t("trello.labels.lane_actions")}
-
- ✖
-
-
-
- {t("trello.labels.delete_lane")}
-
-
- );
-};
-
-export default LaneMenu;
diff --git a/client/src/components/trello-board/components/NewCardForm.jsx b/client/src/components/trello-board/components/NewCardForm.jsx
deleted file mode 100644
index 585cc202b..000000000
--- a/client/src/components/trello-board/components/NewCardForm.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React, { useState } from "react";
-import PropTypes from "prop-types";
-import { CardForm, CardHeader, CardRightContent, CardTitle, CardWrapper, Detail } from "../styles/Base";
-import { AddButton, CancelButton } from "../styles/Elements";
-import EditableLabel from "../widgets/EditableLabel.jsx";
-import { useTranslation } from "react-i18next";
-
-const NewCardForm = ({ onCancel, onAdd }) => {
- const [state, setState] = useState({});
- const { t } = useTranslation();
-
- const updateField = (field, value) => {
- setState((prevState) => ({ ...prevState, [field]: value }));
- };
-
- const handleAdd = () => {
- onAdd(state);
- };
-
- return (
-
-
-
-
- updateField("title", val)}
- autoFocus
- />
-
-
- updateField("label", val)} />
-
-
-
- updateField("description", val)}
- />
-
-
- {t("trello.labels.add_card")}
- {t("trello.labels.cancel")}
-
- );
-};
-
-NewCardForm.propTypes = {
- onCancel: PropTypes.func.isRequired,
- onAdd: PropTypes.func.isRequired
-};
-
-export default NewCardForm;
diff --git a/client/src/components/trello-board/components/NewLaneForm.jsx b/client/src/components/trello-board/components/NewLaneForm.jsx
deleted file mode 100644
index 1aa38e584..000000000
--- a/client/src/components/trello-board/components/NewLaneForm.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import React, { useRef } from "react";
-import PropTypes from "prop-types";
-import { LaneTitle, NewLaneButtons, Section } from "../styles/Base";
-import { AddButton, CancelButton } from "../styles/Elements";
-import NewLaneTitleEditor from "../widgets/NewLaneTitleEditor.jsx";
-import { v1 } from "uuid";
-import { useTranslation } from "react-i18next";
-
-const NewLane = ({ onCancel, onAdd }) => {
- const refInput = useRef(null);
- const { t } = useTranslation();
-
- const handleSubmit = () => {
- onAdd({
- id: v1(),
- title: getValue()
- });
- };
-
- const getValue = () => refInput.current.getValue();
-
- // TODO: Commented out because it was never called and it was causing a error
- // const onClickOutside = (a, b, c) => {
- // if (getValue().length > 0) {
- // handleSubmit();
- // } else {
- // onCancel();
- // }
- // };
-
- return (
-
-
-
-
-
- {t("trello.labels.add_lane")}
- {t("trello.labels.cancel")}
-
-
- );
-};
-
-NewLane.propTypes = {
- onCancel: PropTypes.func.isRequired,
- onAdd: PropTypes.func.isRequired
-};
-
-export default NewLane;
diff --git a/client/src/components/trello-board/components/NewLaneSection.jsx b/client/src/components/trello-board/components/NewLaneSection.jsx
deleted file mode 100644
index edfbe5434..000000000
--- a/client/src/components/trello-board/components/NewLaneSection.jsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from "react";
-import { NewLaneSection } from "../styles/Base";
-import { AddLaneLink } from "../styles/Elements";
-import { useTranslation } from "react-i18next";
-
-const NewLaneSectionComponent = ({ onClick }) => {
- const { t } = useTranslation();
-
- return (
-
- {t("trello.labels.add_lane")}
-
- );
-};
-
-export default NewLaneSectionComponent;
diff --git a/client/src/components/trello-board/components/index.js b/client/src/components/trello-board/components/index.js
index 59a41d085..78448c5b1 100644
--- a/client/src/components/trello-board/components/index.js
+++ b/client/src/components/trello-board/components/index.js
@@ -1,11 +1,7 @@
-import LaneHeader from "./Lane/LaneHeader";
import LaneFooter from "./Lane/LaneFooter";
import Card from "./Card";
import Loader from "./Loader.jsx";
-import NewLaneForm from "./NewLaneForm.jsx";
-import NewCardForm from "./NewCardForm.jsx";
-import AddCardLink from "./AddCardLink";
-import NewLaneSection from "./NewLaneSection.jsx";
+
import { BoardWrapper, StyleHorizontal, GlobalStyle, StyleVertical, ScrollableLane, Section } from "../styles/Base";
const exports = {
@@ -15,14 +11,9 @@ const exports = {
BoardWrapper,
Loader,
ScrollableLane,
- LaneHeader,
LaneFooter,
Section,
- NewLaneForm,
- NewLaneSection,
- NewCardForm,
- Card,
- AddCardLink
+ Card
};
export default exports;
diff --git a/client/src/components/trello-board/controllers/Board.jsx b/client/src/components/trello-board/controllers/Board.jsx
index 028e41518..be5c317dc 100644
--- a/client/src/components/trello-board/controllers/Board.jsx
+++ b/client/src/components/trello-board/controllers/Board.jsx
@@ -1,12 +1,11 @@
import { BoardContainer } from "../index";
-import classNames from "classnames";
import { useMemo, useState } from "react";
import { v1 } from "uuid";
const Board = ({ id, className, components, orientation, ...additionalProps }) => {
const [storeId] = useState(id || v1());
- const allClassNames = useMemo(() => classNames("react-trello-board", className || ""), [className]);
+ const allClassNames = useMemo(() => `react-trello-board ${className || ""}`.trim(), [className]);
const OrientationStyle = useMemo(
() => (orientation === "horizontal" ? components.StyleHorizontal : components.StyleVertical),
[orientation, components.StyleHorizontal, components.StyleVertical]
diff --git a/client/src/components/trello-board/controllers/BoardContainer.jsx b/client/src/components/trello-board/controllers/BoardContainer.jsx
index 4cb642a05..1b761e486 100644
--- a/client/src/components/trello-board/controllers/BoardContainer.jsx
+++ b/client/src/components/trello-board/controllers/BoardContainer.jsx
@@ -7,6 +7,7 @@ import isEqual from "lodash/isEqual";
import Lane from "./Lane";
import { PopoverWrapper } from "react-popopo";
import * as actions from "../../../redux/trello/trello.actions.js";
+import { BoardWrapper } from "../styles/Base.js";
/**
* BoardContainer is a React component that represents a Trello-like board.
@@ -17,17 +18,10 @@ import * as actions from "../../../redux/trello/trello.actions.js";
* @param {string} props.id - The unique identifier for the board
* @param {Object} props.components - Custom components to use in the board
* @param {Object} props.data - The initial data for the board
- * @param {boolean} props.draggable - Whether the board is draggable
- * @param {Object} props.style - The CSS styles to apply to the board
- * @param {Function} props.onDataChange - Callback function when the board data changes
* @param {Function} props.onDragEnd - Callback function when a drag ends
- * @param {boolean} props.editable - Whether the board is editable
- * @param {boolean} props.canAddLanes - Whether lanes can be added to the board
- * @param {Object} props.laneStyle - The CSS styles to apply to the lanes
* @param {string} props.orientation - The orientation of the board ("horizontal" or "vertical")
* @param {Function} props.eventBusHandle - Function to handle events from the event bus
* @param {Object} props.reducerData - The initial data for the Redux reducer
- * @param {Object} props.cardStyle - The CSS styles to apply to the cards
* @param {Object} props.otherProps - Any other props to pass to the board
* @returns {JSX.Element} A Trello-like board
*/
@@ -35,17 +29,11 @@ const BoardContainer = ({
id,
components,
data,
- draggable = false,
- style,
onDataChange = () => {},
onDragEnd = () => {},
- editable = false,
- canAddLanes = false,
- laneStyle,
orientation = "horizontal",
eventBusHandle,
reducerData,
- cardStyle,
...otherProps
}) => {
const [isDragging, setIsDragging] = useState(false);
@@ -60,12 +48,20 @@ const BoardContainer = ({
const eventBus = {
publish: (event) => {
switch (event.type) {
- case "ADD_CARD":
- return dispatch(actions.addCard({ laneId: event.laneId, card: event.card }));
- case "REMOVE_CARD":
- return dispatch(actions.removeCard({ laneId: event.laneId, cardId: event.cardId }));
- case "REFRESH_BOARD":
- return dispatch(actions.loadBoard(event.data));
+ // case "ADD_CARD":
+ // return dispatch(actions.addCard({ laneId: event.laneId, card: event.card }));
+ // case "REMOVE_CARD":
+ // return dispatch(actions.removeCard({ laneId: event.laneId, cardId: event.cardId }));
+ // case "REFRESH_BOARD":
+ // return dispatch(actions.loadBoard(event.data));
+ // case "UPDATE_CARDS":
+ // return dispatch(actions.updateCards({ laneId: event.laneId, cards: event.cards }));
+ // case "UPDATE_CARD":
+ // return dispatch(actions.updateCard({ laneId: event.laneId, updatedCard: event.card }));
+ // case "UPDATE_LANES":
+ // return dispatch(actions.updateLanes(event.lanes));
+ // case "UPDATE_LANE":
+ // return dispatch(actions.updateLane(event.lane));
case "MOVE_CARD":
return dispatch(
actions.moveCardAcrossLanes({
@@ -76,14 +72,7 @@ const BoardContainer = ({
event
})
);
- case "UPDATE_CARDS":
- return dispatch(actions.updateCards({ laneId: event.laneId, cards: event.cards }));
- case "UPDATE_CARD":
- return dispatch(actions.updateCard({ laneId: event.laneId, updatedCard: event.card }));
- case "UPDATE_LANES":
- return dispatch(actions.updateLanes(event.lanes));
- case "UPDATE_LANE":
- return dispatch(actions.updateLane(event.lane));
+
default:
return;
}
@@ -109,13 +98,6 @@ const BoardContainer = ({
setIsDragging(true);
}, [setIsDragging]);
- const getCardDetails = useCallback(
- (laneId, cardIndex) => {
- return currentReducerData.lanes.find((lane) => lane.id === laneId).cards[cardIndex];
- },
- [currentReducerData]
- );
-
const passThroughProps = useMemo(
() =>
pick(
@@ -123,59 +105,15 @@ const BoardContainer = ({
id,
components,
data,
- draggable,
- style,
onDataChange,
- editable,
- canAddLanes,
- laneStyle,
orientation,
eventBusHandle,
reducerData,
- cardStyle,
...otherProps
},
- [
- "onLaneScroll",
- "onLaneDelete",
- "onLaneUpdate",
- "onCardClick",
- "onBeforeCardDelete",
- "onCardDelete",
- "onCardAdd",
- "onCardUpdate",
- "onLaneClick",
- "laneSortFunction",
- "draggable",
- "cardDraggable",
- "collapsibleLanes",
- "canAddLanes",
- "hideCardDeleteIcon",
- "tagStyle",
- "handleDragStart",
- "handleDragEnd",
- "cardDragClass",
- "editLaneTitle",
- "orientation"
- ]
+ ["laneSortFunction", "collapsibleLanes", "orientation"]
),
- [
- id,
- components,
- data,
- draggable,
- style,
- onDataChange,
-
- editable,
- canAddLanes,
- laneStyle,
- orientation,
- eventBusHandle,
- reducerData,
- cardStyle,
- otherProps
- ]
+ [id, components, data, onDataChange, orientation, eventBusHandle, reducerData, otherProps]
);
const onLaneDrag = useCallback(
@@ -207,7 +145,7 @@ const BoardContainer = ({
);
return (
-
+
{currentReducerData.lanes.map((lane, index) => {
@@ -218,13 +156,7 @@ const BoardContainer = ({
boardId={groupName}
components={components}
id={id}
- getCardDetails={getCardDetails}
index={index}
- droppable={droppable === undefined ? true : droppable}
- style={laneStyle || lane.style || {}}
- labelStyle={lane.labelStyle || {}}
- cardStyle={cardStyle || lane.cardStyle}
- editable={editable && !lane.disallowAddingCard}
{...laneOtherProps}
{...passThroughProps}
cards={lane.cards}
@@ -235,7 +167,7 @@ const BoardContainer = ({
})}
-
+
);
};
@@ -247,30 +179,10 @@ BoardContainer.propTypes = {
reducerData: PropTypes.object,
onDataChange: PropTypes.func,
eventBusHandle: PropTypes.func,
- onLaneScroll: PropTypes.func,
- onCardClick: PropTypes.func,
- onBeforeCardDelete: PropTypes.func,
- onCardDelete: PropTypes.func,
- onCardAdd: PropTypes.func,
- onCardUpdate: PropTypes.func,
- onLaneAdd: PropTypes.func,
- onLaneDelete: PropTypes.func,
- onLaneClick: PropTypes.func,
- onLaneUpdate: PropTypes.func,
laneSortFunction: PropTypes.func,
- draggable: PropTypes.bool,
collapsibleLanes: PropTypes.bool,
- editable: PropTypes.bool,
- canAddLanes: PropTypes.bool,
- hideCardDeleteIcon: PropTypes.bool,
- handleDragStart: PropTypes.func,
handleDragEnd: PropTypes.func,
- style: PropTypes.object,
- tagStyle: PropTypes.object,
- cardDraggable: PropTypes.bool,
- cardDragClass: PropTypes.string,
- orientation: PropTypes.string,
- cardStyle: PropTypes.object
+ orientation: PropTypes.string
};
export default BoardContainer;
diff --git a/client/src/components/trello-board/controllers/Lane.jsx b/client/src/components/trello-board/controllers/Lane.jsx
index 5e26d60ea..2e67e5857 100644
--- a/client/src/components/trello-board/controllers/Lane.jsx
+++ b/client/src/components/trello-board/controllers/Lane.jsx
@@ -1,14 +1,14 @@
-import React, { forwardRef, useCallback, useMemo, useState, useEffect } from "react";
-import classNames from "classnames";
+import React, { forwardRef, useCallback, useEffect, useMemo, useState } from "react";
import PropTypes from "prop-types";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
-import { v1 } from "uuid";
import * as actions from "../../../redux/trello/trello.actions.js";
import { Draggable, Droppable } from "../dnd/lib";
import { Virtuoso, VirtuosoGrid } from "react-virtuoso";
import HeightPreservingItem from "../components/Lane/HeightPreservingItem.jsx";
+import { Section } from "../styles/Base.js";
+import LaneFooter from "../components/Lane/LaneFooter.jsx";
const Lane = ({
actions,
@@ -20,36 +20,14 @@ const Lane = ({
laneSortFunction,
style = {},
cardStyle = {},
- tagStyle = {},
- titleStyle = {},
- labelStyle = {},
cards,
- label,
- draggable = false,
collapsibleLanes = false,
- droppable = true,
- onCardClick = () => {},
- onBeforeCardDelete = () => {},
- onCardDelete = () => {},
- onCardAdd = () => {},
- onCardUpdate = () => {},
- onLaneDelete = () => {},
- onLaneUpdate = () => {},
- onLaneClick = () => {},
- onLaneScroll = () => {},
- editable = false,
- cardDraggable = true,
- cardDragClass,
- cardDropClass,
- canAddLanes = false,
- hideCardDeleteIcon = false,
+
components = {},
orientation = "vertical",
className,
- currentPage,
...otherProps
}) => {
- const [addCardMode, setAddCardMode] = useState(false);
const [collapsed, setCollapsed] = useState(false);
const [isVisible, setIsVisible] = useState(true);
@@ -65,76 +43,11 @@ const Lane = ({
return cards.concat().sort((card1, card2) => sortFunction(card1, card2));
}, []);
- const removeCard = useCallback(
- (cardId) => {
- if (onBeforeCardDelete && typeof onBeforeCardDelete === "function") {
- onBeforeCardDelete(() => {
- onCardDelete && onCardDelete(cardId, id);
- actions.removeCard({ laneId: id, cardId: cardId });
- });
- } else {
- onCardDelete && onCardDelete(cardId, id);
- actions.removeCard({ laneId: id, cardId: cardId });
- }
- },
- [onBeforeCardDelete, onCardDelete, actions, id]
- );
-
- const handleCardClick = useCallback(
- (e, card) => {
- onCardClick && onCardClick(card.id, card.metadata, card.laneId);
- e.stopPropagation();
- },
- [onCardClick]
- );
-
- const showEditableCard = useCallback(() => {
- setAddCardMode(true);
- }, [setAddCardMode]);
-
- const hideEditableCard = useCallback(() => {
- setAddCardMode(false);
- }, [setAddCardMode]);
-
- const addNewCard = useCallback(
- (params) => {
- const laneId = id;
- const newCardId = v1();
- hideEditableCard();
- let card = { id: newCardId, ...params };
- actions.addCard({ laneId, card });
- onCardAdd(card, laneId);
- },
- [actions, id, onCardAdd, hideEditableCard]
- );
-
- const updateCard = useCallback(
- (updatedCard) => {
- actions.updateCard({ laneId: id, card: updatedCard });
- onCardUpdate(id, updatedCard);
- },
- [actions, id, onCardUpdate]
- );
-
- const removeLane = useCallback(() => {
- actions.removeLane({ laneId: id });
- onLaneDelete(id);
- }, [actions, id, onLaneDelete]);
-
- const updateTitle = useCallback(
- (value) => {
- actions.updateLane({ id, title: value });
- onLaneUpdate(id, { title: value });
- },
- [actions, id, onLaneUpdate]
- );
-
const toggleLaneCollapsed = useCallback(() => {
collapsibleLanes && setCollapsed(!collapsed);
}, [collapsibleLanes, collapsed]);
const Card = React.memo(({ provided, item: card, isDragging }) => {
- const onDeleteCard = () => removeCard(card.id);
return (
- handleCardClick(e, card)}
- onChange={(updatedCard) => updateCard(updatedCard)}
- showDeleteButton={!hideCardDeleteIcon}
- tagStyle={tagStyle}
- cardDraggable={cardDraggable}
- editable={editable}
- {...card}
- />
+
);
});
@@ -174,16 +75,6 @@ const Lane = ({
);
};
- const renderAddCardLink = useMemo(
- () => editable && !addCardMode && ,
- [editable, addCardMode, showEditableCard, id]
- );
-
- const renderNewCardForm = useMemo(
- () => addCardMode && ,
- [addCardMode, hideEditableCard, addNewCard, id]
- );
-
const ItemWrapper = ({ children, ...props }) => (
{children}
@@ -196,43 +87,46 @@ const Lane = ({
const commonProps = {
useWindowScroll: true,
- data: renderedCards,
- overscan: {
- main: 22,
- reverse: 22
- }
+ data: renderedCards
};
- const componentProps =
- orientation === "vertical"
- ? {
- ...commonProps,
- scrollerRef: provided.innerRef,
- listClassName: "grid-container",
- itemClassName: "grid-item",
- components: {
- List: forwardRef(({ style, children, ...props }, ref) => (
-
- {children}
-
- )),
- Item: ({ children, ...props }) =>
{children}
- },
- itemContent: (index, item) =>
{renderDraggable(index, item)}
- }
- : {
- ...commonProps,
- components: { Item: HeightPreservingItem },
- itemContent: (index, item) => renderDraggable(index, item),
- scrollerRef: provided.innerRef
- };
+ const verticalProps = {
+ ...commonProps,
+ // we are using the useWindowScroll, so we don't need to pass the scrollerRef
+ // scrollerRef: provided.innerRef,
+ listClassName: "grid-container",
+ itemClassName: "grid-item",
+ components: {
+ List: forwardRef(({ style, children, ...props }, ref) => (
+
+ {children}
+
+ )),
+ Item: ({ children, ...props }) =>
{children}
+ },
+ itemContent: (index, item) =>
{renderDraggable(index, item)},
+ overscan: { main: 10, reverse: 10 }
+ };
+
+ const horizontalProps = {
+ ...commonProps,
+ components: { Item: HeightPreservingItem },
+ overscan: { main: 1, reverse: 1 },
+ itemContent: (index, item) => renderDraggable(index, item),
+ scrollerRef: provided.innerRef
+ };
+
+ const componentProps = orientation === "vertical" ? verticalProps : horizontalProps;
+
+ // A collapsed lane does not need to render the Virtuoso component
const finalComponentProps = collapsed ? {} : componentProps;
+
return (
}
{(orientation === "horizontal" || renderedCards.length === 0 || collapsed) && provided.placeholder}
- {renderAddCardLink}
- {renderNewCardForm}
);
};
@@ -275,18 +167,13 @@ const Lane = ({
};
const renderHeader = (pickedProps) => {
- return (
-
- );
+ return ;
};
- const allClassNames = classNames("react-trello-lane", collapsed ? "lane-collapsed" : "", className || "");
-
+ const allClassNames = useMemo(
+ () => `react-trello-lane ${collapsed ? "lane-collapsed" : ""} ${className || ""}`.trim(),
+ [collapsed, className]
+ );
const passedProps = {
actions,
id,
@@ -296,37 +183,20 @@ const Lane = ({
laneSortFunction,
style,
cardStyle,
- tagStyle,
- titleStyle,
- labelStyle,
cards,
- label,
- draggable,
collapsibleLanes,
- droppable,
- editable,
- cardDraggable,
- cardDragClass,
- cardDropClass,
- canAddLanes,
- hideCardDeleteIcon,
+
components,
orientation,
className,
- currentPage,
...otherProps
};
return (
- onLaneClick && onLaneClick(id)}
- orientation={orientation}
- {...passedProps}
- >
+
{renderHeader({ id, cards, ...passedProps })}
{renderDragContainer()}
- {collapsibleLanes && }
-
+ {collapsibleLanes && }
+
);
};
@@ -339,20 +209,9 @@ Lane.propTypes = {
laneSortFunction: PropTypes.func,
style: PropTypes.object,
cardStyle: PropTypes.object,
- tagStyle: PropTypes.object,
- titleStyle: PropTypes.object,
- labelStyle: PropTypes.object,
cards: PropTypes.array,
label: PropTypes.string,
- draggable: PropTypes.bool,
collapsibleLanes: PropTypes.bool,
- droppable: PropTypes.bool,
- editable: PropTypes.bool,
- cardDraggable: PropTypes.bool,
- cardDragClass: PropTypes.string,
- cardDropClass: PropTypes.string,
- canAddLanes: PropTypes.bool,
- hideCardDeleteIcon: PropTypes.bool,
components: PropTypes.object,
orientation: PropTypes.string
};
diff --git a/client/src/components/trello-board/helpers/LaneHelper.js b/client/src/components/trello-board/helpers/LaneHelper.js
index 69b9edb52..d4f31d704 100644
--- a/client/src/components/trello-board/helpers/LaneHelper.js
+++ b/client/src/components/trello-board/helpers/LaneHelper.js
@@ -1,10 +1,25 @@
import update from "immutability-helper";
import cloneDeep from "lodash/cloneDeep";
+/**
+ * Update the lanes in the state
+ * @param state
+ * @param lanes
+ * @returns {unknown}
+ */
const updateLanes = (state, lanes) => update(state, { lanes: { $set: lanes } });
-const updateLaneCards = (lane, cards) => update(lane, { cards: { $set: cards } });
+/**
+ * Helper functions for managing lanes
+ * @type {{moveCardAcrossLanes: (function(*, {fromLaneId: *, toLaneId: *, cardId: *, index: *}): *), initialiseLanes: (function(*, {lanes: *}): {lanes: *})}}
+ */
const LaneHelper = {
+ /**
+ * Initialise the lanes
+ * @param state
+ * @param lanes
+ * @returns {unknown}
+ */
initialiseLanes: (state, { lanes }) => {
const newLanes = lanes.map((lane) => {
lane.currentPage = 1;
@@ -14,79 +29,6 @@ const LaneHelper = {
return updateLanes(state, newLanes);
},
- paginateLane: (state, { laneId, newCards, nextPage }) => {
- const updatedLanes = LaneHelper.appendCardsToLane(state, { laneId: laneId, newCards: newCards });
- updatedLanes.find((lane) => lane.id === laneId).currentPage = nextPage;
- return updateLanes(state, updatedLanes);
- },
-
- appendCardsToLane: (state, { laneId, newCards, index }) => {
- const lane = state.lanes.find((lane) => lane.id === laneId);
- newCards = newCards
- .map((c) => update(c, { laneId: { $set: laneId } }))
- .filter((c) => lane.cards.find((card) => card.id === c.id) == null);
- return state.lanes.map((lane) => {
- if (lane.id === laneId) {
- const cardsToUpdate =
- index !== undefined
- ? [...lane.cards.slice(0, index), ...newCards, ...lane.cards.slice(index)]
- : [...lane.cards, ...newCards];
- return updateLaneCards(lane, cardsToUpdate);
- } else {
- return lane;
- }
- });
- },
-
- appendCardToLane: (state, { laneId, card, index }) => {
- const newLanes = LaneHelper.appendCardsToLane(state, { laneId: laneId, newCards: [card], index });
- return updateLanes(state, newLanes);
- },
-
- addLane: (state, lane) => {
- const newLane = { cards: [], ...lane };
- return updateLanes(state, [...state.lanes, newLane]);
- },
-
- updateLane: (state, updatedLane) => {
- const newLanes = state.lanes.map((lane) => (updatedLane.id === lane.id ? { ...lane, ...updatedLane } : lane));
- return updateLanes(state, newLanes);
- },
-
- removeCardFromLane: (state, { laneId, cardId }) => {
- // Clone the state to avoid mutation
- const newLanes = cloneDeep(state.lanes);
-
- // Find the lane from which the card will be removed
- const lane = newLanes.find((lane) => lane.id === laneId);
-
- // Find the card in the lane
- const cardIndex = lane.cards.findIndex((card) => card.id === cardId);
- if (cardIndex === -1) {
- throw new Error("Card not found in the lane");
- }
-
- // Remove the card from the lane
- lane.cards.splice(cardIndex, 1);
-
- let idx = 0;
-
- // Update the lane and card indexes for all lanes
- newLanes.forEach((lane, laneIndex) => {
- lane.cards.forEach((card, cardIndex) => {
- card.idx = idx;
- card.laneIndex = laneIndex;
- card.cardIndex = cardIndex;
- card.laneId = lane.id;
- idx++;
- });
- });
-
- return update(state, {
- lanes: { $set: newLanes }
- });
- },
-
/**
* Move a card from one lane to another
* @param state
@@ -136,28 +78,104 @@ const LaneHelper = {
return update(state, {
lanes: { $set: newLanes }
});
- },
- updateCardsForLane: (state, { laneId, cards }) => {
- const lanes = state.lanes.map((lane) => (lane.id === laneId ? updateLaneCards(lane, cards) : lane));
- return updateLanes(state, lanes);
- },
-
- updateCardForLane: (state, { laneId, card: updatedCard }) => {
- const lanes = state.lanes.map((lane) => {
- if (lane.id === laneId) {
- const cards = lane.cards.map((card) => (card.id === updatedCard.id ? { ...card, ...updatedCard } : card));
- return updateLaneCards(lane, cards);
- } else {
- return lane;
- }
- });
- return updateLanes(state, lanes);
- },
-
- removeLane: (state, { laneId }) => {
- const updatedLanes = state.lanes.filter((lane) => lane.id !== laneId);
- return updateLanes(state, updatedLanes);
}
+
+ // TODO: (Note), the rest of this commented out logic is for the way the original Trello board was implemented
+ // It would not be hard to adapt should we need to use it in the future
+
+ // const updateLaneCards = (lane, cards) => update(lane, { cards: { $set: cards } });
+ // paginateLane: (state, { laneId, newCards, nextPage }) => {
+ // const updatedLanes = LaneHelper.appendCardsToLane(state, { laneId: laneId, newCards: newCards });
+ // updatedLanes.find((lane) => lane.id === laneId).currentPage = nextPage;
+ // return updateLanes(state, updatedLanes);
+ // },
+ // appendCardsToLane: (state, { laneId, newCards, index }) => {
+ // const lane = state.lanes.find((lane) => lane.id === laneId);
+ // newCards = newCards
+ // .map((c) => update(c, { laneId: { $set: laneId } }))
+ // .filter((c) => lane.cards.find((card) => card.id === c.id) == null);
+ // return state.lanes.map((lane) => {
+ // if (lane.id === laneId) {
+ // const cardsToUpdate =
+ // index !== undefined
+ // ? [...lane.cards.slice(0, index), ...newCards, ...lane.cards.slice(index)]
+ // : [...lane.cards, ...newCards];
+ // return updateLaneCards(lane, cardsToUpdate);
+ // } else {
+ // return lane;
+ // }
+ // });
+ // },
+
+ // appendCardToLane: (state, { laneId, card, index }) => {
+ // const newLanes = LaneHelper.appendCardsToLane(state, { laneId: laneId, newCards: [card], index });
+ // return updateLanes(state, newLanes);
+ // },
+ //
+ // addLane: (state, lane) => {
+ // const newLane = { cards: [], ...lane };
+ // return updateLanes(state, [...state.lanes, newLane]);
+ // },
+ //
+ // updateLane: (state, updatedLane) => {
+ // const newLanes = state.lanes.map((lane) => (updatedLane.id === lane.id ? { ...lane, ...updatedLane } : lane));
+ // return updateLanes(state, newLanes);
+ // },
+ //
+ // removeCardFromLane: (state, { laneId, cardId }) => {
+ // // Clone the state to avoid mutation
+ // const newLanes = cloneDeep(state.lanes);
+ //
+ // // Find the lane from which the card will be removed
+ // const lane = newLanes.find((lane) => lane.id === laneId);
+ //
+ // // Find the card in the lane
+ // const cardIndex = lane.cards.findIndex((card) => card.id === cardId);
+ // if (cardIndex === -1) {
+ // throw new Error("Card not found in the lane");
+ // }
+ //
+ // // Remove the card from the lane
+ // lane.cards.splice(cardIndex, 1);
+ //
+ // let idx = 0;
+ //
+ // // Update the lane and card indexes for all lanes
+ // newLanes.forEach((lane, laneIndex) => {
+ // lane.cards.forEach((card, cardIndex) => {
+ // card.idx = idx;
+ // card.laneIndex = laneIndex;
+ // card.cardIndex = cardIndex;
+ // card.laneId = lane.id;
+ // idx++;
+ // });
+ // });
+ //
+ // return update(state, {
+ // lanes: { $set: newLanes }
+ // });
+ // },
+ // updateCardsForLane: (state, { laneId, cards }) => {
+ // const lanes = state.lanes.map((lane) => (lane.id === laneId ? updateLaneCards(lane, cards) : lane));
+ // return updateLanes(state, lanes);
+ // },
+ //
+ // updateCardForLane: (state, { laneId, card: updatedCard }) => {
+ // const lanes = state.lanes.map((lane) => {
+ // if (lane.id === laneId) {
+ // const cards = lane.cards.map((card) => (card.id === updatedCard.id ? { ...card, ...updatedCard } : card));
+ // return updateLaneCards(lane, cards);
+ // } else {
+ // return lane;
+ // }
+ // });
+ // return updateLanes(state, lanes);
+ // },
+ //
+ // removeLane: (state, { laneId }) => {
+ // const updatedLanes = state.lanes.filter((lane) => lane.id !== laneId);
+ // return updateLanes(state, updatedLanes);
+ // }
};
export default LaneHelper;
diff --git a/client/src/components/trello-board/styles/Base.js b/client/src/components/trello-board/styles/Base.js
index 4d2166a97..f45aa4b5d 100644
--- a/client/src/components/trello-board/styles/Base.js
+++ b/client/src/components/trello-board/styles/Base.js
@@ -24,6 +24,10 @@ const getSectionStyles = (props) => {
white-space: nowrap;
// overflow-y: none;
min-width: 8.5%;
+ flex-wrap: wrap;
+ align-content: center;
+ justify-content: center;
+ align-items: stretch;
`;
}
return `
@@ -31,6 +35,18 @@ const getSectionStyles = (props) => {
`;
};
+const getLaneFooterStyles = (props) => {
+ if (props.operation === "horizontal") {
+ return `
+ height: 50px;
+ margin-top: 20px;
+ `;
+ }
+ return `
+ height: 25px;
+ `;
+};
+
export const GlobalStyle = createGlobalStyle`
.comPlainTextContentEditable {
-webkit-user-modify: read-write-plaintext-only;
@@ -84,15 +100,18 @@ export const StyleHorizontal = styled.div`
.react-trello-lane.lane-collapsed {
min-height: 15px;
}
+
.ant-card-body {
padding: 4px;
}
+
.item-wrapper {
display: flex;
flex: 1 1 auto;
white-space: nowrap;
min-width: 4%;
}
+
.react-trello-card {
height: auto;
margin: 2px;
@@ -118,10 +137,12 @@ export const StyleVertical = styled.div`
width: 100%;
height: 100%;
}
+
.grid-container {
display: flex;
flex-wrap: wrap;
}
+
.grid-item {
width: 8%; // TODO: THIS IS WHERE WE GET VERTICAL CARD CUSTOMIZATION
display: flex;
@@ -133,6 +154,7 @@ export const StyleVertical = styled.div`
height: 100%;
width: 100%;
}
+
.item-wrapper {
width: 100%;
height: 100%;
@@ -219,27 +241,12 @@ export const Section = styled.section`
${getSectionStyles};
`;
-export const LaneHeader = styled(Header)`
- margin-bottom: 0;
- ${(props) =>
- props.editLaneTitle &&
- css`
- padding: 0;
- line-height: 30px;
- `} ${(props) =>
- !props.editLaneTitle &&
- css`
- padding: 0 5px;
- `};
-`;
-
export const LaneFooter = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
- position: relative;
- height: 10px;
+ ${getLaneFooterStyles};
`;
export const ScrollableLane = styled.div`
diff --git a/client/src/components/trello-board/widgets/DeleteButton.jsx b/client/src/components/trello-board/widgets/DeleteButton.jsx
deleted file mode 100644
index 0076921c8..000000000
--- a/client/src/components/trello-board/widgets/DeleteButton.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from "react";
-import { DeleteWrapper } from "../styles/Elements";
-import { Button } from "antd";
-
-const DeleteButton = (props) => {
- return (
-
-
-
- );
-};
-
-export default DeleteButton;
diff --git a/client/src/components/trello-board/widgets/EditableLabel.jsx b/client/src/components/trello-board/widgets/EditableLabel.jsx
deleted file mode 100644
index 13564234e..000000000
--- a/client/src/components/trello-board/widgets/EditableLabel.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-
-class EditableLabel extends React.Component {
- constructor({value}) {
- super()
- this.state = {value: value}
- }
-
- getText = el => {
- return el.innerText
- }
-
- onTextChange = ev => {
- const value = this.getText(ev.target)
- this.setState({value: value})
- }
-
- componentDidMount() {
- if (this.props.autoFocus) {
- this.refDiv.focus()
- }
- }
-
- onBlur = () => {
- this.props.onChange(this.state.value)
- }
-
- onPaste = ev => {
- ev.preventDefault()
- const value = ev.clipboardData.getData('text')
- document.execCommand('insertText', false, value)
- }
-
- getClassName = () => {
- const placeholder = this.state.value === '' ? 'comPlainTextContentEditable--has-placeholder' : ''
- return `comPlainTextContentEditable ${placeholder}`
- }
-
- onKeyDown = e => {
- if (e.keyCode === 13) {
- this.props.onChange(this.state.value)
- this.refDiv.blur()
- e.preventDefault()
- }
- if (e.keyCode === 27) {
- this.refDiv.value = this.props.value
- this.setState({value: this.props.value})
- // this.refDiv.blur()
- e.preventDefault()
- e.stopPropagation()
- }
- }
-
- render() {
- const placeholder = this.props.value.length > 0 ? false : this.props.placeholder
- return (
- (this.refDiv = ref)}
- contentEditable="true"
- className={this.getClassName()}
- onPaste={this.onPaste}
- onBlur={this.onBlur}
- onInput={this.onTextChange}
- onKeyDown={this.onKeyDown}
- placeholder={placeholder}
- />
- )
- }
-}
-
-EditableLabel.propTypes = {
- onChange: PropTypes.func,
- placeholder: PropTypes.string,
- autoFocus: PropTypes.bool,
- inline: PropTypes.bool,
- value: PropTypes.string
-}
-
-EditableLabel.defaultProps = {
- onChange: () => {},
- placeholder: '',
- autoFocus: false,
- inline: false,
- value: ''
-}
-export default EditableLabel
diff --git a/client/src/components/trello-board/widgets/InlineInput.jsx b/client/src/components/trello-board/widgets/InlineInput.jsx
deleted file mode 100644
index 56c311931..000000000
--- a/client/src/components/trello-board/widgets/InlineInput.jsx
+++ /dev/null
@@ -1,106 +0,0 @@
-import React, { useEffect, useRef, useState } from "react";
-import PropTypes from "prop-types";
-import { InlineInput } from "../styles/Base";
-import autosize from "autosize";
-
-const InlineInputController = ({ onSave, border, placeholder, value, autoFocus, resize, onCancel }) => {
- const inputRef = useRef(null);
- const [inputValue, setInputValue] = useState(value);
-
- // Effect for autosizing and initial autoFocus
- useEffect(() => {
- if (inputRef.current && resize !== "none") {
- autosize(inputRef.current);
- }
- if (inputRef.current && autoFocus) {
- inputRef.current.focus();
- }
- }, [resize, autoFocus]);
-
- // Effect to update value when props change
- useEffect(() => {
- setInputValue(value);
- }, [value]);
-
- const handleFocus = (e) => e.target.select();
-
- const handleMouseDown = (e) => {
- if (document.activeElement !== e.target) {
- e.preventDefault();
- inputRef.current.focus();
- }
- };
-
- const handleBlur = () => {
- updateValue();
- };
-
- const handleKeyDown = (e) => {
- if (e.keyCode === 13) {
- // Enter
- inputRef.current.blur();
- e.preventDefault();
- } else if (e.keyCode === 27) {
- // Escape
- setInputValue(value); // Reset to initial value
- inputRef.current.blur();
- e.preventDefault();
- } else if (e.keyCode === 9) {
- // Tab
- if (inputValue.length === 0) {
- onCancel();
- }
- inputRef.current.blur();
- e.preventDefault();
- }
- };
-
- const updateValue = () => {
- if (inputValue !== value) {
- onSave(inputValue);
- }
- };
-
- return (
- setInputValue(e.target.value)}
- autoComplete="off"
- autoCorrect="off"
- autoCapitalize="off"
- spellCheck="false"
- dataGramm="false"
- rows={1}
- autoFocus={autoFocus}
- />
- );
-};
-
-InlineInputController.propTypes = {
- onSave: PropTypes.func,
- onCancel: PropTypes.func,
- border: PropTypes.bool,
- placeholder: PropTypes.string,
- value: PropTypes.string,
- autoFocus: PropTypes.bool,
- resize: PropTypes.oneOf(["none", "vertical", "horizontal"])
-};
-
-InlineInputController.defaultProps = {
- onSave: () => {},
- onCancel: () => {},
- placeholder: "",
- value: "",
- border: false,
- autoFocus: false,
- resize: "none"
-};
-
-export default InlineInputController;
diff --git a/client/src/components/trello-board/widgets/NewLaneTitleEditor.jsx b/client/src/components/trello-board/widgets/NewLaneTitleEditor.jsx
deleted file mode 100644
index 572046d70..000000000
--- a/client/src/components/trello-board/widgets/NewLaneTitleEditor.jsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import React from "react";
-import PropTypes from "prop-types";
-import { InlineInput } from "../styles/Base";
-import autosize from "autosize";
-
-class NewLaneTitleEditor extends React.Component {
- onKeyDown = (e) => {
- if (e.keyCode === 13) {
- this.refInput.blur();
- this.props.onSave();
- e.preventDefault();
- }
- if (e.keyCode === 27) {
- this.cancel();
- e.preventDefault();
- }
-
- if (e.keyCode === 9) {
- if (this.getValue().length === 0) {
- this.cancel();
- } else {
- this.props.onSave();
- }
- e.preventDefault();
- }
- };
-
- cancel = () => {
- this.setValue("");
- this.props.onCancel();
- this.refInput.blur();
- };
-
- getValue = () => this.refInput.value;
- setValue = (value) => (this.refInput.value = value);
-
- saveValue = () => {
- if (this.getValue() !== this.props.value) {
- this.props.onSave(this.getValue());
- }
- };
-
- focus = () => this.refInput.focus();
-
- setRef = (ref) => {
- this.refInput = ref;
- if (this.props.resize !== "none") {
- autosize(this.refInput);
- }
- };
-
- render() {
- const { autoFocus, resize, border, autoResize, value, placeholder } = this.props;
-
- return (
-
- );
- }
-}
-
-NewLaneTitleEditor.propTypes = {
- onSave: PropTypes.func,
- onCancel: PropTypes.func,
- border: PropTypes.bool,
- placeholder: PropTypes.string,
- value: PropTypes.string,
- autoFocus: PropTypes.bool,
- autoResize: PropTypes.bool,
- resize: PropTypes.oneOf(["none", "vertical", "horizontal"])
-};
-
-NewLaneTitleEditor.defaultProps = {
- inputRef: () => {},
- onSave: () => {},
- onCancel: () => {},
- placeholder: "",
- value: "",
- border: false,
- autoFocus: false,
- autoResize: false,
- resize: "none"
-};
-
-export default NewLaneTitleEditor;
diff --git a/client/src/components/trello-board/widgets/index.jsx b/client/src/components/trello-board/widgets/index.jsx
deleted file mode 100644
index b58eedfd6..000000000
--- a/client/src/components/trello-board/widgets/index.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import DeleteButton from "./DeleteButton";
-import EditableLabel from "./EditableLabel";
-import InlineInput from "./InlineInput";
-
-const exports = {
- DeleteButton,
- EditableLabel,
- InlineInput
-};
-
-export default exports;