diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 95d869399..3aacdbdec 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -29808,6 +29808,27 @@ + + selectview + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + sublets false @@ -29850,6 +29871,27 @@ + + viewname + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + diff --git a/client/src/components/production-list-save-config-button/production-list-save-config-button.component.jsx b/client/src/components/production-list-save-config-button/production-list-save-config-button.component.jsx index f6e16daec..0f7381c84 100644 --- a/client/src/components/production-list-save-config-button/production-list-save-config-button.component.jsx +++ b/client/src/components/production-list-save-config-button/production-list-save-config-button.component.jsx @@ -3,7 +3,7 @@ import React, { useState } from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; -import { Button, notification } from "antd"; +import { Button, Form, Input, notification, Popover, Space } from "antd"; import { useTranslation } from "react-i18next"; import { UPDATE_SHOP } from "../../graphql/bodyshop.queries"; import { logImEXEvent } from "../../firebase/firebase.utils"; @@ -23,21 +23,31 @@ export function ProductionListSaveConfigButton({ }) { const [updateShop] = useMutation(UPDATE_SHOP); const [loading, setLoading] = useState(false); + const [visible, setVisible] = useState(false); + const [form] = Form.useForm(); + const { t } = useTranslation(); - const handleSaveConfig = async () => { + const handleSaveConfig = async (values) => { logImEXEvent("production_save_config"); setLoading(true); const result = await updateShop({ variables: { id: bodyshop.id, shop: { - production_config: { - columnKeys: columns.map((i) => { - return { key: i.key, width: i.width }; - }), - tableState, - }, + production_config: [ + ...bodyshop.production_config.filter((b) => b.name !== values.name), + //Assign it to the name + { + name: values.name, + columns: { + columnKeys: columns.map((i) => { + return { key: i.key, width: i.width }; + }), + tableState, + }, + }, + ], }, }, }); @@ -50,13 +60,44 @@ export function ProductionListSaveConfigButton({ }), }); } + form.resetFields(); + setVisible(false); setLoading(false); }; + const popMenu = ( +
+
+ + + + + + + + +
+
+ ); return ( - + + + ); } export default connect( diff --git a/client/src/components/production-list-table/production-list-table-view-select.component.jsx b/client/src/components/production-list-table/production-list-table-view-select.component.jsx new file mode 100644 index 000000000..3cc78c102 --- /dev/null +++ b/client/src/components/production-list-table/production-list-table-view-select.component.jsx @@ -0,0 +1,119 @@ +import { useMutation } from "@apollo/client"; +import { Button, Popconfirm, Select } from "antd"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { UPDATE_ACTIVE_PROD_LIST_VIEW } from "../../graphql/associations.queries"; +import { UPDATE_SHOP } from "../../graphql/bodyshop.queries"; +import { selectTechnician } from "../../redux/tech/tech.selectors"; +import { + selectBodyshop, + selectCurrentUser, +} from "../../redux/user/user.selectors"; +import ProductionListColumns from "../production-list-columns/production-list-columns.data"; +import { DeleteOutlined } from "@ant-design/icons"; +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, + technician: selectTechnician, + currentUser: selectCurrentUser, +}); + +export function ProductionListTable({ + bodyshop, + technician, + currentUser, + state, + setColumns, +}) { + const { t } = useTranslation(); + const [updateDefaultProdView] = useMutation(UPDATE_ACTIVE_PROD_LIST_VIEW); + const [updateShop] = useMutation(UPDATE_SHOP); + + const handleSelect = async (value, option) => { + setColumns( + bodyshop.production_config + .filter((pc) => pc.name === value)[0] + .columns.columnKeys.map((k) => { + return { + ...ProductionListColumns({ technician, state }).find( + (e) => e.key === k.key + ), + width: k.width, + }; + }) + ); + + const assoc = bodyshop.associations.find( + (a) => a.useremail === currentUser.email + ); + if (assoc) { + await updateDefaultProdView({ + variables: { assocId: assoc.id, view: value }, + }); + } + }; + + const handleTrash = async (name) => { + await updateShop({ + variables: { + id: bodyshop.id, + shop: { + production_config: bodyshop.production_config.filter( + (b) => b.name !== name + ), + }, + }, + awaitRefetchQueries: true, + }); + + setColumns( + bodyshop.production_config[0].columns.columnKeys.map((k) => { + return { + ...ProductionListColumns({ technician, state }).find( + (e) => e.key === k.key + ), + width: k.width, + }; + }) + ); + }; + + return ( +
+ +
+ ); +} +export default connect(mapStateToProps, null)(ProductionListTable); diff --git a/client/src/components/production-list-table/production-list-table.component.jsx b/client/src/components/production-list-table/production-list-table.component.jsx index cd6a51108..5ea082771 100644 --- a/client/src/components/production-list-table/production-list-table.component.jsx +++ b/client/src/components/production-list-table/production-list-table.component.jsx @@ -1,21 +1,25 @@ -import { SyncOutlined } from "@ant-design/icons"; -import { Button, Dropdown, Input, Menu, PageHeader, Space, Table } from "antd"; -import React, { useState } from "react"; +import { Dropdown, Input, Menu, PageHeader, Space, Table } from "antd"; +import React, { useMemo, useState } from "react"; import ReactDragListView from "react-drag-listview"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectTechnician } from "../../redux/tech/tech.selectors"; -import { selectBodyshop } from "../../redux/user/user.selectors"; +import { + selectBodyshop, + selectCurrentUser, +} from "../../redux/user/user.selectors"; import ProductionListColumnsAdd from "../production-list-columns/production-list-columns.add.component"; +import ProductionListColumns from "../production-list-columns/production-list-columns.data"; import ProductionListDetail from "../production-list-detail/production-list-detail.component"; import ProductionListSaveConfigButton from "../production-list-save-config-button/production-list-save-config-button.component"; +import ProductionListTableViewSelect from "./production-list-table-view-select.component"; import ResizeableTitle from "./production-list-table.resizeable.component"; -import ProductionListColumns from "../production-list-columns/production-list-columns.data"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, technician: selectTechnician, + currentUser: selectCurrentUser, }); export function ProductionListTable({ @@ -23,23 +27,37 @@ export function ProductionListTable({ data, bodyshop, technician, - refetch, + currentUser, }) { const [searchText, setSearchText] = useState(""); + const defaultView = useMemo(() => { + const assoc = bodyshop.associations.find( + (a) => a.useremail === currentUser.email + ); + return assoc && assoc.default_prod_list_view; + }, [bodyshop.associations, currentUser.email]); + const [state, setState] = useState( - (bodyshop.production_config && bodyshop.production_config.tableState) || { - sortedInfo: {}, - filteredInfo: { text: "" }, - } + (bodyshop.production_config && + bodyshop.production_config.find((p) => p.name === defaultView) + ?.tableState) || + bodyshop.production_config[0]?.tableState || { + sortedInfo: {}, + filteredInfo: { text: "" }, + } ); const { t } = useTranslation(); + const matchingColumnConfig = useMemo(() => { + return bodyshop.production_config.find((p) => p.name === defaultView); + }, [bodyshop.production_config, defaultView]); + const [columns, setColumns] = useState( (state && - bodyshop.production_config && - bodyshop.production_config.columnKeys.map((k) => { + matchingColumnConfig && + matchingColumnConfig.columns.columnKeys.map((k) => { return { ...ProductionListColumns({ technician, state }).find( (e) => e.key === k.key @@ -126,8 +144,6 @@ export function ProductionListTable({ .includes(searchText.toLowerCase()) ); - const tableTitle = () =>
; - // const handleSelectRecord = (record) => { // if (selected !== record.id) { // setSelected(record.id); @@ -151,13 +167,12 @@ export function ProductionListTable({ columns={columns} tableState={state} /> - + + + setSearchText(e.target.value)} placeholder={t("general.labels.search")} @@ -180,7 +195,6 @@ export function ProductionListTable({ cell: ResizeableTitle, }, }} - title={tableTitle} columns={columns.map((c, index) => { return { ...c, diff --git a/client/src/components/production-list-table/production-list-table.container.jsx b/client/src/components/production-list-table/production-list-table.container.jsx index be95ec10e..d13a71d33 100644 --- a/client/src/components/production-list-table/production-list-table.container.jsx +++ b/client/src/components/production-list-table/production-list-table.container.jsx @@ -1,20 +1,9 @@ import { useSubscription } from "@apollo/client"; import React from "react"; -import { connect } from "react-redux"; -import { createStructuredSelector } from "reselect"; import { SUBSCRIPTION_JOBS_IN_PRODUCTION } from "../../graphql/jobs.queries"; -import { selectTechnician } from "../../redux/tech/tech.selectors"; -import { selectBodyshop } from "../../redux/user/user.selectors"; import ProductionListTable from "./production-list-table.component"; -const mapStateToProps = createStructuredSelector({ - bodyshop: selectBodyshop, - technician: selectTechnician, -}); - -export default connect(mapStateToProps, null)(ProductionListTableContainer); - -export function ProductionListTableContainer({ bodyshop, technician }) { +export default function ProductionListTableContainer() { const { loading, data } = useSubscription( SUBSCRIPTION_JOBS_IN_PRODUCTION, {} diff --git a/client/src/graphql/associations.queries.js b/client/src/graphql/associations.queries.js index 5c051f7c8..e97d4c267 100644 --- a/client/src/graphql/associations.queries.js +++ b/client/src/graphql/associations.queries.js @@ -21,6 +21,22 @@ export const UPDATE_ASSOCIATION = gql` returning { id active + authlevel + default_prod_list_view + } + } + } +`; + +export const UPDATE_ACTIVE_PROD_LIST_VIEW = gql` + mutation UPDATE_ACTIVE_PROD_LIST_VIEW($assocId: uuid, $view: String) { + update_associations( + where: { id: { _eq: $assocId } } + _set: { default_prod_list_view: $view } + ) { + returning { + id + default_prod_list_view } } } diff --git a/client/src/graphql/bodyshop.queries.js b/client/src/graphql/bodyshop.queries.js index 70e08a05e..2f95d0c2c 100644 --- a/client/src/graphql/bodyshop.queries.js +++ b/client/src/graphql/bodyshop.queries.js @@ -14,6 +14,7 @@ export const QUERY_BODYSHOP = gql` associations { authlevel useremail + default_prod_list_view user { authid email diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 63e9b4795..f6bbbea2c 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -1785,8 +1785,10 @@ "note": "Production Note", "paintpriority": "P/P", "refinishhours": "R", + "selectview": "Select a View", "sublets": "Sublets", - "touchtime": "T/T" + "touchtime": "T/T", + "viewname": "View Name" }, "successes": { "removed": "Job removed from production." diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 299eeec63..10e8ec52d 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -1785,8 +1785,10 @@ "note": "", "paintpriority": "", "refinishhours": "", + "selectview": "", "sublets": "", - "touchtime": "" + "touchtime": "", + "viewname": "" }, "successes": { "removed": "" diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 7806e70f9..26438a0d7 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1785,8 +1785,10 @@ "note": "", "paintpriority": "", "refinishhours": "", + "selectview": "", "sublets": "", - "touchtime": "" + "touchtime": "", + "viewname": "" }, "successes": { "removed": "" diff --git a/hasura/migrations/1620083105072_alter_table_public_associations_add_column_default_prod_list_view/down.yaml b/hasura/migrations/1620083105072_alter_table_public_associations_add_column_default_prod_list_view/down.yaml new file mode 100644 index 000000000..0d0e75aa4 --- /dev/null +++ b/hasura/migrations/1620083105072_alter_table_public_associations_add_column_default_prod_list_view/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."associations" DROP COLUMN "default_prod_list_view"; + type: run_sql diff --git a/hasura/migrations/1620083105072_alter_table_public_associations_add_column_default_prod_list_view/up.yaml b/hasura/migrations/1620083105072_alter_table_public_associations_add_column_default_prod_list_view/up.yaml new file mode 100644 index 000000000..03f394ff2 --- /dev/null +++ b/hasura/migrations/1620083105072_alter_table_public_associations_add_column_default_prod_list_view/up.yaml @@ -0,0 +1,6 @@ +- args: + cascade: false + read_only: false + sql: ALTER TABLE "public"."associations" ADD COLUMN "default_prod_list_view" text + NULL; + type: run_sql diff --git a/hasura/migrations/1620083115002_update_permission_user_public_table_associations/down.yaml b/hasura/migrations/1620083115002_update_permission_user_public_table_associations/down.yaml new file mode 100644 index 000000000..015c4e179 --- /dev/null +++ b/hasura/migrations/1620083115002_update_permission_user_public_table_associations/down.yaml @@ -0,0 +1,25 @@ +- args: + role: user + table: + name: associations + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - active + - authlevel + - id + - shopid + - useremail + computed_fields: [] + filter: + user: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: associations + schema: public + type: create_select_permission diff --git a/hasura/migrations/1620083115002_update_permission_user_public_table_associations/up.yaml b/hasura/migrations/1620083115002_update_permission_user_public_table_associations/up.yaml new file mode 100644 index 000000000..ff0e61c7e --- /dev/null +++ b/hasura/migrations/1620083115002_update_permission_user_public_table_associations/up.yaml @@ -0,0 +1,26 @@ +- args: + role: user + table: + name: associations + schema: public + type: drop_select_permission +- args: + permission: + allow_aggregations: false + columns: + - active + - authlevel + - default_prod_list_view + - id + - shopid + - useremail + computed_fields: [] + filter: + user: + authid: + _eq: X-Hasura-User-Id + role: user + table: + name: associations + schema: public + type: create_select_permission diff --git a/hasura/migrations/1620083126422_update_permission_user_public_table_associations/down.yaml b/hasura/migrations/1620083126422_update_permission_user_public_table_associations/down.yaml new file mode 100644 index 000000000..8ac8d69eb --- /dev/null +++ b/hasura/migrations/1620083126422_update_permission_user_public_table_associations/down.yaml @@ -0,0 +1,23 @@ +- args: + role: user + table: + name: associations + schema: public + type: drop_update_permission +- args: + permission: + columns: + - active + - authlevel + filter: + bodyshop: + associations: + user: + authid: + _eq: X-Hasura-User-Id + set: {} + role: user + table: + name: associations + schema: public + type: create_update_permission diff --git a/hasura/migrations/1620083126422_update_permission_user_public_table_associations/up.yaml b/hasura/migrations/1620083126422_update_permission_user_public_table_associations/up.yaml new file mode 100644 index 000000000..b5bbb9670 --- /dev/null +++ b/hasura/migrations/1620083126422_update_permission_user_public_table_associations/up.yaml @@ -0,0 +1,24 @@ +- args: + role: user + table: + name: associations + schema: public + type: drop_update_permission +- args: + permission: + columns: + - active + - authlevel + - default_prod_list_view + filter: + bodyshop: + associations: + user: + authid: + _eq: X-Hasura-User-Id + set: {} + role: user + table: + name: associations + schema: public + type: create_update_permission diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml index fbb20cb85..6fe569748 100644 --- a/hasura/migrations/metadata.yaml +++ b/hasura/migrations/metadata.yaml @@ -200,6 +200,7 @@ tables: columns: - active - authlevel + - default_prod_list_view - id - shopid - useremail @@ -213,6 +214,7 @@ tables: columns: - active - authlevel + - default_prod_list_view filter: bodyshop: associations: