diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 4a7ea303..00000000
--- a/.editorconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-root = true
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
-
-[*.md]
-trim_trailing_whitespace = false
diff --git a/.erb/configs/.eslintrc b/.erb/configs/.eslintrc
deleted file mode 100644
index 83dd1e44..00000000
--- a/.erb/configs/.eslintrc
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "rules": {
- "no-console": "off",
- "global-require": "off",
- "import/no-dynamic-require": "off"
- }
-}
\ No newline at end of file
diff --git a/.erb/configs/webpack.config.eslint.ts b/.erb/configs/webpack.config.eslint.ts
deleted file mode 100644
index af7ab2a9..00000000
--- a/.erb/configs/webpack.config.eslint.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-/* eslint import/no-unresolved: off, import/no-self-import: off */
-
-module.exports = require('./webpack.config.renderer.dev').default;
\ No newline at end of file
diff --git a/.erb/configs/webpack.config.main.prod.ts b/.erb/configs/webpack.config.main.prod.ts
index 747c1513..e4309c99 100644
--- a/.erb/configs/webpack.config.main.prod.ts
+++ b/.erb/configs/webpack.config.main.prod.ts
@@ -35,6 +35,10 @@ const configuration: webpack.Configuration = {
},
},
+ resolve: {
+ extensions: ['.tsx', '.ts', '.js'],
+ },
+
optimization: {
minimizer: [
new TerserPlugin({
diff --git a/.erb/scripts/.eslintrc b/.erb/scripts/.eslintrc
deleted file mode 100644
index 35dc618d..00000000
--- a/.erb/scripts/.eslintrc
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "rules": {
- "no-console": "off",
- "global-require": "off",
- "import/no-dynamic-require": "off",
- "import/no-extraneous-dependencies": "off"
- }
-}
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 16585b65..00000000
--- a/.eslintignore
+++ /dev/null
@@ -1,33 +0,0 @@
-# Logs
-logs
-*.log
-
-# Runtime data
-pids
-*.pid
-*.seed
-
-# Coverage directory used by tools like istanbul
-coverage
-.eslintcache
-
-# Dependency directory
-# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
-node_modules
-
-# OSX
-.DS_Store
-
-release/app/dist
-release/build
-.erb/dll
-
-.idea
-npm-debug.log.*
-*.css.d.ts
-*.sass.d.ts
-*.scss.d.ts
-
-# eslint ignores hidden directories by default:
-# https://github.com/eslint/eslint/issues/8429
-!.erb
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index aa8d5860..00000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,37 +0,0 @@
-module.exports = {
- extends: 'erb',
- plugins: ['@typescript-eslint'],
- rules: {
- // A temporary hack related to IDE not resolving correct package.json
- 'import/no-extraneous-dependencies': 'off',
- 'react/react-in-jsx-scope': 'off',
- 'react/jsx-filename-extension': 'off',
- 'import/extensions': 'off',
- 'import/no-unresolved': 'off',
- 'import/no-import-module-exports': 'off',
- 'no-shadow': 'off',
- '@typescript-eslint/no-shadow': 'error',
- 'no-unused-vars': 'off',
- '@typescript-eslint/no-unused-vars': 'error',
- },
- parserOptions: {
- ecmaVersion: 2020,
- sourceType: 'module',
- project: './tsconfig.json',
- tsconfigRootDir: __dirname,
- createDefaultProgram: true,
- },
- settings: {
- 'import/resolver': {
- // See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below
- node: {},
- webpack: {
- config: require.resolve('./.erb/configs/webpack.config.eslint.ts'),
- },
- typescript: {},
- },
- 'import/parsers': {
- '@typescript-eslint/parser': ['.ts', '.tsx'],
- },
- },
-};
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 20570f2f..00000000
--- a/.gitattributes
+++ /dev/null
@@ -1,12 +0,0 @@
-* text eol=lf
-*.exe binary
-*.png binary
-*.jpg binary
-*.jpeg binary
-*.ico binary
-*.icns binary
-*.eot binary
-*.otf binary
-*.ttf binary
-*.woff binary
-*.woff2 binary
diff --git a/SECURITY.md b/SECURITY.md
index e109eda5..61e61692 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -12,4 +12,4 @@ The following versions of sleek are provided with security updates.
## Reporting a Vulnerability
-If you find a vulnerability in sleek, please send as much detail as possible to ransome@duck.com.
\ No newline at end of file
+If you find a vulnerability in sleek, please send as much detail as possible to ransome@mailbox.org.
\ No newline at end of file
diff --git a/assets/architecture.drawio b/assets/architecture.drawio
deleted file mode 100644
index 9295c7f5..00000000
--- a/assets/architecture.drawio
+++ /dev/null
@@ -1,154 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/flatpak/com.github.ransome1.sleek.appdata.xml b/flatpak/com.github.ransome1.sleek.appdata.xml
index 10594c3e..b111a764 100755
--- a/flatpak/com.github.ransome1.sleek.appdata.xml
+++ b/flatpak/com.github.ransome1.sleek.appdata.xml
@@ -9,7 +9,7 @@
Robin Ahle
-
+
https://github.com/ransome1/sleek
https://github.com/ransome1/sleek/issues
diff --git a/flatpak/com.github.ransome1.sleek.desktop b/flatpak/com.github.ransome1.sleek.desktop
index 02ea2f5e..36569b08 100755
--- a/flatpak/com.github.ransome1.sleek.desktop
+++ b/flatpak/com.github.ransome1.sleek.desktop
@@ -1,5 +1,5 @@
[Desktop Entry]
-Version=2.0.4-rc.3
+Version=2.0.4-rc.4
Name=sleek
Exec=sleek
Type=Application
diff --git a/package.json b/package.json
index 23b59a9b..f740f7ca 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "sleek",
- "version": "2.0.4-rc.3",
+ "version": "2.0.4-rc.4",
"main": "./src/main/main.tsx",
"scripts": {
"build": "concurrently \"yarn run peggy\" \"yarn run build:main\" \"yarn run build:renderer\"",
@@ -90,15 +90,15 @@
"sugar": "^2.0.6"
},
"devDependencies": {
- "@electron/notarize": "^1.2.3",
+ "@electron/notarize": "^2.2.0",
"@electron/rebuild": "^3.2.13",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"@svgr/webpack": "^8.0.1",
"@teamsupercell/typings-for-css-modules-loader": "^2.5.2",
- "@testing-library/jest-dom": "^5.16.5",
+ "@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.0.0",
"@types/jest": "^29.5.2",
- "@types/node": "20.2.5",
+ "@types/node": "20.10.5",
"@types/react": "^18.2.8",
"@types/react-dom": "^18.2.4",
"@types/react-test-renderer": "^18.0.0",
@@ -119,7 +119,7 @@
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"mini-css-extract-plugin": "^2.7.6",
- "prettier": "^2.8.8",
+ "prettier": "^3.1.1",
"react-refresh": "^0.14.0",
"react-test-renderer": "^18.2.0",
"rimraf": "^5.0.1",
diff --git a/release/app/package.json b/release/app/package.json
index 975f2371..567d46d1 100644
--- a/release/app/package.json
+++ b/release/app/package.json
@@ -1,6 +1,6 @@
{
"name": "sleek",
- "version": "2.0.4-rc.3",
+ "version": "2.0.4-rc.4",
"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": [
@@ -18,7 +18,7 @@
"type": "git",
"url": "https://github.com/ransome1/sleek.git"
},
- "author": "Robin Ahle ",
+ "author": "Robin Ahle ",
"copyright": "Copyright © 2023 ${author}",
"license": "MIT",
"main": "./dist/main/main.js",
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index ca62142c..1f38ecaf 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -1,6 +1,6 @@
name: sleek
base: core20
-version: "2.0.4-rc.3"
+version: "2.0.4-rc.4"
summary: todo.txt manager for Linux, free and open-source (FOSS)
description: |
sleek is an open-source (FOSS) todo manager based on the todo.txt syntax. Stripped down to only the most necessary features, and with a clean and simple interface, sleek aims to help you focus on getting things done.
diff --git a/src/__tests__/__mock__/recurrence.txt b/src/__tests__/__mock__/recurrence.txt
index c3b5fbdc..9da1efd0 100644
--- a/src/__tests__/__mock__/recurrence.txt
+++ b/src/__tests__/__mock__/recurrence.txt
@@ -1,15 +1,15 @@
-2023-12-19 Line 1 rec:1d due:2023-12-20
-2023-12-19 Line 1 rec:w due:2023-12-26
-2023-12-19 Line 1 rec:2m due:2024-02-19
-2023-12-19 Line 1 rec:+1d due:2023-12-21
-2023-12-19 Line 1 rec:7w due:2024-02-06
-2023-12-19 Line 1 due:2023-07-24 rec:+1b
-2023-12-19 taxes are due in one year t:2022-03-30 due:2022-04-30 rec:+1y
-2023-12-19 Water plants @home +quick due:2023-12-26 t:2023-12-16 rec:1w
-2023-12-19 Line 1 rec:+1d t:2023-09-20
-2023-12-19 Line 1 rec:1d pri:A due:2023-12-20
-2023-12-19 (A) Do something rec:d t:2023-12-20 @SomeContext
-2023-12-19 Do something rec:0d
-2023-12-19 Do something rec:0d due:2023-12-19
-2023-12-19 Do something rec:0d due:2023-12-19 t:2023-12-19
\ No newline at end of file
+2023-12-23 Line 1 rec:1d due:2023-12-24
+2023-12-23 Line 1 rec:w due:2023-12-30
+2023-12-23 Line 1 rec:2m due:2024-02-23
+2023-12-23 Line 1 rec:+1d due:2023-12-25
+2023-12-23 Line 1 rec:7w due:2024-02-10
+2023-12-23 Line 1 due:2023-07-24 rec:+1b
+2023-12-23 taxes are due in one year t:2022-03-30 due:2022-04-30 rec:+1y
+2023-12-23 Water plants @home +quick due:2023-12-30 t:2023-12-20 rec:1w
+2023-12-23 Line 1 rec:+1d t:2023-09-20
+2023-12-23 Line 1 rec:1d pri:A due:2023-12-24
+2023-12-23 (A) Do something rec:d t:2023-12-24 @SomeContext
+2023-12-23 Do something rec:0d
+2023-12-23 Do something rec:0d due:2023-12-23
+2023-12-23 Do something rec:0d due:2023-12-23 t:2023-12-23
\ No newline at end of file
diff --git a/src/__tests__/main/Write.tsx b/src/__tests__/main/Write.tsx
index 61680548..5603bbdf 100644
--- a/src/__tests__/main/Write.tsx
+++ b/src/__tests__/main/Write.tsx
@@ -98,9 +98,7 @@ describe('Writing to file', () => {
test('should append 3 new lines at the end of the file', async () => {
const originalGet = configStorage.get;
configStorage.get = (key: string) => {
- if(key === 'multilineTextField') {
- return true;
- } else if(key === 'useMultilineForBulkTodoCreation') {
+ if(key === 'bulkTodoCreation') {
return true;
}
return originalGet.call(configStorage, key);
@@ -117,9 +115,7 @@ describe('Writing to file', () => {
test('should update a specific line and append 2 lines to the updated line', async () => {
const originalGet = configStorage.get;
configStorage.get = (key: string) => {
- if(key === 'multilineTextField') {
- return true;
- } else if(key === 'useMultilineForBulkTodoCreation') {
+ if(key === 'bulkTodoCreation') {
return true;
}
return originalGet.call(configStorage, key);
@@ -136,9 +132,7 @@ describe('Writing to file', () => {
test('should append a multi line todo', async () => {
const originalGet = configStorage.get;
configStorage.get = (key: string) => {
- if(key === 'multilineTextField') {
- return true;
- } else if(key === 'useMultilineForBulkTodoCreation') {
+ if(key === 'bulkTodoCreation') {
return false;
}
return originalGet.call(configStorage, key);
@@ -155,9 +149,7 @@ describe('Writing to file', () => {
test('should update line with a multi line todo', async () => {
const originalGet = configStorage.get;
configStorage.get = (key: string) => {
- if(key === 'multilineTextField') {
- return true;
- } else if(key === 'useMultilineForBulkTodoCreation') {
+ if(key === 'bulkTodoCreation') {
return false;
}
return originalGet.call(configStorage, key);
diff --git a/src/locales/cs.json b/src/locales/cs.json
index 50d5efdc..ca6a6015 100644
--- a/src/locales/cs.json
+++ b/src/locales/cs.json
@@ -21,7 +21,7 @@
"settings.dark": "Tmavé",
"settings.language": "Jazyk",
"settings.notificationThreshold": "Hranice oznámení",
- "settings.useMultilineForBulkTodoCreation": "Každý řádek v textovém poli vytvoří samostatnou položku úkolu",
+ "settings.bulkTodoCreation": "Každý řádek v textovém poli vytvoří samostatnou položku úkolu",
"settings.matomo": "Povolit analýzu Matomo",
"drawer.tabs.attributes": "Atributy",
"drawer.tabs.filters": "Filtry",
diff --git a/src/locales/de.json b/src/locales/de.json
index d4c6ee00..feda98c1 100644
--- a/src/locales/de.json
+++ b/src/locales/de.json
@@ -21,7 +21,7 @@
"settings.dark": "Dunkel",
"settings.language": "Sprache",
"settings.notificationThreshold": "Benachrichtigungsschwelle",
- "settings.useMultilineForBulkTodoCreation": "Jede Zeile im Textfeld erstellt eine separate Todo",
+ "settings.bulkTodoCreation": "Jede Zeile im Textfeld erstellt eine separate Todo",
"settings.matomo": "Matomo-Analyse erlauben",
"drawer.tabs.attributes": "Attribute",
"drawer.tabs.filters": "Filter",
diff --git a/src/locales/en-gb.json b/src/locales/en-gb.json
index a02c588e..3648d754 100644
--- a/src/locales/en-gb.json
+++ b/src/locales/en-gb.json
@@ -21,7 +21,7 @@
"settings.dark": "Dark",
"settings.language": "Language",
"settings.notificationThreshold": "Notification threshold",
- "settings.useMultilineForBulkTodoCreation": "Each row in the text field creates a separate to-do item",
+ "settings.bulkTodoCreation": "Each row in the text field creates a separate to-do item",
"settings.matomo": "Allow Matomo Analysis",
"drawer.tabs.attributes": "Attributes",
"drawer.tabs.filters": "Filters",
diff --git a/src/locales/en.json b/src/locales/en.json
index a02c588e..3648d754 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -21,7 +21,7 @@
"settings.dark": "Dark",
"settings.language": "Language",
"settings.notificationThreshold": "Notification threshold",
- "settings.useMultilineForBulkTodoCreation": "Each row in the text field creates a separate to-do item",
+ "settings.bulkTodoCreation": "Each row in the text field creates a separate to-do item",
"settings.matomo": "Allow Matomo Analysis",
"drawer.tabs.attributes": "Attributes",
"drawer.tabs.filters": "Filters",
diff --git a/src/locales/es.json b/src/locales/es.json
index 3ed6c50d..3132b3f3 100644
--- a/src/locales/es.json
+++ b/src/locales/es.json
@@ -21,7 +21,7 @@
"settings.dark": "Oscuro",
"settings.language": "Idioma",
"settings.notificationThreshold": "Umbral de notificación",
- "settings.useMultilineForBulkTodoCreation": "Cada línea en el campo de texto crea un elemento de tarea separado",
+ "settings.bulkTodoCreation": "Cada línea en el campo de texto crea un elemento de tarea separado",
"settings.matomo": "Permitir análisis de Matomo",
"drawer.tabs.attributes": "Atributos",
"drawer.tabs.filters": "Filtros",
diff --git a/src/locales/fr.json b/src/locales/fr.json
index eb448a16..2c35edbd 100644
--- a/src/locales/fr.json
+++ b/src/locales/fr.json
@@ -21,7 +21,7 @@
"settings.dark": "Sombre",
"settings.language": "Langue",
"settings.notificationThreshold": "Umbral de notificación",
- "settings.useMultilineForBulkTodoCreation": "Chaque ligne dans le champ de texte crée un élément de tâche séparé",
+ "settings.bulkTodoCreation": "Chaque ligne dans le champ de texte crée un élément de tâche séparé",
"settings.matomo": "Autoriser l'analyse Matomo",
"drawer.tabs.attributes": "Attributs",
"drawer.tabs.filters": "Filtres",
diff --git a/src/locales/hi.json b/src/locales/hi.json
index dd386b7b..cae1c53c 100644
--- a/src/locales/hi.json
+++ b/src/locales/hi.json
@@ -21,7 +21,7 @@
"settings.dark": "डार्क",
"settings.language": "भाषा",
"settings.notificationThreshold": "सूचना सीमा",
- "settings.useMultilineForBulkTodoCreation": "पाठ क्षेत्र में प्रत्येक पंक्ति स्वतंत्र टूडू आइटम बनाती है",
+ "settings.bulkTodoCreation": "पाठ क्षेत्र में प्रत्येक पंक्ति स्वतंत्र टूडू आइटम बनाती है",
"settings.matomo": "मैटोमो विश्लेषण की अनुमति दें",
"drawer.tabs.attributes": "गुण",
"drawer.tabs.filters": "फ़िल्टर",
diff --git a/src/locales/hu.json b/src/locales/hu.json
index 9faa2d2c..a4b51c0f 100644
--- a/src/locales/hu.json
+++ b/src/locales/hu.json
@@ -21,7 +21,7 @@
"settings.dark": "Sötét",
"settings.language": "Nyelv",
"settings.notificationThreshold": "Értesítés küszöbérték",
- "settings.useMultilineForBulkTodoCreation": "Minden sor külön teendőelemet hoz létre a szövegmezőben",
+ "settings.bulkTodoCreation": "Minden sor külön teendőelemet hoz létre a szövegmezőben",
"settings.matomo": "Matomo elemzés engedélyezése",
"drawer.tabs.attributes": "Tulajdonságok",
"drawer.tabs.filters": "Szűrők",
diff --git a/src/locales/it.json b/src/locales/it.json
index 4f438e7e..7bb74cc8 100644
--- a/src/locales/it.json
+++ b/src/locales/it.json
@@ -21,7 +21,7 @@
"settings.dark": "Scuro",
"settings.language": "Lingua",
"settings.notificationThreshold": "Soglia di notifica",
- "settings.useMultilineForBulkTodoCreation": "Ogni riga nel campo di testo crea un'attività separata",
+ "settings.bulkTodoCreation": "Ogni riga nel campo di testo crea un'attività separata",
"settings.matomo": "Consenti l'analisi di Matomo",
"drawer.tabs.attributes": "Attributi",
"drawer.tabs.filters": "Filtri",
diff --git a/src/locales/jp.json b/src/locales/jp.json
index 6f20488d..6c973c6b 100644
--- a/src/locales/jp.json
+++ b/src/locales/jp.json
@@ -21,7 +21,7 @@
"settings.dark": "ダーク",
"settings.language": "言語",
"settings.notificationThreshold": "通知しきい値",
- "settings.useMultilineForBulkTodoCreation": "テキストフィールド内の各行は別々のタスクを作成します",
+ "settings.bulkTodoCreation": "テキストフィールド内の各行は別々のタスクを作成します",
"settings.matomo": "Matomoの分析を許可",
"drawer.tabs.attributes": "属性",
"drawer.tabs.filters": "フィルター",
diff --git a/src/locales/ko.json b/src/locales/ko.json
index 3d253b45..23ac5199 100644
--- a/src/locales/ko.json
+++ b/src/locales/ko.json
@@ -21,7 +21,7 @@
"settings.dark": "다크",
"settings.language": "언어",
"settings.notificationThreshold": "알림 임계값",
- "settings.useMultilineForBulkTodoCreation": "텍스트 필드의 각 줄은 별도의 할 일 항목을 생성합니다",
+ "settings.bulkTodoCreation": "텍스트 필드의 각 줄은 별도의 할 일 항목을 생성합니다",
"settings.matomo": "Matomo 분석 허용",
"drawer.tabs.attributes": "속성",
"drawer.tabs.filters": "필터",
diff --git a/src/locales/pl.json b/src/locales/pl.json
index 8e61c9a4..289ec71e 100644
--- a/src/locales/pl.json
+++ b/src/locales/pl.json
@@ -21,7 +21,7 @@
"settings.dark": "Ciemny",
"settings.language": "Język",
"settings.notificationThreshold": "Prog powiadomień",
- "settings.useMultilineForBulkTodoCreation": "Każdy wiersz w polu tekstowym tworzy oddzielną pozycję na liście zadań",
+ "settings.bulkTodoCreation": "Każdy wiersz w polu tekstowym tworzy oddzielną pozycję na liście zadań",
"settings.matomo": "Zezwalaj na analizę Matomo",
"drawer.tabs.attributes": "Atrybuty",
"drawer.tabs.filters": "Filtry",
diff --git a/src/locales/pt.json b/src/locales/pt.json
index 220076d8..de8a8e0e 100644
--- a/src/locales/pt.json
+++ b/src/locales/pt.json
@@ -21,7 +21,7 @@
"settings.dark": "Escuro",
"settings.language": "Idioma",
"settings.notificationThreshold": "Prog powiadomień",
- "settings.useMultilineForBulkTodoCreation": "Cada linha no campo de texto cria um item de tarefa separado",
+ "settings.bulkTodoCreation": "Cada linha no campo de texto cria um item de tarefa separado",
"settings.matomo": "Permitir Análise do Matomo",
"drawer.tabs.attributes": "Atributos",
"drawer.tabs.filters": "Filtros",
diff --git a/src/locales/ru.json b/src/locales/ru.json
index 66a2d074..d9e5a723 100644
--- a/src/locales/ru.json
+++ b/src/locales/ru.json
@@ -21,7 +21,7 @@
"settings.dark": "Темная",
"settings.language": "Язык",
"settings.notificationThreshold": "Порог уведомлений",
- "settings.useMultilineForBulkTodoCreation": "Каждая строка в текстовом поле создает отдельную задачу",
+ "settings.bulkTodoCreation": "Каждая строка в текстовом поле создает отдельную задачу",
"settings.matomo": "Разрешить анализ Matomo",
"drawer.tabs.attributes": "Атрибуты",
"drawer.tabs.filters": "Фильтры",
diff --git a/src/locales/tr.json b/src/locales/tr.json
index 591acc29..4d8eef0d 100644
--- a/src/locales/tr.json
+++ b/src/locales/tr.json
@@ -21,7 +21,7 @@
"settings.dark": "Koyu",
"settings.language": "Dil",
"settings.notificationThreshold": "Bildirim Eşik Değeri",
- "settings.useMultilineForBulkTodoCreation": "Metin alanındaki her satır ayrı bir görev oluşturur",
+ "settings.bulkTodoCreation": "Metin alanındaki her satır ayrı bir görev oluşturur",
"settings.matomo": "Matomo Analizine İzin Ver",
"drawer.tabs.attributes": "Özellikler",
"drawer.tabs.filters": "Filtreler",
diff --git a/src/locales/zh.json b/src/locales/zh.json
index 1d1f9446..c3f43f2a 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -21,7 +21,7 @@
"settings.dark": "暗黑",
"settings.language": "语言",
"settings.notificationThreshold": "通知阈值",
- "settings.useMultilineForBulkTodoCreation": "文本字段中的每一行都创建一个单独的待办事项",
+ "settings.bulkTodoCreation": "文本字段中的每一行都创建一个单独的待办事项",
"settings.matomo": "允许Matomo分析",
"drawer.tabs.attributes": "属性",
"drawer.tabs.filters": "过滤器",
diff --git a/src/main/config.tsx b/src/main/config.tsx
index dac2917c..442a511a 100644
--- a/src/main/config.tsx
+++ b/src/main/config.tsx
@@ -74,6 +74,12 @@ const configStorage = new Store({
'2.0.2': store => {
store.set('dueDateInTheFuture', true);
},
+ '2.0.4': store => {
+ store.delete('multilineTextField');
+ store.delete('isDrawerOpen');
+ store.delete('useMultilineForBulkTodoCreation');
+ store.set('bulkTodoCreation', false);
+ },
}
});
diff --git a/src/main/modules/File/Write.tsx b/src/main/modules/File/Write.tsx
index b50aaa23..89816d49 100644
--- a/src/main/modules/File/Write.tsx
+++ b/src/main/modules/File/Write.tsx
@@ -28,12 +28,23 @@ async function removeLineFromFile(id: number): Promise {
return `Line ${id} removed from file`;
}
-async function writeTodoObjectToFile(id: number, inputString: string): Promise {
- const multilineTextField: boolean = configStorage.get('multilineTextField');
- const useMultilineForBulkTodoCreation: boolean = configStorage.get('useMultilineForBulkTodoCreation');
+async function writeTodoObjectToFile(id: number, string: string): Promise {
+ const activeFile: FileObject | null = getActiveFile();
+ if(!activeFile) {
+ throw new Error('Todo file is not defined');
+ }
+ const bookmark = activeFile.todoFileBookmark;
+ const todoFilePath = activeFile.todoFilePath;
+
+ const bulkTodoCreation: boolean = configStorage.get('bulkTodoCreation');
const convertRelativeToAbsoluteDates = configStorage.get('convertRelativeToAbsoluteDates');
const appendCreationDate = configStorage.get('appendCreationDate');
- const content = (multilineTextField && useMultilineForBulkTodoCreation) ? inputString : inputString.replaceAll(/\n/g, String.fromCharCode(16));
+
+ const content =
+ (bulkTodoCreation)
+ ? string.replaceAll(String.fromCharCode(16), '\n')
+ : string.replaceAll(/\n/g, String.fromCharCode(16));
+
const linesToWrite = content.split('\n').filter(line => line.trim() !== '');
if(linesToWrite.length === 0 && id < 1) {
@@ -57,25 +68,11 @@ async function writeTodoObjectToFile(id: number, inputString: string): Promise {
try {
@@ -17,6 +18,16 @@ async function handleDataRequest(event: IpcMainEvent, searchString: string): Pro
}
}
+async function handleCreateTodoObject(event: IpcMainEvent, string: string, index: number, refreshTextField: boolean): Promise {
+ try {
+ const todoObject = await createTodoObject(string, index);
+ event.reply('createTodoObject', todoObject, refreshTextField);
+ } catch(error) {
+ console.error(error);
+ event.reply('handleError', error);
+ }
+}
+
async function handleWriteTodoToFile(event: IpcMainEvent, id: number, string: string, state: boolean): Promise {
try {
let updatedString: string | null = string;
@@ -173,6 +184,7 @@ function removeEventListeners(): void {
ipcMain.off('removeFile', handleRemoveFile);
ipcMain.off('openFile', handleOpenFile);
ipcMain.off('createFile', handleCreateFile);
+ ipcMain.off('createTodoObject', handleCreateTodoObject);
ipcMain.off('requestData', handleDataRequest);
ipcMain.off('writeTodoToFile', handleWriteTodoToFile);
ipcMain.off('archiveTodos', handleArchiveTodos);
@@ -193,6 +205,7 @@ ipcMain.on('setFile', handleSetFile);
ipcMain.on('removeFile', handleRemoveFile);
ipcMain.on('openFile', handleOpenFile);
ipcMain.on('createFile', handleCreateFile);
+ipcMain.on('createTodoObject', handleCreateTodoObject);
ipcMain.on('requestData', handleDataRequest);
ipcMain.on('writeTodoToFile', handleWriteTodoToFile);
ipcMain.on('archiveTodos', handleArchiveTodos);
diff --git a/src/main/modules/Menu.tsx b/src/main/modules/Menu.tsx
index ee846e25..255b819a 100644
--- a/src/main/modules/Menu.tsx
+++ b/src/main/modules/Menu.tsx
@@ -9,6 +9,10 @@ const isMac: boolean = process.platform === 'darwin';
const description = appPackage.description;
function createMenu(files: FileObject[]) {
+ // @ts-ignore
+ // @ts-ignore
+ // @ts-ignore
+ // @ts-ignore
const template: Electron.MenuItemConstructorOptions[] = [
{
label: 'sleek',
diff --git a/src/main/modules/ProcessDataRequest/CreateRecurringTodo.tsx b/src/main/modules/ProcessDataRequest/CreateRecurringTodo.tsx
index 25f3317f..cd47b884 100644
--- a/src/main/modules/ProcessDataRequest/CreateRecurringTodo.tsx
+++ b/src/main/modules/ProcessDataRequest/CreateRecurringTodo.tsx
@@ -49,9 +49,9 @@ const createRecurringTodo = async (todoString: string, recurrence: string): Prom
if(recurrence) {
const strictRecurrence: boolean = recurrence.startsWith('+');
- const temp: any = strictRecurrence ? recurrence.slice(1) : recurrence;
- const recurrenceInterval = temp.slice(-1) as RecurrenceInterval;
- const recurrenceValue = parseInt(temp.slice(0, -1));
+ const updatedRecurrence: any = strictRecurrence ? recurrence.slice(1) : recurrence;
+ const recurrenceInterval = updatedRecurrence.slice(-1) as RecurrenceInterval;
+ const recurrenceValue = parseInt(updatedRecurrence.slice(0, -1));
const oldDueDate: any = JsTodoTxtObject?.extensions()?.find((item) => item.key === 'due')?.value;
const oldThresholdDate: any = JsTodoTxtObject?.extensions()?.find((item) => item.key === 't')?.value;
diff --git a/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx b/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx
index 67fe5b4f..9b81ecdd 100644
--- a/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx
+++ b/src/main/modules/ProcessDataRequest/CreateTodoObjects.tsx
@@ -1,12 +1,50 @@
import { app } from 'electron';
import { Item } from 'jstodotxt';
-import dayjs from 'dayjs';
import { handleNotification } from '../Notifications';
import { extractSpeakingDates } from '../Date';
+import { configStorage } from '../../config';
+import dayjs from 'dayjs';
let lines: string[];
export const badge: Badge = { count: 0 };
+function createTodoObject(string: string, index: number): TodoObject {
+ const content = string.replaceAll(/[\x10\r\n]/g, ' ');
+ const JsTodoTxtObject = new Item(content);
+ const body = JsTodoTxtObject.body();
+ const speakingDates: DateAttributes = extractSpeakingDates(body);
+ const due = speakingDates['due:']?.date || null;
+ const dueString = speakingDates['due:']?.string || null;
+ const notify = speakingDates['due:']?.notify || false;
+ const t = speakingDates['t:']?.date || null;
+ const tString = speakingDates['t:']?.string || null;
+ const extensions = JsTodoTxtObject.extensions();
+ const hidden = extensions.some(extension => extension.key === 'h' && extension.value === '1');
+ const pm = extensions.find(extension => extension.key === 'pm')?.value || null;
+ const rec = extensions.find(extension => extension.key === 'rec')?.value || null;
+ const creation = dayjs(JsTodoTxtObject.created()).isValid() ? dayjs(JsTodoTxtObject.created()).format('YYYY-MM-DD') : null;
+ const completed = dayjs(JsTodoTxtObject.completed()).isValid() ? dayjs(JsTodoTxtObject.completed()).format('YYYY-MM-DD') : null;
+ return {
+ id: index,
+ body,
+ created: creation,
+ complete: JsTodoTxtObject.complete(),
+ completed: completed,
+ priority: JsTodoTxtObject.priority(),
+ contexts: JsTodoTxtObject.contexts(),
+ projects: JsTodoTxtObject.projects(),
+ due,
+ dueString,
+ notify,
+ t,
+ tString,
+ rec,
+ hidden,
+ pm,
+ string: string,
+ };
+}
+
async function createTodoObjects(fileContent: string | null): Promise {
if(!fileContent) {
lines = [];
@@ -14,47 +52,12 @@ async function createTodoObjects(fileContent: string | null): Promise line.trim() !== '');
- const items: Item[] = lines.map(line => new Item(line.replaceAll(String.fromCharCode(16), ' ')));
-
- const todoObjects: TodoObject[] = await Promise.all(items.map(async (JsTodoTxtObject, i) => {
- const body = JsTodoTxtObject.body();
- const speakingDates: DateAttributes = extractSpeakingDates(body);
- const due = speakingDates['due:']?.date || null;
- const dueString = speakingDates['due:']?.string || null;
- const notify = speakingDates['due:']?.notify || false;
- const t = speakingDates['t:']?.date || null;
- const tString = speakingDates['t:']?.string || null;
- const extensions = JsTodoTxtObject.extensions();
- const hidden = extensions.some(extension => extension.key === 'h' && extension.value === '1');
- const pm = extensions.find(extension => extension.key === 'pm')?.value || null;
- const rec = extensions.find(extension => extension.key === 'rec')?.value || null;
- const creation = dayjs(JsTodoTxtObject.created()).isValid() ? dayjs(JsTodoTxtObject.created()).format('YYYY-MM-DD') : null;
- const completed = dayjs(JsTodoTxtObject.completed()).isValid() ? dayjs(JsTodoTxtObject.completed()).format('YYYY-MM-DD') : null;
-
- const todoObject: TodoObject = {
- id: i,
- body,
- created: creation,
- complete: JsTodoTxtObject.complete(),
- completed: completed,
- priority: JsTodoTxtObject.priority(),
- contexts: JsTodoTxtObject.contexts(),
- projects: JsTodoTxtObject.projects(),
- due,
- dueString,
- notify,
- t,
- tString,
- rec,
- hidden,
- pm,
- string: lines[i],
- };
-
- if(due && !todoObject.complete) {
- handleNotification(due, body, badge);
+
+ const todoObjects: TodoObject[] = await Promise.all(lines.map(async (line, i) => {
+ const todoObject: TodoObject = await createTodoObject(line, i);
+ if(todoObject.due && todoObject.body && !todoObject.complete) {
+ handleNotification(todoObject.due, todoObject.body, badge);
}
-
return todoObject;
}));
@@ -63,4 +66,4 @@ async function createTodoObjects(fileContent: string | null): Promise {
const [searchString, setSearchString] = useState('');
const [flattenedTodoObjects, setTodoObjects] = useState(null);
const [todoObject, setTodoObject] = useState(null);
+ const [attributeFields, setAttributeFields] = useState(null);
const [headers, setHeaders] = useState(null);
const [filters, setFilters] = useState(null);
const [attributes, setAttributes] = useState(null);
@@ -46,11 +47,20 @@ const App = () => {
const [contextMenuPosition, setContextMenuPosition] = useState(null);
const [contextMenuItems, setContextMenuItems] = useState(null);
const [attributeMapping, setAttributeMapping] = useState(translatedAttributes(i18n.t) || {});
- const [textFieldValue, setTextFieldValue] = useState(null);
+ const [textFieldValue, setTextFieldValue] = useState('');
const [promptItem, setPromptItem] = useState(null);
const [triggerArchiving, setTriggerArchiving] = useState(false);
const [showPromptDoneFile, setShowPromptDoneFile] = useState(false);
const [matomo, setMatomo] = useState(store.get('matomo') || false);
+ const [selectedLanguage, setSelectedLanguage] = useState(() => {
+ const storedLanguage = store.get('language') || navigator.language;
+ const supportedLanguages: false | readonly string[] | undefined = i18n.options.supportedLngs;
+ if(supportedLanguages && supportedLanguages.includes(storedLanguage)) {
+ return storedLanguage;
+ }
+ return 'en';
+ });
+
const searchFieldRef = useRef(null);
const handleRequestedData = (requestedData: RequestedData) => {
@@ -184,13 +194,6 @@ const App = () => {
setSnackBarOpen(true);
}, [snackBarContent]);
- useEffect(() => {
- if(!dialogOpen) {
- setTodoObject(null);
- setTextFieldValue('');
- }
- }, [dialogOpen]);
-
useEffect(() => {
store.set('zoom', zoom);
const adjustedFontSize = 16 * (zoom / 100);
@@ -210,7 +213,7 @@ const App = () => {
s = d.getElementsByTagName('script')[0];
g.async = true;
g.src = matomoContainer;
- s.parentNode.insertBefore(g, s);
+ s.parentNode?.insertBefore(g, s);
}
}, [matomo]);
@@ -231,6 +234,7 @@ const App = () => {
ipcRenderer.on('saveToClipboard', handleResponse);
ipcRenderer.on('triggerArchiving', () => setTriggerArchiving(true));
ipcRenderer.on('ArchivingResult', handleResponse);
+ ipcRenderer.on('createTodoObject', (todoObject: TodoObject) => setAttributeFields(todoObject));
window.addEventListener('drop', handleDrop);
window.addEventListener('dragover', handleDragOver);
return () => {
@@ -250,6 +254,7 @@ const App = () => {
ipcRenderer.off('saveToClipboard', handleResponse);
ipcRenderer.off('triggerArchiving', () => setTriggerArchiving(true));
ipcRenderer.off('ArchivingResult', handleResponse);
+ ipcRenderer.off('createTodoObject', (todoObject: TodoObject) => setAttributeFields(todoObject));
window.removeEventListener('drop', handleDrop);
window.removeEventListener('dragover', handleDragOver);
};
@@ -271,6 +276,7 @@ const App = () => {
setTodoObject={setTodoObject}
setTriggerArchiving={setTriggerArchiving}
headers={headers}
+ setAttributeFields={setAttributeFields}
/>
{files?.length > 0 && (
<>
@@ -325,7 +331,6 @@ const App = () => {
setContextMenuPosition={setContextMenuPosition}
contextMenuItems={contextMenuItems}
setContextMenuItems={setContextMenuItems}
- setTextFieldValue={setTextFieldValue}
setPromptItem={setPromptItem}
/>
{
/>
-
+ {dialogOpen ? (
+
+ ) : null}
setIsSettingsOpen(false)}
setAttributeMapping={setAttributeMapping}
zoom={zoom}
setZoom={setZoom}
+ selectedLanguage={selectedLanguage}
+ setSelectedLanguage={setSelectedLanguage}
/>
{contextMenuItems && (
= ({
type,
todoObject,
date,
- filters
+ filters,
+ selectedLanguage,
}) => {
const [open, setOpen] = useState(false);
const chipText = type === 'due' ? "due:" : type === 't' ? "t:" : null;
- const handleChange = (updatedDate: dayjs.Dayjs | null) => {
- if(!updatedDate || !dayjs(updatedDate).isValid()) return;
+ const handleChange = (date: dayjs.Dayjs | null) => {
+ if(!date || !dayjs(date).isValid() || !todoObject.id) return;
+ const validDate = dayjs(date).format('YYYY-MM-DD');
- const formattedDate = dayjs(updatedDate).format('YYYY-MM-DD');
+ const string = todoObject.string.replaceAll(/[\x10\r\n]/g, ` ${String.fromCharCode(16)} `);
- if(todoObject?.dueString) {
- const stringToReplace = ` ${type}:${todoObject.dueString}`;
- todoObject.string = todoObject.string.replace(stringToReplace, '');
- }
+ const JsTodoTxtObject = new Item(string);
+ JsTodoTxtObject.setExtension(type, validDate);
- const JsTodoTxtObject = new Item(todoObject.string);
- JsTodoTxtObject.setExtension(type, formattedDate);
+ const updatedString = JsTodoTxtObject.toString().replaceAll(` ${String.fromCharCode(16)} `, String.fromCharCode(16))
+
+ ipcRenderer.send('writeTodoToFile', todoObject.id, updatedString);
setOpen(false);
- ipcRenderer.send('writeTodoToFile', todoObject.id, JsTodoTxtObject.toString());
};
const DatePickerInline = ({ date, ...props }) => {
@@ -71,8 +72,6 @@ const DatePickerInline: React.FC = ({
);
};
- const selectedLanguage = store.get('language');
-
return (
= memo(({
let matched = false;
for (const expression of expressions) {
-
const regex = new RegExp(`^(${expression.pattern.source})`);
const match = body.match(regex);
diff --git a/src/renderer/DataGrid/Grid.tsx b/src/renderer/DataGrid/Grid.tsx
index a9604d0b..dc1426b4 100644
--- a/src/renderer/DataGrid/Grid.tsx
+++ b/src/renderer/DataGrid/Grid.tsx
@@ -8,7 +8,6 @@ interface TodoDataGridProps {
attributes: Attributes | null;
filters: Filters | null;
setDialogOpen: (open: boolean) => void;
- setTextFieldValue: (value: string) => void;
contextMenuPosition: { top: number; left: number } | null;
setContextMenuPosition: (position: { top: number; left: number } | null) => void;
contextMenuItems: ContextMenuItem[];
@@ -22,7 +21,6 @@ const TodoDataGrid: React.FC = memo(({
attributes,
filters,
setDialogOpen,
- setTextFieldValue,
contextMenuPosition,
setContextMenuPosition,
contextMenuItems,
@@ -95,7 +93,6 @@ const TodoDataGrid: React.FC = memo(({
setTodoObject={setTodoObject}
filters={filters}
setDialogOpen={setDialogOpen}
- setTextFieldValue={setTextFieldValue}
contextMenuPosition={contextMenuPosition}
setContextMenuPosition={setContextMenuPosition}
contextMenuItems={contextMenuItems}
diff --git a/src/renderer/DataGrid/Row.tsx b/src/renderer/DataGrid/Row.tsx
index 68c421ab..2edef59f 100644
--- a/src/renderer/DataGrid/Row.tsx
+++ b/src/renderer/DataGrid/Row.tsx
@@ -16,7 +16,6 @@ interface Props extends WithTranslation {
row: TodoObject;
filters: Filters;
setDialogOpen: React.Dispatch>;
- setTextFieldValue: React.Dispatch>;
setTodoObject: React.Dispatch>;
setContextMenuPosition: React.Dispatch>;
setContextMenuItems: React.Dispatch>;
@@ -28,7 +27,6 @@ const Row: React.FC = memo(({
row,
filters,
setDialogOpen,
- setTextFieldValue,
setTodoObject,
setContextMenuPosition,
setContextMenuItems,
@@ -52,20 +50,11 @@ const Row: React.FC = memo(({
const handleContextMenu = (event: React.MouseEvent) => {
event.preventDefault();
setContextMenuPosition({ top: event.clientY, left: event.clientX });
- setContextMenuItems([
- itemCopy,
- itemDelete,
- ]);
+ setContextMenuItems([itemCopy, itemDelete]);
};
const handleCheckboxChange = (event: React.ChangeEvent) => {
- ipcRenderer.send(
- 'writeTodoToFile',
- row.id,
- row.string,
- event.target.checked,
- false
- );
+ ipcRenderer.send('writeTodoToFile', row.id, row.string, event.target.checked, false);
};
const handleRowClick = (event: React.KeyboardEvent | React.MouseEvent) => {
@@ -86,7 +75,6 @@ const Row: React.FC = memo(({
setTodoObject(row);
setDialogOpen(true);
}
- setTextFieldValue(row.string);
}
} else if((event.metaKey || event.ctrlKey) && (event.key === 'Delete' || event.key === 'Backspace')) {
setPromptItem(itemDelete);
diff --git a/src/renderer/LanguageSelector.tsx b/src/renderer/LanguageSelector.tsx
index 9ffb27a2..1ec0f826 100644
--- a/src/renderer/LanguageSelector.tsx
+++ b/src/renderer/LanguageSelector.tsx
@@ -97,19 +97,16 @@ const friendlyLanguageName: Record = {
interface Props {
setAttributeMapping: (attributes: Record) => void;
+ selectedLanguage: string;
+ setSelectedLanguage: React.Dispatch>;
}
const LanguageSelector: React.FC = ({
- setAttributeMapping
+ setAttributeMapping,
+ selectedLanguage,
+ setSelectedLanguage,
}) => {
const supportedLanguages: false | readonly string[] | undefined = i18n.options.supportedLngs;
- const [selectedLanguage, setSelectedLanguage] = useState(() => {
- const storedLanguage = store.get('language') || navigator.language;
- if(supportedLanguages && supportedLanguages.includes(storedLanguage)) {
- return storedLanguage;
- }
- return 'en';
- });
const changeLanguage = (event: React.ChangeEvent<{ value: string }>) => {
const language = event.target.value;
diff --git a/src/renderer/Navigation.tsx b/src/renderer/Navigation.tsx
index 8d7a0208..797e9384 100644
--- a/src/renderer/Navigation.tsx
+++ b/src/renderer/Navigation.tsx
@@ -20,6 +20,8 @@ interface Props {
setIsNavigationOpen: React.Dispatch>;
setTriggerArchiving: React.Dispatch>;
headers: HeadersObject;
+ setTodoObject: React.Dispatch>;
+ setAttributeFields: React.Dispatch>;
}
const NavigationComponent: React.FC = memo(({
@@ -31,11 +33,20 @@ const NavigationComponent: React.FC = memo(({
setIsNavigationOpen,
setTriggerArchiving,
headers,
+ setTodoObject,
+ setAttributeFields
}) => {
+
+ const handleOpen = () => {
+ setTodoObject(null);
+ setDialogOpen(true);
+ setAttributeFields(null);
+ };
+
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if(files.length > 0 && (event.metaKey || event.ctrlKey) && event.key === 'n') {
- setDialogOpen(true);
+ handleOpen();
}
};
document.addEventListener('keydown', handleKeyDown);
@@ -50,7 +61,7 @@ const NavigationComponent: React.FC = memo(({
sleek
{files?.length > 0 && (
<>
-