- Checkpoint, this thing is fast has heck.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
import { SyncOutlined, UnorderedListOutlined } from "@ant-design/icons";
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
import Board from "../../components/trello-board/index";
|
||||
import { Button, Grid, notification, Skeleton, Space, Statistic } from "antd";
|
||||
import { Button, notification, Skeleton, Space, Statistic } from "antd";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import styled from "styled-components";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
@@ -20,7 +19,7 @@ import ProductionBoardCard from "../production-board-kanban-card/production-boar
|
||||
import ProductionListDetailComponent from "../production-list-detail/production-list-detail.component";
|
||||
import CardColorLegend from "../production-board-kanban-card/production-board-kanban-card-color-legend.component";
|
||||
import "./production-board-kanban.styles.scss";
|
||||
import { createBoardData, createFakeBoardData } from "./production-board-kanban.utils.js";
|
||||
import { createFakeBoardData, createBoardData } from "./production-board-kanban.utils.js";
|
||||
import ProductionBoardKanbanSettings from "./production-board-kanban.settings.component.jsx";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -54,6 +53,7 @@ export function ProductionBoardKanbanComponent({
|
||||
const [isMoving, setIsMoving] = useState(false);
|
||||
|
||||
const orientation = associationSettings?.kanban_settings?.orientation ? "vertical" : "horizontal";
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -63,7 +63,7 @@ export function ProductionBoardKanbanComponent({
|
||||
}, [associationSettings]);
|
||||
|
||||
useEffect(() => {
|
||||
const boardData = createFakeBoardData(
|
||||
const boardData = createBoardData(
|
||||
[...bodyshop.md_ro_statuses.production_statuses, ...(bodyshop.md_ro_statuses.additional_board_statuses || [])],
|
||||
data,
|
||||
filter
|
||||
@@ -113,89 +113,88 @@ export function ProductionBoardKanbanComponent({
|
||||
};
|
||||
|
||||
// TODO, refine and use action
|
||||
const onDragEnd = async (...args) => {
|
||||
console.dir(args);
|
||||
const onDragEnd = async ({ type, source, destination, draggableId, ...args }) => {
|
||||
// //cardId, sourceLaneId, targetLaneId, position, cardDetails
|
||||
// logImEXEvent("kanban_drag_end");
|
||||
logImEXEvent("kanban_drag_end");
|
||||
|
||||
// Early Gate
|
||||
if (!type || type !== "lane" || !source || !destination) return;
|
||||
|
||||
setIsMoving(true);
|
||||
|
||||
const targetLane = boardLanes.lanes.find((lane) => lane.id === destination.droppableId);
|
||||
const sourceLane = boardLanes.lanes.find((lane) => lane.id === source.droppableId);
|
||||
|
||||
const sameColumnTransfer = source.droppableId === destination.droppableId;
|
||||
const sourceCard = getCardByID(boardLanes, draggableId);
|
||||
|
||||
const movedCardWillBeFirst = destination.index === 0;
|
||||
const movedCardWillBeLast = destination.index > targetLane.cards.length - 1;
|
||||
const movedCardIsFirstNewCard = movedCardWillBeFirst && movedCardWillBeLast;
|
||||
|
||||
const lastCardInTargetLane = targetLane.cards[targetLane.cards.length - 1];
|
||||
|
||||
const oldChildCard = sourceLane.cards[destination.index + 1];
|
||||
|
||||
//
|
||||
// // Early Gate
|
||||
// if (!type || type !== "lane" || !source || !destination) return;
|
||||
const newChildCard = movedCardWillBeLast
|
||||
? null
|
||||
: targetLane.cards[
|
||||
sameColumnTransfer
|
||||
? destination.index - destination.index > 0
|
||||
? destination.index
|
||||
: destination.index + 1
|
||||
: destination.index
|
||||
];
|
||||
|
||||
const oldChildCardNewParent = oldChildCard ? sourceCard.metadata.kanbanparent : null;
|
||||
//
|
||||
// setIsMoving(true);
|
||||
//
|
||||
// const sameColumnTransfer = source.droppableId === destination.droppableId;
|
||||
// const targetLane = boardLanes.lanes[Number.parseInt(destination.droppableId)];
|
||||
// const sourceLane = boardLanes.lanes[Number.parseInt(source.droppableId)];
|
||||
// const sourceCard = getCardByID(boardLanes, draggableId);
|
||||
//
|
||||
// const movedCardWillBeFirst = destination.index === 0;
|
||||
// const movedCardWillBeLast = destination.index > targetLane.cards.length - 1;
|
||||
// const movedCardIsFirstNewCard = movedCardWillBeFirst && movedCardWillBeLast;
|
||||
//
|
||||
// const lastCardInTargetLane = targetLane.cards[targetLane.cards.length - 1];
|
||||
//
|
||||
// const oldChildCard = sourceLane.cards[destination.index + 1];
|
||||
//
|
||||
// //
|
||||
// const newChildCard = movedCardWillBeLast
|
||||
// ? null
|
||||
// : targetLane.cards[
|
||||
// sameColumnTransfer
|
||||
// ? destination.index - destination.index > 0
|
||||
// ? destination.index
|
||||
// : destination.index + 1
|
||||
// : destination.index
|
||||
// ];
|
||||
//
|
||||
// const oldChildCardNewParent = oldChildCard ? sourceCard.metadata.kanbanparent : null;
|
||||
//
|
||||
// let movedCardNewKanbanParent;
|
||||
// if (movedCardWillBeFirst) {
|
||||
// movedCardNewKanbanParent = "-1";
|
||||
// } else if (movedCardWillBeLast) {
|
||||
// movedCardNewKanbanParent = lastCardInTargetLane.id;
|
||||
// } else if (!!newChildCard) {
|
||||
// movedCardNewKanbanParent = newChildCard.metadata.kanbanparent;
|
||||
// } else {
|
||||
// console.log("==> !!!!!!Couldn't find a parent.!!!! <==");
|
||||
// }
|
||||
// const newChildCardNewParent = newChildCard ? draggableId : null;
|
||||
// try {
|
||||
// const update = await client.mutate({
|
||||
// mutation: generate_UPDATE_JOB_KANBAN(
|
||||
// oldChildCard ? oldChildCard.id : null,
|
||||
// oldChildCardNewParent,
|
||||
// draggableId,
|
||||
// movedCardNewKanbanParent,
|
||||
// targetLane.id,
|
||||
// newChildCard ? newChildCard.id : null,
|
||||
// newChildCardNewParent
|
||||
// )
|
||||
// });
|
||||
//
|
||||
// insertAuditTrail({
|
||||
// jobid: draggableId,
|
||||
// operation: AuditTrailMapping.jobstatuschange(targetLane.id),
|
||||
// type: "jobstatuschange"
|
||||
// });
|
||||
//
|
||||
// if (update.errors) {
|
||||
// notification["error"]({
|
||||
// message: t("production.errors.boardupdate", {
|
||||
// message: JSON.stringify(update.errors)
|
||||
// })
|
||||
// });
|
||||
// }
|
||||
// } catch (error) {
|
||||
// notification["error"]({
|
||||
// message: t("production.errors.boardupdate", {
|
||||
// message: error.message
|
||||
// })
|
||||
// });
|
||||
// } finally {
|
||||
// setIsMoving(false);
|
||||
// }
|
||||
// };
|
||||
let movedCardNewKanbanParent;
|
||||
if (movedCardWillBeFirst) {
|
||||
movedCardNewKanbanParent = "-1";
|
||||
} else if (movedCardWillBeLast) {
|
||||
movedCardNewKanbanParent = lastCardInTargetLane.id;
|
||||
} else if (!!newChildCard) {
|
||||
movedCardNewKanbanParent = newChildCard.metadata.kanbanparent;
|
||||
} else {
|
||||
console.log("==> !!!!!!Couldn't find a parent.!!!! <==");
|
||||
}
|
||||
const newChildCardNewParent = newChildCard ? draggableId : null;
|
||||
try {
|
||||
const update = await client.mutate({
|
||||
mutation: generate_UPDATE_JOB_KANBAN(
|
||||
oldChildCard ? oldChildCard.id : null,
|
||||
oldChildCardNewParent,
|
||||
draggableId,
|
||||
movedCardNewKanbanParent,
|
||||
targetLane.id,
|
||||
newChildCard ? newChildCard.id : null,
|
||||
newChildCardNewParent
|
||||
)
|
||||
});
|
||||
|
||||
insertAuditTrail({
|
||||
jobid: draggableId,
|
||||
operation: AuditTrailMapping.jobstatuschange(targetLane.id),
|
||||
type: "jobstatuschange"
|
||||
});
|
||||
|
||||
if (update.errors) {
|
||||
notification["error"]({
|
||||
message: t("production.errors.boardupdate", {
|
||||
message: JSON.stringify(update.errors)
|
||||
})
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
notification["error"]({
|
||||
message: t("production.errors.boardupdate", {
|
||||
message: error.message
|
||||
})
|
||||
});
|
||||
} finally {
|
||||
setIsMoving(false);
|
||||
}
|
||||
};
|
||||
const totalHrs = useMemo(
|
||||
() =>
|
||||
|
||||
@@ -118,7 +118,6 @@
|
||||
}
|
||||
|
||||
.react-trello-column-header {
|
||||
padding-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
const HeightPreservingItem = ({ children, ...props }) => {
|
||||
const [size, setSize] = useState(0);
|
||||
const { "data-known-size": knownSize = 0 } = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (knownSize !== 0) {
|
||||
setSize(knownSize);
|
||||
}
|
||||
}, [knownSize]);
|
||||
//
|
||||
// useEffect(() => {
|
||||
// if (knownSize !== 0 && knownSize !== size) {
|
||||
// setSize(knownSize);
|
||||
// }
|
||||
// }, [knownSize, size]);
|
||||
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className="height-preserving-container"
|
||||
style={{
|
||||
"--child-height": `${size}px`
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeightPreservingItem;
|
||||
@@ -9,29 +9,7 @@ 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";
|
||||
|
||||
function HeightPreservingItem({ children, ...props }) {
|
||||
const [size, setSize] = useState(0);
|
||||
const { "data-known-size": knownSize = 0 } = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (knownSize !== 0) {
|
||||
setSize(knownSize);
|
||||
}
|
||||
}, [knownSize]);
|
||||
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className="height-preserving-container"
|
||||
style={{
|
||||
"--child-height": `${size}px`
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
import HeightPreservingItem from "../components/Lane/HeightPreservingItem.jsx";
|
||||
|
||||
function Lane({
|
||||
actions,
|
||||
@@ -164,7 +142,7 @@ function Lane({
|
||||
// const onDragStart = ({ payload }) => {
|
||||
// handleDragStart && handleDragStart(payload.id, payload.laneId);
|
||||
// };
|
||||
//
|
||||
|
||||
// const shouldAcceptDrop = (sourceContainerOptions) => {
|
||||
// return droppable && sourceContainerOptions.groupName === groupName;
|
||||
// };
|
||||
@@ -188,6 +166,10 @@ function Lane({
|
||||
collapsibleLanes && setCollapsed(!collapsed);
|
||||
};
|
||||
|
||||
/**
|
||||
* Card component
|
||||
* @type {React.NamedExoticComponent<{readonly item?: *, readonly provided?: *, readonly isDragging?: *}>}
|
||||
*/
|
||||
const Card = React.memo(({ provided, item: card, isDragging }) => {
|
||||
const onDeleteCard = () => removeCard(card.id);
|
||||
return (
|
||||
@@ -216,31 +198,56 @@ function Lane({
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Render the draggable component
|
||||
* @param index
|
||||
* @param item
|
||||
* @returns {React.JSX.Element}
|
||||
*/
|
||||
const renderDraggable = (index, item) => (
|
||||
<Draggable draggableId={item.id} index={index} key={item.id}>
|
||||
{(provided, snapshot) => <Card provided={provided} item={item} isDragging={snapshot.isDragging} />}
|
||||
</Draggable>
|
||||
);
|
||||
|
||||
/**
|
||||
* Render the add card link
|
||||
* @returns {false|React.JSX.Element}
|
||||
*/
|
||||
const renderAddCardLink = () =>
|
||||
editable && !addCardMode && <components.AddCardLink onClick={showEditableCard} laneId={id} />;
|
||||
|
||||
/**
|
||||
* Render the new card form
|
||||
* @returns {false|React.JSX.Element}
|
||||
*/
|
||||
const renderNewCardForm = () =>
|
||||
addCardMode && <components.NewCardForm onCancel={hideEditableCard} laneId={id} onAdd={addNewCard} />;
|
||||
|
||||
/**
|
||||
* Wrapper for the item in the grid layout
|
||||
* @param children
|
||||
* @param props
|
||||
* @returns {React.JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const ItemWrapper = ({ children, ...props }) => (
|
||||
<div
|
||||
{...props}
|
||||
style={{
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
whiteSpace: "nowrap"
|
||||
whiteSpace: "wrap"
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
/**
|
||||
* Components for the grid layout
|
||||
* @type {{Item: (function({children: *, [p: string]: *}): *), List: React.ForwardRefExoticComponent<React.PropsWithoutRef<{readonly children?: *, readonly style?: *}> & React.RefAttributes<unknown>>}}
|
||||
*/
|
||||
const gridComponents = {
|
||||
List: forwardRef(({ style, children, ...props }, ref) => (
|
||||
<div
|
||||
@@ -259,8 +266,6 @@ function Lane({
|
||||
<div
|
||||
{...props}
|
||||
style={{
|
||||
width: "10%",
|
||||
display: "flex",
|
||||
alignContent: "stretch",
|
||||
boxSizing: "border-box"
|
||||
}}
|
||||
@@ -270,8 +275,15 @@ function Lane({
|
||||
)
|
||||
};
|
||||
|
||||
/**
|
||||
* Render the droppable component with the provided cards and the provided props from react-beautiful-dnd
|
||||
* @param provided
|
||||
* @param renderedCards
|
||||
* @returns {Element}
|
||||
*/
|
||||
const renderDroppable = (provided, renderedCards) => {
|
||||
const Component = orientation === "vertical" ? VirtuosoGrid : Virtuoso;
|
||||
const FinalComponent = collapsed ? "div" : Component;
|
||||
|
||||
const commonProps = {
|
||||
useWindowScroll: true,
|
||||
@@ -298,7 +310,7 @@ function Lane({
|
||||
itemContent: (index, item) => renderDraggable(index, item),
|
||||
scrollerRef: provided.innerRef
|
||||
};
|
||||
|
||||
const finalComponentProps = collapsed ? {} : componentProps;
|
||||
return (
|
||||
<div
|
||||
{...provided.droppableProps}
|
||||
@@ -306,7 +318,7 @@ function Lane({
|
||||
className={allClassNames}
|
||||
style={{ ...provided.droppableProps.style }}
|
||||
>
|
||||
<Component {...componentProps} />
|
||||
<FinalComponent {...finalComponentProps} />
|
||||
{renderAddCardLink()}
|
||||
{renderNewCardForm()}
|
||||
{provided.placeholder}
|
||||
@@ -315,11 +327,12 @@ function Lane({
|
||||
};
|
||||
|
||||
const renderDragContainer = () => {
|
||||
if (collapsed) return <></>;
|
||||
const renderedCards = sortCards(cards, laneSortFunction);
|
||||
|
||||
return (
|
||||
<Droppable
|
||||
droppableId={id}
|
||||
index={index}
|
||||
type="lane"
|
||||
direction={orientation === "horizontal" ? "vertical" : "grid"}
|
||||
mode="virtual"
|
||||
|
||||
@@ -76,7 +76,7 @@ export const StyleHorizontal = styled.div`
|
||||
// TODO: This will need to be changed
|
||||
min-width: 250px;
|
||||
min-height: 25px;
|
||||
margin-bottom: 42px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.react-trello-lane.lane-collapsed {
|
||||
@@ -89,6 +89,14 @@ export const StyleVertical = styled.div`
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.react-trello-lane {
|
||||
min-height: 5px;
|
||||
}
|
||||
|
||||
.react-trello-lane.lane-collapsed {
|
||||
min-height: 5px;
|
||||
}
|
||||
|
||||
.react-trello-card {
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user