Added scoreboard initial design BOD-91

This commit is contained in:
Patrick Fic
2020-06-26 16:25:54 -07:00
parent 4516491c8c
commit 3df456e2dd
41 changed files with 1388 additions and 11 deletions

View File

@@ -1085,6 +1085,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>dailybodytarget</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>dailypainttarget</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>email</name>
<definition_loaded>false</definition_loaded>
@@ -13167,6 +13209,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>scoreboard</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>shop</name>
<definition_loaded>false</definition_loaded>
@@ -16143,6 +16206,121 @@
</folder_node>
</children>
</folder_node>
<folder_node>
<name>scoreboard</name>
<children>
<folder_node>
<name>labels</name>
<children>
<concept_node>
<name>asoftodaytarget</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>dailytarget</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>monthlytarget</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>weeklytarget</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>workingdays</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
</children>
</folder_node>
<folder_node>
<name>templates</name>
<children>
@@ -17024,6 +17202,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>scoreboard</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>shop</name>
<definition_loaded>false</definition_loaded>
@@ -17614,6 +17813,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>scoreboard</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>shop</name>
<definition_loaded>false</definition_loaded>

View File

@@ -26,6 +26,7 @@
"i18next": "^19.4.5",
"i18next-browser-languagedetector": "^4.2.0",
"logrocket": "^1.0.7",
"moment-business-days": "^1.2.0",
"node-sass": "^4.14.1",
"phone": "^2.4.12",
"query-string": "^6.13.1",
@@ -50,6 +51,7 @@
"react-scripts": "3.4.1",
"react-trello": "^2.2.6",
"react-virtualized": "^9.21.2",
"recharts": "^1.8.5",
"redux": "^4.0.5",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",

View File

@@ -5,11 +5,13 @@ import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conv
export default function ChatConversationTitle({ conversation }) {
return (
<div style={{ display: "flex" }}>
{conversation.phone_num}
{conversation && conversation.phone_num}
<ChatConversationTitleTags
jobConversations={conversation.job_conversations || []}
jobConversations={
(conversation && conversation.job_conversations) || []
}
/>
<ChatTagRoContainer conversation={conversation} />
<ChatTagRoContainer conversation={conversation || []} />
</div>
);
}

View File

