Repository: campudus/tableaux-frontend
Pull request #453: GRUD_DEV-1123: Open table search on Ctrl+F
Author: login: hermann-p
Created: 2025-04-07T13:43:17Z | Merged: 2025-04-10T21:54:14Z

- [x] I gave the PR a meaningful name
- [x] I checked that the correct target branch is selected
- [x] I rebased the branch on the target branch and it can be merged
- [x] I ran the linter and it did pass
- [x] I checked for unused code / dead code / debug code
- [x] I checked that variables/functions have meaningful names
- [x] I checked that the behaviour is as the documentation/task describes and I tested it
- [x] I updated the docs / specifications if possible
- [x] I could explain all that code when someone wakes me up at 3am
- [x] I checked that the code considers failures and not just the happy path
- [x] There are no new dependencies OR I listed them and explained them below
- [x] PR introduces no breaking changes OR I listed them and described them below
- [x] I added/updated tests for new/modified unit-testable functions/helpers
- [x] I ran the tests and they did pass


Diff:
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 2178ecfc6..fc4c48b45 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -39,7 +39,7 @@ module.exports = {
     quotes: ["error", "double"],
     "no-console": "off",
     "trailing-comma": "off",
-    "prettier/prettier": "error",
+    "prettier/prettier": "warn",
     camelcase: ["warn", { properties: "always" }],
     eqeqeq: ["error", "allow-null"],
     "no-eval": "error",
diff --git a/.prettierrc b/.prettierrc.yaml
similarity index 100%
rename from .prettierrc
rename to .prettierrc.yaml
diff --git a/Dockerfile b/Dockerfile
index cd3cde0d4..fdea5197c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,7 +6,7 @@ RUN apk update && apk upgrade && \
 WORKDIR /usr/app
 
 COPY package*.json vite.config* tsconfig.* ./
-COPY .npmrc .eslint* .prettierrc ./
+COPY .npmrc .eslint* .prettierrc.yaml ./
 
 RUN npm ci -d
 
diff --git a/package-lock.json b/package-lock.json
index 3e2d1159f..db4897439 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -58,7 +58,8 @@
         "match-iz": "4.0.2",
         "moment": "2.29.4",
         "postcss": "^8.5.3",
-        "prettier": "1.18.2",
+        "pragmatic-fp-ts": "^1.7.0",
+        "prettier": "1.19.1",
         "react": "16.14.0",
         "react-datetime": "3.2.0",
         "react-dom": "16.14.0",
@@ -1026,262 +1027,6 @@
       "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
       "dev": true
     },
-    "node_modules/@esbuild/aix-ppc64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
-      "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "aix"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-arm": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
-      "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
-      "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
-      "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
-      "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/darwin-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
-      "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
-      "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
-      "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-arm": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
-      "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
-      "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-ia32": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
-      "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-loong64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
-      "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
-      "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
-      "cpu": [
-        "mips64el"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
-      "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
-      "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-s390x": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
-      "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
     "node_modules/@esbuild/linux-x64": {
       "version": "0.25.0",
       "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
@@ -1298,134 +1043,6 @@
         "node": ">=18"
       }
     },
-    "node_modules/@esbuild/netbsd-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
-      "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
-      "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
-      "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
-      "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/sunos-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
-      "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "sunos"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-arm64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
-      "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-ia32": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
-      "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-x64": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
-      "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
     "node_modules/@eslint-community/eslint-utils": {
       "version": "4.5.1",
       "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz",
@@ -1915,194 +1532,12 @@
     },
     "node_modules/@remix-run/router": {
       "version": "1.16.0",
-      "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.0.tgz",
-      "integrity": "sha512-Quz1KOffeEf/zwkCBM3kBtH4ZoZ+pT3xIXBG4PPW/XFtDP7EGhtTiC2+gpL9GnR7+Qdet5Oa6cYSvwKYg6kN9Q==",
-      "dev": true,
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/@rollup/rollup-android-arm-eabi": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz",
-      "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ]
-    },
-    "node_modules/@rollup/rollup-android-arm64": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz",
-      "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ]
-    },
-    "node_modules/@rollup/rollup-darwin-arm64": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz",
-      "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ]
-    },
-    "node_modules/@rollup/rollup-darwin-x64": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz",
-      "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ]
-    },
-    "node_modules/@rollup/rollup-freebsd-arm64": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz",
-      "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ]
-    },
-    "node_modules/@rollup/rollup-freebsd-x64": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz",
-      "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "freebsd"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz",
-      "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz",
-      "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-arm64-gnu": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz",
-      "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-arm64-musl": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz",
-      "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz",
-      "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz",
-      "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz",
-      "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-s390x-gnu": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz",
-      "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==",
-      "cpu": [
-        "s390x"
-      ],
+      "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.0.tgz",
+      "integrity": "sha512-Quz1KOffeEf/zwkCBM3kBtH4ZoZ+pT3xIXBG4PPW/XFtDP7EGhtTiC2+gpL9GnR7+Qdet5Oa6cYSvwKYg6kN9Q==",
       "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ]
