diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml index e67673cc..1982889f 100644 --- a/.github/workflows/close-stale-issues.yml +++ b/.github/workflows/close-stale-issues.yml @@ -24,7 +24,7 @@ jobs: in 15 days from now. Your efforts are greatly appreciated, and we value your contributions to the project. stale-issue-label: no-issue-activity - days-before-stale: 90 + days-before-stale: 120 days-before-close: 15 env: REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/release/app/package.json b/release/app/package.json index ae5eceba..c357d120 100644 --- a/release/app/package.json +++ b/release/app/package.json @@ -1,6 +1,6 @@ { "name": "sleek", - "version": "2.0.12-rc.2", + "version": "2.0.12-rc.3", "description": "todo.txt manager for Linux, Windows and MacOS, free and open-source (FOSS)", "synopsis": "todo.txt manager for Linux, Windows and MacOS, free and open-source (FOSS)", "keywords": [ diff --git a/src/locales/cs.json b/src/locales/cs.json index 620f4bc1..f2486c3f 100644 --- a/src/locales/cs.json +++ b/src/locales/cs.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "příští týden", "drawer.attributes.yesterday": "včera", "drawer.attributes.lastWeek": "minulý týden", + "drawer.attributes.thisWeek": "tento týden", + "drawer.attributes.thisMonth": "tento měsíc", "drawer.sorting.fileSorting": "Seřadit úkoly podle pořadí v souboru", "shared.attributeMapping.t": "Termín", "shared.attributeMapping.due": "Termín splnění", diff --git a/src/locales/de.json b/src/locales/de.json index 08bdea4c..0adb8013 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "nächste Woche", "drawer.attributes.yesterday": "gestern", "drawer.attributes.lastWeek": "letzte Woche", + "drawer.attributes.thisWeek": "diese Woche", + "drawer.attributes.thisMonth": "diesen Monat", "drawer.sorting.fileSorting": "Aufgaben in der Reihenfolge der Datei anordnen", "shared.attributeMapping.t": "Schwellenwertdatum", "shared.attributeMapping.due": "Fälligkeitsdatum", diff --git a/src/locales/en-gb.json b/src/locales/en-gb.json index 25a9183a..fdd11b15 100644 --- a/src/locales/en-gb.json +++ b/src/locales/en-gb.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "next week", "drawer.attributes.yesterday": "yesterday", "drawer.attributes.lastWeek": "last week", + "drawer.attributes.thisWeek": "this week", + "drawer.attributes.thisMonth": "this month", "drawer.sorting.fileSorting": "Order todos as they appear in the file", "shared.attributeMapping.t": "Threshold date", "shared.attributeMapping.due": "Due date", diff --git a/src/locales/en.json b/src/locales/en.json index 25a9183a..fdd11b15 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "next week", "drawer.attributes.yesterday": "yesterday", "drawer.attributes.lastWeek": "last week", + "drawer.attributes.thisWeek": "this week", + "drawer.attributes.thisMonth": "this month", "drawer.sorting.fileSorting": "Order todos as they appear in the file", "shared.attributeMapping.t": "Threshold date", "shared.attributeMapping.due": "Due date", diff --git a/src/locales/es.json b/src/locales/es.json index 9424fc62..157f18f0 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -39,6 +39,8 @@ "drawer.attributes.nextWeek": "próxima semana", "drawer.attributes.yesterday": "ayer", "drawer.attributes.lastWeek": "la semana pasada", + "drawer.attributes.thisWeek": "esta semana", + "drawer.attributes.thisMonth": "este mes", "drawer.sorting.fileSorting": "Ordenar tareas como aparecen en el archivo", "shared.attributeMapping.t": "Fecha umbral", "shared.attributeMapping.due": "Fecha de vencimiento", diff --git a/src/locales/fr.json b/src/locales/fr.json index 365c620c..167fb412 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "la semaine prochaine", "drawer.attributes.yesterday": "hier", "drawer.attributes.lastWeek": "la semaine dernière", + "drawer.attributes.thisWeek": "cette semaine", + "drawer.attributes.thisMonth": "ce mois", "drawer.sorting.fileSorting": "Classer les tâches comme elles apparaissent dans le fichier", "shared.attributeMapping.t": "Date limite", "shared.attributeMapping.due": "Date d'échéance", diff --git a/src/locales/hi.json b/src/locales/hi.json index 6b3f9a4d..9cd142d9 100644 --- a/src/locales/hi.json +++ b/src/locales/hi.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "अगले हफ्ते", "drawer.attributes.yesterday": "कल", "drawer.attributes.lastWeek": "पिछले हफ्ते", + "drawer.attributes.thisWeek": "इस सप्ताह", + "drawer.attributes.thisMonth": "इस महीने", "drawer.sorting.fileSorting": "वे दिखाई देते हैं जैसे कि वे फ़ाइल में हैं, कार्य क्रमबद्ध करें", "shared.attributeMapping.t": "सीमा तिथि", "shared.attributeMapping.due": "समापन तिथि", diff --git a/src/locales/hu.json b/src/locales/hu.json index bc0b082d..7e9fcb3b 100644 --- a/src/locales/hu.json +++ b/src/locales/hu.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "jövő hét", "drawer.attributes.yesterday": "tegnap", "drawer.attributes.lastWeek": "múlt hét", + "drawer.attributes.thisWeek": "ez a hét", + "drawer.attributes.thisMonth": "ez a hónap", "drawer.sorting.fileSorting": "Feladatok rendezése, ahogy megjelennek a fájlban", "shared.attributeMapping.t": "Hátralévő dátum", "shared.attributeMapping.due": "Határidő", diff --git a/src/locales/it.json b/src/locales/it.json index 2f64168b..674761fe 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "la prossima settimana", "drawer.attributes.yesterday": "ieri", "drawer.attributes.lastWeek": "la settimana scorsa", + "drawer.attributes.thisWeek": "questa settimana", + "drawer.attributes.thisMonth": "questo mese", "drawer.sorting.fileSorting": "Ordina i compiti come appaiono nel file", "shared.attributeMapping.t": "Data di scadenza", "shared.attributeMapping.due": "Data di scadenza", diff --git a/src/locales/jp.json b/src/locales/jp.json index 3298c722..96e1a8ba 100644 --- a/src/locales/jp.json +++ b/src/locales/jp.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "来週", "drawer.attributes.yesterday": "昨日", "drawer.attributes.lastWeek": "先週", + "drawer.attributes.thisWeek": "今週", + "drawer.attributes.thisMonth": "今月", "drawer.sorting.fileSorting": "ファイルに表示される順にタスクを並べ替え", "shared.attributeMapping.t": "期限日", "shared.attributeMapping.due": "期日", diff --git a/src/locales/ko.json b/src/locales/ko.json index 11e24e86..81794e70 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -39,7 +39,9 @@ "drawer.attributes.tomorrow": "내일", "drawer.attributes.nextWeek": "다음 주", "drawer.attributes.yesterday": "어제", - "drawer.attributes.lastWeek": "지난 주", + "drawer.attributes.lastWeek": "지난 주", + "drawer.attributes.thisWeek": "이번 주", + "drawer.attributes.thisMonth": "이번 달", "drawer.sorting.fileSorting": "파일에 나타나는 대로 작업 정렬", "shared.attributeMapping.t": "임계 날짜", "shared.attributeMapping.due": "마감일", diff --git a/src/locales/pl.json b/src/locales/pl.json index ed1f9a6c..21b23d5a 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "następny tydzień", "drawer.attributes.yesterday": "wczoraj", "drawer.attributes.lastWeek": "ostatni tydzień", + "drawer.attributes.thisWeek": "w tym tygodniu", + "drawer.attributes.thisMonth": "w tym miesiącu", "drawer.sorting.fileSorting": "Sortuj zadania tak, jak występują w pliku", "shared.attributeMapping.t": "Data progowa", "shared.attributeMapping.due": "Termin", diff --git a/src/locales/pt.json b/src/locales/pt.json index 7aa5c0f7..df19d2ff 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "próxima semana", "drawer.attributes.yesterday": "ontem", "drawer.attributes.lastWeek": "semana passada", + "drawer.attributes.thisWeek": "esta semana", + "drawer.attributes.thisMonth": "este mês", "drawer.sorting.fileSorting": "Ordenar tarefas como aparecem no ficheiro", "shared.attributeMapping.t": "Data de limite", "shared.attributeMapping.due": "Data de vencimento", diff --git a/src/locales/ru.json b/src/locales/ru.json index 0b8a0456..88a358a7 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -39,7 +39,9 @@ "drawer.attributes.tomorrow": "завтра", "drawer.attributes.nextWeek": "на следующей неделе", "drawer.attributes.yesterday": "вчера", - "drawer.attributes.lastWeek": "на прошлой неделе", + "drawer.attributes.lastWeek": "на прошлой неделе", + "drawer.attributes.thisWeek": "на этой неделе", + "drawer.attributes.thisMonth": "в этом месяце", "drawer.sorting.fileSorting": "Сортировать задачи в порядке их появления в файле", "shared.attributeMapping.t": "Дата порога", "shared.attributeMapping.due": "Дата выполнения", diff --git a/src/locales/tr.json b/src/locales/tr.json index 51da9cd0..b3793878 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -40,6 +40,8 @@ "drawer.attributes.nextWeek": "на следующей неделе", "drawer.attributes.yesterday": "вчера", "drawer.attributes.lastWeek": "на прошлой неделе", + "drawer.attributes.thisWeek": "bu hafta", + "drawer.attributes.thisMonth": "bu ay", "drawer.sorting.fileSorting": "Görevleri dosyada göründükleri sıraya göre sırala", "shared.attributeMapping.t": "Eşik tarihi", "shared.attributeMapping.due": "Bitiş tarihi", diff --git a/src/locales/zh.json b/src/locales/zh.json index 990a3fa7..b89f9cf7 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -39,7 +39,9 @@ "drawer.attributes.tomorrow": "明天", "drawer.attributes.nextWeek": "下周", "drawer.attributes.yesterday": "昨天", - "drawer.attributes.lastWeek": "上周", + "drawer.attributes.lastWeek": "上周", + "drawer.attributes.thisWeek": "本周", + "drawer.attributes.thisMonth": "本月", "drawer.sorting.fileSorting": "按照它们在文件中出现的顺序排序任务", "shared.attributeMapping.t": "阈值日期", "shared.attributeMapping.due": "截止日期", diff --git a/src/renderer/Dialog/RecurrencePicker.tsx b/src/renderer/Dialog/RecurrencePicker.tsx index 87e62e96..7db452ed 100644 --- a/src/renderer/Dialog/RecurrencePicker.tsx +++ b/src/renderer/Dialog/RecurrencePicker.tsx @@ -53,7 +53,6 @@ const RecurrencePicker: React.FC = ({ const getInterval = (recurrence) => recurrence ? recurrence.match(/[a-zA-Z]+/) : null; const getAmount = (recurrence) => recurrence ? recurrence.match(/\d+/) : null; const getStrictIndicator = (recurrence: string | null) => !!recurrence?.startsWith('+'); - setStrictRecurrence(getStrictIndicator(recurrence)); setInterval(getInterval(recurrence)); setAmount(getAmount(recurrence)); diff --git a/src/renderer/Drawer/Attributes.tsx b/src/renderer/Drawer/Attributes.tsx index 92b9c497..f565b500 100644 --- a/src/renderer/Drawer/Attributes.tsx +++ b/src/renderer/Drawer/Attributes.tsx @@ -12,7 +12,6 @@ import { withTranslation, WithTranslation } from 'react-i18next'; import { i18n } from '../Settings/LanguageSelector'; import './Attributes.scss'; - const { store } = window.api; interface DrawerAttributesProps extends WithTranslation { @@ -31,42 +30,52 @@ const DrawerAttributes: React.FC = memo(({ const firstTabbableElementRef = useRef(null); const [hovered, setHovered] = useState(null); + const isAttributesEmpty = useMemo( + () => !attributes || Object.values(attributes).every((attribute) => !Object.keys(attribute).length), + [attributes] + ); + const preprocessAttributes = (attributeKey, attributes) => { if (!attributes) { return null; } - const isDate: boolean = ['due', 't', 'completed', 'created'].includes(attributeKey); + const isDate = ['due', 't', 'completed', 'created'].includes(attributeKey); const processedAttributes = {}; Object.keys(attributes).forEach((key) => { if (attributes[key]) { const count = attributes[key].count; - const formattedValue = settings.useHumanFriendlyDates && isDate ? friendlyDate(key, t) : key; - - if (!processedAttributes[formattedValue]) { - processedAttributes[formattedValue] = { - key: attributeKey, - name: formattedValue, - count, - notify: attributes[key].notify, - aggregatedValues: [key] - }; - } else { - processedAttributes[formattedValue].count += count; - processedAttributes[formattedValue].notify = processedAttributes[formattedValue].notify || attributes[key].notify; - processedAttributes[formattedValue].aggregatedValues.push(key); - } + const formattedValues = settings.useHumanFriendlyDates && isDate ? friendlyDate(key, settings.language, t) : [key]; + + formattedValues.forEach((formattedValue) => { + if (!processedAttributes[formattedValue]) { + processedAttributes[formattedValue] = { + key: attributeKey, + name: formattedValue, + count, + notify: attributes[key].notify, + aggregatedValues: [key] + }; + } else { + processedAttributes[formattedValue].count += count; + processedAttributes[formattedValue].notify = processedAttributes[formattedValue].notify || attributes[key].notify; + processedAttributes[formattedValue].aggregatedValues.push(key); + } + }); } }); - return processedAttributes; - }; + const sortedAttributes = Object.fromEntries( + Object.entries(processedAttributes).sort(([, a], [, b]) => { + const lastDateA = a.aggregatedValues.length > 0 ? a.aggregatedValues[a.aggregatedValues.length - 1] : 0; + const lastDateB = b.aggregatedValues.length > 0 ? b.aggregatedValues[b.aggregatedValues.length - 1] : 0; + return new Date(lastDateA).getTime() - new Date(lastDateB).getTime(); + }) + ); - const isAttributesEmpty = useMemo( - () => !attributes || Object.values(attributes).every((attribute) => !Object.keys(attribute).length), - [attributes] - ); + return sortedAttributes; + }; const handleAccordionToggle = (index: number) => { const updatedAccordionOpenState = settings.accordionOpenState; @@ -143,8 +152,8 @@ const DrawerAttributes: React.FC = memo(({ return (
{!isAttributesEmpty ? ( - Object.keys(attributes).map((key, index) => { + Object.keys(attributes).map((key, index) => { const preprocessedAttributes: Attributes = preprocessAttributes(key, attributes[key]); const attributeHeadline: string = translatedAttributes(t)[key]; diff --git a/src/renderer/Grid/DatePickerInline.tsx b/src/renderer/Grid/DatePickerInline.tsx index 8155c621..52a461bc 100644 --- a/src/renderer/Grid/DatePickerInline.tsx +++ b/src/renderer/Grid/DatePickerInline.tsx @@ -4,16 +4,10 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import Button from '@mui/material/Button'; import Chip from '@mui/material/Chip'; import Badge from '@mui/material/Badge'; -import { handleFilterSelect } from '../Shared'; +import { handleFilterSelect, friendlyDate } from '../Shared'; import { withTranslation } from 'react-i18next'; import { i18n } from '../Settings/LanguageSelector'; import dayjs from 'dayjs'; -import relativeTime from 'dayjs/plugin/relativeTime'; -import duration from 'dayjs/plugin/duration'; -import calendar from 'dayjs/plugin/calendar'; -dayjs.extend(relativeTime); -dayjs.extend(duration); -dayjs.extend(calendar); const { ipcRenderer } = window.api; @@ -37,19 +31,6 @@ const DatePickerInline: React.FC = ({ const [open, setOpen] = useState(false); const chipText = type === 'due' ? "due:" : type === 't' ? "t:" : null; - dayjs.locale(settings.language); - - const friendlyDate = (value) => dayjs(value).calendar(null, { - sameDay: `[${t(`drawer.attributes.today`)}]`, - nextDay: `[${t(`drawer.attributes.tomorrow`)}]`, - nextWeek: `[${t(`drawer.attributes.nextWeek`)}]`, - lastDay: `[${t(`drawer.attributes.yesterday`)}]`, - lastWeek: `[${t(`drawer.attributes.lastWeek`)}]`, - sameElse: function () { - return dayjs(this).fromNow(); - } - }); - const handleChange = (date: dayjs.Dayjs | null) => { try { ipcRenderer.send('writeTodoToFile', todoObject.id, todoObject.string, false, type, dayjs(date).format('YYYY-MM-DD')); @@ -74,8 +55,12 @@ const DatePickerInline: React.FC = ({ const ButtonField = ({ ...props }) => { const { disabled, InputProps: { ref } = {}, inputProps: { 'aria-label': ariaLabel } = {} } = props; const mustNotify = (type === 'due') ? !todoObject?.notify : true; - const formattedValue = settings.useHumanFriendlyDates && dayjs(date).isValid() ? friendlyDate(date, settings.language) : date; - const selected = filters && type !== null && (filters[type as keyof Filters] || []).some((filter: Filter) => filter.name === formattedValue); + const formattedValue = settings.useHumanFriendlyDates && dayjs(date).isValid() ? friendlyDate(date, settings.language, t)[0] : date; + + const selected = filters && type !== null && (filters[type as keyof Filters] || []).some((filter: Filter) => { + return filter.values.includes(date); + }); + return (