Merged in feature/IO-3020-IO-3036-imex-lite-rome-lite (pull request #2012)
feature/IO-3020-IO-3036-imex-lite-rome-lite Approved-by: Patrick Fic
This commit is contained in:
79
.gitattributes
vendored
79
.gitattributes
vendored
@@ -1 +1,80 @@
|
||||
# Ensure all text files use LF for line endings
|
||||
* text eol=lf
|
||||
|
||||
# Binary files should not be modified by Git
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.webp binary
|
||||
*.svg binary
|
||||
|
||||
# Fonts
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
*.ttf binary
|
||||
*.otf binary
|
||||
*.eot binary
|
||||
|
||||
# Videos
|
||||
*.mp4 binary
|
||||
*.mov binary
|
||||
*.avi binary
|
||||
*.mkv binary
|
||||
*.webm binary
|
||||
|
||||
# Audio
|
||||
*.mp3 binary
|
||||
*.wav binary
|
||||
*.ogg binary
|
||||
*.flac binary
|
||||
|
||||
# Archives and compressed files
|
||||
*.zip binary
|
||||
*.gz binary
|
||||
*.tar binary
|
||||
*.7z binary
|
||||
*.rar binary
|
||||
|
||||
# PDF and documents
|
||||
*.pdf binary
|
||||
*.doc binary
|
||||
*.docx binary
|
||||
*.xls binary
|
||||
*.xlsx binary
|
||||
*.ppt binary
|
||||
*.pptx binary
|
||||
|
||||
# Exclude JSON and other data files from text processing, if necessary
|
||||
*.json text
|
||||
*.xml text
|
||||
*.csv text
|
||||
|
||||
# Scripts and code files should maintain LF endings
|
||||
*.js text eol=lf
|
||||
*.jsx text eol=lf
|
||||
*.ts text eol=lf
|
||||
*.tsx text eol=lf
|
||||
*.css text eol=lf
|
||||
*.scss text eol=lf
|
||||
*.html text eol=lf
|
||||
*.yml text eol=lf
|
||||
*.yaml text eol=lf
|
||||
*.md text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.py text eol=lf
|
||||
*.rb text eol=lf
|
||||
*.java text eol=lf
|
||||
*.php text eol=lf
|
||||
|
||||
# Git configuration files
|
||||
.gitattributes text eol=lf
|
||||
.gitignore text eol=lf
|
||||
*.gitattributes text eol=lf
|
||||
|
||||
# Exclude some other potential binary files
|
||||
*.db binary
|
||||
*.sqlite binary
|
||||
*.exe binary
|
||||
*.dll binary
|
||||
|
||||
@@ -47,7 +47,7 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
|
||||
md: "100%",
|
||||
lg: "75%",
|
||||
xl: "75%",
|
||||
xxl: "60%"
|
||||
xxl: "75%"
|
||||
};
|
||||
const drawerPercentage = selectedBreakpoint ? bpoints[selectedBreakpoint[0]] : "100%";
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { GenerateThumbUrl } from "../jobs-documents-gallery/job-documents.utility";
|
||||
import CardTemplate from "./job-detail-cards.template.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
export default function JobDetailCardsDocumentsComponent({ loading, data }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -20,15 +21,17 @@ export default function JobDetailCardsDocumentsComponent({ loading, data }) {
|
||||
title={t("jobs.labels.cards.documents")}
|
||||
extraLink={`/manage/jobs/${data.id}?tab=documents`}
|
||||
>
|
||||
{data.documents.length > 0 ? (
|
||||
<Carousel autoplay>
|
||||
{data.documents.map((item) => (
|
||||
<img key={item.id} src={GenerateThumbUrl(item)} alt={item.name} />
|
||||
))}
|
||||
</Carousel>
|
||||
) : (
|
||||
<div>{t("documents.errors.nodocuments")}</div>
|
||||
)}
|
||||
<UpsellComponent disableMask upsell={upsellEnum().media.general}>
|
||||
{data.documents.length > 0 ? (
|
||||
<Carousel autoplay>
|
||||
{data.documents.map((item) => (
|
||||
<img key={item.id} src={GenerateThumbUrl(item)} alt={item.name} />
|
||||
))}
|
||||
</Carousel>
|
||||
) : (
|
||||
<div>{t("documents.errors.nodocuments")}</div>
|
||||
)}
|
||||
</UpsellComponent>
|
||||
</CardTemplate>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -892,16 +892,16 @@ export function JobsDetailHeaderActions({
|
||||
key: "postbills",
|
||||
id: "job-actions-postbills",
|
||||
disabled: !job.converted,
|
||||
label: <LockerWrapperComponent featureName="bill">{t("jobs.actions.postbills")}</LockerWrapperComponent>,
|
||||
label: <LockerWrapperComponent featureName="bills">{t("jobs.actions.postbills")}</LockerWrapperComponent>,
|
||||
onClick: () => {
|
||||
logImEXEvent("job_header_enter_bills");
|
||||
|
||||
setBillEnterContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
job: job
|
||||
}
|
||||
});
|
||||
HasFeatureAccess({ featureName: "bills", bodyshop }) &&
|
||||
setBillEnterContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
job: job
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ function JobsDocumentsComponent({
|
||||
{!hasMediaAccess && (
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<UpsellComponent upsell={upsellEnum().media.general} />
|
||||
<UpsellComponent disableMask upsell={upsellEnum().media.general} />
|
||||
</Card>
|
||||
</Col>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FileExcelFilled, SyncOutlined } from "@ant-design/icons";
|
||||
import { Alert, Button, Card, Space } from "antd";
|
||||
import { Alert, Button, Card, Col, Row, Space } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Gallery } from "react-grid-gallery";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -18,6 +18,7 @@ import JobsDocumentsLocalGallerySelectAllComponent from "./jobs-documents-local-
|
||||
import Lightbox from "react-image-lightbox";
|
||||
import "react-image-lightbox/style.css";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -88,95 +89,117 @@ export function JobsDocumentsLocalGallery({
|
||||
const hasMediaAccess = HasFeatureAccess({ bodyshop, featureName: "media" });
|
||||
return (
|
||||
<div>
|
||||
<Space wrap>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (job) {
|
||||
if (invoice_number) {
|
||||
getBillMedia({ jobid: job.id, invoice_number });
|
||||
} else {
|
||||
getJobMedia(job.id);
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
<a href={CreateExplorerLinkForJob({ jobid: job.id })}>
|
||||
<Button>{t("documents.labels.openinexplorer")}</Button>
|
||||
</a>
|
||||
<JobsDocumentsLocalGalleryReassign jobid={job.id} />
|
||||
<JobsDocumentsLocalGallerySelectAllComponent jobid={job.id} />
|
||||
<JobsLocalGalleryDownloadButton job={job} />
|
||||
<JobsDocumentsLocalDeleteButton jobid={job.id} />
|
||||
</Space>
|
||||
<Card>
|
||||
<DocumentsLocalUploadComponent job={job} invoice_number={invoice_number} vendorid={vendorid} allowAllTypes />
|
||||
</Card>
|
||||
<Card title={t("jobs.labels.documents-images")}>
|
||||
<Gallery
|
||||
images={jobMedia.images}
|
||||
onSelect={(index, image) => {
|
||||
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
||||
}}
|
||||
{...(optimized && {
|
||||
customControls: [
|
||||
<Alert style={{ margin: "4px" }} message={t("documents.labels.optimizedimage")} type="success" />
|
||||
]
|
||||
})}
|
||||
onClick={(index) => {
|
||||
setModalState({ open: true, index: index });
|
||||
// const media = allMedia[job.id].find(
|
||||
// (m) => m.optimized === item.src
|
||||
// );
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<Space wrap>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (job) {
|
||||
if (invoice_number) {
|
||||
getBillMedia({ jobid: job.id, invoice_number });
|
||||
} else {
|
||||
getJobMedia(job.id);
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
<a href={CreateExplorerLinkForJob({ jobid: job.id })}>
|
||||
<Button>{t("documents.labels.openinexplorer")}</Button>
|
||||
</a>
|
||||
<JobsDocumentsLocalGalleryReassign jobid={job.id} />
|
||||
<JobsDocumentsLocalGallerySelectAllComponent jobid={job.id} />
|
||||
<JobsLocalGalleryDownloadButton job={job} />
|
||||
<JobsDocumentsLocalDeleteButton jobid={job.id} />
|
||||
</Space>
|
||||
</Col>
|
||||
{!hasMediaAccess && (
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<UpsellComponent disableMask upsell={upsellEnum().media.general} />
|
||||
</Card>
|
||||
</Col>
|
||||
)}
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<DocumentsLocalUploadComponent
|
||||
job={job}
|
||||
invoice_number={invoice_number}
|
||||
vendorid={vendorid}
|
||||
allowAllTypes
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Card title={t("jobs.labels.documents-images")}>
|
||||
<Gallery
|
||||
images={jobMedia.images}
|
||||
onSelect={(index, image) => {
|
||||
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
||||
}}
|
||||
{...(optimized && {
|
||||
customControls: [
|
||||
<Alert style={{ margin: "4px" }} message={t("documents.labels.optimizedimage")} type="success" />
|
||||
]
|
||||
})}
|
||||
onClick={(index) => {
|
||||
setModalState({ open: true, index: index });
|
||||
// const media = allMedia[job.id].find(
|
||||
// (m) => m.optimized === item.src
|
||||
// );
|
||||
|
||||
// window.open(
|
||||
// media ? media.fullsize : item.fullsize,
|
||||
// "_blank",
|
||||
// "toolbar=0,location=0,menubar=0"
|
||||
// );
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
<Card title={t("jobs.labels.documents-other")}>
|
||||
<Gallery
|
||||
images={jobMedia.other}
|
||||
thumbnailStyle={() => {
|
||||
return {
|
||||
backgroundImage: <FileExcelFilled />,
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
cursor: "pointer"
|
||||
};
|
||||
}}
|
||||
onClick={(index) => {
|
||||
window.open(jobMedia.other[index].fullsize, "_blank", "toolbar=0,location=0,menubar=0");
|
||||
}}
|
||||
onSelect={(index, image) => {
|
||||
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
{modalState.open && (
|
||||
<Lightbox
|
||||
mainSrc={jobMedia.images[modalState.index].fullsize}
|
||||
nextSrc={jobMedia.images[(modalState.index + 1) % jobMedia.images.length].fullsize}
|
||||
prevSrc={jobMedia.images[(modalState.index + jobMedia.images.length - 1) % jobMedia.images.length].fullsize}
|
||||
onCloseRequest={() => setModalState({ open: false, index: 0 })}
|
||||
onMovePrevRequest={() =>
|
||||
setModalState({
|
||||
...modalState,
|
||||
index: (modalState.index + jobMedia.images.length - 1) % jobMedia.images.length
|
||||
})
|
||||
}
|
||||
onMoveNextRequest={() =>
|
||||
setModalState({
|
||||
...modalState,
|
||||
index: (modalState.index + 1) % jobMedia.images.length
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
// window.open(
|
||||
// media ? media.fullsize : item.fullsize,
|
||||
// "_blank",
|
||||
// "toolbar=0,location=0,menubar=0"
|
||||
// );
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Card title={t("jobs.labels.documents-other")}>
|
||||
<Gallery
|
||||
images={jobMedia.other}
|
||||
thumbnailStyle={() => {
|
||||
return {
|
||||
backgroundImage: <FileExcelFilled />,
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
cursor: "pointer"
|
||||
};
|
||||
}}
|
||||
onClick={(index) => {
|
||||
window.open(jobMedia.other[index].fullsize, "_blank", "toolbar=0,location=0,menubar=0");
|
||||
}}
|
||||
onSelect={(index, image) => {
|
||||
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
{modalState.open && (
|
||||
<Lightbox
|
||||
mainSrc={jobMedia.images[modalState.index].fullsize}
|
||||
nextSrc={jobMedia.images[(modalState.index + 1) % jobMedia.images.length].fullsize}
|
||||
prevSrc={jobMedia.images[(modalState.index + jobMedia.images.length - 1) % jobMedia.images.length].fullsize}
|
||||
onCloseRequest={() => setModalState({ open: false, index: 0 })}
|
||||
onMovePrevRequest={() =>
|
||||
setModalState({
|
||||
...modalState,
|
||||
index: (modalState.index + jobMedia.images.length - 1) % jobMedia.images.length
|
||||
})
|
||||
}
|
||||
onMoveNextRequest={() =>
|
||||
setModalState({
|
||||
...modalState,
|
||||
index: (modalState.index + 1) % jobMedia.images.length
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Alert, Form, InputNumber, Switch } from "antd";
|
||||
import { Alert, Form, Switch } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Col, Row, Typography } from "antd";
|
||||
import { Card, Col, Row, Typography } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -14,6 +14,8 @@ import { QUERY_JOB_CHECKLISTS } from "../../graphql/jobs.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -73,38 +75,47 @@ export function JobsChecklistViewContainer({ bodyshop, setBreadcrumbs, setSelect
|
||||
);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:checklist-view">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={12}>
|
||||
<Typography.Title level={4}>{t("jobs.labels.intakechecklist")}</Typography.Title>
|
||||
{data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form}
|
||||
type="intake"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
/>
|
||||
<CompletedBy checklist={data.jobs_by_pk.intakechecklist} />
|
||||
</>
|
||||
)}
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Typography.Title level={4}>{t("jobs.labels.deliverchecklist")}</Typography.Title>
|
||||
{data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form}
|
||||
type="deliver"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
/>
|
||||
<CompletedBy checklist={data.jobs_by_pk.deliverchecklist} />
|
||||
</>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
<FeatureWrapperComponent
|
||||
featureName="checklist"
|
||||
noauth={
|
||||
<Card>
|
||||
<UpsellComponent upsell={upsellEnum().checklist.general} />
|
||||
</Card>
|
||||
}
|
||||
>
|
||||
<RbacWrapper action="jobs:checklist-view">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={12}>
|
||||
<Typography.Title level={4}>{t("jobs.labels.intakechecklist")}</Typography.Title>
|
||||
{data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form}
|
||||
type="intake"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
/>
|
||||
<CompletedBy checklist={data.jobs_by_pk.intakechecklist} />
|
||||
</>
|
||||
)}
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Typography.Title level={4}>{t("jobs.labels.deliverchecklist")}</Typography.Title>
|
||||
{data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form}
|
||||
type="deliver"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
/>
|
||||
<CompletedBy checklist={data.jobs_by_pk.deliverchecklist} />
|
||||
</>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user