Skip to content

Commit 30e492d

Browse files
committed
Added 'Year' section generation
1 parent fc21b61 commit 30e492d

5 files changed

Lines changed: 202 additions & 11 deletions

File tree

‎jgclark.Dashboard/CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ For more details see the [plugin's documentation](https://github.com/NotePlan/pl
1010
-->
1111

1212
## [2.3.3] 2025-12-03
13+
- new 'Year' section available
1314
- change order of display of tag sections to the order they are defined in the settings, not alphabetical.
15+
- dev: removed `sectionNumStr` throughout, now using `sectionCode` instead
1416

1517
## [2.3.2] 2025-12-02
1618
- fix display when there are no priority items shown.

‎jgclark.Dashboard/src/constants.js‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @flow
22
//-----------------------------------------------------------------------------
33
// Constants for Dashboard code
4-
// Last updated 2025-12-01 for v2.3.0.b14+, @jgclark
4+
// Last updated 2025-12-03 for v2.3.3, @jgclark
55
//-----------------------------------------------------------------------------
66
import pluginJson from '../plugin.json'
77
import type { TSectionDetails, TSectionCode } from './types'
@@ -19,6 +19,7 @@ export const allSectionDetails: Array<TSectionDetails> = [
1919
{ sectionCode: 'W', sectionName: 'This Week', showSettingName: 'showWeekSection' },
2020
{ sectionCode: 'M', sectionName: 'Month', showSettingName: 'showMonthSection' },
2121
{ sectionCode: 'Q', sectionName: 'Quarter', showSettingName: 'showQuarterSection' },
22+
{ sectionCode: 'Y', sectionName: 'Year', showSettingName: 'showYearSection' },
2223
// TAG types are treated specially (one for each tag a user wants to see).
2324
// Use getTagSectionDetails() to get them
2425
// sectionName set later to reflect the tagsToShow setting
@@ -35,20 +36,20 @@ export const allSectionDetails: Array<TSectionDetails> = [
3536

3637
export const allSectionCodes: Array<TSectionCode> = allSectionDetails.map((s) => s.sectionCode)
3738

38-
export const allCalendarSectionCodes = ['DT', 'DY', 'DO', 'LW', 'W', 'M', 'Q']
39+
export const allCalendarSectionCodes = ['DT', 'DY', 'DO', 'LW', 'W', 'M', 'Q', 'Y']
3940

40-
export const defaultSectionDisplayOrder = ['SEARCH', 'INFO', 'SAVEDSEARCH', 'TB', 'DT', 'DY', 'DO', 'LW', 'W', 'M', 'Q', 'TAG', 'OVERDUE', 'PRIORITY', 'PROJ']
41+
export const defaultSectionDisplayOrder = ['SEARCH', 'INFO', 'SAVEDSEARCH', 'TB', 'DT', 'DY', 'DO', 'LW', 'W', 'M', 'Q', 'Y', 'TAG', 'OVERDUE', 'PRIORITY', 'PROJ']
4142

4243
// change this order to change which duplicate items get kept - the first on the list. Should not include 'dontDedupeSectionCodes' below.
43-
export const sectionPriority = ['TB', 'TAG', 'DT', 'DY', 'DO', 'W', 'M', 'Q', 'PRIORITY', 'OVERDUE']
44+
export const sectionPriority = ['TB', 'TAG', 'DT', 'DY', 'DO', 'W', 'M', 'Q', 'Y', 'PRIORITY', 'OVERDUE']
4445

4546
// Those sections we can't or shouldn't attempt to dedupe:
4647
// - TB as its for info only
4748
// - PROJ as it isn't about paragraphs, but notes
4849
export const dontDedupeSectionCodes = ['INFO', 'PROJ', 'SEARCH', 'SAVEDSEARCH']
4950

5051
// Enable interactive processing for these itemTypes:
51-
export const interactiveProcessingPossibleSectionTypes = ['DT', 'DY', 'DO', 'LW', 'W', 'M', 'Q', 'TAG', 'OVERDUE', 'PRIORITY']
52+
export const interactiveProcessingPossibleSectionTypes = ['DT', 'DY', 'DO', 'LW', 'W', 'M', 'Q', 'Y', 'TAG', 'OVERDUE', 'PRIORITY']
5253

5354
// Treat these itemTypes as if they are zero items, so we don't show the Interactive or other Processing buttons, and correct the count in the description
5455
export const treatSingleItemTypesAsZeroItems = ['itemCongrats', 'projectCongrats', 'noSearchResults', 'preLimitOverdues']

‎jgclark.Dashboard/src/dashboardHelpers.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ export function getListOfEnabledSections(config: TDashboardSettings): Array<TSec
201201
if (config.showWeekSection) sectionsToShow.push('W')
202202
if (config.showMonthSection) sectionsToShow.push('M')
203203
if (config.showQuarterSection) sectionsToShow.push('Q')
204+
if (config.showYearSection) sectionsToShow.push('Y')
204205
if (config.showProjectSection) sectionsToShow.push('PROJ')
205206
if (config.tagsToShow) sectionsToShow.push('TAG')
206207
if (config.showOverdueSection) sectionsToShow.push('OVERDUE')

‎jgclark.Dashboard/src/dataGeneration.js‎

Lines changed: 190 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { openMonthParas, refMonthParas, tagParasFromNote } from './demoData'
2727
import { getTagSectionDetails } from './react/components/Section/sectionHelpers'
2828
import { removeInvalidTagSections } from './perspectiveHelpers'
2929
import { getNestedValue, setNestedValue } from '@helpers/dataManipulation'
30-
import { getDateStringFromCalendarFilename, getNPMonthStr, getNPQuarterStr } from '@helpers/dateTime'
30+
import { getDateStringFromCalendarFilename, getNPMonthStr, getNPQuarterStr, getNPYearStr } from '@helpers/dateTime'
3131
import { clo, JSP, logDebug, logError, logInfo, logTimer, logWarn, timer } from '@helpers/dev'
3232
import { getHeadingsFromNote } from '@helpers/NPnote'
3333
// import { sortListBy } from '@helpers/sorting'
@@ -90,6 +90,7 @@ export async function getSomeSectionsData(
9090
if (sectionCodesToGet.includes('W') && config.showWeekSection) sections.push(...getThisWeekSectionData(config, useDemoData, useEditorWherePossible))
9191
if (sectionCodesToGet.includes('M') && config.showMonthSection) sections.push(...getThisMonthSectionData(config, useDemoData, useEditorWherePossible))
9292
if (sectionCodesToGet.includes('Q') && config.showQuarterSection) sections.push(...getThisQuarterSectionData(config, useDemoData, useEditorWherePossible))
93+
if (sectionCodesToGet.includes('Y') && config.showYearSection) sections.push(...getThisYearSectionData(config, useDemoData, useEditorWherePossible))
9394
// moderately quick to generate
9495
if (sectionCodesToGet.includes('PROJ') && config.showProjectSection) {
9596
logInfo('getSomeSectionsData', `🔹 Getting Project section data as part of ${sectionCodesToGet.toString()}`)
@@ -559,9 +560,194 @@ export function getThisQuarterSectionData(config: TDashboardSettings, useDemoDat
559560
}
560561
}
561562

562-
//----------------------------------------------------------------
563-
// Note: If we want to do yearly in the future then the icon is
564-
// fa-calendar-days (same as quarter). This would be section #6
563+
/**
564+
* Get open items from this Year's note
565+
* @param {TDashboardSettings} config
566+
* @param {boolean} useDemoData?
567+
* @param {boolean} useEditorWherePossible?
568+
* @returns {TSection} data
569+
*/
570+
export function getThisYearSectionData(config: TDashboardSettings, useDemoData: boolean = false, useEditorWherePossible: boolean): Array<TSection> {
571+
try {
572+
const thisSectionCode = 'Y'
573+
const sections: Array<TSection> = []
574+
let items: Array<TSectionItem> = []
575+
let itemCount = 0
576+
const today = new moment().toDate() // use moment instead of `new Date` to ensure we get a date in the local timezone
577+
const dateStr = getNPYearStr(today)
578+
const NPSettings = getNotePlanSettings()
579+
const currentYearlyNote = DataStore.calendarNoteByDate(today, 'year')
580+
const thisFilename = `${dateStr}.${NPSettings.defaultFileExtension}`
581+
let sortedOrCombinedParas: Array<TParagraphForDashboard> = []
582+
let sortedRefParas: Array<TParagraphForDashboard> = []
583+
logDebug('getDataForDashboard', `---------- Gathering Year's ${useDemoData ? 'DEMO' : ''} items for section ${thisSectionCode} ------------`)
584+
const startTime = new Date() // for timing only
585+
586+
if (useDemoData) {
587+
// Deliberately no demo data defined
588+
} else {
589+
if (currentYearlyNote) {
590+
// Get list of open tasks/checklists from this yearly note (if it exists)
591+
;[sortedOrCombinedParas, sortedRefParas] = getOpenItemParasForTimePeriod(dateStr, 'year', config, useEditorWherePossible)
592+
593+
// Iterate and write items for first (or combined) section
594+
items = createSectionOpenItemsFromParas(sortedOrCombinedParas, thisSectionCode)
595+
itemCount += items.length
596+
597+
// logDebug('getDataForDashboard', `- finished finding Yearly items from ${dateStr} after ${timer(startTime)}`)
598+
} else {
599+
logDebug('getDataForDashboard', `No Yearly note found for filename '${thisFilename}'`)
600+
}
601+
}
602+
const nextPeriodNote = DataStore.calendarNoteByDate(new moment().add(1, 'year').toDate(), 'year')
603+
const nextPeriodFilename = nextPeriodNote?.filename ?? ''
604+
const doneCountData = getNumCompletedTasksFromNote(thisFilename)
605+
606+
// Set up formFields for the 'add buttons' (applied in Section.jsx)
607+
const formFieldsBase: Array<TSettingItem> = [{ type: 'input', label: 'Task:', key: 'text', focus: true }]
608+
const thisYearHeadings: Array<string> = currentYearlyNote ? getHeadingsFromNote(currentYearlyNote, false, true, true, true) : []
609+
const nextYearHeadings: Array<string> = nextPeriodNote ? getHeadingsFromNote(nextPeriodNote, false, true, true, true) : []
610+
// Set the default heading to add to, unless it's '<<carry forward>>', in which case we'll use an empty string
611+
const defaultHeadingToAddTo: string = config.newTaskSectionHeading !== '<<carry forward>>' ? config.newTaskSectionHeading : ''
612+
const thisYearFormFields: Array<TSettingItem> = formFieldsBase.concat(
613+
thisYearHeadings.length
614+
? // $FlowIgnore[incompatible-type]
615+
[
616+
{
617+
type: 'dropdown-select',
618+
label: 'Under Heading:',
619+
key: 'heading',
620+
// $FlowFixMe[incompatible-type]
621+
options: thisYearHeadings,
622+
noWrapOptions: true,
623+
value: defaultHeadingToAddTo,
624+
},
625+
]
626+
: [],
627+
)
628+
const nextYearFormFields: Array<TSettingItem> = formFieldsBase.concat(
629+
nextYearHeadings.length
630+
? // $FlowIgnore[incompatible-type]
631+
[
632+
{
633+
type: 'dropdown-select',
634+
label: 'Under Heading:',
635+
key: 'heading',
636+
// $FlowFixMe[incompatible-type]
637+
options: nextYearHeadings,
638+
noWrapOptions: true,
639+
value: defaultHeadingToAddTo,
640+
},
641+
]
642+
: [],
643+
)
644+
645+
let sectionDescription = `{countWithLimit} from ${dateStr}`
646+
if (config?.FFlag_ShowSectionTimings) sectionDescription += ` [${timer(startTime)}]`
647+
648+
const section: TSection = {
649+
ID: thisSectionCode,
650+
name: 'This Year',
651+
showSettingName: 'showYearSection',
652+
sectionCode: thisSectionCode,
653+
description: sectionDescription,
654+
FAIconClass: 'fa-regular fa-calendar-days',
655+
sectionTitleColorPart: 'sidebarYearly',
656+
sectionFilename: thisFilename,
657+
sectionItems: items,
658+
generatedDate: new Date(),
659+
doneCounts: doneCountData,
660+
totalCount: items.length,
661+
actionButtons: [
662+
{
663+
actionName: 'addTask',
664+
actionPluginID: `${pluginJson['plugin.id']}`,
665+
tooltip: "Add a new task to this year's note",
666+
display: '<i class= "fa-regular fa-fw fa-circle-plus sidebarYearly" ></i> ',
667+
actionParam: thisFilename,
668+
postActionRefresh: ['Y'],
669+
formFields: thisYearFormFields,
670+
submitOnEnter: true,
671+
submitButtonText: 'Add & Close',
672+
},
673+
{
674+
actionName: 'addChecklist',
675+
actionPluginID: `${pluginJson['plugin.id']}`,
676+
tooltip: "Add a checklist item to this year's note",
677+
display: '<i class= "fa-regular fa-fw fa-square-plus sidebarYearly" ></i> ',
678+
actionParam: thisFilename,
679+
postActionRefresh: ['Y'],
680+
formFields: thisYearFormFields,
681+
submitOnEnter: true,
682+
submitButtonText: 'Add & Close',
683+
},
684+
{
685+
actionName: 'addTask',
686+
actionPluginID: `${pluginJson['plugin.id']}`,
687+
tooltip: "Add a new task to next year's note",
688+
display: '<i class= "fa-regular fa-fw fa-circle-arrow-right sidebarYearly" ></i> ',
689+
actionParam: nextPeriodFilename,
690+
formFields: nextYearFormFields,
691+
submitOnEnter: true,
692+
submitButtonText: 'Add & Close',
693+
},
694+
{
695+
actionName: 'addChecklist',
696+
actionPluginID: `${pluginJson['plugin.id']}`,
697+
tooltip: "Add a checklist item to next year's note",
698+
display: '<i class= "fa-regular fa-fw fa-square-arrow-right sidebarYearly" ></i> ',
699+
actionParam: nextPeriodFilename,
700+
formFields: nextYearFormFields,
701+
submitOnEnter: true,
702+
submitButtonText: 'Add & Close',
703+
},
704+
],
705+
isReferenced: false,
706+
}
707+
sections.push(section)
708+
709+
// If we want this separated from the referenced items, then form a second section
710+
if (config.separateSectionForReferencedNotes) {
711+
let items: Array<TSectionItem> = []
712+
const referencedSectionCode = `${thisSectionCode}_REF`
713+
if (useDemoData) {
714+
// No demo data
715+
} else {
716+
// Get list of open tasks/checklists from current yearly note (if it exists)
717+
if (sortedRefParas.length > 0) {
718+
// Iterate and write items for this section
719+
items = createSectionOpenItemsFromParas(sortedRefParas, referencedSectionCode)
720+
itemCount += items.length
721+
}
722+
}
723+
724+
// Add separate section (if there are any items found)
725+
const section: TSection = {
726+
ID: referencedSectionCode,
727+
name: '>This Year',
728+
showSettingName: 'showYearSection',
729+
sectionCode: thisSectionCode,
730+
description: `{count} scheduled to ${dateStr}`,
731+
FAIconClass: 'fa-regular fa-calendar-days',
732+
sectionTitleColorPart: 'sidebarYearly',
733+
sectionFilename: thisFilename,
734+
sectionItems: items,
735+
totalCount: items.length,
736+
generatedDate: new Date(),
737+
actionButtons: [],
738+
isReferenced: true,
739+
}
740+
sections.push(section)
741+
}
742+
743+
logDebug('getDataForDashboard', `- found ${itemCount} yearly items from ${dateStr} in ${timer(startTime)}`)
744+
return sections
745+
} catch (error) {
746+
logError('getDataForDashboard/year', `ERROR: ${error.message}`)
747+
return []
748+
}
749+
}
750+
565751
//----------------------------------------------------------------
566752

567753
/**

‎jgclark.Dashboard/src/types.js‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @flow
22
//-----------------------------------------------------------------------------
33
// Types for Dashboard code
4-
// Last updated 2025-11-30 for v2.3.2 by @jgclark
4+
// Last updated 2025-12-03 for v2.3.3 by @jgclark
55
//-----------------------------------------------------------------------------
66
// Types for Settings
77

@@ -105,6 +105,7 @@ export type TDashboardSettings = {
105105
showPrioritySection: boolean,
106106
showProjectSection: boolean,
107107
showQuarterSection: boolean,
108+
showYearSection: boolean,
108109
showSavedSearchSection: boolean, // Note: the SEARCH Section doesn't need a setting. This is for future use for SAVEDSEARCH section(s).
109110
showTimeBlockSection: boolean,
110111
showTodaySection: boolean,
@@ -135,7 +136,7 @@ export type TDashboardPluginSettings = {
135136
//-----------------------------------------------------------------------------
136137
// Other types
137138

138-
export type TSectionCode = 'DT' | 'DY' | 'DO' | 'W' | 'LW' | 'M' | 'Q' | 'TAG' | 'PRIORITY' | 'OVERDUE' | 'PROJ' | 'TB' | 'SEARCH' | 'SAVEDSEARCH' | 'INFO' // where DT = today, DY = yesterday, TAG = Tag, PROJ = Projects section, TB = Top Bar / TimeBlock
139+
export type TSectionCode = 'DT' | 'DY' | 'DO' | 'W' | 'LW' | 'M' | 'Q' | 'Y' | 'TAG' | 'PRIORITY' | 'OVERDUE' | 'PROJ' | 'TB' | 'SEARCH' | 'SAVEDSEARCH' | 'INFO' // where DT = today, DY = yesterday, TAG = Tag, PROJ = Projects section, TB = Top Bar / TimeBlock
139140
// Note: INFO is a new section code for v2.3.0 for testing.
140141
// Note: When adding a new section code, make sure to update the constants in constants.js and dashboardSettings.js files, and getSomeSectionsData in dataGeneration.js
141142

0 commit comments

Comments
 (0)