From 6ad0b47c7cb1690f1869913d6809e86629dadfbd Mon Sep 17 00:00:00 2001 From: Neil <55785687+carkom@users.noreply.github.com> Date: Mon, 17 Jun 2024 20:09:38 +0100 Subject: [PATCH] Custom Reports: Include current (#2684) * include current * notes * label change * add migration and fix merge issues * fix extra year/month * default and disabled lists * default on * fixes * rerun --- .../src/components/reports/ReportOptions.ts | 24 +++++----- .../src/components/reports/ReportSidebar.tsx | 45 +++++++++++++++++-- .../src/components/reports/disabledList.ts | 26 +++++++++++ .../src/components/reports/getLiveRange.ts | 5 ++- .../src/components/reports/reportRanges.ts | 2 +- .../reports/reports/CustomReport.tsx | 8 ++++ .../reports/reports/GetCardData.tsx | 1 + .../1716359441000_include_current.sql | 5 +++ .../src/client/data-hooks/reports.ts | 1 + .../loot-core/src/server/aql/schema/index.ts | 1 + packages/loot-core/src/server/reports/app.ts | 2 + packages/loot-core/src/shared/months.ts | 6 ++- .../loot-core/src/types/models/reports.d.ts | 2 + upcoming-release-notes/2684.md | 6 +++ 14 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 packages/loot-core/migrations/1716359441000_include_current.sql create mode 100644 upcoming-release-notes/2684.md diff --git a/packages/desktop-client/src/components/reports/ReportOptions.ts b/packages/desktop-client/src/components/reports/ReportOptions.ts index 53f0b3bb7..25fc25551 100644 --- a/packages/desktop-client/src/components/reports/ReportOptions.ts +++ b/packages/desktop-client/src/components/reports/ReportOptions.ts @@ -24,6 +24,7 @@ export const defaultReport: CustomReportEntity = { showEmpty: false, showOffBudget: false, showHiddenCategories: false, + includeCurrentInterval: true, showUncategorized: false, graphType: 'BarGraph', conditions: [], @@ -58,7 +59,7 @@ const dateRangeOptions: dateRangeProps[] = [ { description: 'This week', name: 0, - type: 'Weeks', + type: 'Week', Daily: true, Weekly: true, Monthly: false, @@ -67,7 +68,7 @@ const dateRangeOptions: dateRangeProps[] = [ { description: 'Last week', name: 1, - type: 'Weeks', + type: 'Week', Daily: true, Weekly: true, Monthly: false, @@ -76,7 +77,7 @@ const dateRangeOptions: dateRangeProps[] = [ { description: 'This month', name: 0, - type: 'Months', + type: 'Month', Daily: true, Weekly: true, Monthly: true, @@ -85,7 +86,7 @@ const dateRangeOptions: dateRangeProps[] = [ { description: 'Last month', name: 1, - type: 'Months', + type: 'Month', Daily: true, Weekly: true, Monthly: true, @@ -93,8 +94,8 @@ const dateRangeOptions: dateRangeProps[] = [ }, { description: 'Last 3 months', - name: 2, - type: 'Months', + name: 3, + type: 'Month', Daily: true, Weekly: true, Monthly: true, @@ -102,8 +103,8 @@ const dateRangeOptions: dateRangeProps[] = [ }, { description: 'Last 6 months', - name: 5, - type: 'Months', + name: 6, + type: 'Month', Daily: false, Weekly: false, Monthly: true, @@ -111,8 +112,8 @@ const dateRangeOptions: dateRangeProps[] = [ }, { description: 'Last 12 months', - name: 11, - type: 'Months', + name: 12, + type: 'Month', Daily: false, Weekly: false, Monthly: true, @@ -121,6 +122,7 @@ const dateRangeOptions: dateRangeProps[] = [ { description: 'Year to date', name: 'yearToDate', + type: 'Month', Daily: false, Weekly: true, Monthly: true, @@ -129,6 +131,7 @@ const dateRangeOptions: dateRangeProps[] = [ { description: 'Last year', name: 'lastYear', + type: 'Month', Daily: false, Weekly: true, Monthly: true, @@ -137,6 +140,7 @@ const dateRangeOptions: dateRangeProps[] = [ { description: 'All time', name: 'allTime', + type: 'Month', Daily: false, Weekly: true, Monthly: true, diff --git a/packages/desktop-client/src/components/reports/ReportSidebar.tsx b/packages/desktop-client/src/components/reports/ReportSidebar.tsx index 35aba3f7b..f449f5e59 100644 --- a/packages/desktop-client/src/components/reports/ReportSidebar.tsx +++ b/packages/desktop-client/src/components/reports/ReportSidebar.tsx @@ -15,7 +15,7 @@ import { Text } from '../common/Text'; import { View } from '../common/View'; import { CategorySelector } from './CategorySelector'; -import { defaultsList } from './disabledList'; +import { defaultsList, disabledList } from './disabledList'; import { getLiveRange } from './getLiveRange'; import { ModeButton } from './ModeButton'; import { type dateRangeProps, ReportOptions } from './ReportOptions'; @@ -38,6 +38,7 @@ type ReportSidebarProps = { setShowOffBudget: (value: boolean) => void; setShowHiddenCategories: (value: boolean) => void; setShowUncategorized: (value: boolean) => void; + setIncludeCurrentInterval: (value: boolean) => void; setSelectedCategories: (value: CategoryEntity[]) => void; onChangeDates: (dateStart: string, dateEnd: string) => void; onReportChange: ({ @@ -69,6 +70,7 @@ export function ReportSidebar({ setShowEmpty, setShowOffBudget, setShowHiddenCategories, + setIncludeCurrentInterval, setShowUncategorized, setSelectedCategories, onChangeDates, @@ -86,7 +88,12 @@ export function ReportSidebar({ onReportChange({ type: 'modify' }); setDateRange(cond); onChangeDates( - ...getLiveRange(cond, earliestTransaction, firstDayOfWeekIdx), + ...getLiveRange( + cond, + earliestTransaction, + customReportItems.includeCurrentInterval, + firstDayOfWeekIdx, + ), ); }; @@ -269,7 +276,15 @@ export function ReportSidebar({ onMenuSelect={type => { onReportChange({ type: 'modify' }); - if (type === 'show-hidden-categories') { + if (type === 'include-current-interval') { + setSessionReport( + 'includeCurrentInterval', + !customReportItems.includeCurrentInterval, + ); + setIncludeCurrentInterval( + !customReportItems.includeCurrentInterval, + ); + } else if (type === 'show-hidden-categories') { setSessionReport( 'showHiddenCategories', !customReportItems.showHiddenCategories, @@ -295,6 +310,30 @@ export function ReportSidebar({ } }} items={[ + { + name: 'include-current-interval', + text: + 'Include current ' + + ( + ReportOptions.dateRangeType.get( + customReportItems.dateRange, + ) || '' + ).toLowerCase(), + tooltip: + 'Include current ' + + ( + ReportOptions.dateRangeType.get( + customReportItems.dateRange, + ) || '' + ).toLowerCase() + + ' in live range', + toggle: customReportItems.includeCurrentInterval, + disabled: + customReportItems.isDateStatic || + disabledList.currentInterval.get( + customReportItems.dateRange, + ), + }, { name: 'show-hidden-categories', text: 'Show hidden categories', diff --git a/packages/desktop-client/src/components/reports/disabledList.ts b/packages/desktop-client/src/components/reports/disabledList.ts index ad3caadb6..eb3e70971 100644 --- a/packages/desktop-client/src/components/reports/disabledList.ts +++ b/packages/desktop-client/src/components/reports/disabledList.ts @@ -17,6 +17,29 @@ const intervalOptions = [ }, ]; +const currentIntervalOptions = [ + { + description: 'This week', + disableInclude: true, + }, + { + description: 'This month', + disableInclude: true, + }, + { + description: 'Year to date', + disableInclude: true, + }, + { + description: 'Last year', + disableInclude: true, + }, + { + description: 'All time', + disableInclude: true, + }, +]; + type graphOptions = { description: string; disabledSplit: string[]; @@ -164,6 +187,9 @@ export const disabledList = { modeGraphsMap: new Map( modeOptions.map(item => [item.description, item.disabledGraph]), ), + currentInterval: new Map( + currentIntervalOptions.map(item => [item.description, item.disableInclude]), + ), }; export const defaultsList = { diff --git a/packages/desktop-client/src/components/reports/getLiveRange.ts b/packages/desktop-client/src/components/reports/getLiveRange.ts index 437892f6f..fffed8e22 100644 --- a/packages/desktop-client/src/components/reports/getLiveRange.ts +++ b/packages/desktop-client/src/components/reports/getLiveRange.ts @@ -7,6 +7,7 @@ import { getSpecificRange, validateRange } from './reportRanges'; export function getLiveRange( cond: string, earliestTransaction: string, + includeCurrentInterval: boolean, firstDayOfWeekIdx?: LocalPrefs['firstDayOfWeekIdx'], ): [string, string] { let dateStart = earliestTransaction; @@ -38,7 +39,9 @@ export function getLiveRange( if (typeof rangeName === 'number') { [dateStart, dateEnd] = getSpecificRange( rangeName, - cond === 'Last month' || cond === 'Last week' ? 0 : null, + ['This month', 'This week'].includes(cond) + ? null + : rangeName - (includeCurrentInterval ? 0 : 1), ReportOptions.dateRangeType.get(cond), firstDayOfWeekIdx, ); diff --git a/packages/desktop-client/src/components/reports/reportRanges.ts b/packages/desktop-client/src/components/reports/reportRanges.ts index 97183d6d9..4e0ee2d29 100644 --- a/packages/desktop-client/src/components/reports/reportRanges.ts +++ b/packages/desktop-client/src/components/reports/reportRanges.ts @@ -142,7 +142,7 @@ export function getSpecificRange( '-01', ); - if (type === 'Weeks') { + if (type === 'Week') { dateStart = monthUtils.subWeeks(currentWeek, offset); dateEnd = monthUtils.getWeekEnd( monthUtils.addWeeks(dateStart, addNumber === null ? offset : addNumber), diff --git a/packages/desktop-client/src/components/reports/reports/CustomReport.tsx b/packages/desktop-client/src/components/reports/reports/CustomReport.tsx index 10a1f870c..7171fb521 100644 --- a/packages/desktop-client/src/components/reports/reports/CustomReport.tsx +++ b/packages/desktop-client/src/components/reports/reports/CustomReport.tsx @@ -113,6 +113,9 @@ export function CustomReport() { const [balanceType, setBalanceType] = useState(loadReport.balanceType); const [showEmpty, setShowEmpty] = useState(loadReport.showEmpty); const [showOffBudget, setShowOffBudget] = useState(loadReport.showOffBudget); + const [includeCurrentInterval, setIncludeCurrentInterval] = useState( + loadReport.includeCurrentInterval, + ); const [showHiddenCategories, setShowHiddenCategories] = useState( loadReport.showHiddenCategories, ); @@ -212,6 +215,7 @@ export function CustomReport() { const [dateStart, dateEnd] = getLiveRange( dateRange, trans ? trans.date : monthUtils.currentDay(), + includeCurrentInterval, firstDayOfWeekIdx, ); setStartDate(dateStart); @@ -226,6 +230,7 @@ export function CustomReport() { isDateStatic, onApplyFilter, report.conditions, + includeCurrentInterval, ]); useEffect(() => { @@ -340,6 +345,7 @@ export function CustomReport() { showEmpty, showOffBudget, showHiddenCategories, + includeCurrentInterval, showUncategorized, selectedCategories, graphType, @@ -482,6 +488,7 @@ export function CustomReport() { setShowEmpty(input.showEmpty); setShowOffBudget(input.showOffBudget); setShowHiddenCategories(input.showHiddenCategories); + setIncludeCurrentInterval(input.includeCurrentInterval); setShowUncategorized(input.showUncategorized); setSelectedCategories(input.selectedCategories || selectAll); setGraphType(input.graphType); @@ -583,6 +590,7 @@ export function CustomReport() { setShowEmpty={setShowEmpty} setShowOffBudget={setShowOffBudget} setShowHiddenCategories={setShowHiddenCategories} + setIncludeCurrentInterval={setIncludeCurrentInterval} setShowUncategorized={setShowUncategorized} setSelectedCategories={setSelectedCategories} onChangeDates={onChangeDates} diff --git a/packages/desktop-client/src/components/reports/reports/GetCardData.tsx b/packages/desktop-client/src/components/reports/reports/GetCardData.tsx index ad9e9e732..5004f19c0 100644 --- a/packages/desktop-client/src/components/reports/reports/GetCardData.tsx +++ b/packages/desktop-client/src/components/reports/reports/GetCardData.tsx @@ -81,6 +81,7 @@ export function GetCardData({ const [dateStart, dateEnd] = getLiveRange( report.dateRange, earliestTransaction, + report.includeCurrentInterval, firstDayOfWeekIdx, ); startDate = dateStart || report.startDate; diff --git a/packages/loot-core/migrations/1716359441000_include_current.sql b/packages/loot-core/migrations/1716359441000_include_current.sql new file mode 100644 index 000000000..806b00245 --- /dev/null +++ b/packages/loot-core/migrations/1716359441000_include_current.sql @@ -0,0 +1,5 @@ +BEGIN TRANSACTION; + +ALTER TABLE custom_reports ADD COLUMN include_current INTEGER DEFAULT 0; + +COMMIT; \ No newline at end of file diff --git a/packages/loot-core/src/client/data-hooks/reports.ts b/packages/loot-core/src/client/data-hooks/reports.ts index 275ef64d1..8153d68ee 100644 --- a/packages/loot-core/src/client/data-hooks/reports.ts +++ b/packages/loot-core/src/client/data-hooks/reports.ts @@ -23,6 +23,7 @@ function toJS(rows: CustomReportData[]) { showEmpty: row.show_empty === 1, showOffBudget: row.show_offbudget === 1, showHiddenCategories: row.show_hidden === 1, + includeCurrentInterval: row.include_current === 1, showUncategorized: row.show_uncategorized === 1, selectedCategories: row.selected_categories, graphType: row.graph_type, diff --git a/packages/loot-core/src/server/aql/schema/index.ts b/packages/loot-core/src/server/aql/schema/index.ts index f6799cdd9..1b9a92045 100644 --- a/packages/loot-core/src/server/aql/schema/index.ts +++ b/packages/loot-core/src/server/aql/schema/index.ts @@ -140,6 +140,7 @@ export const schema = { show_offbudget: f('integer', { default: 0 }), show_hidden: f('integer', { default: 0 }), show_uncategorized: f('integer', { default: 0 }), + include_current: f('integer', { default: 0 }), selected_categories: f('json'), graph_type: f('string', { default: 'BarGraph' }), conditions: f('json'), diff --git a/packages/loot-core/src/server/reports/app.ts b/packages/loot-core/src/server/reports/app.ts index 5e1238509..e295f6f78 100644 --- a/packages/loot-core/src/server/reports/app.ts +++ b/packages/loot-core/src/server/reports/app.ts @@ -41,6 +41,7 @@ const reportModel = { showOffBudget: row.show_offbudget === 1, showHiddenCategories: row.show_hidden === 1, showUncategorized: row.show_uncategorized === 1, + includeCurrentInterval: row.include_current === 1, selectedCategories: row.selected_categories, graphType: row.graph_type, conditions: row.conditions, @@ -65,6 +66,7 @@ const reportModel = { show_offbudget: report.showOffBudget ? 1 : 0, show_hidden: report.showHiddenCategories ? 1 : 0, show_uncategorized: report.showUncategorized ? 1 : 0, + include_current: report.includeCurrentInterval ? 1 : 0, selected_categories: report.selectedCategories, graph_type: report.graphType, conditions: report.conditions, diff --git a/packages/loot-core/src/shared/months.ts b/packages/loot-core/src/shared/months.ts index 482843466..89aee77ea 100644 --- a/packages/loot-core/src/shared/months.ts +++ b/packages/loot-core/src/shared/months.ts @@ -232,7 +232,8 @@ export function _yearRange( ): string[] { const years: string[] = []; let year = yearFromDate(start); - while (d.isBefore(_parse(year), _parse(end))) { + const endYear = yearFromDate(end); + while (d.isBefore(_parse(year), _parse(endYear))) { years.push(year); year = addYears(year, 1); } @@ -284,7 +285,8 @@ export function _range( ): string[] { const months: string[] = []; let month = monthFromDate(start); - while (d.isBefore(_parse(month), _parse(end))) { + const endMonth = monthFromDate(end); + while (d.isBefore(_parse(month), _parse(endMonth))) { months.push(month); month = addMonths(month, 1); } diff --git a/packages/loot-core/src/types/models/reports.d.ts b/packages/loot-core/src/types/models/reports.d.ts index 42ed96875..d7e04a5f8 100644 --- a/packages/loot-core/src/types/models/reports.d.ts +++ b/packages/loot-core/src/types/models/reports.d.ts @@ -15,6 +15,7 @@ export interface CustomReportEntity { showEmpty: boolean; showOffBudget: boolean; showHiddenCategories: boolean; + includeCurrentInterval: boolean; showUncategorized: boolean; selectedCategories?: CategoryEntity[]; graphType: string; @@ -114,6 +115,7 @@ export interface CustomReportData { show_empty: number; show_offbudget: number; show_hidden: number; + include_current: number; show_uncategorized: number; selected_categories?: CategoryEntity[]; graph_type: string; diff --git a/upcoming-release-notes/2684.md b/upcoming-release-notes/2684.md new file mode 100644 index 000000000..7062e8e8c --- /dev/null +++ b/upcoming-release-notes/2684.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [carkom] +--- + +Option to add/remove current interval to "live" ranges -- GitLab