From ddbb1df9d9e627907a6972c10dd99b9b366036a3 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Fri, 23 Apr 2021 09:11:48 -0700 Subject: [PATCH] IO-924 Rest of phonebook implementation --- bodyshop_translations.babel | 450 ++++++++++++++++++ .../components/header/header.component.jsx | 3 + .../phonebook-form.component.jsx | 122 +++++ .../phonebook-form.container.jsx | 151 ++++++ .../components/rbac-wrapper/rbac-defaults.js | 3 + .../shop-info/shop-info.rbac.component.jsx | 24 + client/src/graphql/accounting.queries.js | 38 ++ client/src/graphql/phonebook.queries.js | 92 ++++ .../pages/manage/manage.page.component.jsx | 3 + .../phonebook/phonebook.page.component.jsx | 190 ++++++++ .../phonebook/phonebook.page.container.jsx | 68 +++ client/src/redux/messaging/messaging.sagas.js | 5 +- client/src/translations/en_us/common.json | 32 ++ client/src/translations/es/common.json | 32 ++ client/src/translations/fr/common.json | 32 ++ .../down.yaml | 43 ++ .../up.yaml | 43 ++ hasura/migrations/metadata.yaml | 1 + 18 files changed, 1331 insertions(+), 1 deletion(-) create mode 100644 client/src/components/phonebook-form/phonebook-form.component.jsx create mode 100644 client/src/components/phonebook-form/phonebook-form.container.jsx create mode 100644 client/src/graphql/phonebook.queries.js create mode 100644 client/src/pages/phonebook/phonebook.page.component.jsx create mode 100644 client/src/pages/phonebook/phonebook.page.container.jsx create mode 100644 hasura/migrations/1619191596826_update_permission_user_public_table_phonebook/down.yaml create mode 100644 hasura/migrations/1619191596826_update_permission_user_public_table_phonebook/up.yaml diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 289e7d526..55055d963 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -4531,6 +4531,53 @@ + + phonebook + + + edit + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + view + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + production @@ -23265,6 +23312,27 @@ + + phonebook + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + productionboard false @@ -26862,6 +26930,320 @@ + + phonebook + + + actions + + + new + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + fields + + + city + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + company + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + country + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + email + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + fax + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + firstname + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + lastname + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + phone1 + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + phone2 + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + state + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + street1 + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + street2 + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + successes + + + saved + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + printcenter @@ -28375,6 +28757,32 @@ + + payments + + + ca_bc_etf_table + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + vendors @@ -31961,6 +32369,27 @@ + + phonebook + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + productionboard false @@ -32740,6 +33169,27 @@ + + phonebook + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + productionboard false diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index 625fff46d..b3148f09b 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -276,6 +276,9 @@ function Header({ {t("menus.header.temporarydocs")} + + {t("menus.header.phonebook")} + { // // diff --git a/client/src/components/phonebook-form/phonebook-form.component.jsx b/client/src/components/phonebook-form/phonebook-form.component.jsx new file mode 100644 index 000000000..ac992a285 --- /dev/null +++ b/client/src/components/phonebook-form/phonebook-form.component.jsx @@ -0,0 +1,122 @@ +import { Button, Form, Input, PageHeader, Space } from "antd"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; +import FormItemEmail from "../form-items-formatted/email-form-item.component"; +import PhoneFormItem, { + PhoneItemFormatterValidation, +} from "../form-items-formatted/phone-form-item.component"; +import LayoutFormRow from "../layout-form-row/layout-form-row.component"; + +export default function PhonebookFormComponent({ + form, + formLoading, + handleDelete, +}) { + const { t } = useTranslation(); + + const { getFieldValue } = form; + + return ( +
+ + + + + } + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PhoneItemFormatterValidation(getFieldValue, "phone1"), + ]} + > + + + + PhoneItemFormatterValidation(getFieldValue, "phone2"), + ]} + > + + + + PhoneItemFormatterValidation(getFieldValue, "fax"), + ]} + > + + + +
+ ); +} diff --git a/client/src/components/phonebook-form/phonebook-form.container.jsx b/client/src/components/phonebook-form/phonebook-form.container.jsx new file mode 100644 index 000000000..2b293f349 --- /dev/null +++ b/client/src/components/phonebook-form/phonebook-form.container.jsx @@ -0,0 +1,151 @@ +import { useMutation, useQuery } from "@apollo/client"; +import { Form, notification } from "antd"; +import queryString from "query-string"; +import React, { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { useHistory, useLocation } from "react-router-dom"; +import { createStructuredSelector } from "reselect"; +import { + DELETE_PHONEBOOK, + INSERT_NEW_PHONEBOOK, + QUERY_PHONEBOOK_BY_ID, + UPDATE_PHONEBOOK, +} from "../../graphql/phonebook.queries"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import AlertComponent from "../alert/alert.component"; +import LoadingSpinner from "../loading-spinner/loading-spinner.component"; +import PhonebookFormComponent from "./phonebook-form.component"; + +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, +}); + +function PhonebookFormContainer({ refetch, bodyshop }) { + const history = useHistory(); + const search = queryString.parse(useLocation().search); + const { phonebookentry } = search; + const [formLoading, setFormLoading] = useState(false); + const [form] = Form.useForm(); + const { t } = useTranslation(); + const { loading, error, data } = useQuery(QUERY_PHONEBOOK_BY_ID, { + variables: { id: phonebookentry }, + fetchPolicy: "network-only", + skip: !!!phonebookentry || phonebookentry === "new", + }); + + const [updatePhonebook] = useMutation(UPDATE_PHONEBOOK); + const [insertPhonebook] = useMutation(INSERT_NEW_PHONEBOOK); + const [deletePhonebook] = useMutation(DELETE_PHONEBOOK); + + const handleDelete = async () => { + setFormLoading(true); + const result = await deletePhonebook({ + variables: { id: phonebookentry }, + refetchQueries: ["QUERY_PHONEBOOK_PAGINATED"], + }); + + if (!result.errors) { + notification["success"]({ + message: t("phonebook.successes.deleted"), + }); + delete search.phonebookentry; + history.push({ search: queryString.stringify(search) }); + if (refetch) + refetch().then((r) => { + form.resetFields(); + }); + } else { + notification["error"]({ + message: t("phonebook.errors.deleting", { + message: JSON.stringify(result.errors), + }), + }); + } + + setFormLoading(false); + }; + + const handleFinish = async (values) => { + setFormLoading(true); + if (phonebookentry && phonebookentry !== "new") { + //It's a phonebook to update. + const result = await updatePhonebook({ + variables: { id: phonebookentry, phonebook: values }, + refetchQueries: ["QUERY_PHONEBOOK_PAGINATED"], + }); + + if (!result.errors) { + notification["success"]({ + message: t("Phonebook.successes.saved"), + }); + + if (refetch) await refetch(); + form.setFieldsValue(data.phonebook_by_pk); + form.resetFields(); + + setFormLoading(false); + } else { + notification["error"]({ + message: t("Phonebook.errors.saving"), + }); + + setFormLoading(false); + } + } else { + //It's a new phonebook to insert. + const result = await insertPhonebook({ + variables: { + phonebook_entry: [{ ...values, bodyshopid: bodyshop.id }], + }, + refetchQueries: ["QUERY_PHONEBOOK_PAGINATED"], + }); + + if (!result.errors) { + notification["success"]({ + message: t("phonebook.successes.saved"), + }); + + if (refetch) await refetch(); + form.resetFields(); + form.resetFields(); + delete search.phonebookentry; + history.push({ search: queryString.stringify(search) }); + setFormLoading(false); + } else { + notification["error"]({ + message: t("phonebook.errors.saving"), + }); + setFormLoading(false); + } + } + }; + + useEffect(() => { + if (data || phonebookentry === "new") form.resetFields(); + }, [data, form, phonebookentry]); + + if (loading) return ; + if (error) return ; + + return ( +
+ {phonebookentry ? ( + + ) : ( + t("phonebook.labels.noneselected") + )} + + ); +} +export default connect(mapStateToProps, null)(PhonebookFormContainer); diff --git a/client/src/components/rbac-wrapper/rbac-defaults.js b/client/src/components/rbac-wrapper/rbac-defaults.js index 8f2fa1f1e..e7180126a 100644 --- a/client/src/components/rbac-wrapper/rbac-defaults.js +++ b/client/src/components/rbac-wrapper/rbac-defaults.js @@ -39,6 +39,9 @@ const ret = { "payments:enter": 3, "payments:list": 3, + "phonebook:view": 1, + "phonebook:edit": 2, + "production:board": 1, "production:list": 1, diff --git a/client/src/components/shop-info/shop-info.rbac.component.jsx b/client/src/components/shop-info/shop-info.rbac.component.jsx index 6615754bc..3aadcf16b 100644 --- a/client/src/components/shop-info/shop-info.rbac.component.jsx +++ b/client/src/components/shop-info/shop-info.rbac.component.jsx @@ -561,6 +561,30 @@ export default function ShopInfoRbacComponent({ form }) { > + + + + + + ); diff --git a/client/src/graphql/accounting.queries.js b/client/src/graphql/accounting.queries.js index 85380e14a..d9fa75c83 100644 --- a/client/src/graphql/accounting.queries.js +++ b/client/src/graphql/accounting.queries.js @@ -84,6 +84,44 @@ export const INSERT_EXPORT_LOG = gql` } `; +export const QUERY_PHONEBOOK_PAGINATED = gql` + query QUERY_PHONEBOOK_PAGINATED( + $search: String + $offset: Int + $limit: Int + $order: [phonebook_order_by!] + ) { + search_phonebook( + offset: $offset + limit: $limit + order_by: $order + args: { search: $search } + ) { + id + created_at + firstname + lastname + phone1 + phone2 + state + zip + fax + email + country + company + city + category + address2 + address1 + } + search_phonebook_aggregate(args: { search: $search }) { + aggregate { + count(distinct: true) + } + } + } +`; + export const QUERY_EXPORT_LOG_PAGINATED = gql` query QUERY_ALL_EXPORTLOG_PAGINATED( $search: String diff --git a/client/src/graphql/phonebook.queries.js b/client/src/graphql/phonebook.queries.js new file mode 100644 index 000000000..67f547441 --- /dev/null +++ b/client/src/graphql/phonebook.queries.js @@ -0,0 +1,92 @@ +import { gql } from "@apollo/client"; + +export const QUERY_PHONEBOOK_PAGINATED = gql` + query QUERY_PHONEBOOK_PAGINATED( + $search: String + $offset: Int + $limit: Int + $order: [phonebook_order_by!] + ) { + search_phonebook( + offset: $offset + limit: $limit + order_by: $order + args: { search: $search } + ) { + id + created_at + firstname + lastname + phone1 + phone2 + state + zip + fax + email + country + company + city + category + address2 + address1 + } + search_phonebook_aggregate(args: { search: $search }) { + aggregate { + count(distinct: true) + } + } + } +`; + +export const QUERY_PHONEBOOK_BY_ID = gql` + query QUERY_PHONEBOOK_BY_ID($id: uuid!) { + phonebook_by_pk(id: $id) { + id + created_at + firstname + lastname + phone1 + phone2 + state + zip + fax + email + country + company + city + category + address2 + address1 + } + } +`; + +export const UPDATE_PHONEBOOK = gql` + mutation UPDATE_VENDOR($id: uuid!, $phonebook: phonebook_set_input!) { + update_phonebook(where: { id: { _eq: $id } }, _set: $phonebook) { + returning { + id + } + } + } +`; + +export const INSERT_NEW_PHONEBOOK = gql` + mutation INSERT_NEW_PHONEBOOK($phonebook_entry: [phonebook_insert_input!]!) { + insert_phonebook(objects: $phonebook_entry) { + returning { + id + } + } + } +`; + +export const DELETE_PHONEBOOK = gql` + mutation DELETE_PHONEBOOK($id: uuid!) { + delete_phonebook(where: { id: { _eq: $id } }) { + returning { + id + } + } + } +`; diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx index 130b0efc9..95202c9ff 100644 --- a/client/src/pages/manage/manage.page.component.jsx +++ b/client/src/pages/manage/manage.page.component.jsx @@ -153,6 +153,8 @@ const PartsQueue = lazy(() => const ExportLogs = lazy(() => import("../export-logs/export-logs.page.container") ); +const Phonebook = lazy(() => import("../phonebook/phonebook.page.container")); + const EmailTest = lazy(() => import("../../components/email-test/email-test-component") ); @@ -348,6 +350,7 @@ export function Manage({ match, conflict, bodyshop }) { component={ExportLogs} /> + diff --git a/client/src/pages/phonebook/phonebook.page.component.jsx b/client/src/pages/phonebook/phonebook.page.component.jsx new file mode 100644 index 000000000..cb2c07b7d --- /dev/null +++ b/client/src/pages/phonebook/phonebook.page.component.jsx @@ -0,0 +1,190 @@ +import { SyncOutlined } from "@ant-design/icons"; +import { useQuery } from "@apollo/client"; +import { Button, Card, Input, Space, Table, Typography } from "antd"; +import _ from "lodash"; +import queryString from "query-string"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { useHistory, useLocation } from "react-router-dom"; +import { createStructuredSelector } from "reselect"; +import AlertComponent from "../../components/alert/alert.component"; +import { QUERY_PHONEBOOK_PAGINATED } from "../../graphql/phonebook.queries"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import ChatOpenButton from "../../components/chat-open-button/chat-open-button.component"; + +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, +}); + +export function PhonebookPageComponent({ bodyshop }) { + const searchParams = queryString.parse(useLocation().search); + const { page, sortcolumn, sortorder, search, phonebookentry } = searchParams; + const history = useHistory(); + + const { loading, error, data, refetch } = useQuery( + QUERY_PHONEBOOK_PAGINATED, + { + variables: { + search: search || "", + offset: page ? (page - 1) * 25 : 0, + limit: 25, + order: [ + { + [sortcolumn || "lastname"]: sortorder + ? sortorder === "descend" + ? "desc" + : "asc" + : "desc", + }, + ], + }, + } + ); + + const { t } = useTranslation(); + + if (error) return ; + + const handleTableChange = (pagination, filters, sorter) => { + searchParams.page = pagination.current; + searchParams.sortcolumn = sorter.columnKey; + searchParams.sortorder = sorter.order; + if (filters.status) { + searchParams.statusFilters = JSON.stringify( + _.flattenDeep(filters.status) + ); + } else { + delete searchParams.statusFilters; + } + history.push({ search: queryString.stringify(searchParams) }); + }; + + const columns = [ + { + title: t("phonebook.fields.firstname"), + dataIndex: "firstname", + key: "firstname", + }, + { + title: t("phonebook.fields.lastname"), + dataIndex: "lastname", + key: "lastname", + }, + { + title: t("phonebook.fields.company"), + dataIndex: "company", + key: "company", + }, + { + title: t("phonebook.fields.email"), + dataIndex: "email", + key: "email", + }, + { + title: t("phonebook.fields.phone1"), + dataIndex: "phone1", + key: "phone1", + render: (text, record) => , + }, + { + title: t("phonebook.fields.phone2"), + dataIndex: "phone2", + key: "phone2", + render: (text, record) => , + }, + { + title: t("phonebook.fields.street1"), + dataIndex: "street1", + key: "street1", + }, + { + title: t("phonebook.fields.city"), + dataIndex: "city", + key: "city", + }, + ]; + + const handleNewPhonebook = () => { + searchParams.phonebookentry = "new"; + history.push({ search: queryString.stringify(searchParams) }); + }; + + const handleOnRowClick = (record) => { + if (record) { + searchParams.phonebookentry = record.id; + history.push({ search: queryString.stringify(searchParams) }); + } else { + delete searchParams.phonebookentry; + history.push({ search: queryString.stringify(searchParams) }); + } + }; + + return ( + + {searchParams.search && ( + <> + + {t("general.labels.searchresults", { + search: searchParams.search, + })} + + + + )} + + + { + searchParams.search = value; + history.push({ search: queryString.stringify(searchParams) }); + }} + /> + + } + > + { + return { + onClick: (event) => { + handleOnRowClick(record); + }, + }; + }} + /> + + ); +} + +export default connect(mapStateToProps, null)(PhonebookPageComponent); diff --git a/client/src/pages/phonebook/phonebook.page.container.jsx b/client/src/pages/phonebook/phonebook.page.container.jsx new file mode 100644 index 000000000..a1cd33107 --- /dev/null +++ b/client/src/pages/phonebook/phonebook.page.container.jsx @@ -0,0 +1,68 @@ +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; +import { + setBreadcrumbs, + setSelectedHeader, +} from "../../redux/application/application.actions"; +import PhonebookPage from "./phonebook.page.component"; +import { Drawer, Grid } from "antd"; +import queryString from "query-string"; +import { useHistory, useLocation } from "react-router-dom"; +import PhonebookFormContainer from "../../components/phonebook-form/phonebook-form.container"; +const mapDispatchToProps = (dispatch) => ({ + setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), + setSelectedHeader: (key) => dispatch(setSelectedHeader(key)), +}); + +export function PhonebookContainer({ setBreadcrumbs, setSelectedHeader }) { + const { t } = useTranslation(); + + useEffect(() => { + document.title = t("titles.phonebook"); + setSelectedHeader("phonebook"); + setBreadcrumbs([ + { + link: "/manage/phonebook", + label: t("titles.bc.phonebook"), + }, + ]); + }, [setBreadcrumbs, t, setSelectedHeader]); + const search = queryString.parse(useLocation().search); + const { phonebookentry } = search; + const history = useHistory(); + + const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) + .filter((screen) => !!screen[1]) + .slice(-1)[0]; + + const bpoints = { + xs: "100%", + sm: "100%", + md: "100%", + lg: "50%", + xl: "50%", + xxl: "45%", + }; + const drawerPercentage = selectedBreakpoint + ? bpoints[selectedBreakpoint[0]] + : "100%"; + + return ( + + + { + delete search.phonebookentry; + history.push({ search: queryString.stringify(search) }); + }} + visible={phonebookentry} + > + + + + ); +} +export default connect(null, mapDispatchToProps)(PhonebookContainer); diff --git a/client/src/redux/messaging/messaging.sagas.js b/client/src/redux/messaging/messaging.sagas.js index 296dca198..8a6a9f10e 100644 --- a/client/src/redux/messaging/messaging.sagas.js +++ b/client/src/redux/messaging/messaging.sagas.js @@ -66,7 +66,10 @@ export function* openChatByPhone({ payload }) { yield put(setSelectedConversation(conversations[0].id)); //Check to see if this job ID is already a child of it. If not add the tag. - if (!conversations[0].job_conversations.find((jc) => jc.jobid === jobid)) + if ( + jobid && + !conversations[0].job_conversations.find((jc) => jc.jobid === jobid) + ) yield client.mutate({ mutation: INSERT_CONVERSATION_TAG, variables: { diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 80c49ef36..e51094304 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -295,6 +295,10 @@ "enter": "Payments -> Enter", "list": "Payments -> List" }, + "phonebook": { + "edit": "Phonebook -> Edit", + "view": "Phonebook -> View" + }, "production": { "board": "Production -> Board", "list": "Production -> List" @@ -1373,6 +1377,7 @@ "jobs": "Jobs", "owners": "Owners", "parts-queue": "Parts Queue", + "phonebook": "Phonebook", "productionboard": "Production Board - Visual", "productionlist": "Production Board - List", "recent": "Recent Items", @@ -1606,6 +1611,28 @@ "stripe": "Credit card transaction charged successfully." } }, + "phonebook": { + "actions": { + "new": "New Phonebook Entry" + }, + "fields": { + "city": "City", + "company": "Company", + "country": "Country", + "email": "Email", + "fax": "Fax", + "firstname": "First Name", + "lastname": "Last Name", + "phone1": "Phone 1", + "phone2": "Phone 2", + "state": "state", + "street1": "Street 1", + "street2": "Street 2" + }, + "successes": { + "saved": "" + } + }, "printcenter": { "appointments": { "appointment_confirmation": "Appointment Confirmation" @@ -1693,6 +1720,9 @@ "speedprint": "Speed Print", "title": "Print Center" }, + "payments": { + "ca_bc_etf_table": "ICBC ETF Table" + }, "vendors": { "purchases_by_vendor_detailed": "Purchases by Vendor - Detailed", "purchases_by_vendor_summary": "Purchases by Vendor - Summary" @@ -1921,6 +1951,7 @@ "owners": "Owners", "parts-queue": "Parts Queue", "payments-all": "All Payments", + "phonebook": "Phonebook", "productionboard": "Production Board - Visual", "productionlist": "Production Board - List", "profile": "My Profile", @@ -1959,6 +1990,7 @@ "owners-detail": "{{name}} | $t(titles.app)", "parts-queue": "Parts Queue | $t(titles.app)", "payments-all": "Payments | $t(titles.app)", + "phonebook": "Phonebook | $t(titles.app)", "productionboard": "Production - Board", "productionlist": "Production Board - List | $t(titles.app)", "profile": "My Profile | $t(titles.app)", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 2f47ca2cc..aa29f4c29 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -295,6 +295,10 @@ "enter": "", "list": "" }, + "phonebook": { + "edit": "", + "view": "" + }, "production": { "board": "", "list": "" @@ -1373,6 +1377,7 @@ "jobs": "Trabajos", "owners": "propietarios", "parts-queue": "", + "phonebook": "", "productionboard": "", "productionlist": "", "recent": "", @@ -1606,6 +1611,28 @@ "stripe": "" } }, + "phonebook": { + "actions": { + "new": "" + }, + "fields": { + "city": "", + "company": "", + "country": "", + "email": "", + "fax": "", + "firstname": "", + "lastname": "", + "phone1": "", + "phone2": "", + "state": "", + "street1": "", + "street2": "" + }, + "successes": { + "saved": "" + } + }, "printcenter": { "appointments": { "appointment_confirmation": "" @@ -1693,6 +1720,9 @@ "speedprint": "", "title": "" }, + "payments": { + "ca_bc_etf_table": "" + }, "vendors": { "purchases_by_vendor_detailed": "", "purchases_by_vendor_summary": "" @@ -1921,6 +1951,7 @@ "owners": "", "parts-queue": "", "payments-all": "", + "phonebook": "", "productionboard": "", "productionlist": "", "profile": "", @@ -1959,6 +1990,7 @@ "owners-detail": "", "parts-queue": "", "payments-all": "", + "phonebook": "", "productionboard": "", "productionlist": "", "profile": "Mi perfil | $t(titles.app)", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index da19d7026..65855ea5f 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -295,6 +295,10 @@ "enter": "", "list": "" }, + "phonebook": { + "edit": "", + "view": "" + }, "production": { "board": "", "list": "" @@ -1373,6 +1377,7 @@ "jobs": "Emplois", "owners": "Propriétaires", "parts-queue": "", + "phonebook": "", "productionboard": "", "productionlist": "", "recent": "", @@ -1606,6 +1611,28 @@ "stripe": "" } }, + "phonebook": { + "actions": { + "new": "" + }, + "fields": { + "city": "", + "company": "", + "country": "", + "email": "", + "fax": "", + "firstname": "", + "lastname": "", + "phone1": "", + "phone2": "", + "state": "", + "street1": "", + "street2": "" + }, + "successes": { + "saved": "" + } + }, "printcenter": { "appointments": { "appointment_confirmation": "" @@ -1693,6 +1720,9 @@ "speedprint": "", "title": "" }, + "payments": { + "ca_bc_etf_table": "" + }, "vendors": { "purchases_by_vendor_detailed": "", "purchases_by_vendor_summary": "" @@ -1921,6 +1951,7 @@ "owners": "", "parts-queue": "", "payments-all": "", + "phonebook": "", "productionboard": "", "productionlist": "", "profile": "", @@ -1959,6 +1990,7 @@ "owners-detail": "", "parts-queue": "", "payments-all": "", + "phonebook": "", "productionboard": "", "productionlist": "", "profile": "Mon profil | $t(titles.app)", diff --git a/hasura/migrations/1619191596826_update_permission_user_public_table_phonebook/down.yaml b/hasura/migrations/1619191596826_update_permission_user_public_table_phonebook/down.yaml new file mode 100644 index 000000000..eb63b045d --- /dev/null +++ b/hasura/migrations/1619191596826_update_permission_user_public_table_phonebook/down.yaml @@ -0,0 +1,43 @@ +- args: + role: user + table: + name: phonebook + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - address1 + - address2 + - category + - city + - company + - country + - email + - fax + - firstname + - lastname + - phone1 + - phone2 + - state + - zip + - created_at + - updated_at + - bodyshopid + - id + computed_fields: [] + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + role: user + table: + name: phonebook + schema: public + type: create_select_permission diff --git a/hasura/migrations/1619191596826_update_permission_user_public_table_phonebook/up.yaml b/hasura/migrations/1619191596826_update_permission_user_public_table_phonebook/up.yaml new file mode 100644 index 000000000..f354974de --- /dev/null +++ b/hasura/migrations/1619191596826_update_permission_user_public_table_phonebook/up.yaml @@ -0,0 +1,43 @@ +- args: + role: user + table: + name: phonebook + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: true + columns: + - address1 + - address2 + - category + - city + - company + - country + - email + - fax + - firstname + - lastname + - phone1 + - phone2 + - state + - zip + - created_at + - updated_at + - bodyshopid + - id + computed_fields: [] + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + role: user + table: + name: phonebook + schema: public + type: create_select_permission diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml index 3268efc56..874cb182b 100644 --- a/hasura/migrations/metadata.yaml +++ b/hasura/migrations/metadata.yaml @@ -3854,6 +3854,7 @@ tables: _eq: X-Hasura-User-Id - active: _eq: true + allow_aggregations: true update_permissions: - role: user permission: