mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 04:51:31 +08:00 
			
		
		
		
	fix(server): week notes broken due to misuse of transactions
This commit is contained in:
		
							parent
							
								
									e946bde939
								
							
						
					
					
						commit
						1d58b285de
					
				| @ -6,7 +6,6 @@ import attributeService from "./attributes.js"; | |||||||
| import cloningService from "./cloning.js"; | import cloningService from "./cloning.js"; | ||||||
| import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||||
| import hoistedNoteService from "./hoisted_note.js"; | import hoistedNoteService from "./hoisted_note.js"; | ||||||
| import i18next from "i18next"; |  | ||||||
| import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js"; | import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js"; | ||||||
| import noteService from "./notes.js"; | import noteService from "./notes.js"; | ||||||
| import optionService from "./options.js"; | import optionService from "./options.js"; | ||||||
| @ -16,6 +15,7 @@ import searchContext from "../services/search/search_context.js"; | |||||||
| import searchService from "../services/search/services/search.js"; | import searchService from "../services/search/services/search.js"; | ||||||
| import sql from "./sql.js"; | import sql from "./sql.js"; | ||||||
| import { t } from "i18next"; | import { t } from "i18next"; | ||||||
|  | import { ordinal } from "./i18n.js"; | ||||||
| 
 | 
 | ||||||
