IO-1533 Kanban Customization
This commit is contained in:
@@ -34961,6 +34961,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>cardsettings</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>detailpriority</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"proxy": "http://localhost:4000",
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.4.17",
|
||||
"@asseinfo/react-kanban": "^2.2.0",
|
||||
"@craco/craco": "^6.4.0",
|
||||
"@fingerprintjs/fingerprintjs": "^3.3.0",
|
||||
"@lourenci/react-kanban": "^2.1.0",
|
||||
"@openreplay/tracker": "^3.4.7",
|
||||
"@openreplay/tracker-assist": "^3.4.4",
|
||||
"@openreplay/tracker-graphql": "^3.0.0",
|
||||
|
||||
@@ -10,7 +10,12 @@ import { useTranslation } from "react-i18next";
|
||||
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
||||
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
|
||||
|
||||
export default function ProductionBoardCard(technician, card, bodyshop) {
|
||||
export default function ProductionBoardCard(
|
||||
technician,
|
||||
card,
|
||||
bodyshop,
|
||||
cardSettings
|
||||
) {
|
||||
const { t } = useTranslation();
|
||||
const menu = (
|
||||
<div>
|
||||
@@ -39,7 +44,6 @@ export default function ProductionBoardCard(technician, card, bodyshop) {
|
||||
<Dropdown overlay={menu} trigger={["contextMenu"]}>
|
||||
<Card
|
||||
className="react-kanban-card imex-kanban-card tight-antd-rows"
|
||||
//style={{ margin: ".2rem 0rem" }}
|
||||
title={`${card.ro_number || t("general.labels.na")} - ${
|
||||
card.v_model_yr
|
||||
} ${card.v_make_desc || ""} ${card.v_model_desc || ""}`}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Form, Dropdown, Card, Button, Switch } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { UPDATE_KANBAN_SETTINGS } from "../../graphql/user.queries";
|
||||
import { update } from "lodash";
|
||||
|
||||
export default function ProductionBoardKanbanCardSettings({
|
||||
associationSettings,
|
||||
}) {
|
||||
const [form] = Form.useForm();
|
||||
const [updateKbSettings] = useMutation(UPDATE_KANBAN_SETTINGS);
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(
|
||||
associationSettings && associationSettings.kanban_settings
|
||||
);
|
||||
}, [form, associationSettings]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
const result = await updateKbSettings({
|
||||
variables: {
|
||||
id: associationSettings && associationSettings.id,
|
||||
ks: values,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const overlay = (
|
||||
<div>
|
||||
<Card>
|
||||
<Form form={form} onFinish={handleFinish}>
|
||||
<Form.Item
|
||||
label={t("production.labels.compact")}
|
||||
name="compact"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("production.labels.laborhrs")}
|
||||
name="laborhrs"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("production.labels.employeeassignments")}
|
||||
name="employeeassignments"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("production.labels.alert")}
|
||||
name="alert"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("production.labels.sublets")}
|
||||
name="sublets"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<Dropdown trigger="click" overlay={overlay}>
|
||||
<Button>{t("production.labels.cardsettings")}</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
import Board, { moveCard } from "@lourenci/react-kanban";
|
||||
import "@lourenci/react-kanban/dist/styles.css";
|
||||
import Board, { moveCard } from "@asseinfo/react-kanban";
|
||||
//import "@asseinfo/react-kanban/dist/styles.css";
|
||||
import "./production-board-kanban.styles.scss";
|
||||
import { notification, PageHeader, Space, Statistic } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -16,6 +17,7 @@ import ProductionBoardFilters from "../production-board-filters/production-board
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-settings.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -32,6 +34,7 @@ export function ProductionBoardKanbanComponent({
|
||||
bodyshop,
|
||||
technician,
|
||||
insertAuditTrail,
|
||||
associationSettings,
|
||||
}) {
|
||||
const [boardLanes, setBoardLanes] = useState({
|
||||
columns: [{ id: "Loading...", title: "Loading...", cards: [] }],
|
||||
@@ -116,6 +119,7 @@ export function ProductionBoardKanbanComponent({
|
||||
newChildCard ? newChildCard.id : null,
|
||||
newChildCardNewParent
|
||||
),
|
||||
// TODO: optimisticResponse
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: card.id,
|
||||
@@ -130,6 +134,7 @@ export function ProductionBoardKanbanComponent({
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const totalHrs = data
|
||||
.reduce(
|
||||
(acc, val) =>
|
||||
@@ -139,6 +144,7 @@ export function ProductionBoardKanbanComponent({
|
||||
0
|
||||
)
|
||||
.toFixed(1);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IndefiniteLoading loading={isMoving} />
|
||||
@@ -156,18 +162,30 @@ export function ProductionBoardKanbanComponent({
|
||||
</Space>
|
||||
}
|
||||
extra={
|
||||
<ProductionBoardFilters
|
||||
filter={filter}
|
||||
setFilter={setFilter}
|
||||
loading={isMoving}
|
||||
/>
|
||||
<Space wrap>
|
||||
<ProductionBoardFilters
|
||||
filter={filter}
|
||||
setFilter={setFilter}
|
||||
loading={isMoving}
|
||||
/>
|
||||
<ProductionBoardKanbanCardSettings
|
||||
associationSettings={associationSettings}
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
|
||||
<Board
|
||||
children={boardLanes}
|
||||
disableCardDrag={isMoving}
|
||||
renderCard={(card) => ProductionBoardCard(technician, card, bodyshop)}
|
||||
renderCard={(card) =>
|
||||
ProductionBoardCard(
|
||||
technician,
|
||||
card,
|
||||
bodyshop,
|
||||
associationSettings.kanban_settings
|
||||
)
|
||||
}
|
||||
onCardDragEnd={handleDragEnd}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,25 +1,41 @@
|
||||
import { useSubscription } from "@apollo/client";
|
||||
import { useQuery, useSubscription } from "@apollo/client";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { getCurrentUser } from "../../firebase/firebase.utils";
|
||||
import { SUBSCRIPTION_JOBS_IN_PRODUCTION } from "../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { QUERY_KANBAN_SETTINGS } from "../../graphql/user.queries";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
import ProductionBoardKanbanComponent from "./production-board-kanban.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
|
||||
export function ProductionBoardKanbanContainer({ bodyshop }) {
|
||||
export function ProductionBoardKanbanContainer({ bodyshop, currentUser }) {
|
||||
const { loading, data } = useSubscription(
|
||||
SUBSCRIPTION_JOBS_IN_PRODUCTION,
|
||||
{}
|
||||
);
|
||||
|
||||
const { loading: associationSettingsLoading, data: associationSettings } =
|
||||
useQuery(QUERY_KANBAN_SETTINGS, {
|
||||
variables: { email: currentUser.email },
|
||||
});
|
||||
|
||||
return (
|
||||
<ProductionBoardKanbanComponent
|
||||
loading={loading}
|
||||
loading={loading || associationSettingsLoading}
|
||||
data={data ? data.jobs : []}
|
||||
associationSettings={
|
||||
associationSettings && associationSettings.associations[0]
|
||||
? associationSettings.associations[0]
|
||||
: null
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
.react-kanban-board {
|
||||
padding: 5px;
|
||||
}
|
||||
.react-kanban-card {
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
.react-kanban-card-skeleton,
|
||||
.react-kanban-card,
|
||||
.react-kanban-card-adder-form {
|
||||
box-sizing: border-box;
|
||||
max-width: 250px;
|
||||
min-width: 250px;
|
||||
}
|
||||
.react-kanban-card-skeleton-compact,
|
||||
.react-kanban-card-compact,
|
||||
.react-kanban-card-adder-form-compact {
|
||||
box-sizing: border-box;
|
||||
max-width: 120px;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.react-kanban-card--dragging {
|
||||
box-shadow: 2px 2px grey;
|
||||
}
|
||||
.react-kanban-card__description {
|
||||
padding-top: 10px;
|
||||
}
|
||||
.react-kanban-card__title {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 5px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.react-kanban-column {
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
background-color: #eee;
|
||||
margin: 5px;
|
||||
}
|
||||
.react-kanban-column input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.react-kanban-card-adder-form {
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
.react-kanban-card-adder-form input {
|
||||
border: 0px;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
.react-kanban-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-kanban-card-adder-button:hover {
|
||||
background-color: #ccc;
|
||||
}
|
||||
.react-kanban-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;
|
||||
}
|
||||
.react-kanban-card-adder-form__title:focus {
|
||||
outline: none;
|
||||
}
|
||||
.react-kanban-card-adder-form__description {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.react-kanban-card-adder-form__description:focus {
|
||||
outline: none;
|
||||
}
|
||||
.react-kanban-card-adder-form__button {
|
||||
background-color: #eee;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
width: 45%;
|
||||
margin-top: 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.react-kanban-card-adder-form__button:hover {
|
||||
transition: 0.3s;
|
||||
cursor: pointer;
|
||||
background-color: #ccc;
|
||||
}
|
||||
.react-kanban-column-header {
|
||||
padding-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.react-kanban-column-header input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.react-kanban-column-header__button {
|
||||
color: #333333;
|
||||
background-color: #ffffff;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
.react-kanban-column-header__button:hover,
|
||||
.react-kanban-column-header__button:focus,
|
||||
.react-kanban-column-header__button:active {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
.react-kanban-column-adder-button {
|
||||
border: 2px dashed #eee;
|
||||
height: 132px;
|
||||
margin: 5px;
|
||||
}
|
||||
.react-kanban-column-adder-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -69,3 +69,25 @@ export const UPDATE_FCM_TOKEN = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const QUERY_KANBAN_SETTINGS = gql`
|
||||
query QUERY_KANBAN_SETTINGS($email: String!) {
|
||||
associations(
|
||||
where: { _and: { useremail: { _eq: $email }, active: { _eq: true } } }
|
||||
) {
|
||||
id
|
||||
kanban_settings
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const UPDATE_KANBAN_SETTINGS = gql`
|
||||
mutation UPDATE_KANBAN_SETTINGS($id: uuid!, $ks: jsonb) {
|
||||
update_associations_by_pk(
|
||||
pk_columns: { id: $id }
|
||||
_set: { kanban_settings: $ks }
|
||||
) {
|
||||
id
|
||||
kanban_settings
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -2085,6 +2085,7 @@
|
||||
"alerton": "Add alert to job",
|
||||
"bodyhours": "B",
|
||||
"bodypriority": "B/P",
|
||||
"cardsettings": "Card Settings",
|
||||
"detailpriority": "D/P",
|
||||
"employeesearch": "Employee Search",
|
||||
"jobdetail": "Job Details",
|
||||
|
||||
@@ -2085,6 +2085,7 @@
|
||||
"alerton": "",
|
||||
"bodyhours": "",
|
||||
"bodypriority": "",
|
||||
"cardsettings": "",
|
||||
"detailpriority": "",
|
||||
"employeesearch": "",
|
||||
"jobdetail": "",
|
||||
|
||||
@@ -2085,6 +2085,7 @@
|
||||
"alerton": "",
|
||||
"bodyhours": "",
|
||||
"bodypriority": "",
|
||||
"cardsettings": "",
|
||||
"detailpriority": "",
|
||||
"employeesearch": "",
|
||||
"jobdetail": "",
|
||||
|
||||
@@ -54,6 +54,13 @@
|
||||
tslib "^2.3.0"
|
||||
zen-observable-ts "~1.1.0"
|
||||
|
||||
"@asseinfo/react-kanban@^2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@asseinfo/react-kanban/-/react-kanban-2.2.0.tgz#56b703e9e6d1722a4b2edee321c928fd23749a4d"
|
||||
integrity sha512-/gCigrNXRHeP9VCo8RipTOrA0vAPRIOThJhR4ibVxe6BLkaWFUEuJ1RMT4fODpRRsE3XsdrfVGKkfpRBKgvxXg==
|
||||
dependencies:
|
||||
react-beautiful-dnd "^13.0.0"
|
||||
|
||||
"@babel/code-frame@7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
|
||||
@@ -1977,13 +1984,6 @@
|
||||
"@types/yargs" "^15.0.0"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@lourenci/react-kanban@^2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@lourenci/react-kanban/-/react-kanban-2.1.0.tgz#1e9ffab30d37a19815adcb1a94cb35817ebee8a9"
|
||||
integrity sha512-VZK+HbH2DtfQA7RhMWIZAtieN78n6XzJ8EDkKdaOxbefg1FYEJeyQ/GCav6CW7UvWEIAJxBjaYwF+csadIMYFA==
|
||||
dependencies:
|
||||
react-beautiful-dnd "^13.0.0"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||
|
||||
@@ -203,6 +203,7 @@
|
||||
- authlevel
|
||||
- default_prod_list_view
|
||||
- id
|
||||
- kanban_settings
|
||||
- qbo_realmId
|
||||
- shopid
|
||||
- useremail
|
||||
@@ -217,6 +218,7 @@
|
||||
- active
|
||||
- authlevel
|
||||
- default_prod_list_view
|
||||
- kanban_settings
|
||||
- qbo_realmId
|
||||
filter:
|
||||
bodyshop:
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."associations" add column "kanban_settings" jsonb
|
||||
-- null default jsonb_build_object();
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."associations" add column "kanban_settings" jsonb
|
||||
null default jsonb_build_object();
|
||||
Reference in New Issue
Block a user