+      "engines": {
+        "node": ">=14.0.0"
+      }
     },
     "node_modules/@rollup/rollup-linux-x64-gnu": {
       "version": "4.34.8",
@@ -2130,45 +1565,6 @@
         "linux"
       ]
     },
-    "node_modules/@rollup/rollup-win32-arm64-msvc": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz",
-      "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ]
-    },
-    "node_modules/@rollup/rollup-win32-ia32-msvc": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz",
-      "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ]
-    },
-    "node_modules/@rollup/rollup-win32-x64-msvc": {
-      "version": "4.34.8",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz",
-      "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ]
-    },
     "node_modules/@types/babel__core": {
       "version": "7.20.5",
       "dev": true,
@@ -5126,20 +4522,6 @@
       "dev": true,
       "license": "ISC"
     },
-    "node_modules/fsevents": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
-      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
-      "dev": true,
-      "hasInstallScript": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-      }
-    },
     "node_modules/full-icu": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/full-icu/-/full-icu-1.5.0.tgz",
@@ -7225,6 +6607,12 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/pragmatic-fp-ts": {
+      "version": "1.10.3",
+      "resolved": "https://registry.npmjs.org/pragmatic-fp-ts/-/pragmatic-fp-ts-1.10.3.tgz",
+      "integrity": "sha512-6isxlgMsxEXXUXRyuI9XtGBhqNsjXRxb2Kgn+M4wGzv2QRvhMWrxgX/Rg1ow6/DkdLZGhYAIShvHnLC7EMnDyw==",
+      "dev": true
+    },
     "node_modules/prelude-ls": {
       "version": "1.2.1",
       "dev": true,
@@ -7234,9 +6622,10 @@
       }
     },
     "node_modules/prettier": {
-      "version": "1.18.2",
+      "version": "1.19.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
+      "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
       "dev": true,
-      "license": "MIT",
       "bin": {
         "prettier": "bin-prettier.js"
       },
@@ -8198,230 +7587,6 @@
         "sass-embedded-win32-x64": "1.85.1"
       }
     },
-    "node_modules/sass-embedded-android-arm": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.85.1.tgz",
-      "integrity": "sha512-GkcgUGMZtEF9gheuE1dxCU0ZSAifuaFXi/aX7ZXvjtdwmTl9Zc/OHR9oiUJkc8IW9UI7H8TuwlTAA8+SwgwIeQ==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-android-arm64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.85.1.tgz",
-      "integrity": "sha512-27oRheqNA3SJM2hAxpVbs7mCKUwKPWmEEhyiNFpBINb5ELVLg+Ck5RsGg+SJmo130ul5YX0vinmVB5uPWc8X5w==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-android-ia32": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.85.1.tgz",
-      "integrity": "sha512-f3x16NyRgtXFksIaO/xXKrUhttUBv8V0XsAR2Dhdb/yz4yrDrhzw9Wh8fmw7PlQqECcQvFaoDr3XIIM6lKzasw==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-android-riscv64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.85.1.tgz",
-      "integrity": "sha512-IP6OijpJ8Mqo7XqCe0LsuZVbAxEFVboa0kXqqR5K55LebEplsTIA2GnmRyMay3Yr/2FVGsZbCb6Wlgkw23eCiA==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-android-x64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.85.1.tgz",
-      "integrity": "sha512-Mh7CA53wR3ADvXAYipFc/R3vV4PVOzoKwWzPxmq+7i8UZrtsVjKONxGtqWe9JG1mna0C9CRZAx0sv/BzbOJxWg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-darwin-arm64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.85.1.tgz",
-      "integrity": "sha512-msWxzhvcP9hqGVegxVePVEfv9mVNTlUgGr6k7O7Ihji702mbtrH/lKwF4aRkkt4g1j7tv10+JtQXmTNi/pi9kA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-darwin-x64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.85.1.tgz",
-      "integrity": "sha512-J4UFHUiyI9Z+mwYMwz11Ky9TYr3hY1fCxeQddjNGL/+ovldtb0yAIHvoVM0BGprQDm5JqhtUk8KyJ3RMJqpaAA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-linux-arm": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.85.1.tgz",
-      "integrity": "sha512-X0fDh95nNSw1wfRlnkE4oscoEA5Au4nnk785s9jghPFkTBg+A+5uB6trCjf0fM22+Iw6kiP4YYmDdw3BqxAKLQ==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-linux-arm64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.85.1.tgz",
-      "integrity": "sha512-jGadetB03BMFG2rq3OXub/uvC/lGpbQOiLGEz3NLb2nRZWyauRhzDtvZqkr6BEhxgIWtMtz2020yD8ZJSw/r2w==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-linux-ia32": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.85.1.tgz",
-      "integrity": "sha512-7HlYY90d9mitDtNi5s+S+5wYZrTVbkBH2/kf7ixrzh2BFfT0YM81UHLJRnGX93y9aOMBL6DSZAIfkt1RsV9bkQ==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-linux-musl-arm": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.85.1.tgz",
-      "integrity": "sha512-5vcdEqE8QZnu6i6shZo7x2N36V7YUoFotWj2rGekII5ty7Nkaj+VtZhUEOp9tAzEOlaFuDp5CyO1kUCvweT64A==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-linux-musl-arm64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.85.1.tgz",
-      "integrity": "sha512-FLkIT0p18XOkR6wryJ13LqGBDsrYev2dRk9dtiU18NCpNXruKsdBQ1ZnWHVKB3h1dA9lFyEEisC0sooKdNfeOQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-linux-musl-ia32": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.85.1.tgz",
-      "integrity": "sha512-N1093T84zQJor1yyIAdYScB5eAuQarGK1tKgZ4uTnxVlgA7Xi1lXV8Eh7ox9sDqKCaWkVQ3MjqU26vYRBeRWyw==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-linux-musl-riscv64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.85.1.tgz",
-      "integrity": "sha512-WRsZS/7qlfYXsa93FBpSruieuURIu7ySfFhzYfF1IbKrNAGwmbduutkHZh2ddm5/vQMvQ0Rdosgv+CslaQHMcw==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
     "node_modules/sass-embedded-linux-musl-x64": {
       "version": "1.85.1",
       "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.85.1.tgz",
@@ -8438,22 +7603,6 @@
         "node": ">=14.0.0"
       }
     },
