- Checkpoint, so so much
Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -15,7 +15,6 @@ import ProductionAlert from "../production-list-columns/production-list-columns.
|
|||||||
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
|
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
|
||||||
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
||||||
|
|
||||||
import "./production-board-card.styles.scss";
|
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
|
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
@@ -62,7 +61,7 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
|
|||||||
return metadata?.labhrs && metadata?.larhrs
|
return metadata?.labhrs && metadata?.larhrs
|
||||||
? metadata.labhrs.aggregate.sum.mod_lb_hrs + metadata.larhrs.aggregate.sum.mod_lb_hrs
|
? metadata.labhrs.aggregate.sum.mod_lb_hrs + metadata.larhrs.aggregate.sum.mod_lb_hrs
|
||||||
: 0;
|
: 0;
|
||||||
}, [metadata]);
|
}, [metadata?.labhrs, metadata?.larhrs]);
|
||||||
|
|
||||||
const bgColor = useMemo(() => cardColor(bodyshop.ssbuckets, totalHrs), [bodyshop.ssbuckets, totalHrs]);
|
const bgColor = useMemo(() => cardColor(bodyshop.ssbuckets, totalHrs), [bodyshop.ssbuckets, totalHrs]);
|
||||||
const contrastYIQ = useMemo(() => getContrastYIQ(bgColor), [bgColor]);
|
const contrastYIQ = useMemo(() => getContrastYIQ(bgColor), [bgColor]);
|
||||||
@@ -77,7 +76,14 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
|
|||||||
}}
|
}}
|
||||||
title={
|
title={
|
||||||
<Space>
|
<Space>
|
||||||
<ProductionAlert record={card} key="alert" />
|
<ProductionAlert
|
||||||
|
record={{
|
||||||
|
id: card.id,
|
||||||
|
production_vars: card?.metadata.production_vars,
|
||||||
|
refetch: card?.refetch
|
||||||
|
}}
|
||||||
|
key="alert"
|
||||||
|
/>
|
||||||
{metadata?.suspended && <PauseCircleOutlined style={{ color: "orangered" }} />}
|
{metadata?.suspended && <PauseCircleOutlined style={{ color: "orangered" }} />}
|
||||||
{metadata?.iouparent && (
|
{metadata?.iouparent && (
|
||||||
<Tooltip title={t("jobs.labels.iou")}>
|
<Tooltip title={t("jobs.labels.iou")}>
|
||||||
|
|||||||
@@ -1,32 +1,29 @@
|
|||||||
import { SyncOutlined, UnorderedListOutlined } from "@ant-design/icons";
|
import { SyncOutlined } from "@ant-design/icons";
|
||||||
import { useApolloClient } from "@apollo/client";
|
import { useApolloClient } from "@apollo/client";
|
||||||
import Board from "../../components/trello-board/index";
|
import Board from "../../components/trello-board/index";
|
||||||
import { Button, notification, Skeleton, Space, Statistic } from "antd";
|
import { Button, notification, Skeleton, Space, Statistic } from "antd";
|
||||||
import { PageHeader } from "@ant-design/pro-layout";
|
import { PageHeader } from "@ant-design/pro-layout";
|
||||||
import React, { useEffect, useMemo, useState, useCallback } from "react";
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries";
|
import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries";
|
||||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component";
|
import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component";
|
||||||
import ProductionBoardFilters from "../production-board-filters/production-board-filters.component";
|
import ProductionBoardFilters from "../production-board-filters/production-board-filters.component";
|
||||||
import ProductionBoardCard from "../production-board-kanban-card/production-board-kanban-card.component";
|
|
||||||
import ProductionListDetailComponent from "../production-list-detail/production-list-detail.component";
|
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 CardColorLegend from "../production-board-kanban-card/production-board-kanban-card-color-legend.component";
|
||||||
import "./production-board-kanban.styles.scss";
|
import "./production-board-kanban.styles.scss";
|
||||||
import { createBoardData, createFakeBoardData } from "./production-board-kanban.utils.js";
|
import { createBoardData } from "./production-board-kanban.utils.js";
|
||||||
import ProductionBoardKanbanSettings from "./production-board-kanban.settings.component.jsx";
|
import ProductionBoardKanbanSettings from "./production-board-kanban.settings.component.jsx";
|
||||||
import cloneDeep from "lodash/cloneDeep";
|
import cloneDeep from "lodash/cloneDeep";
|
||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop
|
||||||
technician: selectTechnician
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
@@ -40,20 +37,16 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
export function ProductionBoardKanbanComponent({
|
export function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTrail, associationSettings }) {
|
||||||
data,
|
|
||||||
bodyshop,
|
|
||||||
refetch,
|
|
||||||
technician,
|
|
||||||
insertAuditTrail,
|
|
||||||
associationSettings
|
|
||||||
}) {
|
|
||||||
const [boardLanes, setBoardLanes] = useState({ lanes: [] });
|
const [boardLanes, setBoardLanes] = useState({ lanes: [] });
|
||||||
const [filter, setFilter] = useState({ search: "", employeeId: null });
|
const [filter, setFilter] = useState({ search: "", employeeId: null });
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [isMoving, setIsMoving] = useState(false);
|
const [isMoving, setIsMoving] = useState(false);
|
||||||
|
|
||||||
const orientation = associationSettings?.kanban_settings?.orientation ? "vertical" : "horizontal";
|
const orientation = useMemo(
|
||||||
|
() => (associationSettings?.kanban_settings?.orientation ? "vertical" : "horizontal"),
|
||||||
|
[associationSettings]
|
||||||
|
);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -63,7 +56,7 @@ export function ProductionBoardKanbanComponent({
|
|||||||
}, [associationSettings]);
|
}, [associationSettings]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newBoardData = createFakeBoardData(
|
const newBoardData = createBoardData(
|
||||||
[...bodyshop.md_ro_statuses.production_statuses, ...(bodyshop.md_ro_statuses.additional_board_statuses || [])],
|
[...bodyshop.md_ro_statuses.production_statuses, ...(bodyshop.md_ro_statuses.additional_board_statuses || [])],
|
||||||
data,
|
data,
|
||||||
filter
|
filter
|
||||||
@@ -202,15 +195,6 @@ export function ProductionBoardKanbanComponent({
|
|||||||
[data]
|
[data]
|
||||||
);
|
);
|
||||||
|
|
||||||
const Header = useCallback(
|
|
||||||
({ title }) => (
|
|
||||||
<div className="react-trello-column-header" style={{ backgroundColor: "#e3e3e3" }}>
|
|
||||||
<UnorderedListOutlined style={{ marginRight: "5px" }} /> {title.substring(0, 10)}
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const cardSettings = useMemo(
|
const cardSettings = useMemo(
|
||||||
() =>
|
() =>
|
||||||
associationSettings?.kanban_settings && Object.keys(associationSettings.kanban_settings).length > 0
|
associationSettings?.kanban_settings && Object.keys(associationSettings.kanban_settings).length > 0
|
||||||
@@ -225,23 +209,12 @@ export function ProductionBoardKanbanComponent({
|
|||||||
production_note: true,
|
production_note: true,
|
||||||
employeeassignments: true,
|
employeeassignments: true,
|
||||||
scheduled_completion: true,
|
scheduled_completion: true,
|
||||||
stickyheader: false,
|
|
||||||
cardcolor: false,
|
cardcolor: false,
|
||||||
orientation: false
|
orientation: false
|
||||||
},
|
},
|
||||||
[associationSettings]
|
[associationSettings]
|
||||||
);
|
);
|
||||||
|
|
||||||
const components = useMemo(
|
|
||||||
() => ({
|
|
||||||
Card: (cardProps) => (
|
|
||||||
<ProductionBoardCard card={cardProps} technician={technician} bodyshop={bodyshop} cardSettings={cardSettings} />
|
|
||||||
),
|
|
||||||
LaneHeader: Header
|
|
||||||
}),
|
|
||||||
[Header, bodyshop, cardSettings, technician]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Skeleton active />;
|
return <Skeleton active />;
|
||||||
}
|
}
|
||||||
@@ -270,13 +243,7 @@ export function ProductionBoardKanbanComponent({
|
|||||||
/>
|
/>
|
||||||
{cardSettings.cardcolor && <CardColorLegend cardSettings={cardSettings} bodyshop={bodyshop} />}
|
{cardSettings.cardcolor && <CardColorLegend cardSettings={cardSettings} bodyshop={bodyshop} />}
|
||||||
<ProductionListDetailComponent jobs={data} />
|
<ProductionListDetailComponent jobs={data} />
|
||||||
<Board
|
<Board data={boardLanes} onDragEnd={onDragEnd} orientation={orientation} cardSettings={cardSettings} />
|
||||||
data={boardLanes}
|
|
||||||
onDragEnd={onDragEnd}
|
|
||||||
components={components}
|
|
||||||
collapsibleLanes
|
|
||||||
orientation={orientation}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,147 +2,27 @@
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
//.react-trello-card {
|
.item .is-dragging {
|
||||||
// border-radius: 3px;
|
|
||||||
// background-color: #fff;
|
|
||||||
// padding: 4px;
|
|
||||||
// margin-bottom: 7px;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// .react-trello-card-skeleton,
|
|
||||||
// .react-trello-card,
|
|
||||||
// .react-trello-card-adder-form {
|
|
||||||
// box-sizing: border-box;
|
|
||||||
// max-width: 145px;
|
|
||||||
// min-width: 145px;
|
|
||||||
// }
|
|
||||||
|
|
||||||
.react-trello-card--dragging {
|
|
||||||
box-shadow: 2px 2px grey;
|
box-shadow: 2px 2px grey;
|
||||||
|
rotate: 5deg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-trello-card__description {
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card__title {
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
font-weight: bold;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
//.react-trello-column {
|
|
||||||
// padding: 10px;
|
|
||||||
// border-radius: 2px;
|
|
||||||
// background-color: #eee;
|
|
||||||
// margin: 5px;
|
|
||||||
//}
|
|
||||||
|
|
||||||
.react-trello-column input:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card-adder-form {
|
|
||||||
border-radius: 3px;
|
|
||||||
background-color: #fff;
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card-adder-form input {
|
|
||||||
border: 0px;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card-adder-button {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 5px;
|
|
||||||
background-color: transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 20px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card-adder-button:hover {
|
|
||||||
background-color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card-adder-form__title {
|
|
||||||
font-weight: bold;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
font-weight: bold;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
width: 100%;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
.height-preserving-container:empty {
|
.height-preserving-container:empty {
|
||||||
min-height: calc(var(--child-height));
|
min-height: calc(var(--child-height));
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-trello-card-adder-form__title:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card-adder-form__description {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card-adder-form__description:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card-adder-form__button {
|
|
||||||
background-color: #eee;
|
|
||||||
border: none;
|
|
||||||
padding: 5px;
|
|
||||||
width: 45%;
|
|
||||||
margin-top: 5px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-card-adder-form__button:hover {
|
|
||||||
transition: 0.3s;
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-column-header {
|
.react-trello-column-header {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
background-color: #e3e3e3;
|
||||||
|
.icon {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-trello-column-header input:focus {
|
.production-alert {
|
||||||
outline: none;
|
background: transparent;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-trello-column-header__button {
|
|
||||||
color: #333333;
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-color: #cccccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-column-header__button:hover,
|
|
||||||
.react-trello-column-header__button:focus,
|
|
||||||
.react-trello-column-header__button:active {
|
|
||||||
background-color: #e6e6e6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-column-adder-button {
|
|
||||||
border: 2px dashed #eee;
|
|
||||||
height: 132px;
|
|
||||||
margin: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-column-adder-button:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -43,18 +43,14 @@ const ProductionListColumnAlert = ({ record, insertAuditTrail }) => {
|
|||||||
jobid: record.id,
|
jobid: record.id,
|
||||||
operation: AuditTrailMapping.alertToggle(newAlertState),
|
operation: AuditTrailMapping.alertToggle(newAlertState),
|
||||||
type: "alertToggle"
|
type: "alertToggle"
|
||||||
}).then(() => {
|
|
||||||
if (record.refetch) record.refetch();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (record.refetch) record.refetch();
|
||||||
}, [updateAlert, insertAuditTrail, record]);
|
}, [updateAlert, insertAuditTrail, record]);
|
||||||
|
|
||||||
return (
|
if (!record.production_vars?.alert) return null;
|
||||||
<div style={{ height: "19px" }}>
|
|
||||||
{record.production_vars?.alert && (
|
return <Button className="production-alert" icon={<ExclamationCircleFilled />} onClick={handleAlertToggle} />;
|
||||||
<Button className="production-alert" icon={<ExclamationCircleFilled />} onClick={handleAlertToggle} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ProductionListColumnAlert);
|
export default connect(mapStateToProps, mapDispatchToProps)(ProductionListColumnAlert);
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatme
|
|||||||
key: "alert",
|
key: "alert",
|
||||||
sorter: (a, b) => Number(a.production_vars?.alert || false) - Number(b.production_vars?.alert || false),
|
sorter: (a, b) => Number(a.production_vars?.alert || false) - Number(b.production_vars?.alert || false),
|
||||||
sortOrder: state.sortedInfo.columnKey === "alert" && state.sortedInfo.order,
|
sortOrder: state.sortedInfo.columnKey === "alert" && state.sortedInfo.order,
|
||||||
render: (text, record) => <ProductionListColumnAlert record={record} />
|
render: (text, record) => <ProductionListColumnAlert record={{ record }} />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: i18n.t("production.labels.note"),
|
title: i18n.t("production.labels.note"),
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import LaneFooter from "./Lane/LaneFooter";
|
import LaneFooter from "./Lane/LaneFooter";
|
||||||
|
|
||||||
import { BoardWrapper, StyleHorizontal, GlobalStyle, StyleVertical, ScrollableLane, Section } from "../styles/Base";
|
import { BoardWrapper, StyleHorizontal, StyleVertical, ScrollableLane, Section } from "../styles/Base";
|
||||||
|
|
||||||
const exports = {
|
const exports = {
|
||||||
StyleHorizontal,
|
StyleHorizontal,
|
||||||
StyleVertical,
|
StyleVertical,
|
||||||
GlobalStyle,
|
|
||||||
BoardWrapper,
|
BoardWrapper,
|
||||||
ScrollableLane,
|
ScrollableLane,
|
||||||
LaneFooter,
|
LaneFooter,
|
||||||
|
|||||||
@@ -1,27 +1,21 @@
|
|||||||
import { BoardContainer } from "../index";
|
import { BoardContainer } from "../index";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo } from "react";
|
||||||
import { v1 } from "uuid";
|
import { StyleHorizontal, StyleVertical } from "../styles/Base.js";
|
||||||
import { GlobalStyle } from "../styles/Base.js";
|
|
||||||
|
|
||||||
const Board = ({ id, className, components, orientation, ...additionalProps }) => {
|
const Board = ({ id, className, orientation, cardSettings, ...additionalProps }) => {
|
||||||
const [storeId] = useState(id || v1());
|
|
||||||
|
|
||||||
const allClassNames = useMemo(() => `react-trello-board ${className || ""}`.trim(), [className]);
|
|
||||||
const OrientationStyle = useMemo(
|
const OrientationStyle = useMemo(
|
||||||
() => (orientation === "horizontal" ? components.StyleHorizontal : components.StyleVertical),
|
() => (orientation === "horizontal" ? StyleHorizontal : StyleVertical),
|
||||||
[orientation, components.StyleHorizontal, components.StyleVertical]
|
[orientation]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GlobalStyle />
|
|
||||||
<OrientationStyle>
|
<OrientationStyle>
|
||||||
<BoardContainer
|
<BoardContainer
|
||||||
components={components}
|
|
||||||
orientation={orientation}
|
orientation={orientation}
|
||||||
|
cardSettings={cardSettings}
|
||||||
{...additionalProps}
|
{...additionalProps}
|
||||||
id={storeId}
|
className="react-trello-board"
|
||||||
className={allClassNames}
|
|
||||||
/>
|
/>
|
||||||
</OrientationStyle>
|
</OrientationStyle>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React, { useCallback, useEffect, useState, useMemo } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { DragDropContext } from "../dnd/lib";
|
import { DragDropContext } from "../dnd/lib";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import pick from "lodash/pick";
|
|
||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
import Lane from "./Lane";
|
import Lane from "./Lane";
|
||||||
import { PopoverWrapper } from "react-popopo";
|
import { PopoverWrapper } from "react-popopo";
|
||||||
@@ -15,26 +14,23 @@ import { BoardWrapper } from "../styles/Base.js";
|
|||||||
*
|
*
|
||||||
* @component
|
* @component
|
||||||
* @param {Object} props - Component props
|
* @param {Object} props - Component props
|
||||||
* @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 {Object} props.data - The initial data for the board
|
||||||
* @param {Function} props.onDragEnd - Callback function when a drag ends
|
* @param {Function} props.onDragEnd - Callback function when a drag ends
|
||||||
|
* @param {Function} props.laneSortFunction - Callback function when a drag ends
|
||||||
* @param {string} props.orientation - The orientation of the board ("horizontal" or "vertical")
|
* @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 {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.reducerData - The initial data for the Redux reducer
|
||||||
* @param {Object} props.otherProps - Any other props to pass to the board
|
|
||||||
* @returns {JSX.Element} A Trello-like board
|
* @returns {JSX.Element} A Trello-like board
|
||||||
*/
|
*/
|
||||||
const BoardContainer = ({
|
const BoardContainer = ({
|
||||||
id,
|
|
||||||
components,
|
|
||||||
data,
|
data,
|
||||||
onDataChange = () => {},
|
onDataChange = () => {},
|
||||||
onDragEnd = () => {},
|
onDragEnd = () => {},
|
||||||
|
laneSortFunction = () => {},
|
||||||
orientation = "horizontal",
|
orientation = "horizontal",
|
||||||
|
cardSettings = {},
|
||||||
eventBusHandle,
|
eventBusHandle,
|
||||||
reducerData,
|
reducerData
|
||||||
...otherProps
|
|
||||||
}) => {
|
}) => {
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
const [isProcessing, setIsProcessing] = useState(false);
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
@@ -42,8 +38,6 @@ const BoardContainer = ({
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const currentReducerData = useSelector((state) => (state.trello.lanes ? state.trello : {}));
|
const currentReducerData = useSelector((state) => (state.trello.lanes ? state.trello : {}));
|
||||||
|
|
||||||
const groupName = `TrelloBoard${id}`;
|
|
||||||
|
|
||||||
const wireEventBus = useCallback(() => {
|
const wireEventBus = useCallback(() => {
|
||||||
const eventBus = {
|
const eventBus = {
|
||||||
publish: (event) => {
|
publish: (event) => {
|
||||||
@@ -98,24 +92,6 @@ const BoardContainer = ({
|
|||||||
setIsDragging(true);
|
setIsDragging(true);
|
||||||
}, [setIsDragging]);
|
}, [setIsDragging]);
|
||||||
|
|
||||||
const passThroughProps = useMemo(
|
|
||||||
() =>
|
|
||||||
pick(
|
|
||||||
{
|
|
||||||
id,
|
|
||||||
components,
|
|
||||||
data,
|
|
||||||
onDataChange,
|
|
||||||
orientation,
|
|
||||||
eventBusHandle,
|
|
||||||
reducerData,
|
|
||||||
...otherProps
|
|
||||||
},
|
|
||||||
["laneSortFunction", "collapsibleLanes", "orientation"]
|
|
||||||
),
|
|
||||||
[id, components, data, onDataChange, orientation, eventBusHandle, reducerData, otherProps]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onLaneDrag = useCallback(
|
const onLaneDrag = useCallback(
|
||||||
async ({ draggableId, type, source, reason, mode, destination, combine }) => {
|
async ({ draggableId, type, source, reason, mode, destination, combine }) => {
|
||||||
setIsDragging(false);
|
setIsDragging(false);
|
||||||
@@ -143,44 +119,50 @@ const BoardContainer = ({
|
|||||||
},
|
},
|
||||||
[dispatch, onDragEnd]
|
[dispatch, onDragEnd]
|
||||||
);
|
);
|
||||||
|
// id: PropTypes.string.isRequired,
|
||||||
|
// title: PropTypes.node,
|
||||||
|
// index: PropTypes.number,
|
||||||
|
// laneSortFunction: PropTypes.func,
|
||||||
|
// cards: PropTypes.array,
|
||||||
|
// orientation: PropTypes.string,
|
||||||
|
// isProcessing: PropTypes.bool,
|
||||||
|
// cardSettings: PropTypes.object,
|
||||||
|
// technician: PropTypes.object,
|
||||||
|
// bodyshop: PropTypes.object
|
||||||
return (
|
return (
|
||||||
<BoardWrapper orientation={orientation}>
|
<PopoverWrapper>
|
||||||
<PopoverWrapper>
|
<BoardWrapper orientation={orientation}>
|
||||||
<DragDropContext onDragEnd={onLaneDrag} onDragStart={onDragStart} contextId={groupName}>
|
<DragDropContext onDragEnd={onLaneDrag} onDragStart={onDragStart} contextId="production-board">
|
||||||
{currentReducerData.lanes.map((lane, index) => {
|
{currentReducerData.lanes.map((lane, index) => {
|
||||||
const { id, droppable, ...laneOtherProps } = lane;
|
|
||||||
return (
|
return (
|
||||||
<Lane
|
<Lane
|
||||||
key={id}
|
key={lane.id}
|
||||||
boardId={groupName}
|
id={lane.id}
|
||||||
components={components}
|
title={lane.title}
|
||||||
id={id}
|
|
||||||
index={index}
|
index={index}
|
||||||
{...laneOtherProps}
|
laneSortFunction={laneSortFunction}
|
||||||
{...passThroughProps}
|
orientation={orientation}
|
||||||
cards={lane.cards}
|
cards={lane.cards}
|
||||||
isDragging={isDragging}
|
isDragging={isDragging}
|
||||||
isProcessing={isProcessing}
|
isProcessing={isProcessing}
|
||||||
|
cardSettings={cardSettings}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
</PopoverWrapper>
|
</BoardWrapper>
|
||||||
</BoardWrapper>
|
</PopoverWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
BoardContainer.propTypes = {
|
BoardContainer.propTypes = {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
components: PropTypes.object,
|
|
||||||
actions: PropTypes.object,
|
actions: PropTypes.object,
|
||||||
data: PropTypes.object.isRequired,
|
data: PropTypes.object.isRequired,
|
||||||
reducerData: PropTypes.object,
|
reducerData: PropTypes.object,
|
||||||
onDataChange: PropTypes.func,
|
onDataChange: PropTypes.func,
|
||||||
eventBusHandle: PropTypes.func,
|
eventBusHandle: PropTypes.func,
|
||||||
laneSortFunction: PropTypes.func,
|
laneSortFunction: PropTypes.func,
|
||||||
collapsibleLanes: PropTypes.bool,
|
|
||||||
handleDragEnd: PropTypes.func,
|
handleDragEnd: PropTypes.func,
|
||||||
orientation: PropTypes.string
|
orientation: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,31 +2,29 @@ import React, { forwardRef, useCallback, useEffect, useMemo, useState } from "re
|
|||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { bindActionCreators } from "redux";
|
import { bindActionCreators } from "redux";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import * as actions from "../../../redux/trello/trello.actions.js";
|
import * as actions from "../../../redux/trello/trello.actions.js";
|
||||||
import { Draggable, Droppable } from "../dnd/lib";
|
import { Draggable, Droppable } from "../dnd/lib";
|
||||||
import { Virtuoso, VirtuosoGrid } from "react-virtuoso";
|
import { Virtuoso, VirtuosoGrid } from "react-virtuoso";
|
||||||
import HeightPreservingItem from "../components/Lane/HeightPreservingItem.jsx";
|
import HeightPreservingItem from "../components/Lane/HeightPreservingItem.jsx";
|
||||||
import { Section } from "../styles/Base.js";
|
import { Section } from "../styles/Base.js";
|
||||||
import LaneFooter from "../components/Lane/LaneFooter.jsx";
|
import LaneFooter from "../components/Lane/LaneFooter.jsx";
|
||||||
|
import { UnorderedListOutlined } from "@ant-design/icons";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectBodyshop } from "../../../redux/user/user.selectors.js";
|
||||||
|
import { selectTechnician } from "../../../redux/tech/tech.selectors.js";
|
||||||
|
import ProductionBoardCard from "../../production-board-kanban-card/production-board-kanban-card.component.jsx";
|
||||||
|
|
||||||
const Lane = ({
|
const Lane = ({
|
||||||
actions,
|
|
||||||
id,
|
id,
|
||||||
boardId,
|
|
||||||
title,
|
title,
|
||||||
index,
|
index,
|
||||||
isProcessing,
|
isProcessing,
|
||||||
laneSortFunction,
|
laneSortFunction,
|
||||||
style = {},
|
|
||||||
cardStyle = {},
|
|
||||||
cards,
|
cards,
|
||||||
collapsibleLanes = false,
|
cardSettings = {},
|
||||||
|
|
||||||
components = {},
|
|
||||||
orientation = "vertical",
|
orientation = "vertical",
|
||||||
className,
|
technician,
|
||||||
...otherProps
|
bodyshop
|
||||||
}) => {
|
}) => {
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
const [isVisible, setIsVisible] = useState(true);
|
const [isVisible, setIsVisible] = useState(true);
|
||||||
@@ -37,187 +35,183 @@ const Lane = ({
|
|||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, [cards.length]);
|
}, [cards.length]);
|
||||||
|
|
||||||
const sortCards = useCallback((cards, sortFunction) => {
|
const sortedCards = useMemo(() => {
|
||||||
if (!cards) return [];
|
if (!cards) return [];
|
||||||
if (!sortFunction) return cards;
|
if (!laneSortFunction) return cards;
|
||||||
return cards.concat().sort((card1, card2) => sortFunction(card1, card2));
|
return [...cards].sort(laneSortFunction);
|
||||||
}, []);
|
}, [cards, laneSortFunction]);
|
||||||
|
|
||||||
const toggleLaneCollapsed = useCallback(() => {
|
const toggleLaneCollapsed = useCallback(() => {
|
||||||
collapsibleLanes && setCollapsed(!collapsed);
|
setCollapsed((prevCollapsed) => !prevCollapsed);
|
||||||
}, [collapsibleLanes, collapsed]);
|
}, []);
|
||||||
|
|
||||||
const Card = React.memo(({ provided, item: card, isDragging }) => {
|
const renderDraggable = useCallback(
|
||||||
return (
|
(index, card) => {
|
||||||
<div
|
if (!card) {
|
||||||
{...provided.draggableProps}
|
console.log("null card");
|
||||||
{...provided.dragHandleProps}
|
return null;
|
||||||
ref={provided.innerRef}
|
}
|
||||||
style={provided.draggableProps.style}
|
return (
|
||||||
className={`item ${isDragging ? "is-dragging" : ""}`}
|
<Draggable draggableId={card.id} index={index} key={card.id} isDragDisabled={isProcessing}>
|
||||||
key={card.id}
|
{(provided, snapshot) => (
|
||||||
>
|
<div
|
||||||
<components.Card key={card.id} style={card.style || cardStyle} className="react-trello-card" {...card} />
|
{...provided.draggableProps}
|
||||||
</div>
|
{...provided.dragHandleProps}
|
||||||
);
|
ref={provided.innerRef}
|
||||||
});
|
style={provided.draggableProps.style}
|
||||||
|
className={`item ${snapshot.isDragging ? "is-dragging" : ""}`}
|
||||||
const renderDraggable = (index, item) => {
|
key={card.id}
|
||||||
if (!item) {
|
>
|
||||||
console.log("null Item");
|
<ProductionBoardCard
|
||||||
return null;
|
technician={technician}
|
||||||
}
|
bodyshop={bodyshop}
|
||||||
|
cardSettings={cardSettings}
|
||||||
return (
|
key={card.id}
|
||||||
<Draggable draggableId={item.id} index={index} key={item.id} isDragDisabled={isProcessing}>
|
style={card.style}
|
||||||
{(provided, snapshot) => <Card provided={provided} item={item} isDragging={snapshot.isDragging} />}
|
card={card}
|
||||||
</Draggable>
|
className="react-trello-card"
|
||||||
);
|
/>
|
||||||
};
|
</div>
|
||||||
|
)}
|
||||||
const ItemWrapper = ({ children, ...props }) => (
|
</Draggable>
|
||||||
<div {...props} className="item-wrapper">
|
);
|
||||||
{children}
|
},
|
||||||
</div>
|
[isProcessing, technician, bodyshop, cardSettings]
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderDroppable = (provided, renderedCards) => {
|
const ItemWrapper = useCallback(
|
||||||
const Component = orientation === "vertical" ? VirtuosoGrid : Virtuoso;
|
({ children, ...props }) => (
|
||||||
const FinalComponent = collapsed ? "div" : Component;
|
<div {...props} className="item-wrapper">
|
||||||
|
{children}
|
||||||
const commonProps = {
|
|
||||||
useWindowScroll: true,
|
|
||||||
data: renderedCards
|
|
||||||
};
|
|
||||||
|
|
||||||
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) => (
|
|
||||||
<div
|
|
||||||
ref={ref}
|
|
||||||
{...props}
|
|
||||||
style={{
|
|
||||||
...style
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)),
|
|
||||||
Item: ({ children, ...props }) => <div {...props}>{children}</div>
|
|
||||||
},
|
|
||||||
itemContent: (index, item) => <ItemWrapper>{renderDraggable(index, item)}</ItemWrapper>,
|
|
||||||
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 (
|
|
||||||
<div style={{ height: "100%" }}>
|
|
||||||
<div
|
|
||||||
{...provided.droppableProps}
|
|
||||||
ref={provided.innerRef}
|
|
||||||
className={allClassNames}
|
|
||||||
style={{ ...provided.droppableProps.style }}
|
|
||||||
>
|
|
||||||
{isVisible && <FinalComponent {...finalComponentProps} />}
|
|
||||||
{(orientation === "horizontal" || renderedCards.length === 0 || collapsed) && provided.placeholder}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
),
|
||||||
};
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const renderDragContainer = () => {
|
const renderDroppable = useCallback(
|
||||||
const renderedCards = sortCards(cards, laneSortFunction);
|
(provided, renderedCards) => {
|
||||||
|
const Component = orientation === "vertical" ? VirtuosoGrid : Virtuoso;
|
||||||
|
const FinalComponent = collapsed ? "div" : Component;
|
||||||
|
|
||||||
return (
|
const commonProps = {
|
||||||
|
useWindowScroll: true,
|
||||||
|
data: renderedCards
|
||||||
|
};
|
||||||
|
|
||||||
|
const verticalProps = {
|
||||||
|
...commonProps,
|
||||||
|
listClassName: "grid-container",
|
||||||
|
itemClassName: "grid-item",
|
||||||
|
components: {
|
||||||
|
List: forwardRef(({ style, children, ...props }, ref) => (
|
||||||
|
<div ref={ref} {...props} style={{ ...style }}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)),
|
||||||
|
Item: ({ children, ...props }) => <div {...props}>{children}</div>
|
||||||
|
},
|
||||||
|
itemContent: (index, item) => <ItemWrapper>{renderDraggable(index, item)}</ItemWrapper>,
|
||||||
|
overscan: { main: 10, reverse: 10 }
|
||||||
|
};
|
||||||
|
|
||||||
|
const horizontalProps = {
|
||||||
|
...commonProps,
|
||||||
|
components: { Item: HeightPreservingItem },
|
||||||
|
overscan: { main: 3, reverse: 3 },
|
||||||
|
itemContent: (index, item) => renderDraggable(index, item),
|
||||||
|
scrollerRef: provided.innerRef
|
||||||
|
};
|
||||||
|
|
||||||
|
const componentProps = orientation === "vertical" ? verticalProps : horizontalProps;
|
||||||
|
const finalComponentProps = collapsed ? {} : componentProps;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ height: "100%" }}>
|
||||||
|
<div
|
||||||
|
{...provided.droppableProps}
|
||||||
|
ref={provided.innerRef}
|
||||||
|
className={`react-trello-lane ${collapsed ? "lane-collapsed" : ""}`}
|
||||||
|
style={{ ...provided.droppableProps.style }}
|
||||||
|
>
|
||||||
|
{isVisible && <FinalComponent {...finalComponentProps} />}
|
||||||
|
{(orientation === "horizontal" || renderedCards.length === 0 || collapsed) && provided.placeholder}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[orientation, collapsed, isVisible, renderDraggable]
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderDragContainer = useCallback(
|
||||||
|
() => (
|
||||||
<Droppable
|
<Droppable
|
||||||
droppableId={id}
|
droppableId={id}
|
||||||
index={index}
|
index={index}
|
||||||
type="lane"
|
type="lane"
|
||||||
direction={orientation === "horizontal" ? "vertical" : "grid"}
|
direction={orientation === "horizontal" ? "vertical" : "grid"}
|
||||||
mode="virtual"
|
mode="virtual"
|
||||||
renderClone={(provided, snapshot, rubric) => (
|
renderClone={(provided, snapshot, rubric) => {
|
||||||
<Card
|
const card = sortedCards[rubric.source.index];
|
||||||
clone={true}
|
return (
|
||||||
provided={provided}
|
<div
|
||||||
isDragging={snapshot.isDragging}
|
{...provided.draggableProps}
|
||||||
item={renderedCards[rubric.source.index]}
|
{...provided.dragHandleProps}
|
||||||
/>
|
ref={provided.innerRef}
|
||||||
)}
|
style={provided.draggableProps.style}
|
||||||
|
className={`item ${snapshot.isDragging ? "is-dragging" : ""}`}
|
||||||
|
key={card.id}
|
||||||
|
>
|
||||||
|
<ProductionBoardCard
|
||||||
|
technician={technician}
|
||||||
|
bodyshop={bodyshop}
|
||||||
|
cardSettings={cardSettings}
|
||||||
|
key={card.id}
|
||||||
|
style={card.style}
|
||||||
|
className="react-trello-card"
|
||||||
|
card={card}
|
||||||
|
clone={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{(provided) => renderDroppable(provided, renderedCards)}
|
{(provided) => renderDroppable(provided, sortedCards)}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
);
|
),
|
||||||
};
|
[id, index, orientation, renderDroppable, sortedCards, technician, bodyshop, cardSettings]
|
||||||
|
|
||||||
const renderHeader = (pickedProps) => {
|
|
||||||
return <components.LaneHeader {...pickedProps} onDoubleClick={toggleLaneCollapsed} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
const allClassNames = useMemo(
|
|
||||||
() => `react-trello-lane ${collapsed ? "lane-collapsed" : ""} ${className || ""}`.trim(),
|
|
||||||
[collapsed, className]
|
|
||||||
);
|
);
|
||||||
const passedProps = {
|
|
||||||
actions,
|
|
||||||
id,
|
|
||||||
boardId,
|
|
||||||
title,
|
|
||||||
index,
|
|
||||||
laneSortFunction,
|
|
||||||
style,
|
|
||||||
cardStyle,
|
|
||||||
cards,
|
|
||||||
collapsibleLanes,
|
|
||||||
|
|
||||||
components,
|
|
||||||
orientation,
|
|
||||||
className,
|
|
||||||
...otherProps
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<Section key={id} orientation={orientation} {...passedProps}>
|
<Section key={id} orientation={orientation}>
|
||||||
{renderHeader({ id, cards, ...passedProps })}
|
<div onDoubleClick={toggleLaneCollapsed} className="react-trello-column-header">
|
||||||
|
<UnorderedListOutlined className="icon" /> {title}
|
||||||
|
</div>
|
||||||
{renderDragContainer()}
|
{renderDragContainer()}
|
||||||
{collapsibleLanes && <LaneFooter onClick={toggleLaneCollapsed} collapsed={collapsed} />}
|
<LaneFooter onClick={toggleLaneCollapsed} collapsed={collapsed} />
|
||||||
</Section>
|
</Section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Lane.propTypes = {
|
Lane.propTypes = {
|
||||||
actions: PropTypes.object,
|
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
boardId: PropTypes.string,
|
|
||||||
title: PropTypes.node,
|
title: PropTypes.node,
|
||||||
index: PropTypes.number,
|
index: PropTypes.number,
|
||||||
laneSortFunction: PropTypes.func,
|
laneSortFunction: PropTypes.func,
|
||||||
style: PropTypes.object,
|
|
||||||
cardStyle: PropTypes.object,
|
|
||||||
cards: PropTypes.array,
|
cards: PropTypes.array,
|
||||||
label: PropTypes.string,
|
orientation: PropTypes.string,
|
||||||
collapsibleLanes: PropTypes.bool,
|
isProcessing: PropTypes.bool,
|
||||||
components: PropTypes.object,
|
cardSettings: PropTypes.object,
|
||||||
orientation: PropTypes.string
|
technician: PropTypes.object,
|
||||||
|
bodyshop: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
actions: bindActionCreators(actions, dispatch)
|
actions: bindActionCreators(actions, dispatch)
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(null, mapDispatchToProps)(Lane);
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
technician: selectTechnician
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(Lane);
|
||||||
|
|||||||
@@ -2,21 +2,17 @@ import React from "react";
|
|||||||
|
|
||||||
import BoardContainer from "./controllers/BoardContainer.jsx";
|
import BoardContainer from "./controllers/BoardContainer.jsx";
|
||||||
import Board from "./controllers/Board.jsx";
|
import Board from "./controllers/Board.jsx";
|
||||||
import Lane from "./controllers/Lane.jsx";
|
|
||||||
import DefaultComponents from "./components";
|
|
||||||
|
|
||||||
import { StyleSheetManager } from "styled-components";
|
import { StyleSheetManager } from "styled-components";
|
||||||
import isPropValid from "@emotion/is-prop-valid";
|
import isPropValid from "@emotion/is-prop-valid";
|
||||||
|
|
||||||
export { BoardContainer, Lane };
|
export { BoardContainer };
|
||||||
|
|
||||||
export { DefaultComponents as components };
|
|
||||||
|
|
||||||
// Enhanced default export using arrow function for simplicity
|
// Enhanced default export using arrow function for simplicity
|
||||||
const TrelloBoard = ({ components, ...otherProps }) => {
|
const TrelloBoard = ({ ...otherProps }) => {
|
||||||
return (
|
return (
|
||||||
<StyleSheetManager shouldForwardProp={shouldForwardProp}>
|
<StyleSheetManager shouldForwardProp={shouldForwardProp}>
|
||||||
<Board components={{ ...DefaultComponents, ...components }} {...otherProps} />
|
<Board {...otherProps} />
|
||||||
</StyleSheetManager>
|
</StyleSheetManager>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { PopoverContainer, PopoverContent } from "react-popopo";
|
import { PopoverContainer, PopoverContent } from "react-popopo";
|
||||||
import styled, { createGlobalStyle, css } from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
|
|
||||||
const getBoardWrapperStyles = (props) => {
|
const getBoardWrapperStyles = (props) => {
|
||||||
if (props.orientation === "vertical") {
|
if (props.orientation === "vertical") {
|
||||||
@@ -7,7 +7,6 @@ const getBoardWrapperStyles = (props) => {
|
|||||||
}
|
}
|
||||||
if (props.orientation === "horizontal") {
|
if (props.orientation === "horizontal") {
|
||||||
// TODO: The white-space: nowrap; would be a good place to offer further customization
|
// TODO: The white-space: nowrap; would be a good place to offer further customization
|
||||||
// This will be put in the lane settings and marked as 'Horizontal Wrapping'
|
|
||||||
return `
|
return `
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
@@ -21,13 +20,8 @@ const getSectionStyles = (props) => {
|
|||||||
return `
|
return `
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
white-space: nowrap;
|
// overflow-y: none;
|
||||||
// overflow-y: none;
|
|
||||||
min-width: 8.5%;
|
min-width: 8.5%;
|
||||||
flex-wrap: wrap;
|
|
||||||
align-content: center;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: stretch;
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
return `
|
return `
|
||||||
@@ -47,52 +41,11 @@ const getLaneFooterStyles = (props) => {
|
|||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GlobalStyle = createGlobalStyle`
|
|
||||||
.comPlainTextContentEditable {
|
|
||||||
-webkit-user-modify: read-write-plaintext-only;
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comPlainTextContentEditable--has-placeholder::before {
|
|
||||||
content: attr(placeholder);
|
|
||||||
opacity: 0.5;
|
|
||||||
color: inherit;
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react_trello_dragClass {
|
|
||||||
transform: rotate(3deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.react_trello_dragLaneClass {
|
|
||||||
transform: rotate(3deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-overflow-menu-horizontal:before {
|
|
||||||
content: "\\E91F";
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-lg,
|
|
||||||
.icon-sm {
|
|
||||||
color: #798d99;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-lg {
|
|
||||||
height: 32px;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-trello-column-header {
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const StyleHorizontal = styled.div`
|
export const StyleHorizontal = styled.div`
|
||||||
.react-trello-lane {
|
.react-trello-lane {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
min-height: 1px;
|
||||||
overflow-y: visible;
|
overflow-y: visible;
|
||||||
overflow-x: visible; // change this line
|
overflow-x: visible; // change this line
|
||||||
}
|
}
|
||||||
@@ -111,7 +64,14 @@ export const StyleHorizontal = styled.div`
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
min-width: 4%;
|
min-width: 4%;
|
||||||
}
|
}
|
||||||
|
.react-trello-column-header {
|
||||||
|
border-radius: 5px;
|
||||||
|
min-height: 15px;
|
||||||
|
padding: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
.react-trello-card {
|
.react-trello-card {
|
||||||
height: auto;
|
height: auto;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
@@ -120,9 +80,14 @@ export const StyleHorizontal = styled.div`
|
|||||||
|
|
||||||
export const StyleVertical = styled.div`
|
export const StyleVertical = styled.div`
|
||||||
.react-trello-column-header {
|
.react-trello-column-header {
|
||||||
|
border-radius: 5px;
|
||||||
|
min-height: 15px;
|
||||||
|
padding: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-trello-lane {
|
.react-trello-lane {
|
||||||
min-height: 5px;
|
min-height: 5px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -144,15 +109,15 @@ export const StyleVertical = styled.div`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.grid-item {
|
.grid-item {
|
||||||
width: 8%; // TODO: THIS IS WHERE WE GET VERTICAL CARD CUSTOMIZATION
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
width: 250px; // TODO: (Note) This is where we will set the width of the cards in the vertical orientation
|
||||||
align-content: stretch;
|
align-content: stretch;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 250px; // TODO: (Note) This is where we will set the width of the cards in the vertical orientation
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-wrapper {
|
.item-wrapper {
|
||||||
@@ -172,52 +137,6 @@ export const StyleVertical = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CustomPopoverContainer = styled(PopoverContainer)`
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const CustomPopoverContent = styled(PopoverContent)`
|
|
||||||
visibility: hidden;
|
|
||||||
margin-top: -5px;
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10;
|
|
||||||
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3);
|
|
||||||
transition: all 0.3s ease 0ms;
|
|
||||||
border-radius: 3px;
|
|
||||||
min-width: 7em;
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
background-color: #fff;
|
|
||||||
color: #000;
|
|
||||||
padding: 5px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
|
|
||||||
${(props) =>
|
|
||||||
props.active &&
|
|
||||||
`
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
transition-delay: 100ms;
|
|
||||||
`} &::before {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: rgba(255, 255, 255, 0.56);
|
|
||||||
padding: 0.5em 1em;
|
|
||||||
margin: 0;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #00bcd4 !important;
|
|
||||||
color: #37474f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const BoardWrapper = styled.div`
|
export const BoardWrapper = styled.div`
|
||||||
color: #393939;
|
color: #393939;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -226,13 +145,6 @@ export const BoardWrapper = styled.div`
|
|||||||
${getBoardWrapperStyles};
|
${getBoardWrapperStyles};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Header = styled.header`
|
|
||||||
margin-bottom: 10px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: flex-start;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Section = styled.section`
|
export const Section = styled.section`
|
||||||
background-color: #e3e3e3;
|
background-color: #e3e3e3;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
@@ -258,148 +170,8 @@ export const ScrollableLane = styled.div`
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Title = styled.span`
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 15px;
|
|
||||||
line-height: 18px;
|
|
||||||
cursor: ${(props) => (props.draggable ? "grab" : `auto`)};
|
|
||||||
width: 70%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const RightContent = styled.span`
|
|
||||||
width: 38%;
|
|
||||||
text-align: right;
|
|
||||||
padding-right: 10px;
|
|
||||||
font-size: 13px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const CardWrapper = styled.article`
|
|
||||||
border-radius: 3px;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
background-color: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-bottom: 7px;
|
|
||||||
max-width: 250px;
|
|
||||||
min-width: 230px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const MovableCardWrapper = styled(CardWrapper)`
|
|
||||||
&:hover {
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const CardHeader = styled(Header)`
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
padding-bottom: 6px;
|
|
||||||
color: #000;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const CardTitle = styled(Title)`
|
|
||||||
font-size: 14px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const CardRightContent = styled(RightContent)`
|
|
||||||
font-size: 10px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Detail = styled.div`
|
export const Detail = styled.div`
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #4d4d4d;
|
color: #4d4d4d;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Footer = styled.div`
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
padding-top: 6px;
|
|
||||||
text-align: right;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const TagSpan = styled.span`
|
|
||||||
padding: 2px 3px;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin: 2px 5px;
|
|
||||||
font-size: 70%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const AddCardLink = styled.a`
|
|
||||||
border-radius: 0 0 3px 3px;
|
|
||||||
color: #838c91;
|
|
||||||
display: block;
|
|
||||||
padding: 5px 2px;
|
|
||||||
margin-top: 10px;
|
|
||||||
position: relative;
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
//background-color: #cdd2d4;
|
|
||||||
color: #4d4d4d;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const LaneTitle = styled.div`
|
|
||||||
font-size: 15px;
|
|
||||||
width: 268px;
|
|
||||||
height: auto;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const LaneSection = styled.section`
|
|
||||||
background-color: #2b6aa3;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin: 5px;
|
|
||||||
position: relative;
|
|
||||||
padding: 5px;
|
|
||||||
display: inline-flex;
|
|
||||||
height: 100%;
|
|
||||||
flex-direction: column;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const NewLaneSection = styled(LaneSection)`
|
|
||||||
width: 200px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const NewLaneButtons = styled.div`
|
|
||||||
margin-top: 10px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const CardForm = styled.div`
|
|
||||||
background-color: #e3e3e3;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const InlineInput = styled.textarea`
|
|
||||||
overflow-x: hidden; /* for Firefox (issue #5) */
|
|
||||||
word-wrap: break-word;
|
|
||||||
min-height: 18px;
|
|
||||||
max-height: 112px; /* optional, but recommended */
|
|
||||||
resize: none;
|
|
||||||
width: 100%;
|
|
||||||
height: 18px;
|
|
||||||
font-size: inherit;
|
|
||||||
font-weight: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
text-align: inherit;
|
|
||||||
background-color: transparent;
|
|
||||||
box-shadow: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: 0;
|
|
||||||
padding: 0 8px;
|
|
||||||
outline: 0;
|
|
||||||
|
|
||||||
${(props) =>
|
|
||||||
props.border &&
|
|
||||||
css`
|
|
||||||
&:focus {
|
|
||||||
box-shadow: inset 0 0 0 2px #0079bf;
|
|
||||||
}
|
|
||||||
`} &:focus {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|||||||
@@ -1,154 +1,4 @@
|
|||||||
import styled from 'styled-components'
|
import styled from "styled-components";
|
||||||
import {CardWrapper, MovableCardWrapper} from './Base'
|
|
||||||
|
|
||||||
export const DeleteWrapper = styled.div`
|
|
||||||
text-align: center;
|
|
||||||
position: absolute;
|
|
||||||
top: -1px;
|
|
||||||
right: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const GenDelButton = styled.button`
|
|
||||||
transition: all 0.5s ease;
|
|
||||||
display: inline-block;
|
|
||||||
border: none;
|
|
||||||
font-size: 15px;
|
|
||||||
height: 15px;
|
|
||||||
padding: 0;
|
|
||||||
margin-top: 5px;
|
|
||||||
text-align: center;
|
|
||||||
width: 15px;
|
|
||||||
background: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const DelButton = styled.button`
|
|
||||||
transition: all 0.5s ease;
|
|
||||||
display: inline-block;
|
|
||||||
border: none;
|
|
||||||
font-size: 8px;
|
|
||||||
height: 15px;
|
|
||||||
line-height: 1px;
|
|
||||||
margin: 0 0 8px;
|
|
||||||
padding: 0;
|
|
||||||
text-align: center;
|
|
||||||
width: 15px;
|
|
||||||
background: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
${MovableCardWrapper}:hover & {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const MenuButton = styled.button`
|
|
||||||
transition: all 0.5s ease;
|
|
||||||
display: inline-block;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
height: 15px;
|
|
||||||
line-height: 1px;
|
|
||||||
margin: 0 0 8px;
|
|
||||||
padding: 0;
|
|
||||||
text-align: center;
|
|
||||||
width: 15px;
|
|
||||||
background: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const LaneMenuHeader = styled.div`
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
text-align: center;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const LaneMenuContent = styled.div`
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 0 12px 12px;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const LaneMenuItem = styled.div`
|
|
||||||
cursor: pointer;
|
|
||||||
display: block;
|
|
||||||
font-weight: 700;
|
|
||||||
padding: 6px 12px;
|
|
||||||
position: relative;
|
|
||||||
margin: 0 -12px;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #3179ba;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const LaneMenuTitle = styled.span`
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: #6b808c;
|
|
||||||
display: block;
|
|
||||||
line-height: 30px;
|
|
||||||
border-bottom: 1px solid rgba(9, 45, 66, 0.13);
|
|
||||||
margin: 0 6px;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0 32px;
|
|
||||||
position: relative;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
z-index: 1;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const DeleteIcon = styled.span`
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
width: 4px;
|
|
||||||
height: 4px;
|
|
||||||
opacity: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid #83bd42;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 4px;
|
|
||||||
background-color: #83bd42;
|
|
||||||
|
|
||||||
${CardWrapper}:hover & {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover::before,
|
|
||||||
&:hover::after {
|
|
||||||
background: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before,
|
|
||||||
&:after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
height: 2px;
|
|
||||||
width: 60%;
|
|
||||||
top: 45%;
|
|
||||||
left: 20%;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
-webkit-transform: rotate(45deg);
|
|
||||||
-moz-transform: rotate(45deg);
|
|
||||||
-o-transform: rotate(45deg);
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
-webkit-transform: rotate(-45deg);
|
|
||||||
-moz-transform: rotate(-45deg);
|
|
||||||
-o-transform: rotate(-45deg);
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const ExpandCollapseBase = styled.span`
|
export const ExpandCollapseBase = styled.span`
|
||||||
width: 36px;
|
width: 36px;
|
||||||
@@ -156,11 +6,11 @@ export const ExpandCollapseBase = styled.span`
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
`
|
`;
|
||||||
|
|
||||||
export const CollapseBtn = styled(ExpandCollapseBase)`
|
export const CollapseBtn = styled(ExpandCollapseBase)`
|
||||||
&:before {
|
&:before {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -171,7 +21,7 @@ export const CollapseBtn = styled(ExpandCollapseBase)`
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 4px;
|
left: 4px;
|
||||||
top: 4px;
|
top: 4px;
|
||||||
@@ -179,11 +29,11 @@ export const CollapseBtn = styled(ExpandCollapseBase)`
|
|||||||
border-left: 3px solid transparent;
|
border-left: 3px solid transparent;
|
||||||
border-right: 3px solid transparent;
|
border-right: 3px solid transparent;
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
export const ExpandBtn = styled(ExpandCollapseBase)`
|
export const ExpandBtn = styled(ExpandCollapseBase)`
|
||||||
&:before {
|
&:before {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -194,7 +44,7 @@ export const ExpandBtn = styled(ExpandCollapseBase)`
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 4px;
|
left: 4px;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
@@ -202,50 +52,4 @@ export const ExpandBtn = styled(ExpandCollapseBase)`
|
|||||||
border-left: 3px solid transparent;
|
border-left: 3px solid transparent;
|
||||||
border-right: 3px solid transparent;
|
border-right: 3px solid transparent;
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
export const AddButton = styled.button`
|
|
||||||
background: #5aac44;
|
|
||||||
color: #fff;
|
|
||||||
transition: background 0.3s ease;
|
|
||||||
min-height: 32px;
|
|
||||||
padding: 4px 16px;
|
|
||||||
vertical-align: top;
|
|
||||||
margin-top: 0;
|
|
||||||
margin-right: 8px;
|
|
||||||
font-weight: bold;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 14px;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-bottom: 0;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const CancelButton = styled.button`
|
|
||||||
background: #999999;
|
|
||||||
color: #fff;
|
|
||||||
transition: background 0.3s ease;
|
|
||||||
min-height: 32px;
|
|
||||||
padding: 4px 16px;
|
|
||||||
vertical-align: top;
|
|
||||||
margin-top: 0;
|
|
||||||
font-weight: bold;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 14px;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-bottom: 0;
|
|
||||||
`
|
|
||||||
export const AddLaneLink = styled.button`
|
|
||||||
background: #2b6aa3;
|
|
||||||
border: none;
|
|
||||||
color: #fff;
|
|
||||||
transition: background 0.3s ease;
|
|
||||||
min-height: 32px;
|
|
||||||
padding: 4px 16px;
|
|
||||||
vertical-align: top;
|
|
||||||
margin-top: 0;
|
|
||||||
margin-right: 0px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-bottom: 0;
|
|
||||||
`
|
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
import styled, {keyframes} from 'styled-components'
|
|
||||||
|
|
||||||
const keyframeAnimation = keyframes`
|
|
||||||
0% {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
20% {
|
|
||||||
transform: scale(1, 2.2);
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
`
|
|
||||||
export const LoaderDiv = styled.div`
|
|
||||||
text-align: center;
|
|
||||||
margin: 15px 0;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const LoadingBar = styled.div`
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 2px;
|
|
||||||
width: 4px;
|
|
||||||
height: 18px;
|
|
||||||
border-radius: 4px;
|
|
||||||
animation: ${keyframeAnimation} 1s ease-in-out infinite;
|
|
||||||
background-color: #777;
|
|
||||||
|
|
||||||
&:nth-child(1) {
|
|
||||||
animation-delay: 0.0001s;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(2) {
|
|
||||||
animation-delay: 0.09s;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(3) {
|
|
||||||
animation-delay: 0.18s;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(4) {
|
|
||||||
animation-delay: 0.27s;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
Reference in New Issue
Block a user