@@ -128,6 +128,11 @@ function Header({
{t("menus.header.productionboard")}
</Link>
</Menu.Item>
<Menu.Item key="scoreboard">
<Link to="/manage/scoreboard">
{t("menus.header.scoreboard")}
</Link>
</Menu.Item>
<Menu.Item key="activejobs">
<Link to="/manage/jobs">{t("menus.header.activejobs")}</Link>
</Menu.Item>

View File

@@ -105,8 +105,6 @@ export function ProductionBoardKanbanComponent({ data, bodyshop }) {
}
};
console.log("ismMoving", isMoving);
return (
<div>
<IndefiniteLoading loading={isMoving} />

View File

@@ -0,0 +1,113 @@
import React from "react";
import {
ComposedChart,
Line,
Area,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
} from "recharts";
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
import moment from "moment";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(ScoreboardChart);
export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
const listOfBusDays = Utils.ListOfDaysInCurrentMonth();
const data = listOfBusDays.reduce((acc, val) => {
//Sum up the current day.
let dayhrs;
if (!!sbEntriesByDate[val]) {
dayhrs = sbEntriesByDate[val].reduce(
(dayAcc, dayVal) => {
return {
bodyhrs: dayAcc.bodyhrs + dayVal.bodyhrs,
painthrs: dayAcc.painthrs + dayVal.painthrs,
};
},
{ bodyhrs: 0, painthrs: 0 }
);
} else {
dayhrs = {
bodyhrs: 0,
painthrs: 0,
};
}
const theValue = {
date: moment(val).format("D dd"),
paintHrs: dayhrs.painthrs,
bodyHrs: dayhrs.bodyhrs,
accTargetHrs: Utils.AsOfDateTargetHours(
bodyshop.scoreboard_target.dailyBodyTarget +
bodyshop.scoreboard_target.dailyPaintTarget,
val
),
accHrs:
acc.length > 0
? acc[acc.length - 1].accHrs + dayhrs.painthrs + dayhrs.bodyhrs
: dayhrs.painthrs + dayhrs.bodyhrs,
};
return [...acc, theValue];
}, []);
return (
<div>
<ResponsiveContainer width="100%" height={475}>
<ComposedChart
data={data}
margin={{ top: 20, right: 20, bottom: 20, left: 20 }}
>
<CartesianGrid stroke="#f5f5f5" />
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Legend />
<Area
type="monotone"
name="Accumulated Hours"
dataKey="accHrs"
fill="#8884d8"
stroke="#8884d8"
/>
<Bar
name="Body Hours"
dataKey="bodyHrs"
stackId="day"
barSize={20}
fill="#cecece"
/>
<Bar
name="Paint Hours"
dataKey="paintHrs"
stackId="day"
barSize={20}
fill="#413ea0"
/>
<Line
name="Target Hours"
type="monotone"
dataKey="accTargetHrs"
stroke="#ff7300"
/>
</ComposedChart>
</ResponsiveContainer>
</div>
);
}

View File

@@ -0,0 +1,47 @@
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { Statistic, Card } from "antd";
import moment from "moment";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export function ScoreboardDayStats({ bodyshop, date, entries }) {
const {
lastNumberWorkingDays,
dailyPaintTarget,
dailyBodyTarget,
} = bodyshop.scoreboard_target;
let totalHrs = 0;
const paintHrs = entries.reduce((acc, value) => {
totalHrs = +value.painthrs;
return acc + value.painthrs;
}, 0);
const bodyHrs = entries.reduce((acc, value) => {
totalHrs = +value.bodyhrs;
return acc + value.bodyhrs;
}, 0);
return (
<div className="imex-flex-row__margin">
<Card title={moment(date).format("D - ddd")}>
<Statistic
valueStyle={{ color: dailyBodyTarget > bodyHrs ? "red" : "green" }}
value={bodyHrs.toFixed(1)}
/>
<Statistic
valueStyle={{ color: dailyPaintTarget > paintHrs ? "red" : "green" }}
value={paintHrs.toFixed(1)}
/>
</Card>
</div>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(ScoreboardDayStats);

View File

@@ -0,0 +1,31 @@
import React from "react";
import ScoreboardTargetsTable from "../scoreboard-targets-table/scoreboard-targets-table.component";
import ScoreboardLastDays from "../scoreboard-last-days/scoreboard-last-days.component";
import ScoreboardChart from "../scoreboard-chart/scoreboard-chart.component";
export default function ScoreboardDisplayComponent({ scoreboardSubscription }) {
const { loading, error, data } = scoreboardSubscription;
const scoreBoardlist = (data && data.scoreboard) || [];
console.log("ScoreboardDisplayComponent -> scoreBoardlist", scoreBoardlist);
const sbEntriesByDate = {};
scoreBoardlist.forEach((i) => {
const entryDate = i.date;
if (!!!sbEntriesByDate[entryDate]) {
sbEntriesByDate[entryDate] = [];
}
sbEntriesByDate[entryDate].push(i);
});
console.log("ScoreboardDisplayComponent -> sbEntriesByDate", sbEntriesByDate);
return (
<div>
<ScoreboardTargetsTable />
<ScoreboardLastDays sbEntriesByDate={sbEntriesByDate} />
<ScoreboardChart sbEntriesByDate={sbEntriesByDate} />
</div>
);
}

View File

@@ -0,0 +1,41 @@
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import moment from "moment";
import ScoreboardDayStat from "../scoreboard-day-stats/scoreboard-day-stats.component";
import { Row, Col } from "antd";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export function ScoreboardLastDays({ bodyshop, sbEntriesByDate }) {
const { lastNumberWorkingDays } = bodyshop.scoreboard_target;
const ArrayOfDate = [];
for (var i = lastNumberWorkingDays - 1; i >= 0; i--) {
ArrayOfDate.push(
moment().businessSubtract(i, "day").toISOString().substr(0, 10)
);
}
return (
<Row>
{ArrayOfDate.map((a) => (
<Col span={2} key={a}>
{!!sbEntriesByDate ? (
<ScoreboardDayStat date={a} entries={sbEntriesByDate[a] || []} />
) : (
<LoadingSkeleton />
)}
</Col>
))}
</Row>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(ScoreboardLastDays);

View File

@@ -0,0 +1,109 @@
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import * as Util from "./scoreboard-targets-table.util";
import { Row, Col, Card, Statistic } from "antd";
import { CalendarOutlined } from "@ant-design/icons";
import { useTranslation } from "react-i18next";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
const rowGutter = [16, 16];
const statSpans = { xs: 24, sm: 6 };
export function ScoreboardTargetsTable({ bodyshop }) {
const { t } = useTranslation();
return (
<div>
<Row gutter={rowGutter}>
<Col xs={24} sm={{ offset: 0, span: 4 }} lg={{ offset: 5, span: 4 }}>
<Statistic
title={t("scoreboard.labels.workingdays")}
value={Util.CalculateWorkingDaysThisMonth()}
prefix={<CalendarOutlined />}
/>
</Col>
<Col xs={24} sm={{ offset: 0, span: 20 }} lg={{ offset: 0, span: 13 }}>
<Row>
<Col {...statSpans}>
<Statistic
title={t("scoreboard.labels.dailytarget")}
value={bodyshop.scoreboard_target.dailyBodyTarget}
prefix="B"
/>
</Col>
<Col {...statSpans}>
<Statistic
title={t("scoreboard.labels.weeklytarget")}
value={Util.WeeklyTargetHrs(
bodyshop.scoreboard_target.dailyBodyTarget,
bodyshop
)}
/>
</Col>
<Col {...statSpans}>
<Statistic
title={t("scoreboard.labels.monthlytarget")}
value={Util.MonthlyTargetHrs(
bodyshop.scoreboard_target.dailyBodyTarget,
bodyshop
)}
/>
</Col>
<Col {...statSpans}>
<Statistic
title={t("scoreboard.labels.asoftodaytarget")}
value={Util.AsOfTodayTargetHrs(
bodyshop.scoreboard_target.dailyBodyTarget,
bodyshop
)}
/>
</Col>
</Row>
<Row>
<Col {...statSpans}>
<Statistic
value={bodyshop.scoreboard_target.dailyPaintTarget}
prefix="P"
/>
</Col>
<Col {...statSpans}>
<Statistic
value={Util.WeeklyTargetHrs(
bodyshop.scoreboard_target.dailyPaintTarget,
bodyshop
)}
/>
</Col>
<Col {...statSpans}>
<Statistic
value={Util.MonthlyTargetHrs(
bodyshop.scoreboard_target.dailyPaintTarget,
bodyshop
)}
/>
</Col>
<Col {...statSpans}>
<Statistic
value={Util.AsOfTodayTargetHrs(
bodyshop.scoreboard_target.dailyPaintTarget,
bodyshop
)}
/>
</Col>
</Row>
</Col>
</Row>
</div>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ScoreboardTargetsTable);

View File

@@ -0,0 +1,50 @@
import moment from "moment";
import momentbd from "moment-business-days";
moment.updateLocale("ca", {
workingWeekdays: [1, 2, 3, 4, 5],
});
export const CalculateWorkingDaysThisMonth = () => {
return moment().endOf("month").businessDaysIntoMonth();
};
export const CalculateWorkingDaysAsOfToday = () => {
return moment().businessDaysIntoMonth();
};
export const WeeklyTargetHrs = (dailyTargetHrs, bodyshop) => {
return dailyTargetHrs * 5;
};
export const MonthlyTargetHrs = (dailyTargetHrs, bodyshop) => {
return dailyTargetHrs * CalculateWorkingDaysThisMonth();
};
export const AsOfTodayTargetHrs = (dailyTargetHrs, bodyshop) => {
return dailyTargetHrs * CalculateWorkingDaysAsOfToday();
};
export const AsOfDateTargetHours = (dailyTargetHours, date) => {
return (
dailyTargetHours * moment().startOf("month").businessDiff(moment(date))
);
};
export const ListOfBusinessDaysInCurrentMonth = () => {
const momentListOfDays = moment().monthBusinessDays();
return momentListOfDays.map((i) => i.format("YYYY-MM-DD"));
};
export const ListOfDaysInCurrentMonth = () => {
const days = [];
const dateStart = moment().startOf("month");
const dateEnd = moment().endOf("month");
while (dateEnd.diff(dateStart, "days") > 0) {
days.push(dateStart.format("YYYY-MM-DD"));
dateStart.add(1, "days");
}
days.push(dateEnd.format("YYYY-MM-DD"));
return days;
};

View File

@@ -96,6 +96,45 @@ export default function ShopInfoComponent({ form }) {
<InputNumber min={15} precisio={0} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.dailypainttarget")}
name={["scoreboard_target", "dailyPaintTarget"]}
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<InputNumber min={0} precisio={0} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.dailybodytarget")}
name={["scoreboard_target", "dailyBodyTarget"]}
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<InputNumber min={0} precisio={0} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.lastnumberworkingdays")}
name={["scoreboard_target", "lastNumberWorkingDays"]}
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<InputNumber min={0} max={12} precisio={0} />
</Form.Item>
<Form.Item
label={t("bodyshop.labels.accountingtiers")}
rules={[

View File

@@ -33,6 +33,7 @@ export const QUERY_BODYSHOP = gql`
appt_length
stripe_acct_id
ssbuckets
scoreboard_target
employees {
id
first_name
@@ -83,6 +84,8 @@ export const UPDATE_SHOP = gql`
invoice_tax_rates
appt_length
stripe_acct_id
ssbuckets
scoreboard_target
employees {
id
first_name

View File

@@ -0,0 +1,16 @@
import gql from "graphql-tag";
export const SUBSCRIPTION_SCOREBOARD = gql`
subscription SUBSCRIPTION_SCOREBOARD($start: date!, $end: date!) {
scoreboard(where: { _and: { date: { _gte: $start, _lte: $end } } }) {
id
painthrs
bodyhrs
date
job {
id
ro_number
}
}
}
`;

View File

@@ -113,6 +113,10 @@ const PaymentsAll = lazy(() =>
import("../payments-all/payments-all.container.page")
);
const Scoreboard = lazy(() =>
import("../scoreboard/scoreboard.page.container.jsx")
);
const { Content } = Layout;
const stripePromise = new Promise((resolve, reject) => {
@@ -305,6 +309,11 @@ export function Manage({ match, conflict }) {
path={`${match.path}/payments`}
component={PaymentsAll}
/>
<Route
exact
path={`${match.path}/scoreboard`}
component={Scoreboard}
/>
</Suspense>
)}
</ErrorBoundary>

View File

@@ -0,0 +1,10 @@
import React from "react";
import ScoreboardDisplay from "../../components/scoreboard-display/scoreboard-display.component";
export default function ProductionBoardComponent({ scoreboardSubscription }) {
return (
<div>
<ScoreboardDisplay scoreboardSubscription={scoreboardSubscription} />
</div>
);
}

View File

@@ -0,0 +1,47 @@
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { setBreadcrumbs } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import ScoreboardPageComponent from "./scoreboard.page.component";
import { useSubscription } from "@apollo/react-hooks";
import { SUBSCRIPTION_SCOREBOARD } from "../../graphql/scoreboard.queries";
import moment from "moment";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
});
export function ScoreboardContainer({ setBreadcrumbs }) {
const { t } = useTranslation();
const scoreboardSubscription = useSubscription(SUBSCRIPTION_SCOREBOARD, {
variables: {
start: moment().startOf("month"),
end: moment().endOf("month"),
},
});
useEffect(() => {
document.title = t("titles.scoreboard");
setBreadcrumbs([
{
link: "/manage/scoreboard",
label: t("titles.bc.scoreboard"),
},
]);
}, [t, setBreadcrumbs]);
return (
<ScoreboardPageComponent scoreboardSubscription={scoreboardSubscription} />
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ScoreboardContainer);

View File

@@ -16,7 +16,7 @@ const applicationReducer = (state = INITIAL_STATE, action) => {
case ApplicationActionTypes.ADD_RECENT_ITEM:
return {
...state,
recentItems: [action.payload, ...state.scheduleLoad.slice(0, 9)],
recentItems: [action.payload, ...state.recentItems.slice(0, 9)],
};
case ApplicationActionTypes.SET_BREAD_CRUMBS:
return {

View File

@@ -86,6 +86,8 @@
"appt_length": "Default Appointment Length",
"city": "City",
"country": "Country",
"dailybodytarget": "Scoreboard - Daily Body Target",
"dailypainttarget": "Scoreboard - Daily Paint Target",
"email": "General Shop Email",
"federal_tax_id": "Federal Tax ID (GST/HST)",
"insurance_vendor_id": "Insurance Vendor ID",
@@ -797,6 +799,7 @@
"productionboard": "Production Board",
"productionlist": "Production - List",
"schedule": "Schedule",
"scoreboard": "Scoreboard",
"shop": "My Shop",
"shop_config": "Configuration",
"shop_csi": "CSI",
@@ -1011,6 +1014,15 @@
"state": "Error reading page state. Please refresh."
}
},
"scoreboard": {
"labels": {
"asoftodaytarget": "As of Today",
"dailytarget": "Daily",
"monthlytarget": "Monthly",
"weeklytarget": "Weekly",
"workingdays": "Working Days / Month"
}
},
"templates": {
"errors": {
"updating": "Error updating template {{error}}."
@@ -1067,6 +1079,7 @@
"productionboard": "Production Board",
"productionlist": "Production - List",
"schedule": "Schedule",
"scoreboard": "Scoreboard",
"shop": "Manage my Shop ({{shopname}})",
"shop-csi": "CSI Responses",
"shop-templates": "Shop Templates",
@@ -1096,6 +1109,7 @@
"productionlist": "Production - List View | $t(titles.app)",
"profile": "My Profile | $t(titles.app)",
"schedule": "Schedule | $t(titles.app)",
"scoreboard": "Scoreboard | $t(titles.app)",
"shop": "My Shop | $t(titles.app)",
"shop-csi": "CSI Responses | $t(titles.app)",
"shop-templates": "Shop Templates | $t(titles.app)",

View File

@@ -86,6 +86,8 @@
"appt_length": "",
"city": "",
"country": "",
"dailybodytarget": "",
"dailypainttarget": "",
"email": "",
"federal_tax_id": "",
"insurance_vendor_id": "",
@@ -797,6 +799,7 @@
"productionboard": "",
"productionlist": "",
"schedule": "Programar",
"scoreboard": "",
"shop": "Mi tienda",
"shop_config": "Configuración",
"shop_csi": "",
@@ -1011,6 +1014,15 @@
"state": "Error al leer el estado de la página. Porfavor refresca."
}
},
"scoreboard": {
"labels": {
"asoftodaytarget": "",
"dailytarget": "",
"monthlytarget": "",
"weeklytarget": "",
"workingdays": ""
}
},
"templates": {
"errors": {
"updating": ""
@@ -1067,6 +1079,7 @@
"productionboard": "",
"productionlist": "",
"schedule": "",
"scoreboard": "",
"shop": "",
"shop-csi": "",
"shop-templates": "",
@@ -1096,6 +1109,7 @@
"productionlist": "",
"profile": "Mi perfil | $t(titles.app)",
"schedule": "Horario | $t(titles.app)",
"scoreboard": "",
"shop": "Mi tienda | $t(titles.app)",
"shop-csi": "",
"shop-templates": "",

View File

@@ -86,6 +86,8 @@
"appt_length": "",
"city": "",
"country": "",
"dailybodytarget": "",
"dailypainttarget": "",
"email": "",
"federal_tax_id": "",
"insurance_vendor_id": "",
@@ -797,6 +799,7 @@
"productionboard": "",
"productionlist": "",
"schedule": "Programme",
"scoreboard": "",
"shop": "Mon magasin",
"shop_config": "Configuration",
"shop_csi": "",
@@ -1011,6 +1014,15 @@
"state": "Erreur lors de la lecture de l'état de la page. Rafraichissez, s'il vous plait."
}
},
"scoreboard": {
"labels": {
"asoftodaytarget": "",
"dailytarget": "",
"monthlytarget": "",
"weeklytarget": "",
"workingdays": ""
}
},
"templates": {
"errors": {
"updating": ""
@@ -1067,6 +1079,7 @@
"productionboard": "",
"productionlist": "",
"schedule": "",
"scoreboard": "",
"shop": "",
"shop-csi": "",
"shop-templates": "",
@@ -1096,6 +1109,7 @@
"productionlist": "",
"profile": "Mon profil | $t(titles.app)",
"schedule": "Horaire | $t(titles.app)",
"scoreboard": "",
"shop": "Mon magasin | $t(titles.app)",
"shop-csi": "",
"shop-templates": "",

View File

@@ -3369,6 +3369,11 @@ backo2@^1.0.2:
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
integrity sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
@@ -4304,7 +4309,7 @@ core-js@^1.0.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=
core-js@^2.4.0:
core-js@^2.4.0, core-js@^2.6.10:
version "2.6.11"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
@@ -4704,6 +4709,16 @@ cyclist@^1.0.1:
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.4.0.tgz#87f8b9ad11088769c82b5ea846bcb1cc9393f242"
integrity sha512-KQ41bAF2BMakf/HdKT865ALd4cgND6VcIztVQZUTt0+BH3RWy6ZYnHghVXf6NFjt2ritLr8H1T8LreAAlfiNcw==
d3-array@^1.2.0:
version "1.2.4"
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==
d3-collection@1:
version "1.0.7"
resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e"
integrity sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==
d3-color@1, d3-color@^1.2.3:
version "1.4.0"
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.0.tgz#89c45a995ed773b13314f06460df26d60ba0ecaf"
@@ -4719,7 +4734,7 @@ d3-hierarchy@^1.1.8:
resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83"
integrity sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==
d3-interpolate@1, d3-interpolate@^1.2.0, d3-interpolate@^1.3.2:
d3-interpolate@1, d3-interpolate@^1.2.0, d3-interpolate@^1.3.0, d3-interpolate@^1.3.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987"
integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==
@@ -4739,6 +4754,18 @@ d3-scale-chromatic@^1.3.3:
d3-color "1"
d3-interpolate "1"
d3-scale@^2.1.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f"
integrity sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==
dependencies:
d3-array "^1.2.0"
d3-collection "1"
d3-format "1"
d3-interpolate "1"
d3-time "1"
d3-time-format "2"
d3-scale@^3.0.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.2.1.tgz#da1684adce7261b4bc7a76fe193d887f0e909e69"
@@ -4750,7 +4777,7 @@ d3-scale@^3.0.0:
d3-time "1"
d3-time-format "2"
d3-shape@^1.3.5:
d3-shape@^1.2.0, d3-shape@^1.3.5:
version "1.3.7"
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7"
integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==
@@ -4841,6 +4868,11 @@ decamelize@^1.1.2, decamelize@^1.2.0:
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
decimal.js-light@^2.4.1:
version "2.5.0"
resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.0.tgz#ca7faf504c799326df94b0ab920424fdfc125348"
integrity sha512-b3VJCbd2hwUpeRGG3Toob+CRo8W22xplipNhP3tN7TSVB/cyMX71P1vM2Xjc9H74uV6dS2hDDmo/rHq8L87Upg==
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
@@ -8254,6 +8286,11 @@ lodash.camelcase@^4.3.0:
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
lodash.escape@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98"
@@ -8304,12 +8341,17 @@ lodash.templatesettings@^4.0.0:
dependencies:
lodash._reinterpolate "^3.0.0"
lodash.throttle@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
"lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@~4.17.12:
"lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@~4.17.12, lodash@~4.17.4:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@@ -8417,6 +8459,11 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
math-expression-evaluator@^1.2.14:
version "1.2.22"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.22.tgz#c14dcb3d8b4d150e5dcea9c68c8dad80309b0d5e"
integrity sha512-L0j0tFVZBQQLeEjmWOvDLoRciIY8gQGWahvkztXUal8jH8R5Rlqo9GCvgqvXcy9LQhEWdQCVvzqAbxgYNt4blQ==
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -8718,6 +8765,11 @@ mkdirp@^0.5.3:
dependencies:
minimist "^1.2.5"
moment-business-days@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/moment-business-days/-/moment-business-days-1.2.0.tgz#6172f9f38dbf443c2f859baabeabbd2935f63d65"
integrity sha512-QJlceLfMSxy/jZSOgJYCKeKw+qGYHj8W0jMa/fYruyoJ85+bJuLRiYv5DIaflyuRipmYRfD4kDlSwVYteLN+Jw==
moment@^2.24.0:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
@@ -11416,6 +11468,16 @@ react-resizable@^1.10.1, react-resizable@^1.9.0:
prop-types "15.x"
react-draggable "^4.0.3"
react-resize-detector@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-2.3.0.tgz#57bad1ae26a28a62a2ddb678ba6ffdf8fa2b599c"
integrity sha512-oCAddEWWeFWYH5FAcHdBYcZjAw9fMzRUK9sWSx6WvSSOPVRxcHd5zTIGy/mOus+AhN/u6T4TMiWxvq79PywnJQ==
dependencies:
lodash.debounce "^4.0.8"
lodash.throttle "^4.1.1"
prop-types "^15.6.0"
resize-observer-polyfill "^1.5.0"
react-router-dom@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662"
@@ -11513,6 +11575,16 @@ react-scrolllock@^2.0.1:
exenv "^1.2.2"
react-prop-toggle "^1.0.2"
react-smooth@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-1.0.5.tgz#94ae161d7951cdd893ccb7099d031d342cb762ad"
integrity sha512-eW057HT0lFgCKh8ilr0y2JaH2YbNcuEdFpxyg7Gf/qDKk9hqGMyXryZJ8iMGJEuKH0+wxS0ccSsBBB3W8yCn8w==
dependencies:
lodash "~4.17.4"
prop-types "^15.6.0"
raf "^3.4.0"
react-transition-group "^2.5.0"
react-test-renderer@^16.0.0-0:
version "16.13.0"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.0.tgz#39ba3bf72cedc8210c3f81983f0bb061b14a3014"
@@ -11523,7 +11595,7 @@ react-test-renderer@^16.0.0-0:
react-is "^16.8.6"
scheduler "^0.19.0"
react-transition-group@2:
react-transition-group@2, react-transition-group@^2.5.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
@@ -11694,6 +11766,30 @@ realpath-native@^1.1.0:
dependencies:
util.promisify "^1.0.0"
recharts-scale@^0.4.2:
version "0.4.3"
resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.3.tgz#040b4f638ed687a530357292ecac880578384b59"
integrity sha512-t8p5sccG9Blm7c1JQK/ak9O8o95WGhNXD7TXg/BW5bYbVlr6eCeRBNpgyigD4p6pSSMehC5nSvBUPj6F68rbFA==
dependencies:
decimal.js-light "^2.4.1"
recharts@^1.8.5:
version "1.8.5"
resolved "https://registry.yarnpkg.com/recharts/-/recharts-1.8.5.tgz#ca94a3395550946334a802e35004ceb2583fdb12"
integrity sha512-tM9mprJbXVEBxjM7zHsIy6Cc41oO/pVYqyAsOHLxlJrbNBuLs0PHB3iys2M+RqCF0//k8nJtZF6X6swSkWY3tg==
dependencies:
classnames "^2.2.5"
core-js "^2.6.10"
d3-interpolate "^1.3.0"
d3-scale "^2.1.0"
d3-shape "^1.2.0"
lodash "^4.17.5"
prop-types "^15.6.0"
react-resize-detector "^2.3.0"
react-smooth "^1.0.5"
recharts-scale "^0.4.2"
reduce-css-calc "^1.3.0"
recompose@^0.30.0:
version "0.30.0"
resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0"
@@ -11721,6 +11817,22 @@ redent@^1.0.0:
indent-string "^2.1.0"
strip-indent "^1.0.1"
reduce-css-calc@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
integrity sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=
dependencies:
balanced-match "^0.4.2"
math-expression-evaluator "^1.2.14"
reduce-function-call "^1.0.1"
reduce-function-call@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.3.tgz#60350f7fb252c0a67eb10fd4694d16909971300f"
integrity sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==
dependencies:
balanced-match "^1.0.0"
reduce-reducers@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.4.3.tgz#8e052618801cd8fc2714b4915adaa8937eb6d66c"

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: DROP TABLE "public"."scoreboard";
type: run_sql

View File

@@ -0,0 +1,18 @@
- args:
cascade: false
read_only: false
sql: CREATE EXTENSION IF NOT EXISTS pgcrypto;
type: run_sql
- args:
cascade: false
read_only: false
sql: CREATE TABLE "public"."scoreboard"("id" uuid NOT NULL DEFAULT gen_random_uuid(),
"jobid" uuid NOT NULL, "painthrs" numeric NOT NULL DEFAULT 0, "bodyhrs" numeric
NOT NULL DEFAULT 0, "date" date NOT NULL DEFAULT now(), PRIMARY KEY ("id") ,
FOREIGN KEY ("jobid") REFERENCES "public"."jobs"("id") ON UPDATE cascade ON
DELETE cascade);
type: run_sql
- args:
name: scoreboard
schema: public
type: add_existing_table_or_view

View File

@@ -0,0 +1,12 @@
- args:
relationship: scoreboards
table:
name: jobs
schema: public
type: drop_relationship
- args:
relationship: job
table:
name: scoreboard
schema: public
type: drop_relationship

View File

@@ -0,0 +1,20 @@
- args:
name: scoreboards
table:
name: jobs
schema: public
using:
foreign_key_constraint_on:
column: jobid
table:
name: scoreboard
schema: public
type: create_array_relationship
- args:
name: job
table:
name: scoreboard
schema: public
using:
foreign_key_constraint_on: jobid
type: create_object_relationship

View File

@@ -0,0 +1,6 @@
- args:
role: user
table:
name: scoreboard
schema: public
type: drop_insert_permission

View File

@@ -0,0 +1,26 @@
- args:
permission:
allow_upsert: true
backend_only: false
check:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- id
- jobid
- painthrs
- bodyhrs
- date
set: {}
role: user
table:
name: scoreboard
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,6 @@
- args:
role: user
table:
name: scoreboard
schema: public
type: drop_select_permission

View File

@@ -0,0 +1,27 @@
- args:
permission:
allow_aggregations: true
backend_only: false
columns:
- date
- bodyhrs
- painthrs
- id
- jobid
computed_fields: []
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
limit: null
role: user
table:
name: scoreboard
schema: public
type: create_select_permission

View File

@@ -0,0 +1,6 @@
- args:
role: user
table:
name: scoreboard
schema: public
type: drop_update_permission

View File

@@ -0,0 +1,25 @@
- args:
permission:
backend_only: false
columns:
- date
- bodyhrs
- painthrs
- id
- jobid
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: scoreboard
schema: public
type: create_update_permission

View File

@@ -0,0 +1,6 @@
- args:
role: user
table:
name: scoreboard
schema: public
type: drop_delete_permission

View File

@@ -0,0 +1,18 @@
- args:
permission:
backend_only: false
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: scoreboard
schema: public
type: create_delete_permission

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "scoreboard_target";
type: run_sql

View File

@@ -0,0 +1,6 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "scoreboard_target" jsonb NULL
DEFAULT jsonb_build_object();
type: run_sql

View File

@@ -0,0 +1,54 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- accountingconfig
- address1
- address2
- appt_length
- city
- country
- created_at
- email
- federal_tax_id
- id
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- invoice_tax_rates
- logo_img_path
- md_order_statuses
- md_responsibility_centers
- md_ro_statuses
- messagingservicesid
- production_config
- region_config
- shopname
- shoprates
- ssbuckets
- state
- state_tax_id
- stripe_acct_id
- template_header
- textid
- updated_at
- zip_post
computed_fields: []
filter:
associations:
bodyshop:
associations:
user:
authid:
_eq: X-Hasura-User-Id
role: user
table:
name: bodyshops
schema: public
type: create_select_permission

View File

@@ -0,0 +1,55 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- accountingconfig
- address1
- address2
- appt_length
- city
- country
- created_at
- email
- federal_tax_id
- id
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- invoice_tax_rates
- logo_img_path
- md_order_statuses
- md_responsibility_centers
- md_ro_statuses
- messagingservicesid
- production_config
- region_config
- scoreboard_target
- shopname
- shoprates
- ssbuckets
- state
- state_tax_id
- stripe_acct_id
- template_header
- textid
- updated_at
- zip_post
computed_fields: []
filter:
associations:
bodyshop:
associations:
user:
authid:
_eq: X-Hasura-User-Id
role: user
table:
name: bodyshops
schema: public
type: create_select_permission

View File

@@ -0,0 +1,48 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_update_permission
- args:
permission:
columns:
- accountingconfig
- address1
- address2
- appt_length
- city
- country
- created_at
- email
- federal_tax_id
- id
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- invoice_tax_rates
- logo_img_path
- md_order_statuses
- md_responsibility_centers
- md_ro_statuses
- production_config
- shopname
- shoprates
- ssbuckets
- state
- state_tax_id
- updated_at
- zip_post
filter:
associations:
bodyshop:
associations:
user:
authid:
_eq: X-Hasura-User-Id
set: {}
role: user
table:
name: bodyshops
schema: public
type: create_update_permission

View File

@@ -0,0 +1,49 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_update_permission
- args:
permission:
columns:
- accountingconfig
- address1
- address2
- appt_length
- city
- country
- created_at
- email
- federal_tax_id
- id
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- invoice_tax_rates
- logo_img_path
- md_order_statuses
- md_responsibility_centers
- md_ro_statuses
- production_config
- scoreboard_target
- shopname
- shoprates
- ssbuckets
- state
- state_tax_id
- updated_at
- zip_post
filter:
associations:
bodyshop:
associations:
user:
authid:
_eq: X-Hasura-User-Id
set: {}
role: user
table:
name: bodyshops
schema: public
type: create_update_permission

View File

@@ -472,6 +472,7 @@ tables:
- messagingservicesid
- production_config
- region_config
- scoreboard_target
- shopname
- shoprates
- ssbuckets
@@ -512,6 +513,7 @@ tables:
- md_responsibility_centers
- md_ro_statuses
- production_config
- scoreboard_target
- shopname
- shoprates
- ssbuckets
@@ -1897,6 +1899,13 @@ tables:
table:
schema: public
name: payments
- name: scoreboards
using:
foreign_key_constraint_on:
column: jobid
table:
schema: public
name: scoreboard
- name: timetickets
using:
foreign_key_constraint_on:
@@ -3346,6 +3355,86 @@ tables:
- active:
_eq: true
allow_aggregations: true
- table:
schema: public
name: scoreboard
object_relationships:
- name: job
using:
foreign_key_constraint_on: jobid
insert_permissions:
- role: user
permission:
check:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- id
- jobid
- painthrs
- bodyhrs
- date
backend_only: false
select_permissions:
- role: user
permission:
columns:
- date
- bodyhrs
- painthrs
- id
- jobid
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
allow_aggregations: true
update_permissions:
- role: user
permission:
columns:
- date
- bodyhrs
- painthrs
- id
- jobid
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
check: null
delete_permissions:
- role: user
permission:
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
- table:
schema: public
name: templates