-    "node_modules/sass-embedded-linux-riscv64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.85.1.tgz",
-      "integrity": "sha512-mKKlOwMGLN7yP1p0gB5yG/HX4fYLnpWaqstNuOOXH+fOzTaNg0+1hALg0H0CDIqypPO74M5MS9T6FAJZGdT6dQ==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
     "node_modules/sass-embedded-linux-x64": {
       "version": "1.85.1",
       "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.85.1.tgz",
@@ -8470,54 +7619,6 @@
         "node": ">=14.0.0"
       }
     },
-    "node_modules/sass-embedded-win32-arm64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.85.1.tgz",
-      "integrity": "sha512-/GMiZXBOc6AEMBC3g25Rp+x8fq9Z6Ql7037l5rajBPhZ+DdFwtdHY0Ou3oIU6XuWUwD06U3ii4XufXVFhsP6PA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-win32-ia32": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.85.1.tgz",
-      "integrity": "sha512-L+4BWkKKBGFOKVQ2PQ5HwFfkM5FvTf1Xx2VSRvEWt9HxPXp6SPDho6zC8fqNQ3hSjoaoASEIJcSvgfdQYO0gdg==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/sass-embedded-win32-x64": {
-      "version": "1.85.1",
-      "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.85.1.tgz",
-      "integrity": "sha512-/FO0AGKWxVfCk4GKsC0yXWBpUZdySe3YAAbQQL0lL6xUd1OiUY8Kow6g4Kc1TB/+z0iuQKKTqI/acJMEYl4iTQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
     "node_modules/sass-embedded/node_modules/has-flag": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
diff --git a/package.json b/package.json
index 4abfd6bf0..594e3c7a9 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,8 @@
     "match-iz": "4.0.2",
     "moment": "2.29.4",
     "postcss": "^8.5.3",
-    "prettier": "1.18.2",
+    "pragmatic-fp-ts": "^1.7.0",
+    "prettier": "1.19.1",
     "react": "16.14.0",
     "react-datetime": "3.2.0",
     "react-dom": "16.14.0",
diff --git a/src/app/components/header/filter/Filter.jsx b/src/app/components/header/filter/Filter.jsx
index 50840ba5e..611e331e1 100644
--- a/src/app/components/header/filter/Filter.jsx
+++ b/src/app/components/header/filter/Filter.jsx
@@ -3,8 +3,11 @@ import f from "lodash/fp";
 import PropTypes from "prop-types";
 import React from "react";
 import { translate } from "react-i18next";
+import { useCustomEvent } from "../../../helpers/CustomEvent";
 import FilterPopup from "./FilterPopup.jsx";
 
+export const OpenFilterEvent = "event/open-row-filter-popup";
+
 const FilterButton = ({
   langtag,
   columns,
@@ -14,8 +17,19 @@ const FilterButton = ({
   t
 }) => {
   const [open, setOpen] = React.useState(false);
-  const togglePopup = React.useCallback(() => setOpen(!open));
-  const closePopup = React.useCallback(() => setOpen(false));
+  const [initialFilter, setInitialFilter] = React.useState(currentFilter);
+  const closePopup = React.useCallback(() => setOpen(false), []);
+  const openPopup = React.useCallback(filters => {
+    setInitialFilter(filters);
+    setOpen(true);
+  }, []);
+
+  const togglePopup = React.useCallback(
+    () => (open ? closePopup() : openPopup(currentFilter)),
+    [currentFilter, open]
+  );
+
+  useCustomEvent(OpenFilterEvent, openPopup, document.body);
 
   const buttonCssClass = classNames("filter-popup-button", {
     "ignore-react-onclickoutside": open
@@ -42,7 +56,7 @@ const FilterButton = ({
           langtag={langtag}
           onClickedOutside={closePopup}
           columns={columns}
-          currentFilter={currentFilter}
+          currentFilter={initialFilter}
           actions={actions}
           setRowFilter={setRowFilter}
         />
diff --git a/src/app/components/header/filter/FilterPopup.jsx b/src/app/components/header/filter/FilterPopup.jsx
index 1e11176ad..e54d3c996 100644
--- a/src/app/components/header/filter/FilterPopup.jsx
+++ b/src/app/components/header/filter/FilterPopup.jsx
@@ -7,6 +7,10 @@ import {
   DefaultLangtag,
   SortValue
 } from "../../../constants/TableauxConstants";
+import {
+  getAnnotationColor,
+  getAnnotationTitle
+} from "../../../helpers/annotationHelper";
 import * as Storage from "../../../helpers/localStorage";
 import { getColumnDisplayName } from "../../../helpers/multiLanguage";
 import RowFilters from "../../../RowFilters";
@@ -22,10 +26,6 @@ import {
   mkAnnotationFilterTemplates,
   toCombinedFilter
 } from "./helpers";
-import {
-  getAnnotationColor,
-  getAnnotationTitle
-} from "../../../helpers/annotationHelper";
 
 const of = el => (Array.isArray(el) ? el : [el]);
 
diff --git a/src/app/components/header/filter/FilterRow.jsx b/src/app/components/header/filter/FilterRow.jsx
index d5ca40bd5..908b81ddf 100644
--- a/src/app/components/header/filter/FilterRow.jsx
+++ b/src/app/components/header/filter/FilterRow.jsx
@@ -125,6 +125,7 @@ const ValueInput = ({ column, mode, value, onChange }) => {
       value={value || ""}
       onChange={handleSetEventValue}
       disabled={disabled}
+      autoFocus
     />
   ) : (
     <div className="placeholder" />
diff --git a/src/app/components/helperComponents/NumberInput.jsx b/src/app/components/helperComponents/NumberInput.jsx
index 52077da6f..445c6a403 100644
--- a/src/app/components/helperComponents/NumberInput.jsx
+++ b/src/app/components/helperComponents/NumberInput.jsx
@@ -7,6 +7,18 @@ import React, {
 } from "react";
 import f from "lodash/fp";
 
+const JAVA_INT_MAX = 2_147_483_647;
+const JAVA_INT_MIN = -2_147_483_648;
+
+// Here we can use that JS uses double precicion floats to represent all numbers
+// and thus can handle bigger "integers" than Java.
+// toStorableInteger: Number -> Number
+export const toStorableInteger = f.cond([
+  [n => n > JAVA_INT_MAX, () => JAVA_INT_MAX],
+  [n => n < JAVA_INT_MIN, () => JAVA_INT_MIN],
+  [f.stubTrue, f.identity]
+]);
+
 import PropTypes from "prop-types";
 
 import {
@@ -16,7 +28,7 @@ import {
 } from "../../helpers/multiLanguage";
 import { doto, when } from "../../helpers/functools";
 
-const MAX_DIGITS = 14;
+export const MAX_DIGITS = 14;
 
 const NumberInput = (props, ref) => {
   const {
@@ -40,7 +52,10 @@ const NumberInput = (props, ref) => {
   const thousandSeparator = decimalSeparator === "," ? "." : ",";
 
   const handleChange = event => {
-    onChange && onChange(readLocalizedNumber(event.target.value));
+    const input = readLocalizedNumber(event.target.value);
+    const isInteger = decimalDigits === 0;
+    const newValue = isInteger ? toStorableInteger(input) : input;
+    onChange && onChange(newValue);
   };
 
   const inputRef = useRef();
diff --git a/src/app/components/history/diffItems/NumberDiff.jsx b/src/app/components/history/diffItems/NumberDiff.jsx
index c2ececa1d..1a36ef09a 100644
--- a/src/app/components/history/diffItems/NumberDiff.jsx
+++ b/src/app/components/history/diffItems/NumberDiff.jsx
@@ -4,6 +4,7 @@ import PropTypes from "prop-types";
 import classNames from "classnames";
 
 import { formatNumber } from "../../../helpers/multiLanguage";
+import { MAX_DIGITS } from "../../helperComponents/NumberInput";
 
 const NumberDiff = props => {
   const { diff, shouldFormatNumber = true } = props;
@@ -15,7 +16,9 @@ const NumberDiff = props => {
 
     return (
       <span key={idx} className={cssClass}>
-        {shouldFormatNumber ? formatNumber(value) : value}
+        {shouldFormatNumber
+          ? formatNumber(value, MAX_DIGITS, props.langtag)
+          : value}
       </span>
     );
   });
diff --git a/src/app/components/table/VirtualTable.jsx b/src/app/components/table/VirtualTable.jsx
index 5afe7abaf..7d313bffe 100644
--- a/src/app/components/table/VirtualTable.jsx
+++ b/src/app/components/table/VirtualTable.jsx
@@ -16,7 +16,7 @@ import {
 } from "../../constants/TableauxConstants";
 import { canUserCreateRow } from "../../helpers/accessManagementHelper";
 import { isLocked } from "../../helpers/annotationHelper";
-import { doto, either, mapIndexed, maybe } from "../../helpers/functools";
+import { doto, either, maybe } from "../../helpers/functools";
 import getDisplayValue from "../../helpers/getDisplayValue";
 import KeyboardShortcutsHelper from "../../helpers/KeyboardShortcutsHelper";
 import { saveColumnWidths } from "../../helpers/localStorage";
@@ -48,6 +48,9 @@ class VirtualTable extends PureComponent {
       selectedCell: {}
     };
     this.cacheColumnIndices(props.columns);
+    this.handleKeyDown = KeyboardShortcutsHelper.onKeyboardShortcut(
+      tableNavigationWorker.getKeyboardShortcuts.bind(this)
+    );
   }
 
   colWidths = new Map([[0, META_CELL_WIDTH]]);
@@ -525,6 +528,8 @@ class VirtualTable extends PureComponent {
 
   divRef = null;
 
+  handleKeypresses;
+
   render() {
     const {
       rows,
@@ -553,9 +558,7 @@ class VirtualTable extends PureComponent {
         id="virtual-table-wrapper"
         ref={this.virtualTableRef}
         tabIndex="-1"
-        onKeyDown={KeyboardShortcutsHelper.onKeyboardShortcut(
-          tableNavigationWorker.getKeyboardShortcuts.bind(this)
-        )}
+        onKeyDown={this.handleKeyDown}
       >
         <div id="resize-bar" className={resizeBarClass} />
         <AutoSizer>
diff --git a/src/app/components/table/tableNavigationWorker.jsx b/src/app/components/table/tableNavigationWorker.jsx
index 9fcdbf249..75567bfa0 100644
--- a/src/app/components/table/tableNavigationWorker.jsx
+++ b/src/app/components/table/tableNavigationWorker.jsx
@@ -9,6 +9,7 @@ import {
 import { KEYBOARD_TABLE_HISTORY } from "../../FeatureFlags";
 import { canUserChangeCell } from "../../helpers/accessManagementHelper";
 import { isLocked } from "../../helpers/annotationHelper";
+import CustomEvent from "../../helpers/CustomEvent";
 import { doto, maybe, memoizeWith, unless } from "../../helpers/functools";
 import { getModifiers } from "../../helpers/modifierState";
 import { getTableDisplayName } from "../../helpers/multiLanguage";
@@ -18,6 +19,7 @@ import AttachmentOverlay from "../cells/attachment/AttachmentOverlay";
 import pasteCellValue from "../cells/cellCopyHelper";
 import { openLinkOverlay } from "../cells/link/LinkOverlay";
 import TextEditOverlay from "../cells/text/TextEditOverlay";
+import { OpenFilterEvent } from "../header/filter/Filter";
 import Header from "../overlay/Header";
 
 const tableColumnKey = (tableId, columnId) => `${tableId}-${columnId}`;
@@ -142,7 +144,22 @@ export function getKeyboardShortcuts() {
           ColumnKinds.numeric
         ]);
 
-      if (
+      if (hasActionKey && isKeyPressed("f")) {
+        event.preventDefault();
+        if (selectedCell && selectedCellEditing) {
+          toggleCellEditing.call(this, {
+            editing: false,
+            event
+          });
+        }
+        CustomEvent.emit(
+          OpenFilterEvent,
+          {
+            filters: ["any-value", "contains", ""]
+          },
+          document.body
+        );
+      } else if (
         hasActionKey &&
         isKeyPressed("c") &&
         cellKind !== ColumnKinds.concat &&
@@ -493,10 +510,10 @@ export function getNextColumnCell(getPrev) {
     selectedCell: { selectedCell }
   } = store.getState();
 
-  const getNextColumnId = (visibleColumnOrdering, columns) => {
+  const getNextColumn = (visibleColumnOrdering, columns) => {
     const clampToVisibleRange = range => index => f.clamp(0, index, range);
     const orderedVisibleColumns = f.map(
-      columnIdx => columns[columnIdx],
+      columnId => f.find(col => col.id === columnId, columns),
       visibleColumnOrdering
     );
     return f.compose(
@@ -508,7 +525,7 @@ export function getNextColumnCell(getPrev) {
   };
 
   const currentSelectedRowId = selectedCell.rowId;
-  const nextColumn = getNextColumnId(visibleColumnOrdering, columns);
+  const nextColumn = getNextColumn(visibleColumnOrdering, columns);
 
   const newSelectedCellExpandedRow =
     !nextColumn.multilanguage &&
@@ -540,14 +557,8 @@ export function preventSleepingOnTheKeyboard(cb) {
   }
 }
 
-const getColumnIdx = (columnId, visibleColumns, visibleColumnOrdering) =>
-  f.compose(
-    idx => f.findIndex(colIdx => colIdx === idx, visibleColumnOrdering),
-    f.findIndex(col => col.id === columnId)
-  )(visibleColumns);
-
 function copySelectedCell() {
-  const { actions, rows, columns, visibleColumnOrdering } = this.props;
+  const { actions, rows, visibleColumnOrdering } = this.props;
   const {
     selectedCell: {
       selectedCell: { rowId, columnId, langtag }
@@ -555,7 +566,7 @@ function copySelectedCell() {
   } = store.getState();
 
   const rowIndex = f.findIndex(row => row.id === rowId, rows);
-  const columnIndex = getColumnIdx(columnId, columns, visibleColumnOrdering);
+  const columnIndex = f.findIndex(id => id === columnId, visibleColumnOrdering);
 
   const cell = this.getCell(rowIndex, columnIndex);
 
@@ -568,7 +579,6 @@ function copySelectedCell() {
 function pasteSelectedCell() {
   const {
     rows,
-    columns,
     tableView: { copySource },
     visibleColumnOrdering
   } = this.props;
@@ -579,7 +589,7 @@ function pasteSelectedCell() {
   } = store.getState();
 
   const rowIndex = f.findIndex(row => row.id === rowId, rows);
-  const columnIndex = getColumnIdx(columnId, columns, visibleColumnOrdering);
+  const columnIndex = f.findIndex(id => id === columnId, visibleColumnOrdering);
 
   const selectedCellObject = this.getCell(rowIndex, columnIndex);
 
diff --git a/src/app/helpers/CustomEvent.ts b/src/app/helpers/CustomEvent.ts
new file mode 100644
index 000000000..b1aecda9c
--- /dev/null
+++ b/src/app/helpers/CustomEvent.ts
@@ -0,0 +1,26 @@
+import { useEffect } from "react";
+
+export const useCustomEvent = <T>(
+  name: string,
+  handler: (_: T) => void,
+  element?: HTMLElement
+) => {
+  useEffect(() => {
+    const target = element ?? document;
+    const wrappedHandler = (evt: CustomEvent<T>) => handler(evt.detail);
+    target.addEventListener(name, wrappedHandler as EventListener);
+    return () =>
+      void target.removeEventListener(name, wrappedHandler as EventListener);
+  }, [element, handler]);
+};
+
+const emit = <T>(name: string, detail: T, element?: HTMLElement) => {
+  const target = element ?? document;
+  const evt = new CustomEvent<T>(name, { detail });
+  target.dispatchEvent(evt);
+};
+
+export default {
+  emit,
+  useCustomEvent
+};


Reviews:
user: login: McHunkyTrunk
body: Linter meldet Fehler.
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-04-09T23:06:29Z
user: login: smnhgn
body: Irgendwas stimmt mit dem Focus der Inputfelder nicht.
Öffnet man den Filter oder die EntityView springt der Focus zurück in die Zelle wenn man direkt anfängt zu tippen.
Beim Filter scheint es davon abhängig zu sein ob der Mauszeiger sich über dem FIlter-Popup oder über der Tabelle befindet.

https://github.com/user-attachments/assets/1dcc6a1e-b980-4cac-8c26-65d03c68e6fe




  
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-10T08:13:47Z
user: login: hermann-p
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T10:06:46Z
user: login: hermann-p
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T10:18:37Z
user: login: smnhgn
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-10T11:45:32Z
user: login: McHunkyTrunk
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-04-10T13:50:34Z
user: login: McHunkyTrunk
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-04-10T21:53:53Z

Review comments:
diff_hunk: @@ -3,8 +3,11 @@ import f from "lodash/fp";
 import PropTypes from "prop-types";
 import React from "react";
 import { translate } from "react-i18next";
+import CustomEvent from "../../../helpers/CustomEvent.js";
path: src/app/components/header/filter/Filter.jsx
user: login: smnhgn
body: Hier hat sich ne `.js`-Extension eingeschlichen:

```suggestion
import CustomEvent from "../../../helpers/CustomEvent";
```
created_at: 2025-04-10T07:35:13Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,25 @@
+import { useEffect } from "react";
+
+const useCustomEvent = <T>(
+    name: string,
+  handler: (_: T) => void,
+  element?: HTMLElement
+) => {
+    useEffect(() => {
+        const target = element ?? document
+        const wrappedHandler: (_: CustomEvent<T>) => void = evt => handler(evt.detail)
+        target.addEventListener(name, wrappedHandler as any);
+        return () => void target.removeEventListener(name, wrappedHandler as any)
+    }, [element, handler])
+};
+
+const emit = <T>(name: string, detail: T, element?: HTMLElement) => {
+    const target = element ?? document
+    const evt = new CustomEvent<T>(name, {detail})
+    target.dispatchEvent(evt)
+}
+
+export default {
path: src/app/helpers/CustomEvent.ts
user: login: smnhgn
body: mMn. wäre es besser `useCustomEvent` und `emit` separat zu exportieren, statt beides zusammen in einem default export. So hat man in Zukunft auch die Möglichkeit nur den Hook oder nur den emit-Handler zu importieren. (+ man hat weiterhin die Möglichkeit alles gesammelt zu importieren über `import * as CustomEvent`).
created_at: 2025-04-10T07:39:38Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,25 @@
+import { useEffect } from "react";
+
+const useCustomEvent = <T>(
+    name: string,
+  handler: (_: T) => void,
+  element?: HTMLElement
+) => {
+    useEffect(() => {
+        const target = element ?? document
path: src/app/helpers/CustomEvent.ts
user: login: smnhgn
body: Hier meckert Prettier wegen unsupported Syntax (nullish-coalescing und optional-chaining erst ab prettier version 1.19 verfügbar; aktuell prettier v1.18.2).

Habe auf dem Branch `GRUD_DEV-1103/media-move-files` einen Commit `feat: upgrade to prettier 1.19 for newer es syntax support` den du dir cherry-picken könntest.
In dem Commit habe ich auch prettier im linter auf von `error` auf `warn` gestellt, da prettier in der neueren Version das Styling auch wieder anders macht. 
created_at: 2025-04-10T07:44:55Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,25 @@
+import { useEffect } from "react";
+
+const useCustomEvent = <T>(
+    name: string,
+  handler: (_: T) => void,
+  element?: HTMLElement
+) => {
+    useEffect(() => {
+        const target = element ?? document
+        const wrappedHandler: (_: CustomEvent<T>) => void = evt => handler(evt.detail)
+        target.addEventListener(name, wrappedHandler as any);
+        return () => void target.removeEventListener(name, wrappedHandler as any)
path: src/app/helpers/CustomEvent.ts
user: login: smnhgn
body: In beiden Fällen wäre `as Eventlistener` angebrachter.
created_at: 2025-04-10T07:59:11Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,25 @@
+import { useEffect } from "react";
+
+const useCustomEvent = <T>(
+    name: string,
+  handler: (_: T) => void,
+  element?: HTMLElement
+) => {
+    useEffect(() => {
+        const target = element ?? document
+        const wrappedHandler: (_: CustomEvent<T>) => void = evt => handler(evt.detail)
path: src/app/helpers/CustomEvent.ts
user: login: smnhgn
body: ```suggestion
        const wrappedHandler = (evt: CustomEvent<T>) => handler(evt.detail)
```
created_at: 2025-04-10T08:00:38Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,25 @@
+import { useEffect } from "react";
+
+const useCustomEvent = <T>(
+    name: string,
+  handler: (_: T) => void,
+  element?: HTMLElement
+) => {
+    useEffect(() => {
+        const target = element ?? document
path: src/app/helpers/CustomEvent.ts
user: login: hermann-p
body: Hm, das ist tatsächlich eine schwierige Entscheidung. Eigentlich wollen wir Linterfehler ja als Errors haben… Vermutlich muss man im Anschluss einen eigenen PR machen, in dem wir den Linter auf Error stellen und einmal laufen lassen.
created_at: 2025-04-10T10:06:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+import { useEffect } from "react";
+
+const useCustomEvent = <T>(
+    name: string,
+  handler: (_: T) => void,
+  element?: HTMLElement
+) => {
+    useEffect(() => {
+        const target = element ?? document
+        const wrappedHandler: (_: CustomEvent<T>) => void = evt => handler(evt.detail)
+        target.addEventListener(name, wrappedHandler as any);
+        return () => void target.removeEventListener(name, wrappedHandler as any)
+    }, [element, handler])
+};
+
+const emit = <T>(name: string, detail: T, element?: HTMLElement) => {
+    const target = element ?? document
+    const evt = new CustomEvent<T>(name, {detail})
+    target.dispatchEvent(evt)
+}
+
+export default {
path: src/app/helpers/CustomEvent.ts
user: login: hermann-p
body: Hm, wir exportieren (in allen Projekten) so viele Helper direkt.
Ist zwar vom Tree-Shaking her ganz nett, weil die JS-Bundler das anders nicht auf die Reihe bekommen, führt aber dazu, dass im Laufe der Zeit Funktionen absurde/absurd lange Namen annehmen um ähnliche Dinge verschiedener Domänen unterscheiden zu können. Daher bevorzuge ich es mittlerweile, Namespaces zu exportieren. Weil, was macht `emit` ohne Kontext? Ich würde mal den Mittelweg gehen und `useCustomEvent` direkt exportieren.
created_at: 2025-04-10T10:18:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+import { useEffect } from "react";
+
+const useCustomEvent = <T>(
+    name: string,
+  handler: (_: T) => void,
+  element?: HTMLElement
+) => {
+    useEffect(() => {
+        const target = element ?? document
path: src/app/helpers/CustomEvent.ts
user: login: smnhgn
body: Ja, hätte ich auch so vorgeschlagen.
created_at: 2025-04-10T11:45:32Z
author_association: MEMBER

PR comments:
user: login: hermann-p
created_at: 2025-04-10T10:21:38Z
body: > Irgendwas stimmt mit dem Focus der Inputfelder nicht. Öffnet man den Filter oder die EntityView springt der Focus zurück in die Zelle wenn man direkt anfängt zu tippen. Beim Filter scheint es davon abhängig zu sein ob der Mauszeiger sich über dem FIlter-Popup oder über der Tabelle befindet.

Ist das neu oder unrelated? Am Fokus hat sich nur geändert, dass noch ein `autofocus` hinzugefügt wurde.
author_association: CONTRIBUTOR
user: login: McHunkyTrunk
created_at: 2025-04-10T11:15:35Z
body: > Ist das neu oder unrelated? Am Fokus hat sich nur geändert, dass noch ein `autofocus` hinzugefügt wurde.

Ich erlebe gerade beim Testen auch das Problem mit dem Fokus. Aber ich denke, das hat was mit dem Column Kind zu tun: Für Links funktioniert das wunderbar. Für Input-Column (text, numeric) scheint der Suchefeld-Fokus mit dem Zell-Fokus zu konkurrieren.

author_association: COLLABORATOR
user: login: hermann-p
created_at: 2025-04-10T13:09:43Z
body: > Ich erlebe gerade beim Testen auch das Problem mit dem Fokus […]

Hm. Der allseits beliebte Kampf um den Fokus. Ich hatte den Keyboardhandler testweise verschärft, so dass er nicht nur greift, nachdem man in die Tabelle geklickt hat. Nachteil: durch Tippen wird bei bestimmten Zelltypen automatisch in den Edit-Modus gewechselt, das wird dadurch jetzt ausgelöst. Ich habe mal die Verschärfung wieder rausgenommen; so kann man halt nicht die Suche schließen und sofort wieder mit C-f öffnen sondern muss erst einmal auf die Tabelle klicken… auch nicht 100% optimal aber besser als wenn der Fokus immer wegspringt.
author_association: CONTRIBUTOR