Added scoreboard initial design BOD-91
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -105,8 +105,6 @@ export function ProductionBoardKanbanComponent({ data, bodyshop }) {
|
||||
}
|
||||
};
|
||||
|
||||
console.log("ismMoving", isMoving);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IndefiniteLoading loading={isMoving} />
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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={[
|
||||
|
||||
@@ -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
|
||||
|
||||
16
client/src/graphql/scoreboard.queries.js
Normal file
16
client/src/graphql/scoreboard.queries.js
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -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>
|
||||
|
||||
10
client/src/pages/scoreboard/scoreboard.page.component.jsx
Normal file
10
client/src/pages/scoreboard/scoreboard.page.component.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
47
client/src/pages/scoreboard/scoreboard.page.container.jsx
Normal file
47
client/src/pages/scoreboard/scoreboard.page.container.jsx
Normal 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);
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)",
|
||||
|
||||
@@ -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": "",
|
||||
|
||||
@@ -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": "",
|
||||
|
||||
122
client/yarn.lock
122
client/yarn.lock
@@ -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"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: DROP TABLE "public"."scoreboard";
|
||||
type: run_sql
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: scoreboard
|
||||
schema: public
|
||||
type: drop_insert_permission
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: scoreboard
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: scoreboard
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: scoreboard
|
||||
schema: public
|
||||
type: drop_delete_permission
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "scoreboard_target";
|
||||
type: run_sql
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user