Merged in release/2023-06-09 (pull request #848)

Release/2023 06 09
This commit is contained in:
Patrick Fic
2023-06-07 18:16:35 +00:00
13 changed files with 279 additions and 45 deletions

View File

@@ -145,7 +145,7 @@
//Update row highlighting on production board. //Update row highlighting on production board.
.ant-table-tbody > tr.ant-table-row:hover > td { .ant-table-tbody > tr.ant-table-row:hover > td {
background: #eaeaea !important; background: #e7f3ff !important;
} }
.job-line-manual { .job-line-manual {

View File

@@ -7,7 +7,12 @@ import { selectSelectedConversation } from "../../redux/messaging/messaging.sele
import { TimeAgoFormatter } from "../../utils/DateFormatter"; import { TimeAgoFormatter } from "../../utils/DateFormatter";
import PhoneFormatter from "../../utils/PhoneFormatter"; import PhoneFormatter from "../../utils/PhoneFormatter";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import { List as VirtualizedList, AutoSizer } from "react-virtualized"; import {
List as VirtualizedList,
AutoSizer,
CellMeasurerCache,
CellMeasurer,
} from "react-virtualized";
import "./chat-conversation-list.styles.scss"; import "./chat-conversation-list.styles.scss";
@@ -33,48 +38,64 @@ function ChatConversationListComponent({
[] []
); );
const rowRenderer = ({ index, key, style }) => { const cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 60,
});
const rowRenderer = ({ index, key, style, parent }) => {
const item = conversationList[index]; const item = conversationList[index];
return ( return (
<List.Item <CellMeasurer
key={key} key={key}
onClick={() => setSelectedConversation(item.id)} cache={cache}
className={`chat-list-item ${ parent={parent}
item.id === selectedConversation columnIndex={0}
? "chat-list-selected-conversation" rowIndex={index}
: null
}`}
style={style}
> >
<div sryle={{ display: "inline-block" }}> <List.Item
{item.label && <div className="chat-name">{item.label}</div>} onClick={() => setSelectedConversation(item.id)}
{item.job_conversations.length > 0 ? ( className={`chat-list-item ${
<div className="chat-name"> item.id === selectedConversation
{item.job_conversations.map((j, idx) => ( ? "chat-list-selected-conversation"
<div key={idx}> : null
<OwnerNameDisplay ownerObject={j.job} /> }`}
</div> style={style}
))} >
</div> <div
) : ( style={{
<PhoneFormatter>{item.phone_num}</PhoneFormatter> display: "inline-block",
)} }}
</div> >
<div sryle={{ display: "inline-block" }}> {item.label && <div className="chat-name">{item.label}</div>}
<div> {item.job_conversations.length > 0 ? (
{item.job_conversations.length > 0 <div className="chat-name">
? item.job_conversations.map((j, idx) => ( {item.job_conversations.map((j, idx) => (
<Tag key={idx} className="ro-number-tag"> <div key={idx}>
{j.job.ro_number} <OwnerNameDisplay ownerObject={j.job} />
</Tag> </div>
)) ))}
: null} </div>
) : (
<PhoneFormatter>{item.phone_num}</PhoneFormatter>
)}
</div> </div>
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter> <div style={{ display: "inline-block" }}>
</div> <div>
<Badge count={item.messages_aggregate.aggregate.count || 0} /> {item.job_conversations.length > 0
</List.Item> ? item.job_conversations.map((j, idx) => (
<Tag key={idx} className="ro-number-tag">
{j.job.ro_number}
</Tag>
))
: null}
</div>
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>
</div>
<Badge count={item.messages_aggregate.aggregate.count || 0} />
</List.Item>
</CellMeasurer>
); );
}; };
@@ -86,7 +107,7 @@ function ChatConversationListComponent({
height={height} height={height}
width={width} width={width}
rowCount={conversationList.length} rowCount={conversationList.length}
rowHeight={60} rowHeight={cache.rowHeight}
rowRenderer={rowRenderer} rowRenderer={rowRenderer}
onScroll={({ scrollTop, scrollHeight, clientHeight }) => { onScroll={({ scrollTop, scrollHeight, clientHeight }) => {
if (scrollTop + clientHeight === scrollHeight) { if (scrollTop + clientHeight === scrollHeight) {

View File

@@ -1,14 +1,31 @@
import { Space } from "antd"; import { Space, Button, Col } from "antd";
import React from "react"; import React from "react";
import PhoneNumberFormatter from "../../utils/PhoneFormatter"; import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import ChatArchiveButton from "../chat-archive-button/chat-archive-button.component"; import ChatArchiveButton from "../chat-archive-button/chat-archive-button.component";
import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conversation-title-tags.component"; import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conversation-title-tags.component";
import ChatLabelComponent from "../chat-label/chat-label.component"; import ChatLabelComponent from "../chat-label/chat-label.component";
import ChatTagRoContainer from "../chat-tag-ro/chat-tag-ro.container"; import ChatTagRoContainer from "../chat-tag-ro/chat-tag-ro.container";
import { connect } from "react-redux";
import { setSelectedConversation } from "../../redux/messaging/messaging.actions";
import { LeftOutlined } from "@ant-design/icons";
export default function ChatConversationTitle({ conversation }) { const mapDispatchToProps = (dispatch) => ({
setSelectedConversation: (conversationId) =>
dispatch(setSelectedConversation(conversationId)),
});
function ChatConversationTitle({ conversation, setSelectedConversation }) {
return ( return (
<Space wrap> <Space wrap>
<Col sm={0}>
<Button
onClick={() => setSelectedConversation()}
size="small"
type="text"
>
<LeftOutlined />
</Button>
</Col>
<PhoneNumberFormatter> <PhoneNumberFormatter>
{conversation && conversation.phone_num} {conversation && conversation.phone_num}
</PhoneNumberFormatter> </PhoneNumberFormatter>
@@ -23,3 +40,5 @@ export default function ChatConversationTitle({ conversation }) {
</Space> </Space>
); );
} }
export default connect(null, mapDispatchToProps)(ChatConversationTitle);

View File

@@ -112,7 +112,7 @@ export function ChatPopupComponent({
/> />
<Row gutter={[8, 8]} className="chat-popup-content"> <Row gutter={[8, 8]} className="chat-popup-content">
<Col span={8}> <Col span={8} sm={8} xs={selectedConversation && 0}>
{loading ? ( {loading ? (
<LoadingSpinner /> <LoadingSpinner />
) : ( ) : (

View File

@@ -311,7 +311,9 @@ function Header({
icon={<SettingOutlined />} icon={<SettingOutlined />}
> >
<Menu.Item key="shop" icon={<Icon component={GiSettingsKnobs} />}> <Menu.Item key="shop" icon={<Icon component={GiSettingsKnobs} />}>
<Link to="/manage/shop">{t("menus.header.shop_config")}</Link> <Link to="/manage/shop?tab=info">
{t("menus.header.shop_config")}
</Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="dashboard" icon={<DashboardFilled />}> <Menu.Item key="dashboard" icon={<DashboardFilled />}>
<Link to="/manage/dashboard">{t("menus.header.dashboard")}</Link> <Link to="/manage/dashboard">{t("menus.header.dashboard")}</Link>

View File

@@ -108,7 +108,12 @@ export function JobsConvertButton({
}, },
]} ]}
> >
<Select> <Select
showSearch
filterOption={(input, option) => {
return option.value.toLowerCase().includes(input.toLowerCase());
}}
>
{bodyshop.md_ins_cos.map((s, i) => ( {bodyshop.md_ins_cos.map((s, i) => (
<Select.Option key={i} value={s.name}> <Select.Option key={i} value={s.name}>
{s.name} {s.name}

View File

@@ -52,7 +52,9 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
<Tabs <Tabs
defaultActiveKey={search.subtab} defaultActiveKey={search.subtab}
onChange={(key) => onChange={(key) =>
history.push({ search: `?tab=${search.tab}&subtab=${key}` }) history.push({
search: `?tab=${search.tab}&subtab=${key}`,
})
} }
> >
<Tabs.TabPane key="general" tab={t("bodyshop.labels.shopinfo")}> <Tabs.TabPane key="general" tab={t("bodyshop.labels.shopinfo")}>

View File

@@ -40,6 +40,10 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
]); ]);
}, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]); }, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]);
useEffect(() => {
if (!search.tab) history.push({ search: "?tab=info" });
}, [history, search]);
return ( return (
<RbacWrapper action="shop:config"> <RbacWrapper action="shop:config">
<Tabs <Tabs

View File

@@ -2690,6 +2690,13 @@
table: table:
name: inventory name: inventory
schema: public schema: public
- name: parts_dispatch_lines
using:
foreign_key_constraint_on:
column: joblineid
table:
name: parts_dispatch_lines
schema: public
- name: parts_order_lines - name: parts_order_lines
using: using:
foreign_key_constraint_on: foreign_key_constraint_on:
@@ -3131,6 +3138,13 @@
table: table:
name: notes name: notes
schema: public schema: public
- name: parts_dispatches
using:
foreign_key_constraint_on:
column: jobid
table:
name: parts_dispatch
schema: public
- name: parts_orders - name: parts_orders
using: using:
foreign_key_constraint_on: foreign_key_constraint_on:
@@ -4556,6 +4570,165 @@
template_engine: Kriti template_engine: Kriti
url: '{{$base_url}}/opensearch' url: '{{$base_url}}/opensearch'
version: 2 version: 2
- table:
name: parts_dispatch
schema: public
object_relationships:
- name: job
using:
foreign_key_constraint_on: jobid
array_relationships:
- name: parts_dispatch_lines
using:
foreign_key_constraint_on:
column: partsdispatchid
table:
name: parts_dispatch_lines
schema: public
insert_permissions:
- role: user
permission:
check:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- id
- created_at
- updated_at
- jobid
- number
- employeeid
- dispatched_at
- dispatched_by
select_permissions:
- role: user
permission:
columns:
- number
- dispatched_by
- created_at
- dispatched_at
- updated_at
- employeeid
- id
- jobid
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
update_permissions:
- role: user
permission:
columns:
- number
- dispatched_by
- created_at
- dispatched_at
- updated_at
- employeeid
- id
- jobid
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
check: null
- table:
name: parts_dispatch_lines
schema: public
object_relationships:
- name: jobline
using:
foreign_key_constraint_on: joblineid
- name: parts_dispatch
using:
foreign_key_constraint_on: partsdispatchid
insert_permissions:
- role: user
permission:
check:
parts_dispatch:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- id
- created_at
- updated_at
- partsdispatchid
- joblineid
- quantity
- accepted_at
select_permissions:
- role: user
permission:
columns:
- quantity
- accepted_at
- created_at
- updated_at
- id
- joblineid
- partsdispatchid
filter:
parts_dispatch:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
update_permissions:
- role: user
permission:
columns:
- id
- created_at
- updated_at
- partsdispatchid
- joblineid
- quantity
- accepted_at
filter:
parts_dispatch:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
check: null
- table: - table:
name: parts_order_lines name: parts_order_lines
schema: public schema: public

View File

@@ -0,0 +1 @@
alter table "public"."parts_dispatch_lines" drop constraint "parts_dispatch_lines_partsdispatchid_fkey";

View File

@@ -0,0 +1,5 @@
alter table "public"."parts_dispatch_lines"
add constraint "parts_dispatch_lines_partsdispatchid_fkey"
foreign key ("partsdispatchid")
references "public"."parts_dispatch"
("id") on update cascade on delete cascade;

View File

@@ -0,0 +1 @@
alter table "public"."parts_dispatch_lines" alter column "accepted_at" set not null;

View File

@@ -0,0 +1 @@
alter table "public"."parts_dispatch_lines" alter column "accepted_at" drop not null;