| dayjs.extend(isSameOrAfter); | dayjs.extend(isSameOrAfter); | ||||||
| dayjs.extend(quarterOfYear); | dayjs.extend(quarterOfYear); | ||||||
| @ -67,24 +67,7 @@ function getTimeUnitReplacements(timeUnit: TimeUnit): string[] { | |||||||
|     return units.slice(0, index + 1).flatMap(unit => baseReplacements[unit]); |     return units.slice(0, index + 1).flatMap(unit => baseReplacements[unit]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function ordinal(date: Dayjs, lng: string) { | function getJournalNoteTitle( | ||||||
|     const localeMap: Record<string, string> = { |  | ||||||
|         cn: "zh-cn", |  | ||||||
|         tw: "zh-tw" |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     const dayjsLocale = localeMap[lng] || lng; |  | ||||||
| 
 |  | ||||||
|     try { |  | ||||||
|         await import(`dayjs/locale/${dayjsLocale}.js`); |  | ||||||
|     } catch (err) { |  | ||||||
|         console.warn(`Could not load locale ${dayjsLocale}`, err); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return dayjs(date).locale(dayjsLocale).format("Do"); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| async function getJournalNoteTitle( |  | ||||||
|     rootNote: BNote, |     rootNote: BNote, | ||||||
|     timeUnit: TimeUnit, |     timeUnit: TimeUnit, | ||||||
|     dateObj: Dayjs, |     dateObj: Dayjs, | ||||||
| @ -102,7 +85,7 @@ async function getJournalNoteTitle( | |||||||
|     const monthName = t(MONTH_TRANSLATION_IDS[dateObj.month()]); |     const monthName = t(MONTH_TRANSLATION_IDS[dateObj.month()]); | ||||||
|     const weekDay = t(WEEKDAY_TRANSLATION_IDS[dateObj.day()]); |     const weekDay = t(WEEKDAY_TRANSLATION_IDS[dateObj.day()]); | ||||||
|     const numberStr = number.toString(); |     const numberStr = number.toString(); | ||||||
|     const ordinalStr = await ordinal(dateObj, i18next.language); |     const ordinalStr = ordinal(dateObj); | ||||||
| 
 | 
 | ||||||
|     const allReplacements: Record<string, string> = { |     const allReplacements: Record<string, string> = { | ||||||
|         // Common date formats
 |         // Common date formats
 | ||||||
| @ -228,7 +211,7 @@ function getQuarterNumberStr(date: Dayjs) { | |||||||
|     return `${date.year()}-Q${date.quarter()}`; |     return `${date.year()}-Q${date.quarter()}`; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function getQuarterNote(quarterStr: string, _rootNote: BNote | null = null): Promise<BNote> { | function getQuarterNote(quarterStr: string, _rootNote: BNote | null = null): BNote { | ||||||
|     const rootNote = _rootNote || getRootCalendarNote(); |     const rootNote = _rootNote || getRootCalendarNote(); | ||||||
| 
 | 
 | ||||||
|     quarterStr = quarterStr.trim().substring(0, 7); |     quarterStr = quarterStr.trim().substring(0, 7); | ||||||
| @ -247,7 +230,7 @@ async function getQuarterNote(quarterStr: string, _rootNote: BNote | null = null | |||||||
|     const quarterStartDate = dayjs().year(parseInt(yearStr)).month(firstMonth).date(1); |     const quarterStartDate = dayjs().year(parseInt(yearStr)).month(firstMonth).date(1); | ||||||
| 
 | 
 | ||||||
|     const yearNote = getYearNote(yearStr, rootNote); |     const yearNote = getYearNote(yearStr, rootNote); | ||||||
|     const noteTitle = await getJournalNoteTitle( |     const noteTitle = getJournalNoteTitle( | ||||||
|         rootNote, "quarter", quarterStartDate, quarterNumber |         rootNote, "quarter", quarterStartDate, quarterNumber | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
| @ -269,7 +252,7 @@ async function getQuarterNote(quarterStr: string, _rootNote: BNote | null = null | |||||||
|     return quarterNote as unknown as BNote; |     return quarterNote as unknown as BNote; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function getMonthNote(dateStr: string, _rootNote: BNote | null = null): Promise<BNote> { | function getMonthNote(dateStr: string, _rootNote: BNote | null = null): BNote { | ||||||
|     const rootNote = _rootNote || getRootCalendarNote(); |     const rootNote = _rootNote || getRootCalendarNote(); | ||||||
| 
 | 
 | ||||||
|     const monthStr = dateStr.substring(0, 7); |     const monthStr = dateStr.substring(0, 7); | ||||||
| @ -286,12 +269,12 @@ async function getMonthNote(dateStr: string, _rootNote: BNote | null = null): Pr | |||||||
|     let monthParentNote; |     let monthParentNote; | ||||||
| 
 | 
 | ||||||
|     if (rootNote.hasLabel("enableQuarterNote")) { |     if (rootNote.hasLabel("enableQuarterNote")) { | ||||||
|         monthParentNote = await getQuarterNote(getQuarterNumberStr(dayjs(dateStr)), rootNote); |         monthParentNote = getQuarterNote(getQuarterNumberStr(dayjs(dateStr)), rootNote); | ||||||
|     } else { |     } else { | ||||||
|         monthParentNote = getYearNote(dateStr, rootNote); |         monthParentNote = getYearNote(dateStr, rootNote); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const noteTitle = await getJournalNoteTitle( |     const noteTitle = getJournalNoteTitle( | ||||||
|         rootNote, "month", dayjs(dateStr), parseInt(monthNumber) |         rootNote, "month", dayjs(dateStr), parseInt(monthNumber) | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
| @ -408,7 +391,7 @@ function getWeekFirstDayNote(dateStr: string, rootNote: BNote | null = null) { | |||||||
|  * @param _rootNote a {@link BNote} representing the calendar root, or {@code null} or not specified to use the default root calendar note. |  * @param _rootNote a {@link BNote} representing the calendar root, or {@code null} or not specified to use the default root calendar note. | ||||||
|  * @returns a Promise that resolves to the {@link BNote} corresponding to the week note. |  * @returns a Promise that resolves to the {@link BNote} corresponding to the week note. | ||||||
|  */ |  */ | ||||||
| async function getWeekNote(weekStr: string, _rootNote: BNote | null = null): Promise<BNote | null> { | function getWeekNote(weekStr: string, _rootNote: BNote | null = null): BNote | null { | ||||||
|     const rootNote = _rootNote || getRootCalendarNote(); |     const rootNote = _rootNote || getRootCalendarNote(); | ||||||
|     if (!rootNote.hasLabel("enableWeekNote")) { |     if (!rootNote.hasLabel("enableWeekNote")) { | ||||||
|         return null; |         return null; | ||||||
| @ -435,10 +418,10 @@ async function getWeekNote(weekStr: string, _rootNote: BNote | null = null): Pro | |||||||
|     const startMonth = startDate.month(); |     const startMonth = startDate.month(); | ||||||
|     const endMonth = endDate.month(); |     const endMonth = endDate.month(); | ||||||
| 
 | 
 | ||||||
|     const monthNote = await getMonthNote(startDate.format("YYYY-MM-DD"), rootNote); |     const monthNote = getMonthNote(startDate.format("YYYY-MM-DD"), rootNote); | ||||||
|     const noteTitle = await getJournalNoteTitle(rootNote, "week", startDate, weekNumber); |     const noteTitle = getJournalNoteTitle(rootNote, "week", startDate, weekNumber); | ||||||
| 
 | 
 | ||||||
|     sql.transactional(async () => { |     sql.transactional(() => { | ||||||
|         weekNote = createNote(monthNote, noteTitle); |         weekNote = createNote(monthNote, noteTitle); | ||||||
| 
 | 
 | ||||||
|         attributeService.createLabel(weekNote.noteId, WEEK_LABEL, weekStr); |         attributeService.createLabel(weekNote.noteId, WEEK_LABEL, weekStr); | ||||||
| @ -452,7 +435,7 @@ async function getWeekNote(weekStr: string, _rootNote: BNote | null = null): Pro | |||||||
| 
 | 
 | ||||||
|         // If the week spans different months, clone the week note in the other month as well
 |         // If the week spans different months, clone the week note in the other month as well
 | ||||||
|         if (startMonth !== endMonth) { |         if (startMonth !== endMonth) { | ||||||
|             const secondMonthNote = await getMonthNote(endDate.format("YYYY-MM-DD"), rootNote); |             const secondMonthNote = getMonthNote(endDate.format("YYYY-MM-DD"), rootNote); | ||||||
|             cloningService.cloneNoteToParentNote(weekNote.noteId, secondMonthNote.noteId); |             cloningService.cloneNoteToParentNote(weekNote.noteId, secondMonthNote.noteId); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| @ -460,7 +443,7 @@ async function getWeekNote(weekStr: string, _rootNote: BNote | null = null): Pro | |||||||
|     return weekNote as unknown as BNote; |     return weekNote as unknown as BNote; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function getDayNote(dateStr: string, _rootNote: BNote | null = null): Promise<BNote> { | function getDayNote(dateStr: string, _rootNote: BNote | null = null): BNote { | ||||||
|     const rootNote = _rootNote || getRootCalendarNote(); |     const rootNote = _rootNote || getRootCalendarNote(); | ||||||
| 
 | 
 | ||||||
|     dateStr = dateStr.trim().substring(0, 10); |     dateStr = dateStr.trim().substring(0, 10); | ||||||
| @ -476,13 +459,13 @@ async function getDayNote(dateStr: string, _rootNote: BNote | null = null): Prom | |||||||
|     let dateParentNote; |     let dateParentNote; | ||||||
| 
 | 
 | ||||||
|     if (rootNote.hasLabel("enableWeekNote")) { |     if (rootNote.hasLabel("enableWeekNote")) { | ||||||
|         dateParentNote = await getWeekNote(getWeekNumberStr(dayjs(dateStr)), rootNote); |         dateParentNote = getWeekNote(getWeekNumberStr(dayjs(dateStr)), rootNote); | ||||||
|     } else { |     } else { | ||||||
|         dateParentNote = await getMonthNote(dateStr, rootNote); |         dateParentNote = getMonthNote(dateStr, rootNote); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const dayNumber = dateStr.substring(8, 10); |     const dayNumber = dateStr.substring(8, 10); | ||||||
|     const noteTitle = await getJournalNoteTitle( |     const noteTitle = getJournalNoteTitle( | ||||||
|         rootNote, "day", dayjs(dateStr), parseInt(dayNumber) |         rootNote, "day", dayjs(dateStr), parseInt(dayNumber) | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,20 +5,43 @@ import { join } from "path"; | |||||||
| import { getResourceDir } from "./utils.js"; | import { getResourceDir } from "./utils.js"; | ||||||
| import hidden_subtree from "./hidden_subtree.js"; | import hidden_subtree from "./hidden_subtree.js"; | ||||||
| import { LOCALES, type Locale } from "@triliumnext/commons"; | import { LOCALES, type Locale } from "@triliumnext/commons"; | ||||||
|  | import dayjs, { Dayjs } from "dayjs"; | ||||||
|  | 
 | ||||||
|  | const DAYJS_LOCALE_MAP: Record<string, string> = { | ||||||
|  |     cn: "zh-cn", | ||||||
|  |     tw: "zh-tw" | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | let dayjsLocale: string; | ||||||
| 
 | 
 | ||||||
| export async function initializeTranslations() { | export async function initializeTranslations() { | ||||||
|     const resourceDir = getResourceDir(); |     const resourceDir = getResourceDir(); | ||||||
|     const Backend = (await import("i18next-fs-backend")).default; |     const Backend = (await import("i18next-fs-backend")).default; | ||||||
|  |     const locale = getCurrentLanguage(); | ||||||
| 
 | 
 | ||||||
|     // Initialize translations
 |     // Initialize translations
 | ||||||
|     await i18next.use(Backend).init({ |     await i18next.use(Backend).init({ | ||||||
|         lng: getCurrentLanguage(), |         lng: locale, | ||||||
|         fallbackLng: "en", |         fallbackLng: "en", | ||||||
|         ns: "server", |         ns: "server", | ||||||
|         backend: { |         backend: { | ||||||
|             loadPath: join(resourceDir, "assets/translations/{{lng}}/{{ns}}.json") |             loadPath: join(resourceDir, "assets/translations/{{lng}}/{{ns}}.json") | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     // Initialize dayjs locale.
 | ||||||
|  |     dayjsLocale = DAYJS_LOCALE_MAP[locale] ?? locale; | ||||||
|  |     try { | ||||||
|  |         await import(`dayjs/locale/${dayjsLocale}.js`); | ||||||
|  |     } catch (err) { | ||||||
|  |         console.warn(`Could not load locale ${dayjsLocale}`, err); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function ordinal(date: Dayjs) { | ||||||
|  |     return dayjs(date) | ||||||
|  |         .locale(dayjsLocale) | ||||||
|  |         .format("Do"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function getLocales(): Locale[] { | export function getLocales(): Locale[] { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran