- Finish adjusting the Board Settings component.
- Extract some components out of Lane.jsx into their own files - Fix misc bugs around preserving lane height in Vertical mode - Add missing non english translation strings Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -4,23 +4,26 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { UPDATE_KANBAN_SETTINGS } from "../../graphql/user.queries";
|
import { UPDATE_KANBAN_SETTINGS } from "../../graphql/user.queries";
|
||||||
|
|
||||||
export default function ProductionBoardKanbanSettings({ associationSettings, parentLoading, onSettingsChange }) {
|
export default function ProductionBoardKanbanSettings({ associationSettings, parentLoading }) {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
const [orientation, setOrientation] = useState(true); // Default to vertical
|
const [orientation, setOrientation] = useState(true);
|
||||||
|
const [compact, setCompact] = useState(false);
|
||||||
|
const [colored, setColored] = useState(false);
|
||||||
const [updateKbSettings] = useMutation(UPDATE_KANBAN_SETTINGS);
|
const [updateKbSettings] = useMutation(UPDATE_KANBAN_SETTINGS);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (associationSettings?.kanban_settings) {
|
if (associationSettings?.kanban_settings) {
|
||||||
|
const { orientation = true, compact = true, cardcolor = true } = associationSettings.kanban_settings;
|
||||||
form.setFieldsValue(associationSettings.kanban_settings);
|
form.setFieldsValue(associationSettings.kanban_settings);
|
||||||
setOrientation(associationSettings.kanban_settings?.orientation ?? true);
|
setOrientation(orientation);
|
||||||
|
setCompact(compact);
|
||||||
|
setColored(cardcolor);
|
||||||
}
|
}
|
||||||
}, [form, associationSettings, open]);
|
}, [form, associationSettings]);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -29,9 +32,10 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par
|
|||||||
const result = await updateKbSettings({
|
const result = await updateKbSettings({
|
||||||
variables: {
|
variables: {
|
||||||
id: associationSettings?.id,
|
id: associationSettings?.id,
|
||||||
ks: { ...values, orientation }
|
ks: { ...values, orientation, compact, cardcolor: colored }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.errors) {
|
if (result.errors) {
|
||||||
notification.open({
|
notification.open({
|
||||||
type: "error",
|
type: "error",
|
||||||
@@ -40,40 +44,56 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
parentLoading(false);
|
parentLoading(false);
|
||||||
setHasChanges(false);
|
setHasChanges(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleValuesChange = () => {
|
const handleValuesChange = () => setHasChanges(true);
|
||||||
setHasChanges(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOrientationChange = (checked) => {
|
const handleCheckedChanges = (checked, callback) => {
|
||||||
setOrientation(checked);
|
callback(checked);
|
||||||
setHasChanges(true);
|
setHasChanges(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const cardStyle = { minWidth: "50vw", marginTop: 10 };
|
const cardStyle = { minWidth: "50vw", marginTop: 10 };
|
||||||
|
|
||||||
|
const renderSwitchItem = (name, checked, callback, labelKey, checkedChildrenKey, unCheckedChildrenKey) => (
|
||||||
|
<Col span={4} key={name}>
|
||||||
|
<Form.Item name={name} valuePropName="checked" label={t(labelKey)}>
|
||||||
|
<Switch
|
||||||
|
checkedChildren={t(checkedChildrenKey)}
|
||||||
|
unCheckedChildren={t(unCheckedChildrenKey)}
|
||||||
|
checked={checked}
|
||||||
|
onChange={(checked) => handleCheckedChanges(checked, callback)}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderCheckboxItem = (name, labelKey) => (
|
||||||
|
<Col span={4} key={name}>
|
||||||
|
<Form.Item name={name} valuePropName="checked">
|
||||||
|
<Checkbox>{t(labelKey)}</Checkbox>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
|
||||||
const renderCardSettings = () => (
|
const renderCardSettings = () => (
|
||||||
<>
|
<>
|
||||||
<Card title={t("production.settings.layout")} style={cardStyle}>
|
<Card title={t("production.settings.layout")} style={cardStyle}>
|
||||||
<Row gutter={[16, 16]}>
|
<Row gutter={[16, 16]}>
|
||||||
|
{renderSwitchItem(
|
||||||
|
"orientation",
|
||||||
|
orientation,
|
||||||
|
setOrientation,
|
||||||
|
"production.labels.orientation",
|
||||||
|
"production.labels.vertical",
|
||||||
|
"production.labels.horizontal"
|
||||||
|
)}
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<Form.Item valuePropName="checked" label={t("production.labels.orientation")}>
|
|
||||||
<Switch
|
|
||||||
checkedChildren="Vertical"
|
|
||||||
unCheckedChildren="Horizontal"
|
|
||||||
checked={orientation}
|
|
||||||
onChange={handleOrientationChange}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row gutter={[16, 16]}>
|
|
||||||
<Col span={24}>
|
|
||||||
<Form.Item name="cardSize" label={t("production.labels.card_size")}>
|
<Form.Item name="cardSize" label={t("production.labels.card_size")}>
|
||||||
<Radio.Group>
|
<Radio.Group>
|
||||||
<Radio.Button value="compact">{t("production.options.small")}</Radio.Button>
|
<Radio.Button value="compact">{t("production.options.small")}</Radio.Button>
|
||||||
@@ -82,77 +102,39 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par
|
|||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
{renderSwitchItem(
|
||||||
<Row gutter={[16, 16]}>
|
"compact",
|
||||||
<Col span={4}>
|
compact,
|
||||||
<Form.Item name="compact" valuePropName="checked">
|
setCompact,
|
||||||
<Checkbox>{t("production.labels.compact")}</Checkbox>
|
"production.labels.compact",
|
||||||
</Form.Item>
|
"production.labels.tall",
|
||||||
</Col>
|
"production.labels.wide"
|
||||||
<Col span={4}>
|
)}
|
||||||
<Form.Item name="cardcolor" valuePropName="checked">
|
{renderSwitchItem(
|
||||||
<Checkbox>{t("production.labels.cardcolor")}</Checkbox>
|
"cardcolor",
|
||||||
</Form.Item>
|
colored,
|
||||||
</Col>
|
setColored,
|
||||||
|
"production.labels.cardcolor",
|
||||||
|
"production.labels.on",
|
||||||
|
"production.labels.off"
|
||||||
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
<Card title={t("production.settings.information")} style={cardStyle}>
|
<Card title={t("production.settings.information")} style={cardStyle}>
|
||||||
<Row gutter={[16, 16]}>
|
<Row gutter={[16, 16]}>
|
||||||
<Col span={4}>
|
{[
|
||||||
<Form.Item name="model_info" valuePropName="checked">
|
"model_info",
|
||||||
<Checkbox>{t("production.labels.model_info")}</Checkbox>
|
"ownr_nm",
|
||||||
</Form.Item>
|
"clm_no",
|
||||||
</Col>
|
"ins_co_nm",
|
||||||
<Col span={4}>
|
"employeeassignments",
|
||||||
<Form.Item name="ownr_nm" valuePropName="checked">
|
"actual_in",
|
||||||
<Checkbox>{t("production.labels.ownr_nm")}</Checkbox>
|
"scheduled_completion",
|
||||||
</Form.Item>
|
"ats",
|
||||||
</Col>
|
"production_note",
|
||||||
<Col span={4}>
|
"sublets",
|
||||||
<Form.Item name="clm_no" valuePropName="checked">
|
"partsstatus"
|
||||||
<Checkbox>{t("production.labels.clm_no")}</Checkbox>
|
].map((item) => renderCheckboxItem(item, `production.labels.${item}`))}
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Form.Item name="ins_co_nm" valuePropName="checked">
|
|
||||||
<Checkbox>{t("production.labels.ins_co_nm")}</Checkbox>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Form.Item name="employeeassignments" valuePropName="checked">
|
|
||||||
<Checkbox>{t("production.labels.employeeassignments")}</Checkbox>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Form.Item name="actual_in" valuePropName="checked">
|
|
||||||
<Checkbox>{t("production.labels.actual_in")}</Checkbox>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Form.Item name="scheduled_completion" valuePropName="checked">
|
|
||||||
<Checkbox>{t("production.labels.scheduled_completion")}</Checkbox>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Form.Item name="ats" valuePropName="checked">
|
|
||||||
<Checkbox>{t("production.labels.ats")}</Checkbox>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Form.Item name="production_note" valuePropName="checked">
|
|
||||||
<Checkbox>{t("production.labels.production_note")}</Checkbox>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Form.Item name="sublets" valuePropName="checked">
|
|
||||||
<Checkbox>{t("production.labels.sublets")}</Checkbox>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Form.Item name="partsstatus" valuePropName="checked">
|
|
||||||
<Checkbox>{t("production.labels.partsstatus")}</Checkbox>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
</>
|
</>
|
||||||
@@ -172,7 +154,7 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par
|
|||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<Button block onClick={() => form.submit()} loading={loading} type="primary" disabled={!hasChanges}>
|
<Button block onClick={form.submit} loading={loading} type="primary" disabled={!hasChanges}>
|
||||||
{t("general.actions.save")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const ItemComponent = ({ children, maxCardHeight, maxCardWidth, ...props }) => (
|
||||||
|
<div style={{ minWidth: maxCardWidth, minHeight: maxCardHeight }} {...props}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ItemComponent;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const ItemWrapper = React.memo(({ children, ...props }) => (
|
||||||
|
<div {...props} className="item-wrapper">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
|
||||||
|
export default ItemWrapper;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import React, { forwardRef } from "react";
|
||||||
|
|
||||||
|
const ListComponent = forwardRef(({ style, children, ...props }, ref) => (
|
||||||
|
<div ref={ref} {...props} style={{ ...style }}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
|
||||||
|
export default ListComponent;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
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";
|
||||||
@@ -15,24 +15,9 @@ import { selectTechnician } from "../../../../redux/tech/tech.selectors.js";
|
|||||||
import ProductionBoardCard from "../../../production-board-kanban-card/production-board-kanban-card.component.jsx";
|
import ProductionBoardCard from "../../../production-board-kanban-card/production-board-kanban-card.component.jsx";
|
||||||
import HeightMemoryWrapper from "../components/Lane/HeightMemoryWrapper.jsx";
|
import HeightMemoryWrapper from "../components/Lane/HeightMemoryWrapper.jsx";
|
||||||
import SizeMemoryWrapper from "../components/Lane/SizeMemoryWrapper.jsx";
|
import SizeMemoryWrapper from "../components/Lane/SizeMemoryWrapper.jsx";
|
||||||
|
import ListComponent from "../components/Lane/ListComponent.jsx";
|
||||||
const ListComponent = forwardRef(({ style, children, ...props }, ref) => (
|
import ItemComponent from "../components/Lane/ItemComponent.jsx";
|
||||||
<div ref={ref} {...props} style={{ ...style }}>
|
import ItemWrapper from "../components/Lane/ItemWrapper.jsx";
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
));
|
|
||||||
|
|
||||||
const ItemComponent = ({ children, maxCardHeight, maxCardWidth, ...props }) => (
|
|
||||||
<div style={{ minWidth: maxCardWidth, minHeight: maxCardHeight }} {...props}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const ItemWrapper = React.memo(({ children, ...props }) => (
|
|
||||||
<div {...props} className="item-wrapper">
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lane is a React component that represents a lane in a Trello-like board.
|
* Lane is a React component that represents a lane in a Trello-like board.
|
||||||
@@ -170,6 +155,8 @@ const Lane = ({
|
|||||||
|
|
||||||
const componentProps = orientation === "vertical" ? verticalProps : horizontalProps;
|
const componentProps = orientation === "vertical" ? verticalProps : horizontalProps;
|
||||||
|
|
||||||
|
// If the lane is collapsed, we want to render a div instead of the virtualized list, and we want to set the height to the max height of the lane so that
|
||||||
|
// the lane doesn't shrink when collapsed (in horizontal mode)
|
||||||
const finalComponentProps = collapsed
|
const finalComponentProps = collapsed
|
||||||
? orientation === "horizontal"
|
? orientation === "horizontal"
|
||||||
? {
|
? {
|
||||||
@@ -180,19 +167,19 @@ const Lane = ({
|
|||||||
: {}
|
: {}
|
||||||
: componentProps;
|
: componentProps;
|
||||||
|
|
||||||
|
// If the lane is horizontal and collapsed, we want to override the minHeight style so that the lane doesn't shrink to 0 height
|
||||||
const shouldOverride = orientation !== "horizontal" && (collapsed || !renderedCards.length);
|
const shouldOverride = orientation !== "horizontal" && (collapsed || !renderedCards.length);
|
||||||
|
|
||||||
|
// If the lane is horizontal and collapsed, we want to render a placeholder so that the lane doesn't shrink to 0 height and grows when
|
||||||
|
// a card is dragged over it
|
||||||
const shouldRenderPlaceholder = orientation !== "horizontal" && (collapsed || renderedCards.length === 0);
|
const shouldRenderPlaceholder = orientation !== "horizontal" && (collapsed || renderedCards.length === 0);
|
||||||
|
|
||||||
const hasKey =
|
// Super magic key to maintain max height on the lane when cards are added / removed / resized / etc
|
||||||
orientation === "vertical"
|
const itemKey = `${id}-${orientation}-${cardSettings?.compact}-${renderedCards.length}-${cardSettings?.cardSize}`;
|
||||||
? {
|
|
||||||
key: id
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeightMemoryWrapper
|
<HeightMemoryWrapper
|
||||||
{...hasKey}
|
itemKey={itemKey}
|
||||||
maxHeight={maxLaneHeight}
|
maxHeight={maxLaneHeight}
|
||||||
setMaxHeight={setMaxLaneHeight}
|
setMaxHeight={setMaxLaneHeight}
|
||||||
override={shouldOverride}
|
override={shouldOverride}
|
||||||
@@ -209,7 +196,17 @@ const Lane = ({
|
|||||||
</HeightMemoryWrapper>
|
</HeightMemoryWrapper>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[orientation, collapsed, isVisible, renderDraggable, maxLaneHeight, setMaxLaneHeight, maxCardWidth, id]
|
[
|
||||||
|
orientation,
|
||||||
|
collapsed,
|
||||||
|
isVisible,
|
||||||
|
renderDraggable,
|
||||||
|
maxLaneHeight,
|
||||||
|
setMaxLaneHeight,
|
||||||
|
maxCardWidth,
|
||||||
|
id,
|
||||||
|
cardSettings
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderDragContainer = useCallback(
|
const renderDragContainer = useCallback(
|
||||||
|
|||||||
@@ -2759,7 +2759,13 @@
|
|||||||
"settings": "Error saving board settings: {{error}}"
|
"settings": "Error saving board settings: {{error}}"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"orientation": "Orientation",
|
"on": "On",
|
||||||
|
"off": "Off",
|
||||||
|
"wide": "Wide",
|
||||||
|
"tall": "Tall",
|
||||||
|
"vertical": "Vertical",
|
||||||
|
"horizontal": "Horizontal",
|
||||||
|
"orientation": "Board Orientation",
|
||||||
"card_size": "Card Size",
|
"card_size": "Card Size",
|
||||||
"model_info": "Model Info",
|
"model_info": "Model Info",
|
||||||
"actual_in": "Actual In",
|
"actual_in": "Actual In",
|
||||||
@@ -2775,11 +2781,11 @@
|
|||||||
"qbo_usa": "QBO USA"
|
"qbo_usa": "QBO USA"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cardcolor": "Card Colors",
|
"cardcolor": "Colored Cards",
|
||||||
"cardsettings": "Card Settings",
|
"cardsettings": "Card Settings",
|
||||||
"clm_no": "Claim Number",
|
"clm_no": "Claim Number",
|
||||||
"comment": "Comment",
|
"comment": "Comment",
|
||||||
"compact": "Compact",
|
"compact": "Compact Cards",
|
||||||
"detailpriority": "D/P",
|
"detailpriority": "D/P",
|
||||||
"employeeassignments": "Employee Assignments",
|
"employeeassignments": "Employee Assignments",
|
||||||
"employeesearch": "Employee Search",
|
"employeesearch": "Employee Search",
|
||||||
|
|||||||
@@ -2742,6 +2742,14 @@
|
|||||||
"settings": ""
|
"settings": ""
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
"on": "",
|
||||||
|
"off": "",
|
||||||
|
"wide": "",
|
||||||
|
"tall": "",
|
||||||
|
"vertical": "",
|
||||||
|
"horizontal": "",
|
||||||
|
"orientation": "",
|
||||||
|
"card_size": "",
|
||||||
"model_info": "",
|
"model_info": "",
|
||||||
"actual_in": "",
|
"actual_in": "",
|
||||||
"alert": "",
|
"alert": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user