From 34d93c4de0476242762708d8a8104894ed16b3d9 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Mon, 4 Dec 2023 11:39:20 -0500 Subject: [PATCH 1/5] Reversion --- .../jobs-list/jobs-list.component.jsx | 248 ++++++++---------- 1 file changed, 105 insertions(+), 143 deletions(-) diff --git a/client/src/components/jobs-list/jobs-list.component.jsx b/client/src/components/jobs-list/jobs-list.component.jsx index b7bd3141d..fb2e1daa6 100644 --- a/client/src/components/jobs-list/jobs-list.component.jsx +++ b/client/src/components/jobs-list/jobs-list.component.jsx @@ -1,120 +1,105 @@ -import {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined, SyncOutlined,} from "@ant-design/icons"; -import {useQuery} from "@apollo/client"; -import {Button, Card, Grid, Input, Space, Table, Tooltip, Typography} from "antd"; +import { + SyncOutlined, + ExclamationCircleFilled, + PauseCircleOutlined, + BranchesOutlined, +} from "@ant-design/icons"; +import { useQuery } from "@apollo/client"; +import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd"; import queryString from "query-string"; -import React, {useEffect, useState} from "react"; -import {useTranslation} from "react-i18next"; -import {connect} from "react-redux"; -import {Link, useHistory, useLocation} from "react-router-dom"; -import {createStructuredSelector} from "reselect"; -import {QUERY_ALL_ACTIVE_JOBS_PAGINATED} from "../../graphql/jobs.queries"; -import {selectBodyshop} from "../../redux/user/user.selectors"; -import {onlyUnique} from "../../utils/arrayHelper"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { Link, useHistory, useLocation } from "react-router-dom"; +import { createStructuredSelector } from "reselect"; +import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import { onlyUnique } from "../../utils/arrayHelper"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; +import { alphaSort } from "../../utils/sorters"; import AlertComponent from "../alert/alert.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; -import {flattenDeep} from "lodash"; -import { pageLimit } from '../../utils/config'; -import axios from "axios"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, }); -const mapDispatchToProps = () => ({ -}); - -export function JobsList({bodyshop,}) { - const search = queryString.parse(useLocation().search); - const [openSearchResults, setOpenSearchResults] = useState([]); - const [searchLoading, setSearchLoading] = useState(false); - const {page, selected, sortorder, sortcolumn} = search; - +export function JobsList({ bodyshop }) { + const searchParams = queryString.parse(useLocation().search); + const { selected } = searchParams; const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) .filter((screen) => !!screen[1]) .slice(-1)[0]; - - const {loading, error, data, refetch} = useQuery(QUERY_ALL_ACTIVE_JOBS_PAGINATED, { + const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, { variables: { - offset: page ? (page - 1) * pageLimit : 0, - limit: pageLimit, statuses: bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"], - order: [ - { - [sortcolumn || "ro_number"]: - sortorder && sortorder !== "false" - ? (sortorder === "descend" - ? "desc" - : "asc") - : "desc", - }, - ], }, fetchPolicy: "network-only", nextFetchPolicy: "network-only", }); - const total = data?.jobs_aggregate?.aggregate?.count || 0; - const [state, setState] = useState({ - filteredInfo: {text: ""}, + sortedInfo: {}, + filteredInfo: { text: "" }, }); - const {t} = useTranslation(); + const { t } = useTranslation(); const history = useHistory(); + const [searchText, setSearchText] = useState(""); - const jobs = data?.jobs || []; + if (error) return ; + + const jobs = data + ? searchText === "" + ? data.jobs + : data.jobs.filter( + (j) => + (j.ro_number || "") + .toString() + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.ownr_co_nm || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.comments || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.ownr_fn || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.ownr_ln || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) || + (j.plate_no || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.v_model_desc || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.est_ct_fn || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.est_ct_ln || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.v_make_desc || "") + .toLowerCase() + .includes(searchText.toLowerCase()) + ) + : []; const handleTableChange = (pagination, filters, sorter) => { - // TODO: Is this needed? - setState({...state, filteredInfo: filters}); - - search.page = pagination.current; - search.sortcolumn = sorter.column && sorter.column.key; - search.sortorder = sorter.order; - - if (filters.status) { - search.statusFilters = JSON.stringify(flattenDeep(filters.status)); - } else { - delete search.statusFilters; - } - - history.push({search: queryString.stringify(search)}); + setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); }; - useEffect(() => { - if (search.search && search.search.trim() !== "") { - searchJobs().catch(e => { - console.error('Something went wrong searching for jobs in the job-list component', e); - }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - if (error) return ; - - async function searchJobs(value) { - try { - setSearchLoading(true); - const searchData = await axios.post("/search", { - search: value || search.search, - index: "jobs", - }); - setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source)); - } catch (error) { - console.log("Error while fetching search results", error); - } finally { - setSearchLoading(false); - } - } - const handleOnRowClick = (record) => { if (record) { if (record.id) { history.push({ search: queryString.stringify({ - ...search, + ...searchParams, selected: record.id, }), }); @@ -127,9 +112,11 @@ export function JobsList({bodyshop,}) { title: t("jobs.fields.ro_number"), dataIndex: "ro_number", key: "ro_number", - sorter: true, + sorter: (a, b) => + parseInt((a.ro_number || "0").replace(/\D/g, "")) - + parseInt((b.ro_number || "0").replace(/\D/g, "")), sortOrder: - sortcolumn === "ro_number" && sortorder, + state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order, render: (text, record) => ( {record.ro_number || t("general.labels.na")} {record.production_vars && record.production_vars.alert ? ( - + ) : null} {record.suspended && ( - + )} {record.iouparent && ( - + )} @@ -158,20 +145,22 @@ export function JobsList({bodyshop,}) { dataIndex: "owner", key: "owner", ellipsis: true, + responsive: ["md"], - sorter: false, - sortOrder: sortcolumn === "owner" && sortorder, + sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), + sortOrder: + state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, render: (text, record) => { return record.ownerid ? ( e.stopPropagation()} > - + ) : ( - + ); }, @@ -183,7 +172,7 @@ export function JobsList({bodyshop,}) { ellipsis: true, responsive: ["md"], render: (text, record) => ( - + ), }, { @@ -193,7 +182,7 @@ export function JobsList({bodyshop,}) { ellipsis: true, responsive: ["md"], render: (text, record) => ( - + ), }, @@ -202,9 +191,10 @@ export function JobsList({bodyshop,}) { dataIndex: "status", key: "status", ellipsis: true, - sorter: true, + + sorter: (a, b) => alphaSort(a.status, b.status), sortOrder: - sortcolumn === "status" && sortorder, + state.sortedInfo.columnKey === "status" && state.sortedInfo.order, filters: (jobs && jobs @@ -219,6 +209,7 @@ export function JobsList({bodyshop,}) { [], onFilter: (value, record) => value.includes(record.status), }, + { title: t("jobs.fields.vehicle"), dataIndex: "vehicle", @@ -246,10 +237,11 @@ export function JobsList({bodyshop,}) { dataIndex: "plate_no", key: "plate_no", ellipsis: true, + responsive: ["md"], - sorter: true, + sorter: (a, b) => alphaSort(a.plate_no, b.plate_no), sortOrder: - sortcolumn === "plate_no" && sortorder, + state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order, }, { title: t("jobs.fields.clm_no"), @@ -257,9 +249,9 @@ export function JobsList({bodyshop,}) { key: "clm_no", ellipsis: true, responsive: ["md"], - sorter: true, + sorter: (a, b) => alphaSort(a.clm_no, b.clm_no), sortOrder: - sortcolumn === "clm_no" && sortorder, + state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order, render: (text, record) => `${record.clm_no || ""}${ record.po_number ? ` (PO: ${record.po_number})` : "" @@ -291,9 +283,10 @@ export function JobsList({bodyshop,}) { key: "clm_total", responsive: ["md"], ellipsis: true, - sorter: true, + + sorter: (a, b) => a.clm_total - b.clm_total, sortOrder: - sortcolumn === "clm_total" && sortorder, + state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order, render: (text, record) => ( {record.clm_total} ), @@ -356,57 +349,26 @@ export function JobsList({bodyshop,}) { title={t("titles.bc.jobs-active")} extra={ - {search.search && ( - <> - - {t("general.labels.searchresults", { search: search.search })} - - - - )} { - search.search = value; - history.push({ search: queryString.stringify(search) }); - searchJobs(value); + placeholder={t("general.labels.search")} + onChange={(e) => { + setSearchText(e.target.value); }} - loading={loading || searchLoading} + value={searchText} enterButton /> } > { + onRow={(record, rowIndex) => { return { - onClick: () => { + onClick: (event) => { handleOnRowClick(record); }, }; @@ -430,4 +392,4 @@ export function JobsList({bodyshop,}) { ); } -export default connect(mapStateToProps, mapDispatchToProps)(JobsList); +export default connect(mapStateToProps, null)(JobsList); From b97de32a44d46dc1fa90ee35315b5090b161ee32 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 12 Dec 2023 15:41:36 -0800 Subject: [PATCH 2/5] IO-2501 Add Jobs Complete Not Invoiced Section to Stats --- .../scoreboard-timetickets.component.jsx | 19 ++++++++- ...scoreboard-timetickets.stats.component.jsx | 42 +++++++++++++++++-- client/src/graphql/timetickets.queries.js | 31 +++++++++++++- client/src/translations/en_us/common.json | 2 + client/src/translations/es/common.json | 2 + client/src/translations/fr/common.json | 2 + 6 files changed, 90 insertions(+), 8 deletions(-) diff --git a/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx b/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx index 0117279d5..af4f28695 100644 --- a/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx +++ b/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx @@ -29,7 +29,7 @@ export default connect( export function ScoreboardTimeTicketsStats({ bodyshop }) { const { t } = useTranslation(); - const startDate = moment().startOf("month") + const startDate = moment().startOf("month"); const endDate = moment().endOf("month"); const fixedPeriods = useMemo(() => { @@ -84,6 +84,8 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) { end: endDate.format("YYYY-MM-DD"), fixedStart: fixedPeriods.start.format("YYYY-MM-DD"), fixedEnd: fixedPeriods.end.format("YYYY-MM-DD"), + jobStart: startDate, + jobEnd: endDate, }, fetchPolicy: "network-only", nextFetchPolicy: "network-only", @@ -340,11 +342,21 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) { larData.push({ ...r, ...lar }); }); + const jobData = {}; + data.jobs.forEach((job) => { + job.tthrs = job.joblines.reduce((acc, val) => acc + val.mod_lb_hrs, 0); + }); + jobData.tthrs = data.jobs + .reduce((acc, val) => acc + val.tthrs, 0) + .toFixed(1); + jobData.count = data.jobs.length.toFixed(0); + return { fixed: ret, combinedData: combinedData, labData: labData, larData: larData, + jobData: jobData, }; }, [fixedPeriods, data, bodyshop]); @@ -356,7 +368,10 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) { - + {/* This Month */} - + @@ -482,7 +482,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) { {/* Last Month */} - + @@ -556,7 +556,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) { {/* Efficiency Over Period */} - + + + + + + + + + + + + {t("scoreboard.labels.totalhrs")} + + } + value={jobData.tthrs} + valueStyle={{ + fontSize: statisticSize, + fontWeight: statisticWeight, + }} + /> + + + + {/* Disclaimer */} diff --git a/client/src/graphql/timetickets.queries.js b/client/src/graphql/timetickets.queries.js index bb90c4e9d..9f3dec512 100644 --- a/client/src/graphql/timetickets.queries.js +++ b/client/src/graphql/timetickets.queries.js @@ -143,9 +143,14 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql` $end: date! $fixedStart: date! $fixedEnd: date! + $jobStart: timestamptz! + $jobEnd: timestamptz! ) { timetickets( - where: { date: { _gte: $start, _lte: $end }, cost_center: {_neq: "timetickets.labels.shift"} } + where: { + date: { _gte: $start, _lte: $end } + cost_center: { _neq: "timetickets.labels.shift" } + } order_by: { date: desc_nulls_first } ) { actualhrs @@ -176,7 +181,10 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql` } } fixedperiod: timetickets( - where: { date: { _gte: $fixedStart, _lte: $fixedEnd }, cost_center: {_neq: "timetickets.labels.shift"} } + where: { + date: { _gte: $fixedStart, _lte: $fixedEnd } + cost_center: { _neq: "timetickets.labels.shift" } + } order_by: { date: desc_nulls_first } ) { actualhrs @@ -205,6 +213,25 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql` last_name } } + jobs( + where: { + date_invoiced: { _is_null: true } + ro_number: { _is_null: false } + voided: { _eq: false } + _or: [ + { actual_completion: { _gte: $jobStart, _lte: $jobEnd } } + { actual_delivery: { _gte: $jobStart, _lte: $jobEnd } } + ] + } + ) { + id + joblines(order_by: { line_no: asc }, where: { removed: { _eq: false } }) { + convertedtolbr + convertedtolbr_data + mod_lb_hrs + mod_lbr_ty + } + } } `; diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index bbac4cc7b..04a647924 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2695,6 +2695,7 @@ "efficiencyoverperiod": "Efficiency over Selected Dates", "entries": "Scoreboard Entries", "jobs": "Jobs", + "jobscompletednotinvoiced": "Completed Not Invoiced", "lastmonth": "Last Month", "lastweek": "Last Week", "monthlytarget": "Monthly", @@ -2709,6 +2710,7 @@ "timetickets": "Time Tickets", "timeticketsemployee": "Time Tickets by Employee", "todateactual": "Actual (MTD)", + "totalhrs": "Total Hours", "totaloverperiod": "Total over Selected Dates", "weeklyactual": "Actual (W)", "weeklytarget": "Weekly", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 33cf621da..56ca50899 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -2695,6 +2695,7 @@ "efficiencyoverperiod": "", "entries": "", "jobs": "", + "jobscompletednotinvoiced": "", "lastmonth": "", "lastweek": "", "monthlytarget": "", @@ -2709,6 +2710,7 @@ "timetickets": "", "timeticketsemployee": "", "todateactual": "", + "totalhrs": "", "totaloverperiod": "", "weeklyactual": "", "weeklytarget": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 3b5251fa7..690bf246b 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -2695,6 +2695,7 @@ "efficiencyoverperiod": "", "entries": "", "jobs": "", + "jobscompletednotinvoiced": "", "lastmonth": "", "lastweek": "", "monthlytarget": "", @@ -2709,6 +2710,7 @@ "timetickets": "", "timeticketsemployee": "", "todateactual": "", + "totalhrs": "", "totaloverperiod": "", "weeklyactual": "", "weeklytarget": "", From 2dd56590d3f3d799c0b567b6bcc876dbfcf80e3f Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 14 Dec 2023 08:57:36 -0800 Subject: [PATCH 3/5] Admin panel to force email addresses to be lowercase to conform with firebase --- server/firebase/firebase-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/firebase/firebase-handler.js b/server/firebase/firebase-handler.js index 7221649ec..e203bcbf3 100644 --- a/server/firebase/firebase-handler.js +++ b/server/firebase/firebase-handler.js @@ -50,7 +50,7 @@ exports.createUser = async (req, res) => { `, { user: { - email, + email: email.toLowerCase(), authid: userRecord.uid, associations: { data: [{ shopid, authlevel, active: true }], From 661bedbe5b555540a69246f480091a2e715670bf Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 18 Dec 2023 12:36:46 -0800 Subject: [PATCH 4/5] IO-2506 Federal Tax Exempt on Bill Entry Will Toggle Federal Tax off on any new line or retroactively toggle it off on all lines when switch is enabled. Limited to PBS or CDK setups. --- .../bill-form/bill-form.component.jsx | 25 +++++++++++++++++-- .../bill-form/bill-form.lines.component.jsx | 8 +++--- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/client/src/components/bill-form/bill-form.component.jsx b/client/src/components/bill-form/bill-form.component.jsx index 44b8cd815..579d11b7b 100644 --- a/client/src/components/bill-form/bill-form.component.jsx +++ b/client/src/components/bill-form/bill-form.component.jsx @@ -79,6 +79,18 @@ export function BillFormComponent({ }); }; + const handleFederalTaxExemptSwitchToggle = (checked) => { + if (checked) { + const values = form.getFieldsValue("billlines"); + if (values && values.billlines && values.billlines.length > 0) { + values.billlines.forEach((b) => { + b.applicable_taxes.federal = false; + }); + } + form.setFieldsValue({ billlines: values.billlines }); + } + }; + useEffect(() => { if (job) form.validateFields(["is_credit_memo"]); }, [job, form]); @@ -387,7 +399,16 @@ export function BillFormComponent({ > - + {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? ( + + + + ) : null} + {() => { const values = form.getFieldsValue([ "billlines", @@ -405,7 +426,7 @@ export function BillFormComponent({ totals = CalculateBillTotal(values); if (!!totals) return ( -
+
Date: Mon, 18 Dec 2023 14:12:21 -0800 Subject: [PATCH 5/5] IO-2509 Report Center RBAC --- .../components/rbac-wrapper/rbac-defaults.js | 5 +- .../report-center-modal.container.jsx | 5 +- .../shop-info/shop-info.rbac.component.jsx | 428 +++++++++--------- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 6 files changed, 230 insertions(+), 211 deletions(-) diff --git a/client/src/components/rbac-wrapper/rbac-defaults.js b/client/src/components/rbac-wrapper/rbac-defaults.js index 24a564872..a01dd54c2 100644 --- a/client/src/components/rbac-wrapper/rbac-defaults.js +++ b/client/src/components/rbac-wrapper/rbac-defaults.js @@ -55,10 +55,11 @@ const ret = { "shiftclock:view": 2, "shop:config": 4, - "shop:rbac": 5, - "shop:vendors": 2, "shop:dashboard": 3, + "shop:rbac": 5, + "shop:reportcenter": 2, "shop:templates": 4, + "shop:vendors": 2, "temporarydocs:view": 2, diff --git a/client/src/components/report-center-modal/report-center-modal.container.jsx b/client/src/components/report-center-modal/report-center-modal.container.jsx index f0d361785..84fe65560 100644 --- a/client/src/components/report-center-modal/report-center-modal.container.jsx +++ b/client/src/components/report-center-modal/report-center-modal.container.jsx @@ -5,6 +5,7 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { toggleModalVisible } from "../../redux/modals/modals.actions"; import { selectReportCenter } from "../../redux/modals/modals.selectors"; +import RbacWrapperComponent from "../rbac-wrapper/rbac-wrapper.component"; import ReportCenterModalComponent from "./report-center-modal.component"; const mapStateToProps = createStructuredSelector({ @@ -33,7 +34,9 @@ export function ReportCenterModalContainer({ destroyOnClose width="80%" > - + + + ); } 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 fe4f80f31..e4152fb88 100644 --- a/client/src/components/shop-info/shop-info.rbac.component.jsx +++ b/client/src/components/shop-info/shop-info.rbac.component.jsx @@ -28,18 +28,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { return ( - - - + + + + + + + + + + + + @@ -173,26 +209,38 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { + + + @@ -208,30 +256,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { > - - - - - - - - - @@ -280,6 +292,18 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { > + + + + + + + + + + + + + + + @@ -329,74 +401,14 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { - - - - - - - - - - - - - - - @@ -412,18 +424,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { > - - - + + + + + + - - - - - - @@ -556,18 +556,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { > - - - + + + + + + + + + + + + + + + - - - - - - - - - {Simple_Inventory.treatment === "on" && ( <> Config", "dashboard": "Shop -> Dashboard", "rbac": "Shop -> RBAC", + "reportcenter": "Shop -> Report Center", "templates": "Shop -> Templates", "vendors": "Shop -> Vendors" }, diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 33cf621da..1d3784879 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -447,6 +447,7 @@ "config": "", "dashboard": "", "rbac": "", + "reportcenter": "", "templates": "", "vendors": "" }, diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 3b5251fa7..abdb28e00 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -447,6 +447,7 @@ "config": "", "dashboard": "", "rbac": "", + "reportcenter": "", "templates": "", "vendors": "" },