From 50581c98e0630a3f28c34c0661e84a6b39a3a9b5 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Mon, 5 Apr 2021 16:57:44 -0700 Subject: [PATCH] IO-134 Limit shop uploads based on plan. --- bodyshop_translations.babel | 105 ++++++++++++++++++ .../documents-upload.component.jsx | 58 ++++++++-- .../documents-upload.utility.js | 1 + .../jobs-documents-gallery.component.jsx | 5 +- .../jobs-documents-gallery.container.jsx | 1 + .../tech-job-clock-out-button.component.jsx | 9 ++ client/src/graphql/bodyshop.queries.js | 2 + client/src/graphql/documents.queries.js | 13 ++- client/src/translations/en_us/common.json | 7 +- client/src/translations/es/common.json | 7 +- client/src/translations/fr/common.json | 7 +- client/src/utils/formatbytes.js | 10 ++ .../down.yaml | 5 + .../up.yaml | 6 + .../down.yaml | 45 ++++++++ .../up.yaml | 46 ++++++++ .../down.yaml | 46 ++++++++ .../up.yaml | 47 ++++++++ .../down.yaml | 47 ++++++++ .../up.yaml | 47 ++++++++ .../down.yaml | 5 + .../up.yaml | 6 + .../down.yaml | 79 +++++++++++++ .../up.yaml | 80 +++++++++++++ hasura/migrations/metadata.yaml | 4 + 25 files changed, 671 insertions(+), 17 deletions(-) create mode 100644 client/src/utils/formatbytes.js create mode 100644 hasura/migrations/1617658602531_alter_table_public_documents_add_column_size/down.yaml create mode 100644 hasura/migrations/1617658602531_alter_table_public_documents_add_column_size/up.yaml create mode 100644 hasura/migrations/1617658618070_update_permission_user_public_table_documents/down.yaml create mode 100644 hasura/migrations/1617658618070_update_permission_user_public_table_documents/up.yaml create mode 100644 hasura/migrations/1617658628914_update_permission_user_public_table_documents/down.yaml create mode 100644 hasura/migrations/1617658628914_update_permission_user_public_table_documents/up.yaml create mode 100644 hasura/migrations/1617659090899_update_permission_user_public_table_documents/down.yaml create mode 100644 hasura/migrations/1617659090899_update_permission_user_public_table_documents/up.yaml create mode 100644 hasura/migrations/1617659647022_alter_table_public_bodyshops_add_column_jobsizelimit/down.yaml create mode 100644 hasura/migrations/1617659647022_alter_table_public_bodyshops_add_column_jobsizelimit/up.yaml create mode 100644 hasura/migrations/1617659660451_update_permission_user_public_table_bodyshops/down.yaml create mode 100644 hasura/migrations/1617659660451_update_permission_user_public_table_bodyshops/up.yaml diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 74a0173ec..8e654c027 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -10211,6 +10211,48 @@ + + storageexceeded + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + storageexceeded_title + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + upload false @@ -10232,6 +10274,69 @@ + + upload_limitexceeded + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + upload_limitexceeded_title + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + usage + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + diff --git a/client/src/components/documents-upload/documents-upload.component.jsx b/client/src/components/documents-upload/documents-upload.component.jsx index 65934d678..9c6ea830b 100644 --- a/client/src/components/documents-upload/documents-upload.component.jsx +++ b/client/src/components/documents-upload/documents-upload.component.jsx @@ -1,14 +1,15 @@ import { UploadOutlined } from "@ant-design/icons"; -import { Upload } from "antd"; -import React from "react"; +import { notification, Progress, Result, Space, Upload } from "antd"; +import React, { useMemo } from "react"; +import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop, selectCurrentUser, } from "../../redux/user/user.selectors"; +import formatBytes from "../../utils/formatbytes"; import { handleUpload } from "./documents-upload.utility"; - const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, bodyshop: selectBodyshop, @@ -22,10 +23,46 @@ export function DocumentsUploadComponent({ tagsArray, billId, callbackAfterUpload, + totalSize, }) { + const { t } = useTranslation(); + + const pct = useMemo(() => { + return parseInt( + (totalSize / ((bodyshop && bodyshop.jobsizelimit) || 1)) * 100 + ); + }, [bodyshop, totalSize]); + + if (pct > 100) + return ( + + ); + return ( { + const newFiles = fileList.reduce((acc, val) => acc + val.size, 0); + const shouldStopUpload = + (totalSize + newFiles) / ((bodyshop && bodyshop.jobsizelimit) || 1) >= + 1; + + //Check to see if old files plus newly uploaded ones will be too much. + if (shouldStopUpload) { + notification.open({ + key: "cannotuploaddocuments", + type: "error", + message: t("documents.labels.upload_limitexceeded_title"), + description: t("documents.labels.upload_limitexceeded"), + }); + return Upload.LIST_IGNORE; + } + return true; + }} customRequest={(ev) => handleUpload(ev, { bodyshop: bodyshop, @@ -39,11 +76,6 @@ export function DocumentsUploadComponent({ accept="audio/*, video/*, image/*, .pdf, .doc, .docx, .xls, .xlsx" // showUploadList={false} > - { - // - } {children || ( <>

@@ -52,6 +84,16 @@ export function DocumentsUploadComponent({

Click or drag files to this area to upload.

+ + + + {t("documents.labels.usage", { + percent: pct, + used: formatBytes(totalSize), + total: formatBytes(bodyshop && bodyshop.jobsizelimit), + })} + + )}
diff --git a/client/src/components/documents-upload/documents-upload.utility.js b/client/src/components/documents-upload/documents-upload.utility.js index 4d64bbfc5..69622fe0d 100644 --- a/client/src/components/documents-upload/documents-upload.utility.js +++ b/client/src/components/documents-upload/documents-upload.utility.js @@ -134,6 +134,7 @@ export const uploadToCloudinary = async ( type: fileType, extension: extension, bodyshopid: bodyshop.id, + size: file.size || cloudinaryUploadResponse.data.bytes, }, ], }, diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx index 9f41556dd..dc8bede19 100644 --- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx @@ -16,6 +16,8 @@ function JobsDocumentsComponent({ refetch, billId, billsCallback, + totalSize, + bodyshop, }) { const [galleryImages, setgalleryImages] = useState({ images: [], other: [] }); const { t } = useTranslation(); @@ -104,7 +106,7 @@ function JobsDocumentsComponent({ }, [data, setgalleryImages, t]); return ( -
+
@@ -126,6 +128,7 @@ function JobsDocumentsComponent({ diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx index c089131bc..41ea08e29 100644 --- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx @@ -23,6 +23,7 @@ export default function JobsDocumentsContainer({ return ( e.id === technician && technician.id )[0]; + console.log( + "emps :>> ", + emps, + "e", + bodyshop && bodyshop.employees, + "tech", + technician + ); + const handleFinish = async (values) => { logImEXEvent("tech_clock_out_job"); diff --git a/client/src/graphql/bodyshop.queries.js b/client/src/graphql/bodyshop.queries.js index 33d359845..f553d75c5 100644 --- a/client/src/graphql/bodyshop.queries.js +++ b/client/src/graphql/bodyshop.queries.js @@ -81,6 +81,7 @@ export const QUERY_BODYSHOP = gql` md_payment_types md_hour_split sub_status + jobsizelimit employees { id first_name @@ -160,6 +161,7 @@ export const UPDATE_SHOP = gql` md_payment_types md_hour_split sub_status + jobsizelimit employees { id first_name diff --git a/client/src/graphql/documents.queries.js b/client/src/graphql/documents.queries.js index 2d6e53d62..3903f1d2f 100644 --- a/client/src/graphql/documents.queries.js +++ b/client/src/graphql/documents.queries.js @@ -2,15 +2,18 @@ import { gql } from "@apollo/client"; export const GET_DOCUMENTS_BY_JOB = gql` query GET_DOCUMENTS_BY_JOB($jobId: uuid!) { - documents( - where: { jobid: { _eq: $jobId } } - order_by: { updated_at: desc } - ) { + documents_aggregate(where: { jobid: { _eq: $jobId } }) { + aggregate { + sum { + size + } + } + } + documents(order_by: { updated_at: desc }) { id name key type - extension bill { id invoice_number diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index e754e0957..6830d07e2 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -658,7 +658,12 @@ "confirmdelete": "Are you sure you want to delete these documents. This CANNOT be undone.", "doctype": "Document Type", "newjobid": "Assign to Job", - "upload": "Upload" + "storageexceeded": "You've exceeded your storage limit for this job. Please remove documents, or increase your storage plan.", + "storageexceeded_title": "Storage Limit Exceeded", + "upload": "Upload", + "upload_limitexceeded": "Uploading all selected files will exceed the job storage limit for your shop. ", + "upload_limitexceeded_title": "Unable to upload file(s)", + "usage": "of job storage used. ({{used}} / {{total}})" }, "successes": { "delete": "Document deleted successfully.", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 268bf90c6..e12ada3d4 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -658,7 +658,12 @@ "confirmdelete": "", "doctype": "", "newjobid": "", - "upload": "Subir" + "storageexceeded": "", + "storageexceeded_title": "", + "upload": "Subir", + "upload_limitexceeded": "", + "upload_limitexceeded_title": "", + "usage": "" }, "successes": { "delete": "Documento eliminado con éxito.", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 6052e0c0b..9e0e9f0c5 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -658,7 +658,12 @@ "confirmdelete": "", "doctype": "", "newjobid": "", - "upload": "Télécharger" + "storageexceeded": "", + "storageexceeded_title": "", + "upload": "Télécharger", + "upload_limitexceeded": "", + "upload_limitexceeded_title": "", + "usage": "" }, "successes": { "delete": "Le document a bien été supprimé.", diff --git a/client/src/utils/formatbytes.js b/client/src/utils/formatbytes.js new file mode 100644 index 000000000..60e264250 --- /dev/null +++ b/client/src/utils/formatbytes.js @@ -0,0 +1,10 @@ +export default function formatBytes(a, b = 2) { + if (0 === a || !a) return "0 Bytes"; + const c = 0 > b ? 0 : b, + d = Math.floor(Math.log(a) / Math.log(1024)); + return ( + parseFloat((a / Math.pow(1024, d)).toFixed(c)) + + " " + + ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][d] + ); +} diff --git a/hasura/migrations/1617658602531_alter_table_public_documents_add_column_size/down.yaml b/hasura/migrations/1617658602531_alter_table_public_documents_add_column_size/down.yaml new file mode 100644 index 000000000..8e3cf3d99 --- /dev/null +++ b/hasura/migrations/1617658602531_alter_table_public_documents_add_column_size/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."documents" DROP COLUMN "size"; + type: run_sql diff --git a/hasura/migrations/1617658602531_alter_table_public_documents_add_column_size/up.yaml b/hasura/migrations/1617658602531_alter_table_public_documents_add_column_size/up.yaml new file mode 100644 index 000000000..063c6501f --- /dev/null +++ b/hasura/migrations/1617658602531_alter_table_public_documents_add_column_size/up.yaml @@ -0,0 +1,6 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."documents" ADD COLUMN "size" integer NOT NULL DEFAULT + 0; + type: run_sql diff --git a/hasura/migrations/1617658618070_update_permission_user_public_table_documents/down.yaml b/hasura/migrations/1617658618070_update_permission_user_public_table_documents/down.yaml new file mode 100644 index 000000000..962ce61af --- /dev/null +++ b/hasura/migrations/1617658618070_update_permission_user_public_table_documents/down.yaml @@ -0,0 +1,45 @@ +- args: + role: user + table: + name: documents + schema: public + type: drop_insert_permission +- args: + permission: + check: + _or: + - job: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + - bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + columns: + - billid + - bodyshopid + - created_at + - extension + - id + - jobid + - key + - name + - type + - updated_at + - uploaded_by + set: {} + role: user + table: + name: documents + schema: public + type: create_insert_permission diff --git a/hasura/migrations/1617658618070_update_permission_user_public_table_documents/up.yaml b/hasura/migrations/1617658618070_update_permission_user_public_table_documents/up.yaml new file mode 100644 index 000000000..0754a089a --- /dev/null +++ b/hasura/migrations/1617658618070_update_permission_user_public_table_documents/up.yaml @@ -0,0 +1,46 @@ +- args: + role: user + table: + name: documents + schema: public + type: drop_insert_permission +- args: + permission: + check: + _or: + - job: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + - bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + columns: + - billid + - bodyshopid + - created_at + - extension + - id + - jobid + - key + - name + - size + - type + - updated_at + - uploaded_by + set: {} + role: user + table: + name: documents + schema: public + type: create_insert_permission diff --git a/hasura/migrations/1617658628914_update_permission_user_public_table_documents/down.yaml b/hasura/migrations/1617658628914_update_permission_user_public_table_documents/down.yaml new file mode 100644 index 000000000..cb62a4488 --- /dev/null +++ b/hasura/migrations/1617658628914_update_permission_user_public_table_documents/down.yaml @@ -0,0 +1,46 @@ +- args: + role: user + table: + name: documents + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - billid + - bodyshopid + - created_at + - extension + - id + - jobid + - key + - name + - type + - updated_at + - uploaded_by + computed_fields: [] + filter: + _or: + - job: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + - bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + role: user + table: + name: documents + schema: public + type: create_select_permission diff --git a/hasura/migrations/1617658628914_update_permission_user_public_table_documents/up.yaml b/hasura/migrations/1617658628914_update_permission_user_public_table_documents/up.yaml new file mode 100644 index 000000000..9c91df702 --- /dev/null +++ b/hasura/migrations/1617658628914_update_permission_user_public_table_documents/up.yaml @@ -0,0 +1,47 @@ +- args: + role: user + table: + name: documents + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - billid + - bodyshopid + - created_at + - extension + - id + - jobid + - key + - name + - size + - type + - updated_at + - uploaded_by + computed_fields: [] + filter: + _or: + - job: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + - bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + role: user + table: + name: documents + schema: public + type: create_select_permission diff --git a/hasura/migrations/1617659090899_update_permission_user_public_table_documents/down.yaml b/hasura/migrations/1617659090899_update_permission_user_public_table_documents/down.yaml new file mode 100644 index 000000000..9c91df702 --- /dev/null +++ b/hasura/migrations/1617659090899_update_permission_user_public_table_documents/down.yaml @@ -0,0 +1,47 @@ +- args: + role: user + table: + name: documents + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - billid + - bodyshopid + - created_at + - extension + - id + - jobid + - key + - name + - size + - type + - updated_at + - uploaded_by + computed_fields: [] + filter: + _or: + - job: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + - bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + role: user + table: + name: documents + schema: public + type: create_select_permission diff --git a/hasura/migrations/1617659090899_update_permission_user_public_table_documents/up.yaml b/hasura/migrations/1617659090899_update_permission_user_public_table_documents/up.yaml new file mode 100644 index 000000000..2f87c23b2 --- /dev/null +++ b/hasura/migrations/1617659090899_update_permission_user_public_table_documents/up.yaml @@ -0,0 +1,47 @@ +- args: + role: user + table: + name: documents + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: true + columns: + - billid + - bodyshopid + - created_at + - extension + - id + - jobid + - key + - name + - size + - type + - updated_at + - uploaded_by + computed_fields: [] + filter: + _or: + - job: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + - bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + role: user + table: + name: documents + schema: public + type: create_select_permission diff --git a/hasura/migrations/1617659647022_alter_table_public_bodyshops_add_column_jobsizelimit/down.yaml b/hasura/migrations/1617659647022_alter_table_public_bodyshops_add_column_jobsizelimit/down.yaml new file mode 100644 index 000000000..5be09670f --- /dev/null +++ b/hasura/migrations/1617659647022_alter_table_public_bodyshops_add_column_jobsizelimit/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "jobsizelimit"; + type: run_sql diff --git a/hasura/migrations/1617659647022_alter_table_public_bodyshops_add_column_jobsizelimit/up.yaml b/hasura/migrations/1617659647022_alter_table_public_bodyshops_add_column_jobsizelimit/up.yaml new file mode 100644 index 000000000..2447cc1b7 --- /dev/null +++ b/hasura/migrations/1617659647022_alter_table_public_bodyshops_add_column_jobsizelimit/up.yaml @@ -0,0 +1,6 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "jobsizelimit" integer NOT NULL + DEFAULT 26214400; + type: run_sql diff --git a/hasura/migrations/1617659660451_update_permission_user_public_table_bodyshops/down.yaml b/hasura/migrations/1617659660451_update_permission_user_public_table_bodyshops/down.yaml new file mode 100644 index 000000000..7541894cb --- /dev/null +++ b/hasura/migrations/1617659660451_update_permission_user_public_table_bodyshops/down.yaml @@ -0,0 +1,79 @@ +- args: + role: user + table: + name: bodyshops + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - accountingconfig + - address1 + - address2 + - appt_alt_transport + - appt_colors + - appt_length + - bill_tax_rates + - city + - country + - created_at + - default_adjustment_rate + - deliverchecklist + - email + - enforce_class + - federal_tax_id + - id + - imexshopid + - inhousevendorid + - insurance_vendor_id + - intakechecklist + - logo_img_path + - md_categories + - md_classes + - md_hour_split + - md_ins_cos + - md_labor_rates + - md_messaging_presets + - md_notes_presets + - md_order_statuses + - md_parts_locations + - md_payment_types + - md_rbac + - md_referral_sources + - md_responsibility_centers + - md_ro_statuses + - messagingservicesid + - phone + - prodtargethrs + - production_config + - region_config + - schedule_end_time + - schedule_start_time + - scoreboard_target + - shopname + - shoprates + - speedprint + - ssbuckets + - state + - state_tax_id + - stripe_acct_id + - sub_status + - target_touchtime + - template_header + - textid + - updated_at + - use_fippa + - workingdays + - zip_post + computed_fields: [] + filter: + associations: + user: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: bodyshops + schema: public + type: create_select_permission diff --git a/hasura/migrations/1617659660451_update_permission_user_public_table_bodyshops/up.yaml b/hasura/migrations/1617659660451_update_permission_user_public_table_bodyshops/up.yaml new file mode 100644 index 000000000..5a55ed627 --- /dev/null +++ b/hasura/migrations/1617659660451_update_permission_user_public_table_bodyshops/up.yaml @@ -0,0 +1,80 @@ +- args: + role: user + table: + name: bodyshops + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - accountingconfig + - address1 + - address2 + - appt_alt_transport + - appt_colors + - appt_length + - bill_tax_rates + - city + - country + - created_at + - default_adjustment_rate + - deliverchecklist + - email + - enforce_class + - federal_tax_id + - id + - imexshopid + - inhousevendorid + - insurance_vendor_id + - intakechecklist + - jobsizelimit + - logo_img_path + - md_categories + - md_classes + - md_hour_split + - md_ins_cos + - md_labor_rates + - md_messaging_presets + - md_notes_presets + - md_order_statuses + - md_parts_locations + - md_payment_types + - md_rbac + - md_referral_sources + - md_responsibility_centers + - md_ro_statuses + - messagingservicesid + - phone + - prodtargethrs + - production_config + - region_config + - schedule_end_time + - schedule_start_time + - scoreboard_target + - shopname + - shoprates + - speedprint + - ssbuckets + - state + - state_tax_id + - stripe_acct_id + - sub_status + - target_touchtime + - template_header + - textid + - updated_at + - use_fippa + - workingdays + - zip_post + computed_fields: [] + filter: + associations: + user: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: bodyshops + schema: public + type: create_select_permission diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml index 2ccc1c911..a20024e37 100644 --- a/hasura/migrations/metadata.yaml +++ b/hasura/migrations/metadata.yaml @@ -750,6 +750,7 @@ tables: - inhousevendorid - insurance_vendor_id - intakechecklist + - jobsizelimit - logo_img_path - md_categories - md_classes @@ -1488,6 +1489,7 @@ tables: - jobid - key - name + - size - type - updated_at - uploaded_by @@ -1503,6 +1505,7 @@ tables: - jobid - key - name + - size - type - updated_at - uploaded_by @@ -1525,6 +1528,7 @@ tables: _eq: X-Hasura-User-Id - active: _eq: true + allow_aggregations: true update_permissions: - role: user permission: