From 55817b0e70324fb47458634682174a32745ec1ca Mon Sep 17 00:00:00 2001 From: Neil <55785687+carkom@users.noreply.github.com> Date: Wed, 28 Feb 2024 19:47:42 +0000 Subject: [PATCH] Add interval split and menu items to custom reports (#2389) * Add interval split and menu items * notes --- .../src/components/reports/ChooseGraph.tsx | 7 +- .../src/components/reports/ReportLegend.tsx | 9 ++- .../src/components/reports/ReportOptions.ts | 31 ++++---- .../src/components/reports/ReportSidebar.jsx | 76 ++++++++++--------- .../src/components/reports/ReportTopbar.jsx | 6 +- .../components/reports/graphs/BarGraph.tsx | 4 +- .../components/reports/graphs/DonutGraph.tsx | 4 +- .../graphs/tableGraph/ReportTableHeader.tsx | 15 +++- .../graphs/tableGraph/ReportTableList.tsx | 2 +- .../reports/reports/CustomReport.jsx | 14 +++- .../reports/reports/CustomReportListCards.tsx | 1 + .../reports/spreadsheets/calculateLegend.ts | 8 +- .../src/client/data-hooks/reports.ts | 1 + .../loot-core/src/server/aql/schema/index.ts | 2 +- packages/loot-core/src/server/reports/app.ts | 2 + .../loot-core/src/types/models/reports.d.ts | 2 + upcoming-release-notes/2389.md | 6 ++ 17 files changed, 114 insertions(+), 76 deletions(-) create mode 100644 upcoming-release-notes/2389.md diff --git a/packages/desktop-client/src/components/reports/ChooseGraph.tsx b/packages/desktop-client/src/components/reports/ChooseGraph.tsx index dce8850f8..1eef9fabc 100644 --- a/packages/desktop-client/src/components/reports/ChooseGraph.tsx +++ b/packages/desktop-client/src/components/reports/ChooseGraph.tsx @@ -27,6 +27,7 @@ type ChooseGraphProps = { graphType: string; balanceType: string; groupBy: string; + interval: string; setScrollWidth?: (value: number) => void; viewLabels?: boolean; compact?: boolean; @@ -41,6 +42,7 @@ export function ChooseGraph({ graphType, balanceType, groupBy, + interval, setScrollWidth, viewLabels, compact, @@ -52,7 +54,7 @@ export function ChooseGraph({ const groupByData = groupBy === 'Category' ? 'groupedData' - : ['Month', 'Year'].includes(groupBy) + : groupBy === 'Interval' ? 'monthData' : 'data'; @@ -142,8 +144,9 @@ export function ChooseGraph({ <ReportTableHeader headerScrollRef={headerScrollRef} handleScroll={handleScroll} - interval={mode === 'time' && data.monthData} + data={mode === 'time' && data.monthData} groupBy={groupBy} + interval={interval} balanceType={balanceType} compact={compact} style={rowStyle} diff --git a/packages/desktop-client/src/components/reports/ReportLegend.tsx b/packages/desktop-client/src/components/reports/ReportLegend.tsx index 1c4763331..91ea3f86c 100644 --- a/packages/desktop-client/src/components/reports/ReportLegend.tsx +++ b/packages/desktop-client/src/components/reports/ReportLegend.tsx @@ -4,12 +4,15 @@ import { theme, styles } from '../../style'; import { Text } from '../common/Text'; import { View } from '../common/View'; +import { ReportOptions } from './ReportOptions'; + type ReportLegendProps = { legend?: Array<{ name: string; color: string }>; groupBy: string; + interval: string; }; -export function ReportLegend({ legend, groupBy }: ReportLegendProps) { +export function ReportLegend({ legend, groupBy, interval }: ReportLegendProps) { return ( <View style={{ @@ -28,7 +31,9 @@ export function ReportLegend({ legend, groupBy }: ReportLegendProps) { paddingTop: 10, }} > - {groupBy} + {groupBy === 'Interval' + ? ReportOptions.intervalMap.get(interval) + : groupBy} </Text> <View> {legend && diff --git a/packages/desktop-client/src/components/reports/ReportOptions.ts b/packages/desktop-client/src/components/reports/ReportOptions.ts index a79c2059a..1f868ef1f 100644 --- a/packages/desktop-client/src/components/reports/ReportOptions.ts +++ b/packages/desktop-client/src/components/reports/ReportOptions.ts @@ -17,6 +17,7 @@ export const defaultReport: CustomReportEntity = { dateRange: 'Last 6 months', mode: 'total', groupBy: 'Category', + interval: 'Monthly', balanceType: 'Payment', showEmpty: false, showOffBudget: false, @@ -38,8 +39,7 @@ const groupByOptions = [ { description: 'Group' }, { description: 'Payee' }, { description: 'Account' }, - { description: 'Month' }, - { description: 'Year' }, + { description: 'Interval' }, ]; const dateRangeOptions = [ @@ -53,6 +53,14 @@ const dateRangeOptions = [ { description: 'All time', name: 'allMonths' }, ]; +const intervalOptions = [ + //{ value: 1, description: 'Daily', name: 'Day'}, + //{ value: 2, description: 'Weekly', name: 'Week'}, + //{ value: 3, description: 'Fortnightly', name: 3}, + { value: 4, description: 'Monthly', name: 'Month' }, + { value: 5, description: 'Yearly', name: 'Year' }, +]; + export const ReportOptions = { groupBy: groupByOptions, balanceType: balanceTypeOptions, @@ -63,17 +71,12 @@ export const ReportOptions = { dateRangeMap: new Map( dateRangeOptions.map(item => [item.description, item.name]), ), + interval: intervalOptions, + intervalMap: new Map( + intervalOptions.map(item => [item.description, item.name]), + ), }; -/* -const intervalOptions = [ -{ value: 1, description: 'Daily', name: 1, -{ value: 2, description: 'Weekly', name: 2, -{ value: 3, description: 'Fortnightly', name: 3, -{ value: 4, description: 'Monthly', name: 4, -{ value: 5, description: 'Yearly', name: 5, -]; -*/ export type QueryDataEntity = { date: string; category: string; @@ -181,11 +184,7 @@ export const groupBySelections = ( groupByList = accounts; groupByLabel = 'account'; break; - case 'Month': - groupByList = categoryList; - groupByLabel = 'category'; - break; - case 'Year': + case 'Interval': groupByList = categoryList; groupByLabel = 'category'; break; diff --git a/packages/desktop-client/src/components/reports/ReportSidebar.jsx b/packages/desktop-client/src/components/reports/ReportSidebar.jsx index 46981a2c0..6bf50b846 100644 --- a/packages/desktop-client/src/components/reports/ReportSidebar.jsx +++ b/packages/desktop-client/src/components/reports/ReportSidebar.jsx @@ -31,6 +31,7 @@ export function ReportSidebar({ setTypeDisabled, setGraphType, setGroupBy, + setInterval, setBalanceType, setMode, setIsDateStatic, @@ -97,7 +98,7 @@ export function ReportSidebar({ setGraphType('TableGraph'); onChangeViews('viewLegend', false); } - if (['Month', 'Year'].includes(customReportItems.groupBy)) { + if (customReportItems.groupBy === 'Interval') { setGroupBy('Category'); } } else { @@ -115,7 +116,7 @@ export function ReportSidebar({ if (customReportItems.mode === 'total') { if (customReportItems.graphType !== 'TableGraph') { setTypeDisabled( - !['Month', 'Year'].includes(customReportItems.groupBy) ? [] : ['Net'], + customReportItems.groupBy !== 'Interval' ? [] : ['Net'], ); } } @@ -161,7 +162,7 @@ export function ReportSidebar({ alignItems: 'center', }} > - <Text style={{ width: 40, textAlign: 'right', marginRight: 5 }}> + <Text style={{ width: 50, textAlign: 'right', marginRight: 5 }}> Mode: </Text> <ModeButton @@ -184,7 +185,7 @@ export function ReportSidebar({ alignItems: 'center', }} > - <Text style={{ width: 40, textAlign: 'right', marginRight: 5 }}> + <Text style={{ width: 50, textAlign: 'right', marginRight: 5 }}> Split: </Text> <Select @@ -196,10 +197,10 @@ export function ReportSidebar({ ])} disabledKeys={ customReportItems.mode === 'time' - ? ['Month', 'Year'] + ? ['Interval'] : customReportItems.graphType === 'AreaGraph' - ? ['Category', 'Group', 'Payee', 'Account', 'Year'] - : ['Year'] + ? ['Category', 'Group', 'Payee', 'Account'] + : [] } /> </View> @@ -210,7 +211,7 @@ export function ReportSidebar({ alignItems: 'center', }} > - <Text style={{ width: 40, textAlign: 'right', marginRight: 5 }}> + <Text style={{ width: 50, textAlign: 'right', marginRight: 5 }}> Type: </Text> <Select @@ -223,30 +224,6 @@ export function ReportSidebar({ disabledKeys={typeDisabled} /> </View> - {/* //It would be nice to retain this for future usage - <View - style={{ - flexDirection: 'row', - padding: 5, - alignItems: 'center', - }} - > - <Text style={{ width: 40, textAlign: 'right', marginRight: 5, paddingLeft: -10 }}> - Interval: - </Text> - <Select - value={interval} - onChange={setInterval} - options={intervalOptions.map(option => [ - option.value, - option.description, - ])} - disabledKeys={ - [1,2,3,4,5] - } - /> - </View> - */} <View style={{ flexDirection: 'row', @@ -254,7 +231,34 @@ export function ReportSidebar({ alignItems: 'center', }} > - <Text style={{ width: 40, textAlign: 'right', marginRight: 5 }} /> + <Text style={{ width: 50, textAlign: 'right', marginRight: 5 }}> + Interval: + </Text> + <Select + value={customReportItems.interval} + onChange={e => { + setInterval(e); + onReportChange({ type: 'modify' }); + }} + options={ReportOptions.interval.map(option => [ + option.description, + option.description, + ])} + disabledKeys={ + customReportItems.mode === 'time' + ? ['Monthly', 'Yearly'] + : ['Yearly'] + } + /> + </View> + <View + style={{ + flexDirection: 'row', + padding: 5, + alignItems: 'center', + }} + > + <Text style={{ width: 50, textAlign: 'right', marginRight: 5 }} /> <Button onClick={() => { setMenuOpen(true); @@ -372,7 +376,7 @@ export function ReportSidebar({ alignItems: 'center', }} > - <Text style={{ width: 40, textAlign: 'right', marginRight: 5 }}> + <Text style={{ width: 50, textAlign: 'right', marginRight: 5 }}> Range: </Text> <Select @@ -396,7 +400,7 @@ export function ReportSidebar({ alignItems: 'center', }} > - <Text style={{ width: 40, textAlign: 'right', marginRight: 5 }}> + <Text style={{ width: 50, textAlign: 'right', marginRight: 5 }}> From: </Text> <Select @@ -424,7 +428,7 @@ export function ReportSidebar({ alignItems: 'center', }} > - <Text style={{ width: 40, textAlign: 'right', marginRight: 5 }}> + <Text style={{ width: 50, textAlign: 'right', marginRight: 5 }}> To: </Text> <Select diff --git a/packages/desktop-client/src/components/reports/ReportTopbar.jsx b/packages/desktop-client/src/components/reports/ReportTopbar.jsx index d63744e9b..5ffeaee5c 100644 --- a/packages/desktop-client/src/components/reports/ReportTopbar.jsx +++ b/packages/desktop-client/src/components/reports/ReportTopbar.jsx @@ -70,9 +70,7 @@ export function ReportTopbar({ setBalanceType('Payment'); } setTypeDisabled( - ['Month', 'Year'].includes(customReportItems.groupBy) - ? [] - : ['Net'], + ['Interval'].includes(customReportItems.groupBy) ? [] : ['Net'], ); } else { setGraphType('StackedBarGraph'); @@ -90,7 +88,7 @@ export function ReportTopbar({ onSelect={() => { onReportChange({ type: 'modify' }); setGraphType('AreaGraph'); - setGroupBy('Month'); + setGroupBy('Interval'); onChangeViews('viewLegend', false); setTypeDisabled([]); }} diff --git a/packages/desktop-client/src/components/reports/graphs/BarGraph.tsx b/packages/desktop-client/src/components/reports/graphs/BarGraph.tsx index 8489e92dd..5ec4783c1 100644 --- a/packages/desktop-client/src/components/reports/graphs/BarGraph.tsx +++ b/packages/desktop-client/src/components/reports/graphs/BarGraph.tsx @@ -141,8 +141,8 @@ export function BarGraph({ }: BarGraphProps) { const privacyMode = usePrivacyMode(); - const yAxis = ['Month', 'Year'].includes(groupBy) ? 'date' : 'name'; - const splitData = ['Month', 'Year'].includes(groupBy) ? 'monthData' : 'data'; + const yAxis = groupBy === 'Interval' ? 'date' : 'name'; + const splitData = groupBy === 'Interval' ? 'monthData' : 'data'; const labelsMargin = viewLabels ? 30 : 0; const getVal = obj => { diff --git a/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx b/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx index 8714290b0..40ba708aa 100644 --- a/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx +++ b/packages/desktop-client/src/components/reports/graphs/DonutGraph.tsx @@ -187,8 +187,8 @@ export function DonutGraph({ compact, viewLabels, }: DonutGraphProps) { - const yAxis = ['Month', 'Year'].includes(groupBy) ? 'date' : 'name'; - const splitData = ['Month', 'Year'].includes(groupBy) ? 'monthData' : 'data'; + const yAxis = groupBy === 'Interval' ? 'date' : 'name'; + const splitData = groupBy === 'Interval' ? 'monthData' : 'data'; const getVal = obj => { if (balanceTypeOp === 'totalDebts') { diff --git a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableHeader.tsx b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableHeader.tsx index 14cafd14b..2246e4b12 100644 --- a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableHeader.tsx +++ b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableHeader.tsx @@ -8,10 +8,12 @@ import { theme } from '../../../../style'; import { type CSSProperties } from '../../../../style/types'; import { View } from '../../../common/View'; import { Row, Cell } from '../../../table'; +import { ReportOptions } from '../../ReportOptions'; type ReportTableHeaderProps = { groupBy: string; - interval?: DataEntity[]; + interval?: string; + data?: DataEntity[]; balanceType: string; headerScrollRef: RefProp<HTMLDivElement>; handleScroll: UIEventHandler<HTMLDivElement>; @@ -23,6 +25,7 @@ type ReportTableHeaderProps = { export function ReportTableHeader({ groupBy, interval, + data, balanceType, headerScrollRef, handleScroll, @@ -61,10 +64,14 @@ export function ReportTableHeader({ flexShrink: 0, }} valueStyle={compactStyle} - value={groupBy} + value={ + groupBy === 'Interval' + ? ReportOptions.intervalMap.get(interval) + : groupBy + } /> - {interval - ? interval.map((header, index) => { + {data + ? data.map((header, index) => { return ( <Cell style={{ diff --git a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableList.tsx b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableList.tsx index 33f9431a6..b1e56c312 100644 --- a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableList.tsx +++ b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableList.tsx @@ -28,7 +28,7 @@ export function ReportTableList({ style, compactStyle, }: ReportTableListProps) { - const groupByItem = ['Month', 'Year'].includes(groupBy) ? 'date' : 'name'; + const groupByItem = groupBy === 'Interval' ? 'date' : 'name'; type RenderRowProps = { index: number; diff --git a/packages/desktop-client/src/components/reports/reports/CustomReport.jsx b/packages/desktop-client/src/components/reports/reports/CustomReport.jsx index 32b8b7fc2..93559528d 100644 --- a/packages/desktop-client/src/components/reports/reports/CustomReport.jsx +++ b/packages/desktop-client/src/components/reports/reports/CustomReport.jsx @@ -67,6 +67,7 @@ export function CustomReport() { const [mode, setMode] = useState(loadReport.mode); const [isDateStatic, setIsDateStatic] = useState(loadReport.isDateStatic); const [groupBy, setGroupBy] = useState(loadReport.groupBy); + const [interval, setInterval] = useState(loadReport.interval); const [balanceType, setBalanceType] = useState(loadReport.balanceType); const [showEmpty, setShowEmpty] = useState(loadReport.showEmpty); const [showOffBudget, setShowOffBudget] = useState(loadReport.showOffBudget); @@ -146,6 +147,7 @@ export function CustomReport() { startDate, endDate, groupBy, + interval, balanceType, categories, selectedCategories, @@ -184,6 +186,7 @@ export function CustomReport() { startDate, endDate, groupBy, + interval, balanceType, categories, selectedCategories, @@ -208,6 +211,7 @@ export function CustomReport() { dateRange, mode, groupBy, + interval, balanceType, showEmpty, showOffBudget, @@ -256,6 +260,7 @@ export function CustomReport() { setDateRange(defaultReport.dateRange); setMode(defaultReport.mode); setGroupBy(defaultReport.groupBy); + setInterval(defaultReport.interval); setBalanceType(defaultReport.balanceType); setShowEmpty(defaultReport.showEmpty); setShowOffBudget(defaultReport.showOffBudget); @@ -297,6 +302,7 @@ export function CustomReport() { setDateRange(report.dateRange); setMode(report.mode); setGroupBy(report.groupBy); + setInterval(report.interval); setBalanceType(report.balanceType); setShowEmpty(report.showEmpty); setShowOffBudget(report.showOffBudget); @@ -334,6 +340,7 @@ export function CustomReport() { setTypeDisabled={setTypeDisabled} setGraphType={setGraphType} setGroupBy={setGroupBy} + setInterval={setInterval} setBalanceType={setBalanceType} setMode={setMode} setIsDateStatic={setIsDateStatic} @@ -446,6 +453,7 @@ export function CustomReport() { graphType={graphType} balanceType={balanceType} groupBy={groupBy} + interval={interval} showEmpty={showEmpty} scrollWidth={scrollWidth} setScrollWidth={setScrollWidth} @@ -477,7 +485,11 @@ export function CustomReport() { /> )} {viewLegend && ( - <ReportLegend legend={data.legend} groupBy={groupBy} /> + <ReportLegend + legend={data.legend} + groupBy={groupBy} + interval={interval} + /> )} </View> )} diff --git a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx index 40d7742a7..cb7b80e66 100644 --- a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx +++ b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx @@ -154,6 +154,7 @@ export function CustomReportListCards({ graphType={report.graphType} balanceType={report.balanceType} groupBy={report.groupBy} + interval={report.interval} compact={true} style={{ height: 'auto', flex: 1 }} /> diff --git a/packages/desktop-client/src/components/reports/spreadsheets/calculateLegend.ts b/packages/desktop-client/src/components/reports/spreadsheets/calculateLegend.ts index 9ba3410dd..2190b7ea6 100644 --- a/packages/desktop-client/src/components/reports/spreadsheets/calculateLegend.ts +++ b/packages/desktop-client/src/components/reports/spreadsheets/calculateLegend.ts @@ -15,16 +15,14 @@ export function calculateLegend( balanceTypeOp: string, ) { const colorScale = getColorScale('qualitative'); - const chooseData = ['Month', 'Year'].includes(groupBy) - ? monthData - : calcDataFiltered; + const chooseData = groupBy === 'Interval' ? monthData : calcDataFiltered; return chooseData.map((c, index) => { return { - name: ['Month', 'Year'].includes(groupBy) ? c.date : c.name, + name: groupBy === 'Interval' ? c.date : c.name, color: graphType === 'DonutGraph' ? colorScale[index % colorScale.length] - : ['Month', 'Year'].includes(groupBy) + : groupBy === 'Interval' ? balanceTypeOp === 'totalDebts' ? theme.reportsRed : theme.reportsBlue diff --git a/packages/loot-core/src/client/data-hooks/reports.ts b/packages/loot-core/src/client/data-hooks/reports.ts index 78246e477..275ef64d1 100644 --- a/packages/loot-core/src/client/data-hooks/reports.ts +++ b/packages/loot-core/src/client/data-hooks/reports.ts @@ -18,6 +18,7 @@ function toJS(rows: CustomReportData[]) { dateRange: row.date_range, mode: row.mode, groupBy: row.group_by, + interval: row.interval, balanceType: row.balance_type, showEmpty: row.show_empty === 1, showOffBudget: row.show_offbudget === 1, diff --git a/packages/loot-core/src/server/aql/schema/index.ts b/packages/loot-core/src/server/aql/schema/index.ts index cb466d6f8..f6799cdd9 100644 --- a/packages/loot-core/src/server/aql/schema/index.ts +++ b/packages/loot-core/src/server/aql/schema/index.ts @@ -145,7 +145,7 @@ export const schema = { conditions: f('json'), conditions_op: f('string'), metadata: f('json'), - interval: f('string'), + interval: f('string', { default: 'Monthly' }), color_scheme: f('json'), tombstone: f('boolean'), }, diff --git a/packages/loot-core/src/server/reports/app.ts b/packages/loot-core/src/server/reports/app.ts index d78d09cb4..5e1238509 100644 --- a/packages/loot-core/src/server/reports/app.ts +++ b/packages/loot-core/src/server/reports/app.ts @@ -35,6 +35,7 @@ const reportModel = { dateRange: row.date_range, mode: row.mode, groupBy: row.group_by, + interval: row.interval, balanceType: row.balance_type, showEmpty: row.show_empty === 1, showOffBudget: row.show_offbudget === 1, @@ -58,6 +59,7 @@ const reportModel = { date_range: report.dateRange, mode: report.mode, group_by: report.groupBy, + interval: report.interval, balance_type: report.balanceType, show_empty: report.showEmpty ? 1 : 0, show_offbudget: report.showOffBudget ? 1 : 0, diff --git a/packages/loot-core/src/types/models/reports.d.ts b/packages/loot-core/src/types/models/reports.d.ts index 06a6e56e0..cb966d6e3 100644 --- a/packages/loot-core/src/types/models/reports.d.ts +++ b/packages/loot-core/src/types/models/reports.d.ts @@ -10,6 +10,7 @@ export interface CustomReportEntity { dateRange: string; mode: string; groupBy: string; + interval: string; balanceType: string; showEmpty: boolean; showOffBudget: boolean; @@ -80,6 +81,7 @@ export interface CustomReportData { date_range: string; mode: string; group_by: string; + interval: string; balance_type: string; show_empty: number; show_offbudget: number; diff --git a/upcoming-release-notes/2389.md b/upcoming-release-notes/2389.md new file mode 100644 index 000000000..021aa519d --- /dev/null +++ b/upcoming-release-notes/2389.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [carkom] +--- + +Adding an interval menu to custom reports -- GitLab