Compare commits

...

118 Commits
4.1.0 ... 4.3.0

Author SHA1 Message Date
Athou
32e9cd3e35 release 4.3.0 2024-02-09 20:02:17 +01:00
Athou
4bf8b5696d fix metrics page 2024-02-09 18:41:43 +01:00
Athou
0bf44dbc7b make sure we clean any existing file before starting 2024-02-09 18:32:43 +01:00
Athou
bda3ba4b5c mysql/mariadb lowest timestamp is actually 1970-01-01 00:00:01 (#1239) 2024-02-09 17:31:22 +01:00
Athou
23cff9c1e9 columnDataType is required for addNotNullConstraint on mysql 2024-02-09 17:19:47 +01:00
Athou
9691517335 add null check to userSessions 2024-02-09 17:18:18 +01:00
Jérémie Panzer
b38bd8c312 Merge pull request #1234 from Athou/dependabot/npm_and_yarn/commafeed-client/types/react-18.2.55
Bump @types/react from 18.2.53 to 18.2.55 in /commafeed-client
2024-02-09 11:10:17 +01:00
Jérémie Panzer
d8ca58389d Merge pull request #1238 from Athou/dependabot/npm_and_yarn/commafeed-client/vite-5.1.1
Bump vite from 5.0.12 to 5.1.1 in /commafeed-client
2024-02-09 11:09:44 +01:00
dependabot[bot]
20a0cd7192 Bump @types/react from 18.2.53 to 18.2.55 in /commafeed-client
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.53 to 18.2.55.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-09 10:06:24 +00:00
dependabot[bot]
9b895328be Bump vite from 5.0.12 to 5.1.1 in /commafeed-client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.12 to 5.1.1.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.1.1/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-09 10:05:37 +00:00
Jérémie Panzer
cd39ab5f95 Merge pull request #1235 from Athou/dependabot/npm_and_yarn/commafeed-client/monaco-editor-0.46.0
Bump monaco-editor from 0.45.0 to 0.46.0 in /commafeed-client
2024-02-09 11:05:33 +01:00
Jérémie Panzer
a7152a97a6 Merge pull request #1237 from Athou/dependabot/npm_and_yarn/commafeed-client/typescript-eslint/eslint-plugin-6.21.0
Bump @typescript-eslint/eslint-plugin from 6.20.0 to 6.21.0 in /commafeed-client
2024-02-09 11:05:15 +01:00
Jérémie Panzer
3e6e0a0f00 Merge pull request #1233 from Athou/dependabot/npm_and_yarn/commafeed-client/types/react-dom-18.2.19
Bump @types/react-dom from 18.2.18 to 18.2.19 in /commafeed-client
2024-02-09 11:04:49 +01:00
dependabot[bot]
2936dd0d32 Bump @typescript-eslint/eslint-plugin in /commafeed-client
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.20.0 to 6.21.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.21.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-09 09:54:35 +00:00
dependabot[bot]
38a838d210 Bump monaco-editor from 0.45.0 to 0.46.0 in /commafeed-client
Bumps [monaco-editor](https://github.com/microsoft/monaco-editor) from 0.45.0 to 0.46.0.
- [Changelog](https://github.com/microsoft/monaco-editor/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoft/monaco-editor/compare/v0.45.0...v0.46.0)

---
updated-dependencies:
- dependency-name: monaco-editor
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-09 09:53:12 +00:00
dependabot[bot]
0136fa883d Bump @types/react-dom from 18.2.18 to 18.2.19 in /commafeed-client
Bumps [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) from 18.2.18 to 18.2.19.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: "@types/react-dom"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-09 09:52:12 +00:00
Athou
b0890df2f3 add a css class for view mode (#1232) 2024-02-09 10:31:27 +01:00
Athou
91acad0dbf don't try to migrate h2 if database does not exist yet 2024-02-09 10:30:15 +01:00
Athou
14e7d70106 simplify websocket session retrieval 2024-02-05 20:27:26 +01:00
Jérémie Panzer
1cc76ba3ee Merge pull request #1230 from Athou/dependabot/npm_and_yarn/commafeed-client/types/react-18.2.53
Bump @types/react from 18.2.52 to 18.2.53 in /commafeed-client
2024-02-05 09:46:37 +01:00
dependabot[bot]
206800c091 Bump @types/react from 18.2.52 to 18.2.53 in /commafeed-client
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.52 to 18.2.53.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-05 08:42:50 +00:00
Jérémie Panzer
33749c94e3 Merge pull request #1229 from Athou/dependabot/npm_and_yarn/commafeed-client/prettier-3.2.5
Bump prettier from 3.2.4 to 3.2.5 in /commafeed-client
2024-02-04 19:55:52 +01:00
Jérémie Panzer
8bce887e4c Merge pull request #1228 from Athou/dependabot/maven/io.github.hakky54-sslcontext-kickstart-for-apache5-8.3.1
Bump io.github.hakky54:sslcontext-kickstart-for-apache5 from 8.3.0 to 8.3.1
2024-02-04 19:55:46 +01:00
dependabot[bot]
ca4f73fff6 Bump prettier from 3.2.4 to 3.2.5 in /commafeed-client
Bumps [prettier](https://github.com/prettier/prettier) from 3.2.4 to 3.2.5.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.2.4...3.2.5)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-04 18:47:35 +00:00
dependabot[bot]
26443310c9 Bump io.github.hakky54:sslcontext-kickstart-for-apache5
Bumps [io.github.hakky54:sslcontext-kickstart-for-apache5](https://github.com/Hakky54/sslcontext-kickstart) from 8.3.0 to 8.3.1.
- [Changelog](https://github.com/Hakky54/sslcontext-kickstart/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Hakky54/sslcontext-kickstart/compare/v8.3.0...v8.3.1)

---
updated-dependencies:
- dependency-name: io.github.hakky54:sslcontext-kickstart-for-apache5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-04 18:47:02 +00:00
Athou
870593bae8 add H2 migration tool 2024-02-04 18:40:59 +01:00
Jérémie Panzer
cfd5d0faab Merge pull request #1226 from aniol/patch-1
Update messages.po
2024-02-04 08:11:14 +01:00
Aniol
9391c05968 Update messages.po
updated catalan translation
2024-02-04 07:33:44 +01:00
Jérémie Panzer
a13c75981b Merge pull request #1221 from Athou/dependabot/npm_and_yarn/commafeed-client/react-router-dom-6.22.0
Bump react-router-dom from 6.21.1 to 6.22.0 in /commafeed-client
2024-02-03 17:21:28 +01:00
dependabot[bot]
a05baf63c1 Bump react-router-dom from 6.21.1 to 6.22.0 in /commafeed-client
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.21.1 to 6.22.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.22.0/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 16:16:38 +00:00
Jérémie Panzer
32ce265cff Merge pull request #1222 from Athou/dependabot/npm_and_yarn/commafeed-client/prettier-3.2.4
Bump prettier from 3.1.1 to 3.2.4 in /commafeed-client
2024-02-03 17:16:23 +01:00
Jérémie Panzer
b2ad24e7f6 Merge pull request #1223 from Athou/dependabot/npm_and_yarn/commafeed-client/react-icons-5.0.1
Bump react-icons from 4.12.0 to 5.0.1 in /commafeed-client
2024-02-03 17:16:17 +01:00
Jérémie Panzer
fe626ebbe3 Merge pull request #1224 from Athou/dependabot/npm_and_yarn/commafeed-client/react-redux-9.1.0
Bump react-redux from 9.0.4 to 9.1.0 in /commafeed-client
2024-02-03 17:16:10 +01:00
Jérémie Panzer
4431a898a0 Merge pull request #1225 from Athou/dependabot/npm_and_yarn/commafeed-client/vitest-1.2.2
Bump vitest from 1.1.3 to 1.2.2 in /commafeed-client
2024-02-03 17:15:59 +01:00
dependabot[bot]
89bfcfa240 Bump vitest from 1.1.3 to 1.2.2 in /commafeed-client
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 1.1.3 to 1.2.2.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v1.2.2/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 16:10:30 +00:00
dependabot[bot]
d046d26f4e Bump react-redux from 9.0.4 to 9.1.0 in /commafeed-client
Bumps [react-redux](https://github.com/reduxjs/react-redux) from 9.0.4 to 9.1.0.
- [Release notes](https://github.com/reduxjs/react-redux/releases)
- [Changelog](https://github.com/reduxjs/react-redux/blob/master/CHANGELOG.md)
- [Commits](https://github.com/reduxjs/react-redux/compare/v9.0.4...v9.1.0)

---
updated-dependencies:
- dependency-name: react-redux
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 16:10:14 +00:00
dependabot[bot]
26b634b1a3 Bump react-icons from 4.12.0 to 5.0.1 in /commafeed-client
Bumps [react-icons](https://github.com/react-icons/react-icons) from 4.12.0 to 5.0.1.
- [Release notes](https://github.com/react-icons/react-icons/releases)
- [Commits](https://github.com/react-icons/react-icons/compare/v4.12.0...v5.0.1)

---
updated-dependencies:
- dependency-name: react-icons
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 16:09:58 +00:00
dependabot[bot]
3ca18bbd36 Bump prettier from 3.1.1 to 3.2.4 in /commafeed-client
Bumps [prettier](https://github.com/prettier/prettier) from 3.1.1 to 3.2.4.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.1.1...3.2.4)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 16:09:46 +00:00
Jérémie Panzer
7645731fff Merge pull request #1211 from Athou/dependabot/npm_and_yarn/commafeed-client/mantine-5b631ac874
Bump the mantine group in /commafeed-client with 6 updates
2024-02-03 11:51:24 +01:00
Athou
3c116dbabe fix build 2024-02-03 11:44:58 +01:00
dependabot[bot]
3026fd116c Bump the mantine group in /commafeed-client with 6 updates
Bumps the mantine group in /commafeed-client with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@mantine/core](https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/core) | `7.3.2` | `7.5.1` |
| [@mantine/form](https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/form) | `7.3.2` | `7.5.1` |
| [@mantine/hooks](https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks) | `7.3.2` | `7.5.1` |
| [@mantine/modals](https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/modals) | `7.3.2` | `7.5.1` |
| [@mantine/notifications](https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/notifications) | `7.3.2` | `7.5.1` |
| [@mantine/spotlight](https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/spotlight) | `7.3.2` | `7.5.1` |


Updates `@mantine/core` from 7.3.2 to 7.5.1
- [Release notes](https://github.com/mantinedev/mantine/releases)
- [Changelog](https://github.com/mantinedev/mantine/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mantinedev/mantine/commits/7.5.1/packages/@mantine/core)

Updates `@mantine/form` from 7.3.2 to 7.5.1
- [Release notes](https://github.com/mantinedev/mantine/releases)
- [Changelog](https://github.com/mantinedev/mantine/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mantinedev/mantine/commits/7.5.1/packages/@mantine/form)

Updates `@mantine/hooks` from 7.3.2 to 7.5.1
- [Release notes](https://github.com/mantinedev/mantine/releases)
- [Changelog](https://github.com/mantinedev/mantine/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mantinedev/mantine/commits/7.5.1/packages/@mantine/hooks)

Updates `@mantine/modals` from 7.3.2 to 7.5.1
- [Release notes](https://github.com/mantinedev/mantine/releases)
- [Changelog](https://github.com/mantinedev/mantine/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mantinedev/mantine/commits/7.5.1/packages/@mantine/modals)

Updates `@mantine/notifications` from 7.3.2 to 7.5.1
- [Release notes](https://github.com/mantinedev/mantine/releases)
- [Changelog](https://github.com/mantinedev/mantine/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mantinedev/mantine/commits/7.5.1/packages/@mantine/notifications)

Updates `@mantine/spotlight` from 7.3.2 to 7.5.1
- [Release notes](https://github.com/mantinedev/mantine/releases)
- [Changelog](https://github.com/mantinedev/mantine/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mantinedev/mantine/commits/7.5.1/packages/@mantine/spotlight)

---
updated-dependencies:
- dependency-name: "@mantine/core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: mantine
- dependency-name: "@mantine/form"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: mantine
- dependency-name: "@mantine/hooks"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: mantine
- dependency-name: "@mantine/modals"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: mantine
- dependency-name: "@mantine/notifications"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: mantine
- dependency-name: "@mantine/spotlight"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: mantine
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 09:20:11 +00:00
Jérémie Panzer
63fa725a13 Merge pull request #1220 from Athou/dependabot/npm_and_yarn/commafeed-client/reduxjs/toolkit-2.1.0
Bump @reduxjs/toolkit from 2.0.1 to 2.1.0 in /commafeed-client
2024-02-03 10:19:05 +01:00
Jérémie Panzer
ede4e07ff3 Merge pull request #1218 from Athou/dependabot/npm_and_yarn/commafeed-client/eslint-config-standard-with-typescript-43.0.1
Bump eslint-config-standard-with-typescript from 43.0.0 to 43.0.1 in /commafeed-client
2024-02-03 10:18:56 +01:00
dependabot[bot]
de6dfbe8b2 Bump @reduxjs/toolkit from 2.0.1 to 2.1.0 in /commafeed-client
Bumps [@reduxjs/toolkit](https://github.com/reduxjs/redux-toolkit) from 2.0.1 to 2.1.0.
- [Release notes](https://github.com/reduxjs/redux-toolkit/releases)
- [Commits](https://github.com/reduxjs/redux-toolkit/compare/v2.0.1...v2.1.0)

---
updated-dependencies:
- dependency-name: "@reduxjs/toolkit"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 09:13:40 +00:00
Jérémie Panzer
164a57bef5 Merge pull request #1217 from Athou/dependabot/npm_and_yarn/commafeed-client/types/react-18.2.52
Bump @types/react from 18.2.46 to 18.2.52 in /commafeed-client
2024-02-03 10:13:03 +01:00
Jérémie Panzer
fd82b8aaee Merge pull request #1216 from Athou/dependabot/npm_and_yarn/commafeed-client/fontsource/open-sans-5.0.22
Bump @fontsource/open-sans from 5.0.20 to 5.0.22 in /commafeed-client
2024-02-03 10:12:53 +01:00
Jérémie Panzer
facf8b43f2 Merge pull request #1214 from Athou/dependabot/npm_and_yarn/commafeed-client/axios-1.6.7
Bump axios from 1.6.3 to 1.6.7 in /commafeed-client
2024-02-03 10:12:38 +01:00
Jérémie Panzer
3184dfe178 Merge pull request #1213 from Athou/dependabot/npm_and_yarn/commafeed-client/vite-tsconfig-paths-4.3.1
Bump vite-tsconfig-paths from 4.2.3 to 4.3.1 in /commafeed-client
2024-02-03 10:12:27 +01:00
Jérémie Panzer
cc584fd8c8 Merge pull request #1212 from Athou/dependabot/npm_and_yarn/commafeed-client/tss-react-4.9.4
Bump tss-react from 4.9.3 to 4.9.4 in /commafeed-client
2024-02-03 10:12:10 +01:00
Jérémie Panzer
0f8fa1f2e1 Merge pull request #1210 from Athou/dependabot/maven/com.microsoft.playwright-playwright-1.41.2
Bump com.microsoft.playwright:playwright from 1.41.1 to 1.41.2
2024-02-03 10:11:47 +01:00
Jérémie Panzer
d93f7bd20e Merge pull request #1219 from Athou/dependabot/npm_and_yarn/commafeed-client/typescript-eslint/eslint-plugin-6.20.0
Bump @typescript-eslint/eslint-plugin from 6.16.0 to 6.20.0 in /commafeed-client
2024-02-03 10:11:17 +01:00
dependabot[bot]
96aa06d2dd Bump eslint-config-standard-with-typescript in /commafeed-client
Bumps [eslint-config-standard-with-typescript](https://github.com/mightyiam/eslint-config-standard-with-typescript) from 43.0.0 to 43.0.1.
- [Release notes](https://github.com/mightyiam/eslint-config-standard-with-typescript/releases)
- [Changelog](https://github.com/mightyiam/eslint-config-standard-with-typescript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mightyiam/eslint-config-standard-with-typescript/compare/v43.0.0...v43.0.1)

---
updated-dependencies:
- dependency-name: eslint-config-standard-with-typescript
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 09:10:57 +00:00
Jérémie Panzer
fdaff46008 Merge pull request #1215 from Athou/dependabot/npm_and_yarn/commafeed-client/eslint-plugin-prettier-5.1.3
Bump eslint-plugin-prettier from 5.1.2 to 5.1.3 in /commafeed-client
2024-02-03 10:10:12 +01:00
dependabot[bot]
71066cd768 Bump @typescript-eslint/eslint-plugin in /commafeed-client
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.16.0 to 6.20.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.20.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 08:15:57 +00:00
dependabot[bot]
b9610a9058 Bump @types/react from 18.2.46 to 18.2.52 in /commafeed-client
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.46 to 18.2.52.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 08:15:29 +00:00
dependabot[bot]
ca027d5a4d Bump @fontsource/open-sans from 5.0.20 to 5.0.22 in /commafeed-client
Bumps [@fontsource/open-sans](https://github.com/fontsource/font-files/tree/HEAD/fonts/google/open-sans) from 5.0.20 to 5.0.22.
- [Changelog](https://github.com/fontsource/font-files/blob/main/fonts/google/open-sans/CHANGELOG.md)
- [Commits](https://github.com/fontsource/font-files/commits/HEAD/fonts/google/open-sans)

---
updated-dependencies:
- dependency-name: "@fontsource/open-sans"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 08:15:21 +00:00
dependabot[bot]
1dea51c705 Bump eslint-plugin-prettier from 5.1.2 to 5.1.3 in /commafeed-client
Bumps [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) from 5.1.2 to 5.1.3.
- [Release notes](https://github.com/prettier/eslint-plugin-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-plugin-prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-plugin-prettier/compare/v5.1.2...v5.1.3)

---
updated-dependencies:
- dependency-name: eslint-plugin-prettier
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 08:15:11 +00:00
dependabot[bot]
8edc89f3cc Bump axios from 1.6.3 to 1.6.7 in /commafeed-client
Bumps [axios](https://github.com/axios/axios) from 1.6.3 to 1.6.7.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.6.3...v1.6.7)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 08:15:02 +00:00
dependabot[bot]
4cbf32cbb8 Bump vite-tsconfig-paths from 4.2.3 to 4.3.1 in /commafeed-client
Bumps [vite-tsconfig-paths](https://github.com/aleclarson/vite-tsconfig-paths) from 4.2.3 to 4.3.1.
- [Release notes](https://github.com/aleclarson/vite-tsconfig-paths/releases)
- [Commits](https://github.com/aleclarson/vite-tsconfig-paths/compare/v4.2.3...v4.3.1)

---
updated-dependencies:
- dependency-name: vite-tsconfig-paths
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 08:14:53 +00:00
dependabot[bot]
a5dc551b6b Bump tss-react from 4.9.3 to 4.9.4 in /commafeed-client
Bumps [tss-react](https://github.com/garronej/tss-react) from 4.9.3 to 4.9.4.
- [Release notes](https://github.com/garronej/tss-react/releases)
- [Commits](https://github.com/garronej/tss-react/compare/v4.9.3...v4.9.4)

---
updated-dependencies:
- dependency-name: tss-react
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 08:14:43 +00:00
dependabot[bot]
b1e0dbd0b3 Bump com.microsoft.playwright:playwright from 1.41.1 to 1.41.2
Bumps [com.microsoft.playwright:playwright](https://github.com/microsoft/playwright-java) from 1.41.1 to 1.41.2.
- [Release notes](https://github.com/microsoft/playwright-java/releases)
- [Commits](https://github.com/microsoft/playwright-java/compare/v1.41.1...v1.41.2)

---
updated-dependencies:
- dependency-name: com.microsoft.playwright:playwright
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-03 08:13:26 +00:00
Athou
58789b15a3 configure dependabot for client dependencies 2024-02-03 09:13:00 +01:00
Athou
c5f58a2fe9 add test to make sure the session has been invalidated 2024-02-02 20:25:27 +01:00
Athou
253ba5f18b remove unused eslint plugins 2024-01-31 20:13:52 +01:00
Athou
ae859178c0 increase pull request limit 2024-01-30 22:42:55 +01:00
Jérémie Panzer
942dc0befe Merge pull request #1206 from Athou/dependabot/maven/com.microsoft.playwright-playwright-1.41.1
Bump com.microsoft.playwright:playwright from 1.40.0 to 1.41.1
2024-01-30 22:42:02 +01:00
Jérémie Panzer
66c4510fd3 Merge pull request #1205 from Athou/dependabot/maven/org.jsoup-jsoup-1.17.2
Bump org.jsoup:jsoup from 1.17.1 to 1.17.2
2024-01-30 22:41:48 +01:00
Jérémie Panzer
feb7de504c Merge pull request #1204 from Athou/dependabot/maven/io.dropwizard-dropwizard-dependencies-4.0.6
Bump io.dropwizard:dropwizard-dependencies from 4.0.5 to 4.0.6
2024-01-30 22:41:38 +01:00
Jérémie Panzer
ec4b809ff9 Merge pull request #1207 from Athou/dependabot/maven/org.gwtproject-gwt-servlet-2.11.0
Bump org.gwtproject:gwt-servlet from 2.10.0 to 2.11.0
2024-01-30 22:41:28 +01:00
Jérémie Panzer
b8d6a5742b Merge pull request #1203 from Athou/dependabot/maven/com.mysql-mysql-connector-j-8.3.0
Bump com.mysql:mysql-connector-j from 8.2.0 to 8.3.0
2024-01-30 22:41:17 +01:00
dependabot[bot]
31c42403a1 Bump org.gwtproject:gwt-servlet from 2.10.0 to 2.11.0
Bumps org.gwtproject:gwt-servlet from 2.10.0 to 2.11.0.

---
updated-dependencies:
- dependency-name: org.gwtproject:gwt-servlet
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:36:11 +00:00
dependabot[bot]
ead97be3cf Bump com.microsoft.playwright:playwright from 1.40.0 to 1.41.1
Bumps [com.microsoft.playwright:playwright](https://github.com/microsoft/playwright-java) from 1.40.0 to 1.41.1.
- [Release notes](https://github.com/microsoft/playwright-java/releases)
- [Commits](https://github.com/microsoft/playwright-java/compare/v1.40.0...v1.41.1)

---
updated-dependencies:
- dependency-name: com.microsoft.playwright:playwright
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:36:05 +00:00
dependabot[bot]
3ee43f75d6 Bump org.jsoup:jsoup from 1.17.1 to 1.17.2
Bumps [org.jsoup:jsoup](https://github.com/jhy/jsoup) from 1.17.1 to 1.17.2.
- [Release notes](https://github.com/jhy/jsoup/releases)
- [Changelog](https://github.com/jhy/jsoup/blob/master/CHANGES.md)
- [Commits](https://github.com/jhy/jsoup/compare/jsoup-1.17.1...jsoup-1.17.2)

---
updated-dependencies:
- dependency-name: org.jsoup:jsoup
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:35:53 +00:00
dependabot[bot]
f77b91540d Bump io.dropwizard:dropwizard-dependencies from 4.0.5 to 4.0.6
Bumps io.dropwizard:dropwizard-dependencies from 4.0.5 to 4.0.6.

---
updated-dependencies:
- dependency-name: io.dropwizard:dropwizard-dependencies
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:35:34 +00:00
dependabot[bot]
34915c93b8 Bump com.mysql:mysql-connector-j from 8.2.0 to 8.3.0
Bumps [com.mysql:mysql-connector-j](https://github.com/mysql/mysql-connector-j) from 8.2.0 to 8.3.0.
- [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.x/CHANGES)
- [Commits](https://github.com/mysql/mysql-connector-j/compare/8.2.0...8.3.0)

---
updated-dependencies:
- dependency-name: com.mysql:mysql-connector-j
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:35:26 +00:00
Jérémie Panzer
365044d205 Merge pull request #1202 from Athou/dependabot/maven/io.github.hakky54-sslcontext-kickstart-for-apache5-8.3.0
Bump io.github.hakky54:sslcontext-kickstart-for-apache5 from 8.2.0 to 8.3.0
2024-01-30 22:33:57 +01:00
Jérémie Panzer
46f84ab29e Merge pull request #1198 from Athou/dependabot/maven/org.apache.maven.plugins-maven-surefire-plugin-3.2.5
Bump org.apache.maven.plugins:maven-surefire-plugin from 3.2.3 to 3.2.5
2024-01-30 22:33:50 +01:00
Jérémie Panzer
2041823f0d Merge pull request #1199 from Athou/dependabot/maven/org.mariadb.jdbc-mariadb-java-client-3.3.2
Bump org.mariadb.jdbc:mariadb-java-client from 3.3.1 to 3.3.2
2024-01-30 22:33:42 +01:00
Jérémie Panzer
ff01d7a87c Merge pull request #1200 from Athou/dependabot/maven/querydsl.version-5.1.0
Bump querydsl.version from 5.0.0 to 5.1.0
2024-01-30 22:33:35 +01:00
Jérémie Panzer
4d905b118a Merge pull request #1201 from Athou/dependabot/maven/com.diffplug.spotless-spotless-maven-plugin-2.43.0
Bump com.diffplug.spotless:spotless-maven-plugin from 2.41.1 to 2.43.0
2024-01-30 22:33:21 +01:00
Athou
6d74b50751 login to docker hub only if we need to be logged in 2024-01-30 22:28:05 +01:00
dependabot[bot]
f12bdf5841 Bump io.github.hakky54:sslcontext-kickstart-for-apache5
Bumps [io.github.hakky54:sslcontext-kickstart-for-apache5](https://github.com/Hakky54/sslcontext-kickstart) from 8.2.0 to 8.3.0.
- [Changelog](https://github.com/Hakky54/sslcontext-kickstart/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Hakky54/sslcontext-kickstart/compare/v8.2.0...v8.3.0)

---
updated-dependencies:
- dependency-name: io.github.hakky54:sslcontext-kickstart-for-apache5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:16:26 +00:00
dependabot[bot]
6b89e211d8 Bump com.diffplug.spotless:spotless-maven-plugin from 2.41.1 to 2.43.0
Bumps [com.diffplug.spotless:spotless-maven-plugin](https://github.com/diffplug/spotless) from 2.41.1 to 2.43.0.
- [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md)
- [Commits](https://github.com/diffplug/spotless/compare/maven/2.41.1...lib/2.43.0)

---
updated-dependencies:
- dependency-name: com.diffplug.spotless:spotless-maven-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:16:21 +00:00
dependabot[bot]
1b00e5613a Bump querydsl.version from 5.0.0 to 5.1.0
Bumps `querydsl.version` from 5.0.0 to 5.1.0.

Updates `com.querydsl:querydsl-apt` from 5.0.0 to 5.1.0

Updates `com.querydsl:querydsl-jpa` from 5.0.0 to 5.1.0

---
updated-dependencies:
- dependency-name: com.querydsl:querydsl-apt
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.querydsl:querydsl-jpa
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:16:16 +00:00
dependabot[bot]
050a8b24fc Bump org.mariadb.jdbc:mariadb-java-client from 3.3.1 to 3.3.2
Bumps [org.mariadb.jdbc:mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) from 3.3.1 to 3.3.2.
- [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases)
- [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/3.3.1...3.3.2)

---
updated-dependencies:
- dependency-name: org.mariadb.jdbc:mariadb-java-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:16:12 +00:00
dependabot[bot]
c5b1ea486c Bump org.apache.maven.plugins:maven-surefire-plugin from 3.2.3 to 3.2.5
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.3 to 3.2.5.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.3...surefire-3.2.5)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:16:04 +00:00
Jérémie Panzer
7b8c0ac6ff Merge pull request #1193 from Athou/dependabot/maven/com.google.apis-google-api-services-youtube-v3-rev20240123-2.0.0
Bump com.google.apis:google-api-services-youtube from v3-rev20231011-2.0.0 to v3-rev20240123-2.0.0
2024-01-30 22:12:22 +01:00
Jérémie Panzer
d43039cf9f Merge pull request #1197 from Athou/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.12.1
Bump org.apache.maven.plugins:maven-compiler-plugin from 3.11.0 to 3.12.1
2024-01-30 22:12:14 +01:00
Jérémie Panzer
3adc043740 Merge pull request #1196 from Athou/dependabot/maven/org.apache.maven.plugins-maven-failsafe-plugin-3.2.5
Bump org.apache.maven.plugins:maven-failsafe-plugin from 3.2.3 to 3.2.5
2024-01-30 22:11:36 +01:00
Jérémie Panzer
08b95ff3dd Merge pull request #1195 from Athou/dependabot/maven/io.swagger.core.v3-swagger-maven-plugin-jakarta-2.2.20
Bump io.swagger.core.v3:swagger-maven-plugin-jakarta from 2.2.19 to 2.2.20
2024-01-30 22:11:28 +01:00
Jérémie Panzer
e043ce71c3 Merge pull request #1194 from Athou/dependabot/maven/io.swagger.core.v3-swagger-annotations-2.2.20
Bump io.swagger.core.v3:swagger-annotations from 2.2.19 to 2.2.20
2024-01-30 22:11:17 +01:00
Athou
b345319f68 don't try to login to docker hub for pull requests 2024-01-30 22:09:29 +01:00
dependabot[bot]
4c298df9c9 Bump org.apache.maven.plugins:maven-compiler-plugin
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.11.0 to 3.12.1.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.11.0...maven-compiler-plugin-3.12.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:03:03 +00:00
dependabot[bot]
067e01660a Bump org.apache.maven.plugins:maven-failsafe-plugin from 3.2.3 to 3.2.5
Bumps [org.apache.maven.plugins:maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.2.3 to 3.2.5.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.3...surefire-3.2.5)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-failsafe-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:02:57 +00:00
dependabot[bot]
c649a04891 Bump io.swagger.core.v3:swagger-maven-plugin-jakarta
Bumps io.swagger.core.v3:swagger-maven-plugin-jakarta from 2.2.19 to 2.2.20.

---
updated-dependencies:
- dependency-name: io.swagger.core.v3:swagger-maven-plugin-jakarta
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:02:51 +00:00
dependabot[bot]
9b9a4f98f4 Bump io.swagger.core.v3:swagger-annotations from 2.2.19 to 2.2.20
Bumps io.swagger.core.v3:swagger-annotations from 2.2.19 to 2.2.20.

---
updated-dependencies:
- dependency-name: io.swagger.core.v3:swagger-annotations
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:02:48 +00:00
dependabot[bot]
f8b6f2f237 Bump com.google.apis:google-api-services-youtube
Bumps com.google.apis:google-api-services-youtube from v3-rev20231011-2.0.0 to v3-rev20240123-2.0.0.

---
updated-dependencies:
- dependency-name: com.google.apis:google-api-services-youtube
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 21:02:44 +00:00
Jérémie Panzer
371ce0d160 Create dependabot.yml 2024-01-30 22:01:04 +01:00
Athou
a92a7217ff add a setting to completely disable scrolling to selected entry (#1157) 2024-01-29 20:30:49 +01:00
Athou
e69c230678 bump github action versions to remove warnings 2024-01-26 10:11:41 +01:00
Athou
b82077d3ca release 4.2.1 2024-01-26 09:54:07 +01:00
Athou
c624955ea4 websocket notification now takes entry filtering into account (#1191) 2024-01-24 15:47:37 +01:00
Athou
9354fb8e18 release 4.2.0 2024-01-22 15:07:17 +01:00
Jérémie Panzer
664ed317a0 Merge pull request #1189 from Athou/dependabot/npm_and_yarn/commafeed-client/vite-5.0.12
Bump vite from 5.0.11 to 5.0.12 in /commafeed-client
2024-01-20 08:33:52 +01:00
dependabot[bot]
5bf121782b Bump vite from 5.0.11 to 5.0.12 in /commafeed-client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.11 to 5.0.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.0.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.0.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-20 07:29:09 +00:00
Athou
66c361e6a6 no need to render the header twice 2024-01-18 09:39:53 +01:00
Athou
0946c0248e show footer on the bottom of the page on mobile (#1121) 2024-01-18 09:29:12 +01:00
Athou
a8be8f2edf remove unnecessary usage of headerHeight 2024-01-18 09:05:32 +01:00
Athou
99db85328b scroll to the correct position regardless of the position or height of the header 2024-01-18 09:05:32 +01:00
Athou
5f29838bd2 clarify some descriptions in the profile settings 2024-01-16 07:07:49 +01:00
Athou
7d2c0e7576 remove the license from the README because there's already a LICENSE file 2024-01-15 11:10:01 +01:00
Athou
b8211e69e9 remove websocket bundle because it doesn't add much, use jetty directly 2024-01-15 09:53:52 +01:00
Athou
d7b2c5a6e3 add fix for fever api for Unread (#1188) 2024-01-14 18:34:50 +01:00
Athou
18358d5991 don't return last_refreshed_on_time when not set 2024-01-14 18:21:52 +01:00
Athou
e9b4895b0f move timezone logic to a reusable timestamp_type property 2024-01-13 17:23:16 +01:00
Athou
c4fbf98200 convert datetime fields to timestamp fields since we want to store UTC timestamps (#1187) 2024-01-13 14:58:03 +01:00
Athou
b0aa6ae524 the "new-feed-entries" websocket event no longer needs to reload the entire tree 2024-01-13 09:20:56 +01:00
Athou
11dd151a3b fix typo 2024-01-12 08:22:36 +01:00
86 changed files with 2049 additions and 561 deletions

24
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "npm"
directory: "/commafeed-client"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
groups:
mantine:
patterns:
- "@mantine/*"
lingui:
patterns:
- "@lingui/*"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10

View File

@@ -11,19 +11,19 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
# Setup # Setup
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v3
- name: Set up Java - name: Set up Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
distribution: "temurin" distribution: "temurin"
@@ -42,14 +42,14 @@ jobs:
# Docker # Docker
- name: Login to Container Registry - name: Login to Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v3
if: ${{ matrix.java == '17' }} if: ${{ matrix.java == '17' && (github.ref_type == 'tag' || github.ref_name == 'master') }}
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker build and push tag - name: Docker build and push tag
uses: docker/build-push-action@v4 uses: docker/build-push-action@v5
if: ${{ matrix.java == '17' && github.ref_type == 'tag' }} if: ${{ matrix.java == '17' && github.ref_type == 'tag' }}
with: with:
context: . context: .
@@ -60,7 +60,7 @@ jobs:
athou/commafeed:${{ github.ref_name }} athou/commafeed:${{ github.ref_name }}
- name: Docker build and push master - name: Docker build and push master
uses: docker/build-push-action@v4 uses: docker/build-push-action@v5
if: ${{ matrix.java == '17' && github.ref_name == 'master' }} if: ${{ matrix.java == '17' && github.ref_name == 'master' }}
with: with:
context: . context: .

View File

@@ -1,9 +1,32 @@
# Changelog # Changelog
## [4.3.0]
- h2 (the embedded database) has been upgraded to 2.2.224
- this version uses a different file format than 2.1.x, the first time you start CommaFeed with this version, the
database will be automatically converted to the new format
- add a setting to completely disable scrolling to selected entry (#1157)
- add a css class reflecting the current view mode to ease custom css rules (#1232)
- fix an issue that prevents new feeds from being added when mysql/mariadb is used as the database (#1239)
## [4.2.1]
- fix an issue that caused the tree to show an incorrect unread count after a websocket notification because entries
that were already marked as read by a filtering expression were not ignored (#1191)
## [4.2.0]
- add a setting to display the action buttons in the footer instead of in the header on mobile (#1121)
- the websocket notification now contains everything needed to update the UI, the client no longer needs to make an API
call to get the latest data when receiving the notification
- add a workaround to the Fever API for the Unread iOS app (#1188)
- fix an issue that caused dates to be saved incorrectly if the database server and the application server were in
different timezones (#1187)
## [4.1.0] ## [4.1.0]
- it is now possible to open the sidebar on mobile by swiping to the right (#1098) - it is now possible to open the sidebar on mobile by swiping to the right (#1098)
- swiping to mark entries as read/unread changed from swipinig right to left because swiping right now opens the sidebar - swiping to mark entries as read/unread changed from swiping right to left because swiping right now opens the sidebar
- the full hierarchy of categories are now displayed in the category dropdown (#1045) - the full hierarchy of categories are now displayed in the category dropdown (#1045)
- added a setting `maxEntriesAgeDays` to delete old entries based on their age during database cleanup. - added a setting `maxEntriesAgeDays` to delete old entries based on their age during database cleanup.
The setting is disabled by default for existing installations, except for the docker image where it is enabled and set The setting is disabled by default for existing installations, except for the docker image where it is enabled and set

View File

@@ -109,19 +109,3 @@ two-letters [ISO-639-1 language code](http://en.wikipedia.org/wiki/List_of_ISO_6
The frontend server is now running at http://localhost:8082 and is proxying REST requests to the backend running on The frontend server is now running at http://localhost:8082 and is proxying REST requests to the backend running on
port 8083 port 8083
## Copyright and license
Copyright 2013-2023 CommaFeed.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this work except in compliance with the License.
You may obtain a copy of the License in the LICENSE file, or at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

File diff suppressed because it is too large Load Diff

View File

@@ -15,23 +15,23 @@
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.3", "@emotion/react": "^11.11.3",
"@fontsource/open-sans": "^5.0.20", "@fontsource/open-sans": "^5.0.22",
"@lingui/core": "^4.7.0", "@lingui/core": "^4.7.0",
"@lingui/macro": "^4.7.0", "@lingui/macro": "^4.7.0",
"@lingui/react": "^4.7.0", "@lingui/react": "^4.7.0",
"@mantine/core": "^7.3.2", "@mantine/core": "^7.5.1",
"@mantine/form": "^7.3.2", "@mantine/form": "^7.5.1",
"@mantine/hooks": "^7.3.2", "@mantine/hooks": "^7.5.1",
"@mantine/modals": "^7.3.2", "@mantine/modals": "^7.5.1",
"@mantine/notifications": "^7.3.2", "@mantine/notifications": "^7.5.1",
"@mantine/spotlight": "^7.3.2", "@mantine/spotlight": "^7.5.1",
"@monaco-editor/react": "^4.6.0", "@monaco-editor/react": "^4.6.0",
"@reduxjs/toolkit": "^2.0.1", "@reduxjs/toolkit": "^2.1.0",
"axios": "^1.6.3", "axios": "^1.6.7",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"escape-string-regexp": "^5.0.0", "escape-string-regexp": "^5.0.0",
"interweave": "^13.1.0", "interweave": "^13.1.0",
"monaco-editor": "^0.45.0", "monaco-editor": "^0.46.0",
"mousetrap": "^1.6.5", "mousetrap": "^1.6.5",
"react": "^18.2.0", "react": "^18.2.0",
"react-async-hook": "^4.0.0", "react-async-hook": "^4.0.0",
@@ -39,15 +39,15 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-draggable": "^4.4.6", "react-draggable": "^4.4.6",
"react-ga4": "^2.1.0", "react-ga4": "^2.1.0",
"react-icons": "^4.12.0", "react-icons": "^5.0.1",
"react-infinite-scroller": "^1.2.6", "react-infinite-scroller": "^1.2.6",
"react-redux": "^9.0.4", "react-redux": "^9.1.0",
"react-router-dom": "^6.21.1", "react-router-dom": "^6.22.0",
"react-swipeable": "^7.0.1", "react-swipeable": "^7.0.1",
"redoc": "^2.1.3", "redoc": "^2.1.3",
"throttle-debounce": "^5.0.0", "throttle-debounce": "^5.0.0",
"tinycon": "^0.6.8", "tinycon": "^0.6.8",
"tss-react": "^4.9.3", "tss-react": "^4.9.4",
"use-local-storage": "^3.0.0", "use-local-storage": "^3.0.0",
"websocket-heartbeat-js": "^1.1.3" "websocket-heartbeat-js": "^1.1.3"
}, },
@@ -55,31 +55,28 @@
"@lingui/cli": "^4.7.0", "@lingui/cli": "^4.7.0",
"@lingui/vite-plugin": "^4.7.0", "@lingui/vite-plugin": "^4.7.0",
"@types/mousetrap": "^1.6.15", "@types/mousetrap": "^1.6.15",
"@types/react": "^18.2.46", "@types/react": "^18.2.55",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.19",
"@types/react-infinite-scroller": "^1.2.5", "@types/react-infinite-scroller": "^1.2.5",
"@types/swagger-ui-react": "^4.18.3", "@types/swagger-ui-react": "^4.18.3",
"@types/throttle-debounce": "^5.0.2", "@types/throttle-debounce": "^5.0.2",
"@types/tinycon": "^0.6.5", "@types/tinycon": "^0.6.5",
"@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/eslint-plugin": "^6.21.0",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"babel-plugin-macros": "^3.1.0", "babel-plugin-macros": "^3.1.0",
"eslint": "^8.56.0", "eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-config-standard-with-typescript": "^43.0.0", "eslint-config-standard-with-typescript": "^43.0.1",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-n": "^16.5.0",
"eslint-plugin-prettier": "^5.1.2",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"prettier": "^3.1.1", "prettier": "^3.2.5",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.11", "vite": "^5.1.1",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vite-tsconfig-paths": "^4.2.3", "vite-tsconfig-paths": "^4.3.1",
"vitest": "^1.1.3", "vitest": "^1.2.2",
"vitest-mock-extended": "^1.3.1" "vitest-mock-extended": "^1.3.1"
} }
} }

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.commafeed</groupId> <groupId>com.commafeed</groupId>
<artifactId>commafeed</artifactId> <artifactId>commafeed</artifactId>
<version>4.1.0</version> <version>4.3.0</version>
</parent> </parent>
<artifactId>commafeed-client</artifactId> <artifactId>commafeed-client</artifactId>
<name>CommaFeed Client</name> <name>CommaFeed Client</name>

View File

@@ -89,10 +89,18 @@ export const Constants = {
mobileBreakpointName: "md", mobileBreakpointName: "md",
headerHeight: 60, headerHeight: 60,
entryMaxWidth: 650, entryMaxWidth: 650,
isTopVisible: (div: HTMLElement) => div.getBoundingClientRect().top >= Constants.layout.headerHeight, isTopVisible: (div: HTMLElement) => {
isBottomVisible: (div: HTMLElement) => div.getBoundingClientRect().bottom <= window.innerHeight, const header = document.getElementById(Constants.dom.headerId)?.getBoundingClientRect()
return div.getBoundingClientRect().top >= (header?.bottom ?? 0)
},
isBottomVisible: (div: HTMLElement) => {
const footer = document.getElementById(Constants.dom.footerId)?.getBoundingClientRect()
return div.getBoundingClientRect().bottom <= (footer?.top ?? window.innerHeight)
},
}, },
dom: { dom: {
headerId: "header",
footerId: "footer",
entryId: (entry: Entry) => `entry-id-${entry.id}`, entryId: (entry: Entry) => `entry-id-${entry.id}`,
entryContextMenuId: (entry: Entry) => entry.id, entryContextMenuId: (entry: Entry) => entry.id,
}, },

View File

@@ -162,9 +162,9 @@ export const selectEntry = createAppAsyncThunk(
if (arg.scrollToEntry) { if (arg.scrollToEntry) {
const entryElement = document.getElementById(Constants.dom.entryId(entry)) const entryElement = document.getElementById(Constants.dom.entryId(entry))
if (entryElement) { if (entryElement) {
const alwaysScrollToEntry = state.user.settings?.alwaysScrollToEntry const scrollMode = state.user.settings?.scrollMode
const entryEntirelyVisible = Constants.layout.isTopVisible(entryElement) && Constants.layout.isBottomVisible(entryElement) const entryEntirelyVisible = Constants.layout.isTopVisible(entryElement) && Constants.layout.isBottomVisible(entryElement)
if (alwaysScrollToEntry || !entryEntirelyVisible) { if (scrollMode === "always" || (scrollMode === "if_needed" && !entryEntirelyVisible)) {
const scrollSpeed = state.user.settings?.scrollSpeed const scrollSpeed = state.user.settings?.scrollSpeed
thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(true)) thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(true))
scrollToEntry(entryElement, scrollSpeed, () => thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(false))) scrollToEntry(entryElement, scrollSpeed, () => thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(false)))
@@ -174,10 +174,11 @@ export const selectEntry = createAppAsyncThunk(
} }
) )
const scrollToEntry = (entryElement: HTMLElement, scrollSpeed: number | undefined, onScrollEnded: () => void) => { const scrollToEntry = (entryElement: HTMLElement, scrollSpeed: number | undefined, onScrollEnded: () => void) => {
const header = document.getElementById(Constants.dom.headerId)?.getBoundingClientRect()
const offset = (header?.bottom ?? 0) + 3
scrollToWithCallback({ scrollToWithCallback({
options: { options: {
// add a small gap between the top of the content and the top of the page top: entryElement.offsetTop - offset,
top: entryElement.offsetTop - Constants.layout.headerHeight - 3,
behavior: scrollSpeed && scrollSpeed > 0 ? "smooth" : "auto", behavior: scrollSpeed && scrollSpeed > 0 ? "smooth" : "auto",
}, },
onScrollEnded, onScrollEnded,

View File

@@ -26,6 +26,22 @@ export const treeSlice = createSlice({
toggleSidebar: state => { toggleSidebar: state => {
state.sidebarVisible = !state.sidebarVisible state.sidebarVisible = !state.sidebarVisible
}, },
incrementUnreadCount: (
state,
action: PayloadAction<{
feedId: number
amount: number
}>
) => {
if (!state.rootCategory) return
visitCategoryTree(state.rootCategory, c =>
c.feeds
.filter(f => f.id === action.payload.feedId)
.forEach(f => {
f.unread += action.payload.amount
})
)
},
}, },
extraReducers: builder => { extraReducers: builder => {
builder.addCase(reloadTree.fulfilled, (state, action) => { builder.addCase(reloadTree.fulfilled, (state, action) => {
@@ -53,4 +69,4 @@ export const treeSlice = createSlice({
}, },
}) })
export const { setMobileMenuOpen, toggleSidebar } = treeSlice.actions export const { setMobileMenuOpen, toggleSidebar, incrementUnreadCount } = treeSlice.actions

View File

@@ -205,9 +205,10 @@ export interface Settings {
customCss?: string customCss?: string
customJs?: string customJs?: string
scrollSpeed: number scrollSpeed: number
alwaysScrollToEntry: boolean scrollMode: ScrollMode
markAllAsReadConfirmation: boolean markAllAsReadConfirmation: boolean
customContextMenu: boolean customContextMenu: boolean
mobileFooter: boolean
sharingSettings: SharingSettings sharingSettings: SharingSettings
} }
@@ -288,3 +289,5 @@ export type ReadingMode = "all" | "unread"
export type ReadingOrder = "asc" | "desc" export type ReadingOrder = "asc" | "desc"
export type ViewMode = "title" | "cozy" | "detailed" | "expanded" export type ViewMode = "title" | "cozy" | "detailed" | "expanded"
export type ScrollMode = "always" | "never" | "if_needed"

View File

@@ -3,13 +3,14 @@ import { showNotification } from "@mantine/notifications"
import { createSlice, isAnyOf } from "@reduxjs/toolkit" import { createSlice, isAnyOf } from "@reduxjs/toolkit"
import { type Settings, type UserModel } from "app/types" import { type Settings, type UserModel } from "app/types"
import { import {
changeAlwaysScrollToEntry,
changeCustomContextMenu, changeCustomContextMenu,
changeLanguage, changeLanguage,
changeMarkAllAsReadConfirmation, changeMarkAllAsReadConfirmation,
changeMobileFooter,
changeReadingMode, changeReadingMode,
changeReadingOrder, changeReadingOrder,
changeScrollMarks, changeScrollMarks,
changeScrollMode,
changeScrollSpeed, changeScrollSpeed,
changeSharingSetting, changeSharingSetting,
changeShowRead, changeShowRead,
@@ -64,9 +65,9 @@ export const userSlice = createSlice({
if (!state.settings) return if (!state.settings) return
state.settings.scrollMarks = action.meta.arg state.settings.scrollMarks = action.meta.arg
}) })
builder.addCase(changeAlwaysScrollToEntry.pending, (state, action) => { builder.addCase(changeScrollMode.pending, (state, action) => {
if (!state.settings) return if (!state.settings) return
state.settings.alwaysScrollToEntry = action.meta.arg state.settings.scrollMode = action.meta.arg
}) })
builder.addCase(changeMarkAllAsReadConfirmation.pending, (state, action) => { builder.addCase(changeMarkAllAsReadConfirmation.pending, (state, action) => {
if (!state.settings) return if (!state.settings) return
@@ -76,6 +77,10 @@ export const userSlice = createSlice({
if (!state.settings) return if (!state.settings) return
state.settings.customContextMenu = action.meta.arg state.settings.customContextMenu = action.meta.arg
}) })
builder.addCase(changeMobileFooter.pending, (state, action) => {
if (!state.settings) return
state.settings.mobileFooter = action.meta.arg
})
builder.addCase(changeSharingSetting.pending, (state, action) => { builder.addCase(changeSharingSetting.pending, (state, action) => {
if (!state.settings) return if (!state.settings) return
state.settings.sharingSettings[action.meta.arg.site] = action.meta.arg.value state.settings.sharingSettings[action.meta.arg.site] = action.meta.arg.value
@@ -86,9 +91,10 @@ export const userSlice = createSlice({
changeScrollSpeed.fulfilled, changeScrollSpeed.fulfilled,
changeShowRead.fulfilled, changeShowRead.fulfilled,
changeScrollMarks.fulfilled, changeScrollMarks.fulfilled,
changeAlwaysScrollToEntry.fulfilled, changeScrollMode.fulfilled,
changeMarkAllAsReadConfirmation.fulfilled, changeMarkAllAsReadConfirmation.fulfilled,
changeCustomContextMenu.fulfilled, changeCustomContextMenu.fulfilled,
changeMobileFooter.fulfilled,
changeSharingSetting.fulfilled changeSharingSetting.fulfilled
), ),
() => { () => {

View File

@@ -1,7 +1,7 @@
import { createAppAsyncThunk } from "app/async-thunk" import { createAppAsyncThunk } from "app/async-thunk"
import { client } from "app/client" import { client } from "app/client"
import { reloadEntries } from "app/entries/thunks" import { reloadEntries } from "app/entries/thunks"
import type { ReadingMode, ReadingOrder, SharingSettings } from "app/types" import type { ReadingMode, ReadingOrder, ScrollMode, SharingSettings } from "app/types"
export const reloadSettings = createAppAsyncThunk("settings/reload", async () => await client.user.getSettings().then(r => r.data)) export const reloadSettings = createAppAsyncThunk("settings/reload", async () => await client.user.getSettings().then(r => r.data))
export const reloadProfile = createAppAsyncThunk("profile/reload", async () => await client.user.getProfile().then(r => r.data)) export const reloadProfile = createAppAsyncThunk("profile/reload", async () => await client.user.getProfile().then(r => r.data))
@@ -38,10 +38,10 @@ export const changeScrollMarks = createAppAsyncThunk("settings/scrollMarks", (sc
if (!settings) return if (!settings) return
client.user.saveSettings({ ...settings, scrollMarks }) client.user.saveSettings({ ...settings, scrollMarks })
}) })
export const changeAlwaysScrollToEntry = createAppAsyncThunk("settings/alwaysScrollToEntry", (alwaysScrollToEntry: boolean, thunkApi) => { export const changeScrollMode = createAppAsyncThunk("settings/scrollMode", (scrollMode: ScrollMode, thunkApi) => {
const { settings } = thunkApi.getState().user const { settings } = thunkApi.getState().user
if (!settings) return if (!settings) return
client.user.saveSettings({ ...settings, alwaysScrollToEntry }) client.user.saveSettings({ ...settings, scrollMode })
}) })
export const changeMarkAllAsReadConfirmation = createAppAsyncThunk( export const changeMarkAllAsReadConfirmation = createAppAsyncThunk(
"settings/markAllAsReadConfirmation", "settings/markAllAsReadConfirmation",
@@ -56,6 +56,11 @@ export const changeCustomContextMenu = createAppAsyncThunk("settings/customConte
if (!settings) return if (!settings) return
client.user.saveSettings({ ...settings, customContextMenu }) client.user.saveSettings({ ...settings, customContextMenu })
}) })
export const changeMobileFooter = createAppAsyncThunk("settings/mobileFooter", (mobileFooter: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, mobileFooter })
})
export const changeSharingSetting = createAppAsyncThunk( export const changeSharingSetting = createAppAsyncThunk(
"settings/sharingSetting", "settings/sharingSetting",
( (

View File

@@ -6,7 +6,7 @@ import { type ReactNode } from "react"
interface CodeEditorProps { interface CodeEditorProps {
description?: ReactNode description?: ReactNode
language: "css" | "javascript" language: "css" | "javascript"
value: string value?: string
onChange: (value: string | undefined) => void onChange: (value: string | undefined) => void
} }

View File

@@ -27,7 +27,7 @@ const init = async () => {
interface RichCodeEditorProps { interface RichCodeEditorProps {
height: number | string height: number | string
language: "css" | "javascript" language: "css" | "javascript"
value: string value?: string
onChange: (value: string | undefined) => void onChange: (value: string | undefined) => void
} }

View File

@@ -299,6 +299,7 @@ export function FeedEntries() {
return ( return (
<InfiniteScroll <InfiniteScroll
id="entries" id="entries"
className={`view-mode-${viewMode}`}
initialLoad={false} initialLoad={false}
loadMore={async () => await (!loading && dispatch(loadMoreEntries()))} loadMore={async () => await (!loading && dispatch(loadMoreEntries()))}
hasMore={hasMore} hasMore={hasMore}

View File

@@ -1,31 +1,40 @@
import { Trans } from "@lingui/macro" import { Trans } from "@lingui/macro"
import { Divider, Select, SimpleGrid, Stack, Switch } from "@mantine/core" import { Divider, Group, Radio, Select, SimpleGrid, Stack, Switch } from "@mantine/core"
import { Constants } from "app/constants" import { Constants } from "app/constants"
import { useAppDispatch, useAppSelector } from "app/store" import { useAppDispatch, useAppSelector } from "app/store"
import { type SharingSettings } from "app/types" import { type ScrollMode, type SharingSettings } from "app/types"
import { import {
changeAlwaysScrollToEntry,
changeCustomContextMenu, changeCustomContextMenu,
changeLanguage, changeLanguage,
changeMarkAllAsReadConfirmation, changeMarkAllAsReadConfirmation,
changeMobileFooter,
changeScrollMarks, changeScrollMarks,
changeScrollMode,
changeScrollSpeed, changeScrollSpeed,
changeSharingSetting, changeSharingSetting,
changeShowRead, changeShowRead,
} from "app/user/thunks" } from "app/user/thunks"
import { locales } from "i18n" import { locales } from "i18n"
import { type ReactNode } from "react"
export function DisplaySettings() { export function DisplaySettings() {
const language = useAppSelector(state => state.user.settings?.language) const language = useAppSelector(state => state.user.settings?.language)
const scrollSpeed = useAppSelector(state => state.user.settings?.scrollSpeed) const scrollSpeed = useAppSelector(state => state.user.settings?.scrollSpeed)
const showRead = useAppSelector(state => state.user.settings?.showRead) const showRead = useAppSelector(state => state.user.settings?.showRead)
const scrollMarks = useAppSelector(state => state.user.settings?.scrollMarks) const scrollMarks = useAppSelector(state => state.user.settings?.scrollMarks)
const alwaysScrollToEntry = useAppSelector(state => state.user.settings?.alwaysScrollToEntry) const scrollMode = useAppSelector(state => state.user.settings?.scrollMode)
const markAllAsReadConfirmation = useAppSelector(state => state.user.settings?.markAllAsReadConfirmation) const markAllAsReadConfirmation = useAppSelector(state => state.user.settings?.markAllAsReadConfirmation)
const customContextMenu = useAppSelector(state => state.user.settings?.customContextMenu) const customContextMenu = useAppSelector(state => state.user.settings?.customContextMenu)
const mobileFooter = useAppSelector(state => state.user.settings?.mobileFooter)
const sharingSettings = useAppSelector(state => state.user.settings?.sharingSettings) const sharingSettings = useAppSelector(state => state.user.settings?.sharingSettings)
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const scrollModeOptions: Record<ScrollMode, ReactNode> = {
always: <Trans>Always</Trans>,
never: <Trans>Never</Trans>,
if_needed: <Trans>If the entry doesn't entirely fit on the screen</Trans>,
}
return ( return (
<Stack> <Stack>
<Select <Select
@@ -38,30 +47,12 @@ export function DisplaySettings() {
onChange={async s => await (s && dispatch(changeLanguage(s)))} onChange={async s => await (s && dispatch(changeLanguage(s)))}
/> />
<Switch
label={<Trans>Scroll smoothly when navigating between entries</Trans>}
checked={scrollSpeed ? scrollSpeed > 0 : false}
onChange={async e => await dispatch(changeScrollSpeed(e.currentTarget.checked))}
/>
<Switch
label={<Trans>Always scroll selected entry to the top of the page, even if it fits entirely on screen</Trans>}
checked={alwaysScrollToEntry}
onChange={async e => await dispatch(changeAlwaysScrollToEntry(e.currentTarget.checked))}
/>
<Switch <Switch
label={<Trans>Show feeds and categories with no unread entries</Trans>} label={<Trans>Show feeds and categories with no unread entries</Trans>}
checked={showRead} checked={showRead}
onChange={async e => await dispatch(changeShowRead(e.currentTarget.checked))} onChange={async e => await dispatch(changeShowRead(e.currentTarget.checked))}
/> />
<Switch
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
checked={scrollMarks}
onChange={async e => await dispatch(changeScrollMarks(e.currentTarget.checked))}
/>
<Switch <Switch
label={<Trans>Show confirmation when marking all entries as read</Trans>} label={<Trans>Show confirmation when marking all entries as read</Trans>}
checked={markAllAsReadConfirmation} checked={markAllAsReadConfirmation}
@@ -74,6 +65,38 @@ export function DisplaySettings() {
onChange={async e => await dispatch(changeCustomContextMenu(e.currentTarget.checked))} onChange={async e => await dispatch(changeCustomContextMenu(e.currentTarget.checked))}
/> />
<Switch
label={<Trans>On mobile, show action buttons at the bottom of the screen</Trans>}
checked={mobileFooter}
onChange={async e => await dispatch(changeMobileFooter(e.currentTarget.checked))}
/>
<Divider label={<Trans>Scrolling</Trans>} labelPosition="center" />
<Radio.Group
label={<Trans>Scroll selected entry to the top of the page</Trans>}
value={scrollMode}
onChange={async value => await dispatch(changeScrollMode(value as ScrollMode))}
>
<Group mt="xs">
{Object.entries(scrollModeOptions).map(e => (
<Radio key={e[0]} value={e[0]} label={e[1]} />
))}
</Group>
</Radio.Group>
<Switch
label={<Trans>Scroll smoothly when navigating between entries</Trans>}
checked={scrollSpeed ? scrollSpeed > 0 : false}
onChange={async e => await dispatch(changeScrollSpeed(e.currentTarget.checked))}
/>
<Switch
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
checked={scrollMarks}
onChange={async e => await dispatch(changeScrollMarks(e.currentTarget.checked))}
/>
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" /> <Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
<SimpleGrid cols={2}> <SimpleGrid cols={2}>

View File

@@ -78,7 +78,17 @@ export function ProfileSettings() {
<form onSubmit={form.onSubmit(saveProfile.execute)}> <form onSubmit={form.onSubmit(saveProfile.execute)}>
<Stack> <Stack>
<TextInput label={<Trans>User name</Trans>} readOnly value={profile?.name} /> <TextInput label={<Trans>User name</Trans>} readOnly value={profile?.name} />
<TextInput label={<Trans>API key</Trans>} readOnly value={profile?.apiKey} /> <TextInput
label={<Trans>API key</Trans>}
description={
<Trans>
This is your API key. It can be used for some read-only API operations and grants access to the Fever API.
Use the form at the bottom of the page to generate a new API key
</Trans>
}
readOnly
value={profile?.apiKey}
/>
<Input.Wrapper <Input.Wrapper
label={<Trans>OPML export</Trans>} label={<Trans>OPML export</Trans>}
@@ -100,7 +110,7 @@ export function ProfileSettings() {
description={ description={
<Trans> <Trans>
CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client.
The username is your user name and the password is your API key. Login with your username and your <u>API key</u>.
</Trans> </Trans>
} }
> >

View File

@@ -1,9 +1,22 @@
import { setWebSocketConnected } from "app/server/slice" import { setWebSocketConnected } from "app/server/slice"
import { useAppDispatch, useAppSelector } from "app/store" import { type AppDispatch, useAppDispatch, useAppSelector } from "app/store"
import { reloadTree } from "app/tree/thunks" import { incrementUnreadCount } from "app/tree/slice"
import { useEffect } from "react" import { useEffect } from "react"
import WebsocketHeartbeatJs from "websocket-heartbeat-js" import WebsocketHeartbeatJs from "websocket-heartbeat-js"
const handleMessage = (dispatch: AppDispatch, message: string) => {
const parts = message.split(":")
const type = parts[0]
if (type === "new-feed-entries") {
dispatch(
incrementUnreadCount({
feedId: +parts[1],
amount: +parts[2],
})
)
}
}
export const useWebSocket = () => { export const useWebSocket = () => {
const websocketEnabled = useAppSelector(state => state.server.serverInfos?.websocketEnabled) const websocketEnabled = useAppSelector(state => state.server.serverInfos?.websocketEnabled)
const websocketPingInterval = useAppSelector(state => state.server.serverInfos?.websocketPingInterval) const websocketPingInterval = useAppSelector(state => state.server.serverInfos?.websocketPingInterval)
@@ -27,7 +40,7 @@ export const useWebSocket = () => {
ws.onmessage = event => { ws.onmessage = event => {
const { data } = event const { data } = event
if (typeof data === "string") { if (typeof data === "string") {
if (data.startsWith("new-feed-entries:")) dispatch(reloadTree()) handleMessage(dispatch, data)
} }
} }
} }

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "الكل" msgstr "الكل"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "المرجع نفسه"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "إذا لم يكن فارغًا ، فسيتم تقييم التعبير إلى \"صواب\" أو \"خطأ\". " msgstr "إذا لم يكن فارغًا ، فسيتم تقييم التعبير إلى \"صواب\" أو \"خطأ\". "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "إذا واجهت مشكلة ، فالرجاء الإبلاغ عنها على صفحة مشكلات مشروع GitHub." msgstr "إذا واجهت مشكلة ، فالرجاء الإبلاغ عنها على صفحة مشكلات مشروع GitHub."
@@ -541,6 +545,10 @@ msgstr "الاسم"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "انتقل إلى اشتراك بإدخال اسمه" msgstr "انتقل إلى اشتراك بإدخال اسمه"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "كلمة مرور جديدة" msgstr "كلمة مرور جديدة"
@@ -574,6 +582,10 @@ msgstr "لم يتم العثور على شيء"
msgid "Oldest first" msgid "Oldest first"
msgstr "الأقدم أولا" msgstr "الأقدم أولا"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "اوووه!" msgstr "اوووه!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "حفظ" msgstr "حفظ"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "قم بالتمرير بسلاسة عند التنقل بين الإدخالات" msgstr "قم بالتمرير بسلاسة عند التنقل بين الإدخالات"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "عنوان URL للتغذية التي تريد الاشتراك فيه
msgid "Theme" msgid "Theme"
msgstr "الموضوع" msgstr "الموضوع"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "تبديل قراءة حالة الإدخال الحالي" msgstr "تبديل قراءة حالة الإدخال الحالي"

View File

@@ -15,11 +15,11 @@ msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>." msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
msgstr "" msgstr "<0>CommaFeed és un projecte de codi obert. El codi font està allotjat a </0><1>GitHub</1>."
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "<0>Complete syntax is available </0><1>here</1>." msgid "<0>Complete syntax is available </0><1>here</1>."
msgstr "" msgstr "<0>La sintaxi completa està disponible </0><1>aquí</1>."
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "<0>Have an account?</0><1>Log in!</1>" msgid "<0>Have an account?</0><1>Log in!</1>"
@@ -27,7 +27,7 @@ msgstr "<0>Teniu un compte?</0><1>Inicieu la sessió!</1>"
#: src/pages/app/DonatePage.tsx #: src/pages/app/DonatePage.tsx
msgid "<0>Hey,</0><1>I'm Jérémie from Belgium and I've been working on CommaFeed in my free time for over 10 years now. Thanks for taking an interest in helping me continue supporting CommaFeed.</1>" msgid "<0>Hey,</0><1>I'm Jérémie from Belgium and I've been working on CommaFeed in my free time for over 10 years now. Thanks for taking an interest in helping me continue supporting CommaFeed.</1>"
msgstr "" msgstr "<0>Ei,</0><1> sóc la Jérémie de Bèlgica i fa més de 10 anys que treballo a CommaFeed en el meu temps lliure. Gràcies per interessar-te i ajudar-me a continuar donant suport a CommaFeed.</1>"
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "<0>Need an account?</0><1>Sign up!</1>" msgid "<0>Need an account?</0><1>Sign up!</1>"
@@ -68,8 +68,8 @@ msgid "All"
msgstr "Tot" msgstr "Tot"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr "Sempre"
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "An email has been sent if this address was registered. Check your inbox." msgid "An email has been sent if this address was registered. Check your inbox."
@@ -85,7 +85,7 @@ msgstr "Analitzar el feed"
#: src/components/AnnouncementDialog.tsx #: src/components/AnnouncementDialog.tsx
msgid "Announcement" msgid "Announcement"
msgstr "" msgstr "Anunci"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "API key" msgid "API key"
@@ -117,7 +117,7 @@ msgstr "Estàs segur que vols cancel·lar la subscripció a <0>{feedName}</0>?"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
msgid "Asc" msgid "Asc"
msgstr "" msgstr "Asc"
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison." msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
@@ -133,11 +133,11 @@ msgstr "Tornar a iniciar sessió"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Browser extension required for Chrome" msgid "Browser extension required for Chrome"
msgstr "" msgstr "Extensió del navegador necessària per a Chrome"
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "Browser extention" msgid "Browser extention"
msgstr "" msgstr "Extensió del navegador"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
@@ -173,15 +173,15 @@ msgstr "Comproveu que el canal funciona"
#: src/pages/app/Layout.tsx #: src/pages/app/Layout.tsx
msgid "Close menu" msgid "Close menu"
msgstr "" msgstr "Tanca el menu"
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "CommaFeed browser extension version {browserExtensionVersion}." msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr "Versió de l'extensió del navegador CommaFeed {browserExtensionVersion}."
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr "CommaFeed és compatible amb l'API Fever. Utilitzeu l'URL següent al vostre client mòbil compatible amb Fever. Inicieu sessió amb el vostre nom d'usuari i la vostra <0>clau API</0>."
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "CommaFeed next unread item" msgid "CommaFeed next unread item"
@@ -189,7 +189,7 @@ msgstr "CommaFeed següent element no llegit"
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "CommaFeed version {version} ({revision})." msgid "CommaFeed version {version} ({revision})."
msgstr "" msgstr "CommaFeed versió {version} ({version})."
#: src/components/header/ProfileMenu.tsx #: src/components/header/ProfileMenu.tsx
msgid "Compact" msgid "Compact"
@@ -201,7 +201,7 @@ msgstr "Compacte"
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Confirm" msgid "Confirm"
msgstr "Confirmar" msgstr "Confirma"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Confirm password" msgid "Confirm password"
@@ -213,7 +213,7 @@ msgstr "Acollidor"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Ctrl" msgid "Ctrl"
msgstr "" msgstr "Ctrl"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Current password" msgid "Current password"
@@ -221,19 +221,19 @@ msgstr "Contrasenya actual"
#: src/pages/app/SettingsPage.tsx #: src/pages/app/SettingsPage.tsx
msgid "Custom code" msgid "Custom code"
msgstr "" msgstr "Codi personalitzat"
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
msgid "Custom CSS rules that will be applied" msgid "Custom CSS rules that will be applied"
msgstr "" msgstr "Regles CSS personalitzades que s'aplicaran"
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
msgid "Custom JS code that will be executed on page load" msgid "Custom JS code that will be executed on page load"
msgstr "" msgstr "Codi JS personalitzat que s'executarà en carregar la pàgina"
#: src/components/header/ProfileMenu.tsx #: src/components/header/ProfileMenu.tsx
msgid "Dark" msgid "Dark"
msgstr "" msgstr "Fosc"
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
msgid "Date created" msgid "Date created"
@@ -258,11 +258,11 @@ msgstr "Suprimeix l'usuari"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
msgid "Desc" msgid "Desc"
msgstr "" msgstr "Desc"
#: src/components/header/ProfileMenu.tsx #: src/components/header/ProfileMenu.tsx
msgid "Detailed" msgid "Detailed"
msgstr "" msgstr "Detallat"
#: src/components/header/ProfileMenu.tsx #: src/components/header/ProfileMenu.tsx
#: src/pages/app/SettingsPage.tsx #: src/pages/app/SettingsPage.tsx
@@ -272,7 +272,7 @@ msgstr "Mostra"
#: src/components/header/ProfileMenu.tsx #: src/components/header/ProfileMenu.tsx
#: src/pages/app/DonatePage.tsx #: src/pages/app/DonatePage.tsx
msgid "Donate" msgid "Donate"
msgstr "" msgstr "Donar"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Download" msgid "Download"
@@ -314,7 +314,7 @@ msgstr "introduïu la vostra contrasenya actual per canviar la configuració del
#: src/components/Alert.tsx #: src/components/Alert.tsx
msgid "Error" msgid "Error"
msgstr "" msgstr "Error"
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Example: {example}." msgid "Example: {example}."
@@ -331,7 +331,7 @@ msgstr "exporteu les vostres subscripcions i categories com a fitxer OPML que es
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Extension options" msgid "Extension options"
msgstr "" msgstr "Opcions de l'extensió"
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
msgid "Feed name" msgid "Feed name"
@@ -345,7 +345,7 @@ msgstr "URL del canal"
#: src/components/header/ProfileMenu.tsx #: src/components/header/ProfileMenu.tsx
msgid "Fetch all my feeds now" msgid "Fetch all my feeds now"
msgstr "" msgstr "Carrega tots els meus feeds ara"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Fever API" msgid "Fever API"
@@ -385,7 +385,7 @@ msgstr "URL del feed generat"
#: src/components/content/FeedEntryContextMenu.tsx #: src/components/content/FeedEntryContextMenu.tsx
msgid "Go to {0}" msgid "Go to {0}"
msgstr "" msgstr "Vés a {0}"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Go to the All view" msgid "Go to the All view"
@@ -401,12 +401,16 @@ msgstr "Bones"
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
msgid "Id" msgid "Id"
msgstr "" msgstr "Id"
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Si no està buida, una expressió que s'avalua com a \"vertader\" o \"fals\". " msgstr "Si no està buida, una expressió que s'avalua com a \"vertader\" o \"fals\". "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr "Si l'entrada no encaixa del tot a la pantalla"
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Si trobeu un problema, informeu-lo a la pàgina de problemes del projecte GitHub." msgstr "Si trobeu un problema, informeu-lo a la pàgina de problemes del projecte GitHub."
@@ -447,7 +451,7 @@ msgstr "últim missatge d'actualització"
#: src/components/header/ProfileMenu.tsx #: src/components/header/ProfileMenu.tsx
msgid "Light" msgid "Light"
msgstr "" msgstr "Clar"
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
@@ -515,7 +519,7 @@ msgstr "mètriques"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Middle click" msgid "Middle click"
msgstr "" msgstr "Clic central"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Move the page down" msgid "Move the page down"
@@ -541,6 +545,10 @@ msgstr "Nom"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navegueu a una subscripció introduint-ne el nom" msgstr "Navegueu a una subscripció introduint-ne el nom"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr "Mai"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Contrasenya nova" msgstr "Contrasenya nova"
@@ -574,13 +582,17 @@ msgstr "No s'ha trobat res"
msgid "Oldest first" msgid "Oldest first"
msgstr "el més vell primer" msgstr "el més vell primer"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr "Al mòbil, mostra els botons d'acció a la part inferior de la pantalla"
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Vaja!" msgstr "Vaja!"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
msgid "Open CommaFeed" msgid "Open CommaFeed"
msgstr "" msgstr "Obre CommaFeed"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Open current entry in a new tab" msgid "Open current entry in a new tab"
@@ -592,19 +604,19 @@ msgstr "Obre l'entrada actual en una pestanya nova al fons"
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Open link" msgid "Open link"
msgstr "Enllaç obert" msgstr "Obre l'enllaç obert"
#: src/components/content/FeedEntryContextMenu.tsx #: src/components/content/FeedEntryContextMenu.tsx
msgid "Open link in new background tab" msgid "Open link in new background tab"
msgstr "" msgstr "Obre l'enllaç a una pestanya de fons nova"
#: src/components/content/FeedEntryContextMenu.tsx #: src/components/content/FeedEntryContextMenu.tsx
msgid "Open link in new tab" msgid "Open link in new tab"
msgstr "" msgstr "Obre l'enllaç en una pestanya nova"
#: src/pages/app/Layout.tsx #: src/pages/app/Layout.tsx
msgid "Open menu" msgid "Open menu"
msgstr "" msgstr "Obre el menú"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Open next entry" msgid "Open next entry"
@@ -620,7 +632,7 @@ msgstr "Obrir/tancar l'entrada actual"
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "OPML" msgid "OPML"
msgstr "" msgstr "OPML"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "OPML export" msgid "OPML export"
@@ -666,7 +678,7 @@ msgstr "Posició"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
msgid "Previous" msgid "Previous"
msgstr "" msgstr "Anterior"
#: src/pages/app/SettingsPage.tsx #: src/pages/app/SettingsPage.tsx
msgid "Profile" msgid "Profile"
@@ -692,7 +704,7 @@ msgstr "API REST"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "" msgstr "Clic dret"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Desa" msgstr "Desa"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr "Desplaceu-vos per l'entrada seleccionada fins a la part superior de la pàgina"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Desplaceu-vos suaument quan navegueu entre entrades" msgstr "Desplaceu-vos suaument quan navegueu entre entrades"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr "Desplaçament"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -749,19 +769,19 @@ msgstr "canvi"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Show CommaFeed's own context menu on right click" msgid "Show CommaFeed's own context menu on right click"
msgstr "" msgstr "Mostra el menú contextual de CommaFeed fent clic amb el botó dret"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Show confirmation when marking all entries as read" msgid "Show confirmation when marking all entries as read"
msgstr "" msgstr "Mostra la confirmació en marcar totes les entrades com a llegides"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Show entry menu (desktop)" msgid "Show entry menu (desktop)"
msgstr "" msgstr "Mostra el menú d'entrada (escriptori)"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Show entry menu (mobile)" msgid "Show entry menu (mobile)"
msgstr "" msgstr "Mostra el menú d'entrada (mòbil)"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Show feeds and categories with no unread entries" msgid "Show feeds and categories with no unread entries"
@@ -773,13 +793,13 @@ msgstr "Mostra l'ajuda de la drecera del teclat"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Show native menu (desktop)" msgid "Show native menu (desktop)"
msgstr "" msgstr "Mostra el menú natiu (escriptori)"
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
msgstr "Inscriu-te" msgstr "Registra't"
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Something bad just happened..." msgid "Something bad just happened..."
@@ -820,7 +840,7 @@ msgstr "Éxit"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Swipe header to the left" msgid "Swipe header to the left"
msgstr "" msgstr "Feu lliscar la capçalera cap a l'esquerra"
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Switch to dark theme" msgid "Switch to dark theme"
@@ -832,7 +852,7 @@ msgstr "Canvia al tema clar"
#: src/components/header/ProfileMenu.tsx #: src/components/header/ProfileMenu.tsx
msgid "System" msgid "System"
msgstr "" msgstr "Sistema"
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
@@ -847,17 +867,21 @@ msgstr "l'URL del canal al qual us voleu subscriure. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr "Aquesta és la vostra clau de l'API. Es pot utilitzar per a algunes operacions de l'API de només lectura i permet accedir a l'API Fever. Utilitzeu el formulari de la part inferior de la pàgina per generar una nova clau d'API."
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Canvia l'estat de lectura de l'entrada actual" msgstr "Canvia l'estat de lectura de l'entrada actual"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle sidebar" msgid "Toggle sidebar"
msgstr "" msgstr "Canvia la barra lateral"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle starred status of current entry" msgid "Toggle starred status of current entry"
msgstr "" msgstr "Commuta l'estat destacat de l'entrada actual"
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "Try out CommaFeed with the demo account: demo/demo" msgid "Try out CommaFeed with the demo account: demo/demo"
@@ -865,7 +889,7 @@ msgstr "Proveu CommaFeed amb el compte de demostració: demo/demo"
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Try the demo!" msgid "Try the demo!"
msgstr "" msgstr "Prova la demostració!"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
msgid "Unread" msgid "Unread"
@@ -904,4 +928,4 @@ msgstr "Encara no teniu cap subscripció. "
#: src/components/header/ProfileMenu.tsx #: src/components/header/ProfileMenu.tsx
msgid "Your feeds have been queued for refresh." msgid "Your feeds have been queued for refresh."
msgstr "" msgstr "Els vostres feeds s'han posat a la cua per actualitzar-los."

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Všechny" msgstr "Všechny"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Pokud není prázdný, výraz vyhodnocený jako 'true' nebo 'false'. " msgstr "Pokud není prázdný, výraz vyhodnocený jako 'true' nebo 'false'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Pokud narazíte na problém, nahlaste jej prosím na stránce problémů projektu GitHub." msgstr "Pokud narazíte na problém, nahlaste jej prosím na stránce problémů projektu GitHub."
@@ -541,6 +545,10 @@ msgstr "Jméno"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Přejděte na předplatné zadáním jeho názvu" msgstr "Přejděte na předplatné zadáním jeho názvu"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nové heslo" msgstr "Nové heslo"
@@ -574,6 +582,10 @@ msgstr "Nic nebylo nalezeno"
msgid "Oldest first" msgid "Oldest first"
msgstr "Nejdříve nejstarší" msgstr "Nejdříve nejstarší"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Jejda!" msgstr "Jejda!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Uložit" msgstr "Uložit"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Posouvejte plynule při navigaci mezi položkami" msgstr "Posouvejte plynule při navigaci mezi položkami"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "Adresa URL kanálu, k jehož odběru se chcete přihlásit. "
msgid "Theme" msgid "Theme"
msgstr "Téma" msgstr "Téma"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Přepne stav čtení aktuálního záznamu" msgstr "Přepne stav čtení aktuálního záznamu"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Pawb" msgstr "Pawb"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Os nad yw'n wag, mynegiad sy'n gwerthuso i 'gwir' neu 'anghywir'. " msgstr "Os nad yw'n wag, mynegiad sy'n gwerthuso i 'gwir' neu 'anghywir'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Os byddwch yn dod ar draws mater, rhowch wybod amdano ar dudalen materion y prosiect GitHub." msgstr "Os byddwch yn dod ar draws mater, rhowch wybod amdano ar dudalen materion y prosiect GitHub."
@@ -541,6 +545,10 @@ msgstr "Enw"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Llywiwch i danysgrifiad trwy nodi ei enw" msgstr "Llywiwch i danysgrifiad trwy nodi ei enw"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Cyfrinair newydd" msgstr "Cyfrinair newydd"
@@ -574,6 +582,10 @@ msgstr "Dim wedi'i ddarganfod"
msgid "Oldest first" msgid "Oldest first"
msgstr "Hynaf yn gyntaf" msgstr "Hynaf yn gyntaf"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Wps!" msgstr "Wps!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Arbed" msgstr "Arbed"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Sgroliwch yn esmwyth wrth lywio rhwng cofnodion" msgstr "Sgroliwch yn esmwyth wrth lywio rhwng cofnodion"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "Y URL ar gyfer y porthwr rydych chi am danysgrifio iddo. "
msgid "Theme" msgid "Theme"
msgstr "Thema" msgstr "Thema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Toglo statws darllen y cofnod cyfredol" msgstr "Toglo statws darllen y cofnod cyfredol"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Alle" msgstr "Alle"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Hvis det ikke er tomt, et udtryk, der vurderes til 'sand' eller 'falsk'. " msgstr "Hvis det ikke er tomt, et udtryk, der vurderes til 'sand' eller 'falsk'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Hvis du støder på et problem, bedes du rapportere det på problemsiden for GitHub-projektet." msgstr "Hvis du støder på et problem, bedes du rapportere det på problemsiden for GitHub-projektet."
@@ -541,6 +545,10 @@ msgstr "Navn"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Naviger til et abonnement ved at indtaste dets navn" msgstr "Naviger til et abonnement ved at indtaste dets navn"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Ny adgangskode" msgstr "Ny adgangskode"
@@ -574,6 +582,10 @@ msgstr "Intet fundet"
msgid "Oldest first" msgid "Oldest first"
msgstr "Ældst først" msgstr "Ældst først"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Hovsa!" msgstr "Hovsa!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Gem" msgstr "Gem"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Rul jævnt, når du navigerer mellem poster" msgstr "Rul jævnt, når du navigerer mellem poster"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL'en til det feed, du vil abonnere på. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Skift læsestatus for den aktuelle post" msgstr "Skift læsestatus for den aktuelle post"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Alle" msgstr "Alle"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,8 +180,8 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "CommaFeed ist kompatibel zur Fever API. Benutzen Sie folgende URL in Ihrem Fever-kompatiblen Mobilclient. Der Benutzername ist Ihr User Name, das Passwort ist der API-Schlüssel." msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "CommaFeed next unread item" msgid "CommaFeed next unread item"
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Wenn nicht leer, ein Ausdruck, der als „wahr“ oder „falsch“ ausgewertet wird. " msgstr "Wenn nicht leer, ein Ausdruck, der als „wahr“ oder „falsch“ ausgewertet wird. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Wenn Sie auf ein Problem stoßen, melden Sie es bitte auf der Problemseite des GitHub-Projekts." msgstr "Wenn Sie auf ein Problem stoßen, melden Sie es bitte auf der Problemseite des GitHub-Projekts."
@@ -541,6 +545,10 @@ msgstr ""
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navigieren Sie zu einem Abonnement, indem Sie seinen Namen eingeben" msgstr "Navigieren Sie zu einem Abonnement, indem Sie seinen Namen eingeben"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Neues Passwort" msgstr "Neues Passwort"
@@ -574,6 +582,10 @@ msgstr "Nichts gefunden"
msgid "Oldest first" msgid "Oldest first"
msgstr "Älteste zuerst" msgstr "Älteste zuerst"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Ups!" msgstr "Ups!"
@@ -702,10 +714,18 @@ msgstr "Rechtsklick"
msgid "Save" msgid "Save"
msgstr "Speichern" msgstr "Speichern"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Schnelles Scrollen beim Navigieren zwischen Einträgen" msgstr "Schnelles Scrollen beim Navigieren zwischen Einträgen"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "Die URL für den Feed, den Sie abonnieren möchten. "
msgid "Theme" msgid "Theme"
msgstr "Thema" msgstr "Thema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Lesestatus des aktuellen Eintrags umschalten" msgstr "Lesestatus des aktuellen Eintrags umschalten"

View File

@@ -68,8 +68,8 @@ msgid "All"
msgstr "All" msgstr "All"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgstr "Always"
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "An email has been sent if this address was registered. Check your inbox." msgid "An email has been sent if this address was registered. Check your inbox."
@@ -180,8 +180,8 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "CommaFeed browser extension version {browserExtensionVersion}." msgstr "CommaFeed browser extension version {browserExtensionVersion}."
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgstr "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "CommaFeed next unread item" msgid "CommaFeed next unread item"
@@ -407,6 +407,10 @@ msgstr "Id"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgstr "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr "If the entry doesn't entirely fit on the screen"
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "If you encounter an issue, please report it on the issues page of the GitHub project." msgstr "If you encounter an issue, please report it on the issues page of the GitHub project."
@@ -541,6 +545,10 @@ msgstr "Name"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navigate to a subscription by entering its name" msgstr "Navigate to a subscription by entering its name"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr "Never"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "New password" msgstr "New password"
@@ -574,6 +582,10 @@ msgstr "Nothing found"
msgid "Oldest first" msgid "Oldest first"
msgstr "Oldest first" msgstr "Oldest first"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr "On mobile, show action buttons at the bottom of the screen"
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Oops!" msgstr "Oops!"
@@ -702,10 +714,18 @@ msgstr "Right click"
msgid "Save" msgid "Save"
msgstr "Save" msgstr "Save"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr "Scroll selected entry to the top of the page"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Scroll smoothly when navigating between entries" msgstr "Scroll smoothly when navigating between entries"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr "Scrolling"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "The URL for the feed you want to subscribe to. You can also use the webs
msgid "Theme" msgid "Theme"
msgstr "Theme" msgstr "Theme"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Toggle read status of current entry" msgstr "Toggle read status of current entry"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Todo" msgstr "Todo"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "Identificación"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Si no está vacío, una expresión que se evalúa como 'verdadero' o 'falso'. " msgstr "Si no está vacío, una expresión que se evalúa como 'verdadero' o 'falso'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Si encuentra un problema, infórmelo en la página de problemas del proyecto GitHub." msgstr "Si encuentra un problema, infórmelo en la página de problemas del proyecto GitHub."
@@ -541,6 +545,10 @@ msgstr "Nombre"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navegar a una suscripción ingresando su nombre" msgstr "Navegar a una suscripción ingresando su nombre"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nueva contraseña" msgstr "Nueva contraseña"
@@ -574,6 +582,10 @@ msgstr "Nada encontrado"
msgid "Oldest first" msgid "Oldest first"
msgstr "más antigua primero" msgstr "más antigua primero"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "¡Ups!" msgstr "¡Ups!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Guardar" msgstr "Guardar"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Desplazarse suavemente al navegar entre entradas" msgstr "Desplazarse suavemente al navegar entre entradas"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "La URL de la fuente a la que desea suscribirse. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Alternar estado de lectura de la entrada actual" msgstr "Alternar estado de lectura de la entrada actual"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "همه" msgstr "همه"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "شناسه"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "اگر خالی نباشد، عبارتی به \"درست\" یا \"نادرست\" ارزیابی می شود. " msgstr "اگر خالی نباشد، عبارتی به \"درست\" یا \"نادرست\" ارزیابی می شود. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "اگر با مشکلی مواجه شدید، لطفاً آن را در صفحه مشکلات پروژه GitHub گزارش دهید." msgstr "اگر با مشکلی مواجه شدید، لطفاً آن را در صفحه مشکلات پروژه GitHub گزارش دهید."
@@ -541,6 +545,10 @@ msgstr "نام"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "با وارد کردن نام اشتراک، به آن بروید" msgstr "با وارد کردن نام اشتراک، به آن بروید"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "رمز عبور جدید" msgstr "رمز عبور جدید"
@@ -574,6 +582,10 @@ msgstr "چیزی پیدا نشد"
msgid "Oldest first" msgid "Oldest first"
msgstr "قدیمی ترین اول" msgstr "قدیمی ترین اول"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "اوه!" msgstr "اوه!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "ذخیره کنید" msgstr "ذخیره کنید"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "هنگام پیمایش بین ورودی‌ها به آرامی حرکت کنید" msgstr "هنگام پیمایش بین ورودی‌ها به آرامی حرکت کنید"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL فیدی که می خواهید در آن مشترک شوید. "
msgid "Theme" msgid "Theme"
msgstr "تم" msgstr "تم"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "وضعیت خواندن ورودی فعلی را تغییر دهید" msgstr "وضعیت خواندن ورودی فعلی را تغییر دهید"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Kaikki" msgstr "Kaikki"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Jos ei tyhjä, lauseke, jonka arvo on \"tosi\" tai \"epätosi\". " msgstr "Jos ei tyhjä, lauseke, jonka arvo on \"tosi\" tai \"epätosi\". "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Jos kohtaat ongelman, ilmoita siitä GitHub-projektin ongelmasivulla." msgstr "Jos kohtaat ongelman, ilmoita siitä GitHub-projektin ongelmasivulla."
@@ -541,6 +545,10 @@ msgstr "Nimi"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Siirry tilaukseen kirjoittamalla sen nimi" msgstr "Siirry tilaukseen kirjoittamalla sen nimi"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Uusi salasana" msgstr "Uusi salasana"
@@ -574,6 +582,10 @@ msgstr "Mitään ei löytynyt"
msgid "Oldest first" msgid "Oldest first"
msgstr "Vanhin ensin" msgstr "Vanhin ensin"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Hups!" msgstr "Hups!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Tallenna" msgstr "Tallenna"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Selaa sujuvasti navigoidessasi merkintöjen välillä" msgstr "Selaa sujuvasti navigoidessasi merkintöjen välillä"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "Sen syötteen URL-osoite, jonka haluat tilata. "
msgid "Theme" msgid "Theme"
msgstr "Teema" msgstr "Teema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Vaihda nykyisen merkinnän lukutila" msgstr "Vaihda nykyisen merkinnän lukutila"

View File

@@ -68,8 +68,8 @@ msgid "All"
msgstr "Tout" msgstr "Tout"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "Toujours remonter l'entrée sélectionnée en haut de la page, même si elle s'affiche complètement à l'écran" msgstr "Toujours"
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "An email has been sent if this address was registered. Check your inbox." msgid "An email has been sent if this address was registered. Check your inbox."
@@ -180,8 +180,8 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "Extension CommaFeed pour navigateur version {browserExtensionVersion}." msgstr "Extension CommaFeed pour navigateur version {browserExtensionVersion}."
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "Commafeed est compatible avec l'API Fever, en inscrivant l'URL suivante dans votre client mobile compatible. Entrez votre nom d'utilisateur habituel, et votre clef API comme mot de passe." msgstr "Commafeed est compatible avec l'API Fever, en inscrivant l'URL suivante dans votre client mobile compatible. Entrez votre nom d'utilisateur habituel, et votre <0>clef API</0> comme mot de passe."
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "CommaFeed next unread item" msgid "CommaFeed next unread item"
@@ -407,6 +407,10 @@ msgstr "Identifiant"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Si non vide, une expression évaluant à 'vrai' ou 'faux'. Si faux, les nouvelles entrées de ce flux seront marquées comme lues automatiquement." msgstr "Si non vide, une expression évaluant à 'vrai' ou 'faux'. Si faux, les nouvelles entrées de ce flux seront marquées comme lues automatiquement."
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr "Si l'entrée ne tient pas entièrement sur l'écran"
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Si vous rencontrez un problème, merci de le signaler sur la page du projet GitHub." msgstr "Si vous rencontrez un problème, merci de le signaler sur la page du projet GitHub."
@@ -541,6 +545,10 @@ msgstr "Nom"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Naviguer vers un abonnement en entrant son nom" msgstr "Naviguer vers un abonnement en entrant son nom"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr "Jamais"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nouveau mot de passe" msgstr "Nouveau mot de passe"
@@ -574,6 +582,10 @@ msgstr "Aucun résultat"
msgid "Oldest first" msgid "Oldest first"
msgstr "Du plus ancien au plus récent" msgstr "Du plus ancien au plus récent"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr "Sur mobile, afficher les boutons d'action en bas de l'écran"
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Oups !" msgstr "Oups !"
@@ -702,10 +714,18 @@ msgstr "Clic droit"
msgid "Save" msgid "Save"
msgstr "Enregistrer" msgstr "Enregistrer"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr "Faire défiler l'entrée sélectionnée vers le haut de la page"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Défilement animé lors de la navigation entre les entrées" msgstr "Défilement animé lors de la navigation entre les entrées"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr "Défilement"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "L'URL du flux auquel vous souhaitez vous abonner. Vous pouvez aussi util
msgid "Theme" msgid "Theme"
msgstr "Thème" msgstr "Thème"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr "Ceci est votre clef API. Elle peut être utilisée pour certaines opérations en lecture seule et donne accès à l'API Fever. Utilisez le formulaire en bas de la page pour générer une nouvelle clef API"
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Marquer l'entrée actuelle comme lue/non lue" msgstr "Marquer l'entrée actuelle comme lue/non lue"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Todos" msgstr "Todos"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Se non está baleira, unha expresión que se avalía como \"verdadeiro\" ou \"falso\". " msgstr "Se non está baleira, unha expresión que se avalía como \"verdadeiro\" ou \"falso\". "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Se atopas algún problema, infórmao na páxina de problemas do proxecto GitHub." msgstr "Se atopas algún problema, infórmao na páxina de problemas do proxecto GitHub."
@@ -541,6 +545,10 @@ msgstr "Nome"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navega a unha subscrición introducindo o seu nome" msgstr "Navega a unha subscrición introducindo o seu nome"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "novo contrasinal" msgstr "novo contrasinal"
@@ -574,6 +582,10 @@ msgstr "Non se atopou nada"
msgid "Oldest first" msgid "Oldest first"
msgstr "O máis vello primeiro" msgstr "O máis vello primeiro"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Vaia!" msgstr "Vaia!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Gardar" msgstr "Gardar"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Desprácese suavemente ao navegar entre as entradas" msgstr "Desprácese suavemente ao navegar entre as entradas"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "O URL do feed ao que quere subscribirse. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "alternar o estado de lectura da entrada actual" msgstr "alternar o estado de lectura da entrada actual"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Mind" msgstr "Mind"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Ha nem üres, akkor 'igaz' vagy 'hamis' értékre kiértékelő kifejezés. " msgstr "Ha nem üres, akkor 'igaz' vagy 'hamis' értékre kiértékelő kifejezés. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Ha problémát tapasztal, kérjük, jelentse azt a GitHub projekt problémák oldalán." msgstr "Ha problémát tapasztal, kérjük, jelentse azt a GitHub projekt problémák oldalán."
@@ -541,6 +545,10 @@ msgstr "Név"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navigáljon egy előfizetéshez a nevének megadásával" msgstr "Navigáljon egy előfizetéshez a nevének megadásával"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Új jelszó" msgstr "Új jelszó"
@@ -574,6 +582,10 @@ msgstr "Semmi sem található"
msgid "Oldest first" msgid "Oldest first"
msgstr "A legidősebb első" msgstr "A legidősebb első"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Hoppá!" msgstr "Hoppá!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Mentés" msgstr "Mentés"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Sima görgetés, amikor a bejegyzések között navigál" msgstr "Sima görgetés, amikor a bejegyzések között navigál"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "Az előfizetni kívánt hírcsatorna URL-je. "
msgid "Theme" msgid "Theme"
msgstr "Téma" msgstr "Téma"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Az aktuális bejegyzés olvasási állapotának váltása" msgstr "Az aktuális bejegyzés olvasási állapotának váltása"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Semua" msgstr "Semua"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Jika tidak kosong, ekspresi mengevaluasi ke 'benar' atau 'salah'. " msgstr "Jika tidak kosong, ekspresi mengevaluasi ke 'benar' atau 'salah'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Jika Anda mengalami masalah, harap laporkan di halaman masalah proyek GitHub." msgstr "Jika Anda mengalami masalah, harap laporkan di halaman masalah proyek GitHub."
@@ -541,6 +545,10 @@ msgstr "Nama"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navigasikan ke langganan dengan memasukkan namanya" msgstr "Navigasikan ke langganan dengan memasukkan namanya"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Kata sandi baru" msgstr "Kata sandi baru"
@@ -574,6 +582,10 @@ msgstr "Tidak ada yang ditemukan"
msgid "Oldest first" msgid "Oldest first"
msgstr "Tertua dulu" msgstr "Tertua dulu"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Ups!" msgstr "Ups!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Simpan" msgstr "Simpan"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Gulir dengan lancar saat menavigasi antar entri" msgstr "Gulir dengan lancar saat menavigasi antar entri"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL untuk umpan yang ingin Anda langgani. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Beralih status baca entri saat ini" msgstr "Beralih status baca entri saat ini"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Tutto" msgstr "Tutto"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Se non è vuota, un'espressione valutata come 'vero' o 'falso'. " msgstr "Se non è vuota, un'espressione valutata come 'vero' o 'falso'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Se riscontri un problema, segnalalo nella pagina dei problemi del progetto GitHub." msgstr "Se riscontri un problema, segnalalo nella pagina dei problemi del progetto GitHub."
@@ -541,6 +545,10 @@ msgstr "Nome"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navigare verso un abbonamento inserendo il suo nome" msgstr "Navigare verso un abbonamento inserendo il suo nome"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nuova password" msgstr "Nuova password"
@@ -574,6 +582,10 @@ msgstr "Non è stato trovato nulla"
msgid "Oldest first" msgid "Oldest first"
msgstr "Il più vecchio prima" msgstr "Il più vecchio prima"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Ops!" msgstr "Ops!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Salva" msgstr "Salva"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Scorrere senza problemi durante la navigazione tra le voci" msgstr "Scorrere senza problemi durante la navigazione tra le voci"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "L'URL del feed a cui vuoi iscriverti. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Commuta lo stato di lettura della voce corrente" msgstr "Commuta lo stato di lettura della voce corrente"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "全員" msgstr "全員"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "ID"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "空でない場合は、'true' または 'false' に評価される式。 " msgstr "空でない場合は、'true' または 'false' に評価される式。 "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "問題が発生した場合は、GitHub プロジェクトの問題ページで報告してください。" msgstr "問題が発生した場合は、GitHub プロジェクトの問題ページで報告してください。"
@@ -541,6 +545,10 @@ msgstr "名前"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "名前を入力してサブスクリプションに移動します" msgstr "名前を入力してサブスクリプションに移動します"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "新しいパスワード" msgstr "新しいパスワード"
@@ -574,6 +582,10 @@ msgstr "何も見つかりませんでした"
msgid "Oldest first" msgid "Oldest first"
msgstr "古い順" msgstr "古い順"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "おっと!" msgstr "おっと!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "保存" msgstr "保存"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "エントリ間を移動するときにスムーズにスクロールする" msgstr "エントリ間を移動するときにスムーズにスクロールする"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "購読したいフィードのURL。 "
msgid "Theme" msgid "Theme"
msgstr "テーマ" msgstr "テーマ"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "現在のエントリの読み取りステータスを切り替えます" msgstr "現在のエントリの読み取りステータスを切り替えます"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "전체" msgstr "전체"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "아이디"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "비어 있지 않은 경우 'true' 또는 'false'로 평가되는 표현식입니다. " msgstr "비어 있지 않은 경우 'true' 또는 'false'로 평가되는 표현식입니다. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "문제가 발생하면 GitHub 프로젝트의 문제 페이지에서 보고하세요." msgstr "문제가 발생하면 GitHub 프로젝트의 문제 페이지에서 보고하세요."
@@ -541,6 +545,10 @@ msgstr "이름"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "이름을 입력하여 구독으로 이동" msgstr "이름을 입력하여 구독으로 이동"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "새 비밀번호" msgstr "새 비밀번호"
@@ -574,6 +582,10 @@ msgstr "아무것도 찾을 수 없습니다"
msgid "Oldest first" msgid "Oldest first"
msgstr "가장 오래된 것부터" msgstr "가장 오래된 것부터"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "앗!" msgstr "앗!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "저장" msgstr "저장"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "항목 간 탐색 시 부드럽게 스크롤" msgstr "항목 간 탐색 시 부드럽게 스크롤"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "구독하려는 피드의 URL입니다. "
msgid "Theme" msgid "Theme"
msgstr "테마" msgstr "테마"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "현재 항목의 읽기 상태 전환" msgstr "현재 항목의 읽기 상태 전환"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Semua" msgstr "Semua"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Jika tidak kosong, ungkapan yang menilai kepada 'benar' atau 'palsu'. " msgstr "Jika tidak kosong, ungkapan yang menilai kepada 'benar' atau 'palsu'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Jika anda menghadapi isu, sila laporkan pada halaman isu projek GitHub." msgstr "Jika anda menghadapi isu, sila laporkan pada halaman isu projek GitHub."
@@ -541,6 +545,10 @@ msgstr "Nama"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navigasi ke langganan dengan memasukkan namanya" msgstr "Navigasi ke langganan dengan memasukkan namanya"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Kata laluan baharu" msgstr "Kata laluan baharu"
@@ -574,6 +582,10 @@ msgstr "Tiada apa-apa dijumpai"
msgid "Oldest first" msgid "Oldest first"
msgstr "Tertua dahulu" msgstr "Tertua dahulu"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Aduh!" msgstr "Aduh!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Jimat" msgstr "Jimat"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Tatal dengan lancar apabila menavigasi antara entri" msgstr "Tatal dengan lancar apabila menavigasi antara entri"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL untuk suapan yang anda ingin langgan. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Togol status bacaan entri semasa" msgstr "Togol status bacaan entri semasa"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Alle" msgstr "Alle"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Hvis det ikke er tomt, et uttrykk som vurderes til 'sant' eller 'usant'. " msgstr "Hvis det ikke er tomt, et uttrykk som vurderes til 'sant' eller 'usant'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Hvis du støter på et problem, vennligst rapporter det på problemsiden til GitHub-prosjektet." msgstr "Hvis du støter på et problem, vennligst rapporter det på problemsiden til GitHub-prosjektet."
@@ -541,6 +545,10 @@ msgstr "Navn"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Naviger til et abonnement ved å skrive inn navnet" msgstr "Naviger til et abonnement ved å skrive inn navnet"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nytt passord" msgstr "Nytt passord"
@@ -574,6 +582,10 @@ msgstr "Ingenting funnet"
msgid "Oldest first" msgid "Oldest first"
msgstr "Eldste først" msgstr "Eldste først"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Beklager!" msgstr "Beklager!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Lagre" msgstr "Lagre"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Rull jevnt når du navigerer mellom oppføringer" msgstr "Rull jevnt når du navigerer mellom oppføringer"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL-en til feeden du vil abonnere på. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Veksle lesestatus for gjeldende oppføring" msgstr "Veksle lesestatus for gjeldende oppføring"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Alles" msgstr "Alles"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Indien niet leeg, een uitdrukking die evalueert naar 'true' of 'false'. " msgstr "Indien niet leeg, een uitdrukking die evalueert naar 'true' of 'false'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Als je een probleem tegenkomt, meld dit dan op de pagina met problemen van het GitHub-project." msgstr "Als je een probleem tegenkomt, meld dit dan op de pagina met problemen van het GitHub-project."
@@ -541,6 +545,10 @@ msgstr "Naam"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navigeer naar een abonnement door de naam in te voeren" msgstr "Navigeer naar een abonnement door de naam in te voeren"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nieuw wachtwoord" msgstr "Nieuw wachtwoord"
@@ -574,6 +582,10 @@ msgstr "Niets gevonden"
msgid "Oldest first" msgid "Oldest first"
msgstr "Oudste eerst" msgstr "Oudste eerst"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Oeps!" msgstr "Oeps!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Opslaan" msgstr "Opslaan"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Vloeiend scrollen bij het navigeren tussen items" msgstr "Vloeiend scrollen bij het navigeren tussen items"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "De URL voor de feed waarop u zich wilt abonneren. "
msgid "Theme" msgid "Theme"
msgstr "Thema" msgstr "Thema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Toggle leesstatus van huidige invoer" msgstr "Toggle leesstatus van huidige invoer"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Alle" msgstr "Alle"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Hvis det ikke er tomt, et uttrykk som vurderes til 'sant' eller 'usant'. " msgstr "Hvis det ikke er tomt, et uttrykk som vurderes til 'sant' eller 'usant'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Hvis du støter på et problem, vennligst rapporter det på problemsiden til GitHub-prosjektet." msgstr "Hvis du støter på et problem, vennligst rapporter det på problemsiden til GitHub-prosjektet."
@@ -541,6 +545,10 @@ msgstr "Navn"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Naviger til et abonnement ved å skrive inn navnet" msgstr "Naviger til et abonnement ved å skrive inn navnet"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nytt passord" msgstr "Nytt passord"
@@ -574,6 +582,10 @@ msgstr "Ingenting funnet"
msgid "Oldest first" msgid "Oldest first"
msgstr "Eldste først" msgstr "Eldste først"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Beklager!" msgstr "Beklager!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Lagre" msgstr "Lagre"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Rull jevnt når du navigerer mellom oppføringer" msgstr "Rull jevnt når du navigerer mellom oppføringer"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL-en til feeden du vil abonnere på. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Veksle lesestatus for gjeldende oppføring" msgstr "Veksle lesestatus for gjeldende oppføring"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Wszystkie" msgstr "Wszystkie"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "Identyfikator"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Jeśli nie jest puste, wyrażenie oceniające jako „prawda” lub „fałsz”. " msgstr "Jeśli nie jest puste, wyrażenie oceniające jako „prawda” lub „fałsz”. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Jeśli napotkasz problem, zgłoś go na stronie problemów projektu GitHub." msgstr "Jeśli napotkasz problem, zgłoś go na stronie problemów projektu GitHub."
@@ -541,6 +545,10 @@ msgstr "Nazwa"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Przejdź do subskrypcji, wpisując jej nazwę" msgstr "Przejdź do subskrypcji, wpisując jej nazwę"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nowe hasło" msgstr "Nowe hasło"
@@ -574,6 +582,10 @@ msgstr "Nic nie znaleziono"
msgid "Oldest first" msgid "Oldest first"
msgstr "Najstarsze jako pierwsze" msgstr "Najstarsze jako pierwsze"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Ups!" msgstr "Ups!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Zapisz" msgstr "Zapisz"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Przewijaj płynnie podczas nawigowania między wpisami" msgstr "Przewijaj płynnie podczas nawigowania między wpisami"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL kanału, który chcesz subskrybować. "
msgid "Theme" msgid "Theme"
msgstr "Motyw" msgstr "Motyw"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Przełącz stan odczytu bieżącego wpisu" msgstr "Przełącz stan odczytu bieżącego wpisu"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Todos" msgstr "Todos"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "ID"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Se não estiver vazio, uma expressão avaliada como 'true' ou 'false'. " msgstr "Se não estiver vazio, uma expressão avaliada como 'true' ou 'false'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Se você encontrar um problema, informe-o na página de problemas do projeto GitHub." msgstr "Se você encontrar um problema, informe-o na página de problemas do projeto GitHub."
@@ -541,6 +545,10 @@ msgstr "Nome"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navegue até uma assinatura digitando seu nome" msgstr "Navegue até uma assinatura digitando seu nome"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nova senha" msgstr "Nova senha"
@@ -574,6 +582,10 @@ msgstr "Nada encontrado"
msgid "Oldest first" msgid "Oldest first"
msgstr "Mais antigo primeiro" msgstr "Mais antigo primeiro"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Opa!" msgstr "Opa!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Salvar" msgstr "Salvar"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Rolar suavemente ao navegar entre as entradas" msgstr "Rolar suavemente ao navegar entre as entradas"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "A URL do feed que você deseja assinar. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Alternar o status de leitura da entrada atual" msgstr "Alternar o status de leitura da entrada atual"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Все" msgstr "Все"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "идентификатор"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Если не пусто, выражение оценивается как «истина» или «ложь». " msgstr "Если не пусто, выражение оценивается как «истина» или «ложь». "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Если вы столкнулись с проблемой, сообщите о ней на странице проблем проекта GitHub." msgstr "Если вы столкнулись с проблемой, сообщите о ней на странице проблем проекта GitHub."
@@ -541,6 +545,10 @@ msgstr "Имя"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Перейдите к подписке, введя ее имя." msgstr "Перейдите к подписке, введя ее имя."
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Новый пароль" msgstr "Новый пароль"
@@ -574,6 +582,10 @@ msgstr "Ничего не найдено"
msgid "Oldest first" msgid "Oldest first"
msgstr "Сначала самые старые" msgstr "Сначала самые старые"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Ой!" msgstr "Ой!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Сохранить" msgstr "Сохранить"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Плавная прокрутка при переходе между записями" msgstr "Плавная прокрутка при переходе между записями"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL канала, на который вы хотите подписат
msgid "Theme" msgid "Theme"
msgstr "Тема" msgstr "Тема"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Переключить статус чтения текущей записи" msgstr "Переключить статус чтения текущей записи"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Všetky" msgstr "Všetky"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Ak nie je prázdny, výraz vyhodnotený ako 'pravda' alebo 'nepravda'. " msgstr "Ak nie je prázdny, výraz vyhodnotený ako 'pravda' alebo 'nepravda'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Ak narazíte na problém, nahláste ho na stránke problémov projektu GitHub." msgstr "Ak narazíte na problém, nahláste ho na stránke problémov projektu GitHub."
@@ -541,6 +545,10 @@ msgstr "Meno"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Prejdite na predplatné zadaním jeho názvu" msgstr "Prejdite na predplatné zadaním jeho názvu"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nové heslo" msgstr "Nové heslo"
@@ -574,6 +582,10 @@ msgstr "Nič sa nenašlo"
msgid "Oldest first" msgid "Oldest first"
msgstr "Najprv najstarší" msgstr "Najprv najstarší"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Ojoj!" msgstr "Ojoj!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Uložiť" msgstr "Uložiť"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Pri navigácii medzi položkami plynulo rolujte" msgstr "Pri navigácii medzi položkami plynulo rolujte"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL zdroja, na odber ktorého sa chcete prihlásiť. "
msgid "Theme" msgid "Theme"
msgstr "Téma" msgstr "Téma"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Prepne stav čítania aktuálneho záznamu" msgstr "Prepne stav čítania aktuálneho záznamu"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "Alla" msgstr "Alla"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr ""
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Om det inte är tomt, ett uttryck som utvärderas till 'sant' eller 'falskt'. " msgstr "Om det inte är tomt, ett uttryck som utvärderas till 'sant' eller 'falskt'. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Om du stöter på ett problem, vänligen rapportera det på problemsidan för GitHub-projektet." msgstr "Om du stöter på ett problem, vänligen rapportera det på problemsidan för GitHub-projektet."
@@ -541,6 +545,10 @@ msgstr "Namn"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Navigera till ett abonnemang genom att ange dess namn" msgstr "Navigera till ett abonnemang genom att ange dess namn"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Nytt lösenord" msgstr "Nytt lösenord"
@@ -574,6 +582,10 @@ msgstr "Inget hittades"
msgid "Oldest first" msgid "Oldest first"
msgstr "Äldst först" msgstr "Äldst först"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Hoppsan!" msgstr "Hoppsan!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "Spara" msgstr "Spara"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Bläddra mjukt när du navigerar mellan poster" msgstr "Bläddra mjukt när du navigerar mellan poster"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "URL:en för flödet du vill prenumerera på. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Växla lässtatus för aktuell post" msgstr "Växla lässtatus för aktuell post"

View File

@@ -68,8 +68,8 @@ msgid "All"
msgstr "Tümü" msgstr "Tümü"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "Seçilen girişi her zaman sayfanın üstüne kaydır, ekrana tamamen sığsa bile" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "An email has been sent if this address was registered. Check your inbox." msgid "An email has been sent if this address was registered. Check your inbox."
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "CommaFeed tarayıcı eklentisi sürüm {browserExtensionVersion}." msgstr "CommaFeed tarayıcı eklentisi sürüm {browserExtensionVersion}."
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "Kimlik"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "Boş değilse, 'doğru' veya 'yanlış' olarak değerlendirilen bir ifade. " msgstr "Boş değilse, 'doğru' veya 'yanlış' olarak değerlendirilen bir ifade. "
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "Bir sorunla karşılaşırsanız lütfen GitHub projesinin sorunlar sayfasında bildirin." msgstr "Bir sorunla karşılaşırsanız lütfen GitHub projesinin sorunlar sayfasında bildirin."
@@ -541,6 +545,10 @@ msgstr "İsim"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "Adını girerek bir aboneliğe gidin" msgstr "Adını girerek bir aboneliğe gidin"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "Yeni şifre" msgstr "Yeni şifre"
@@ -574,6 +582,10 @@ msgstr "Hiçbir şey bulunamadı"
msgid "Oldest first" msgid "Oldest first"
msgstr "Önce en eski" msgstr "Önce en eski"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "Hata!" msgstr "Hata!"
@@ -702,10 +714,18 @@ msgstr "Sağ tık"
msgid "Save" msgid "Save"
msgstr "Kaydet" msgstr "Kaydet"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "Girişler arasında gezinirken sorunsuz ilerleyin" msgstr "Girişler arasında gezinirken sorunsuz ilerleyin"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "Abone olmak istediğiniz beslemenin URL'si. "
msgid "Theme" msgid "Theme"
msgstr "Tema" msgstr "Tema"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "Geçerli girişin okuma durumunu değiştir" msgstr "Geçerli girişin okuma durumunu değiştir"

View File

@@ -68,7 +68,7 @@ msgid "All"
msgstr "全部" msgstr "全部"
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always scroll selected entry to the top of the page, even if it fits entirely on screen" msgid "Always"
msgstr "" msgstr ""
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
@@ -180,7 +180,7 @@ msgid "CommaFeed browser extension version {browserExtensionVersion}."
msgstr "" msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. The username is your user name and the password is your API key." msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
msgstr "" msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -407,6 +407,10 @@ msgstr "身份证"
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically." msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
msgstr "如果不为空,则表达式评估为“真”或“假”。" msgstr "如果不为空,则表达式评估为“真”或“假”。"
#: src/components/settings/DisplaySettings.tsx
msgid "If the entry doesn't entirely fit on the screen"
msgstr ""
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
msgid "If you encounter an issue, please report it on the issues page of the GitHub project." msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
msgstr "如果遇到问题请在GitHub项目的issues页面上报告。" msgstr "如果遇到问题请在GitHub项目的issues页面上报告。"
@@ -541,6 +545,10 @@ msgstr "​​名称"
msgid "Navigate to a subscription by entering its name" msgid "Navigate to a subscription by entering its name"
msgstr "通过输入订阅名称导航到订阅" msgstr "通过输入订阅名称导航到订阅"
#: src/components/settings/DisplaySettings.tsx
msgid "Never"
msgstr ""
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "New password" msgid "New password"
msgstr "新密码" msgstr "新密码"
@@ -574,6 +582,10 @@ msgstr "没有找到"
msgid "Oldest first" msgid "Oldest first"
msgstr "最早的优先" msgstr "最早的优先"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr ""
#: src/pages/ErrorPage.tsx #: src/pages/ErrorPage.tsx
msgid "Oops!" msgid "Oops!"
msgstr "哎呀!" msgstr "哎呀!"
@@ -702,10 +714,18 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "保存" msgstr "保存"
#: src/components/settings/DisplaySettings.tsx
msgid "Scroll selected entry to the top of the page"
msgstr ""
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Scroll smoothly when navigating between entries" msgid "Scroll smoothly when navigating between entries"
msgstr "在条目之间导航时平滑滚动" msgstr "在条目之间导航时平滑滚动"
#: src/components/settings/DisplaySettings.tsx
msgid "Scrolling"
msgstr ""
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
@@ -847,6 +867,10 @@ msgstr "您要订阅的订阅源的 URL。"
msgid "Theme" msgid "Theme"
msgstr "主题" msgstr "主题"
#: src/components/settings/ProfileSettings.tsx
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
msgstr ""
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Toggle read status of current entry" msgid "Toggle read status of current entry"
msgstr "切换当前条目的读取状态" msgstr "切换当前条目的读取状态"

View File

@@ -14,7 +14,7 @@ const shownMeters: Record<string, string> = {
"com.commafeed.backend.feed.FeedRefreshUpdater.feedUpdated": "Feed update rate", "com.commafeed.backend.feed.FeedRefreshUpdater.feedUpdated": "Feed update rate",
"com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheHit": "Entry cache hit rate", "com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheHit": "Entry cache hit rate",
"com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheMiss": "Entry cache miss rate", "com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheMiss": "Entry cache miss rate",
"com.commafeed.backend.service.DatabaseCleaningService.entriesDeleted": "Entries deleted", "com.commafeed.backend.service.db.DatabaseCleaningService.entriesDeleted": "Entries deleted",
} }
const shownGauges: Record<string, string> = { const shownGauges: Record<string, string> = {

View File

@@ -72,7 +72,7 @@ export function FeedEntriesPage(props: FeedEntriesPageProps) {
if (noSubscriptions) return <NoSubscriptionHelp /> if (noSubscriptions) return <NoSubscriptionHelp />
return ( return (
// add some room at the bottom of the page in order to be able to scroll the current entry at the top of the page when expanding // add some room at the bottom of the page in order to be able to scroll the current entry at the top of the page when expanding
<Box mb={viewport.height - Constants.layout.headerHeight - 210}> <Box mb={viewport.height * 0.75}>
<Group gap="xl"> <Group gap="xl">
{sourceWebsiteUrl && ( {sourceWebsiteUrl && (
<a href={sourceWebsiteUrl} target="_blank" rel="noreferrer" className={classes.sourceWebsiteLink}> <a href={sourceWebsiteUrl} target="_blank" rel="noreferrer" className={classes.sourceWebsiteLink}>

View File

@@ -13,6 +13,8 @@ import { Logo } from "components/Logo"
import { OnDesktop } from "components/responsive/OnDesktop" import { OnDesktop } from "components/responsive/OnDesktop"
import { OnMobile } from "components/responsive/OnMobile" import { OnMobile } from "components/responsive/OnMobile"
import { useAppLoading } from "hooks/useAppLoading" import { useAppLoading } from "hooks/useAppLoading"
import { useBrowserExtension } from "hooks/useBrowserExtension"
import { useMobile } from "hooks/useMobile"
import { useWebSocket } from "hooks/useWebSocket" import { useWebSocket } from "hooks/useWebSocket"
import { LoadingPage } from "pages/LoadingPage" import { LoadingPage } from "pages/LoadingPage"
import { type ReactNode, Suspense, useEffect } from "react" import { type ReactNode, Suspense, useEffect } from "react"
@@ -60,6 +62,8 @@ const useStyles = tss
export default function Layout(props: LayoutProps) { export default function Layout(props: LayoutProps) {
const theme = useMantineTheme() const theme = useMantineTheme()
const mobile = useMobile()
const { isBrowserExtensionPopup } = useBrowserExtension()
const [sidebarWidth, setSidebarWidth] = useLocalStorage("sidebar-width", 350) const [sidebarWidth, setSidebarWidth] = useLocalStorage("sidebar-width", 350)
const sidebarPadding = theme.spacing.xs const sidebarPadding = theme.spacing.xs
const { classes } = useStyles({ const { classes } = useStyles({
@@ -71,6 +75,8 @@ export default function Layout(props: LayoutProps) {
const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen) const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen)
const webSocketConnected = useAppSelector(state => state.server.webSocketConnected) const webSocketConnected = useAppSelector(state => state.server.webSocketConnected)
const treeReloadInterval = useAppSelector(state => state.server.serverInfos?.treeReloadInterval) const treeReloadInterval = useAppSelector(state => state.server.serverInfos?.treeReloadInterval)
const mobileFooter = useAppSelector(state => state.user.settings?.mobileFooter)
const headerInFooter = mobile && !isBrowserExtensionPopup && mobileFooter
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
useWebSocket() useWebSocket()
@@ -112,6 +118,39 @@ export default function Layout(props: LayoutProps) {
</ActionIcon> </ActionIcon>
) )
const header = (
<>
<OnMobile>
{mobileMenuOpen && (
<Group justify="space-between" p="md">
<Box>{burger}</Box>
<Box>
<LogoAndTitle />
</Box>
<Box>{addButton}</Box>
</Group>
)}
{!mobileMenuOpen && (
<Group p="md">
<Box>{burger}</Box>
<Box style={{ flexGrow: 1 }}>{props.header}</Box>
</Group>
)}
</OnMobile>
<OnDesktop>
<Group p="md">
<Group justify="space-between" style={{ width: sidebarWidth - 16 }}>
<Box>
<LogoAndTitle />
</Box>
<Box>{addButton}</Box>
</Group>
<Box style={{ flexGrow: 1 }}>{props.header}</Box>
</Group>
</OnDesktop>
</>
)
const swipeHandlers = useSwipeable({ const swipeHandlers = useSwipeable({
onSwiping: e => { onSwiping: e => {
const threshold = document.documentElement.clientWidth / 6 const threshold = document.documentElement.clientWidth / 6
@@ -125,7 +164,8 @@ export default function Layout(props: LayoutProps) {
return ( return (
<Box {...swipeHandlers}> <Box {...swipeHandlers}>
<AppShell <AppShell
header={{ height: Constants.layout.headerHeight }} header={{ height: Constants.layout.headerHeight, collapsed: headerInFooter }}
footer={{ height: Constants.layout.headerHeight, collapsed: !headerInFooter }}
navbar={{ navbar={{
width: sidebarWidth, width: sidebarWidth,
breakpoint: Constants.layout.mobileBreakpoint, breakpoint: Constants.layout.mobileBreakpoint,
@@ -133,36 +173,8 @@ export default function Layout(props: LayoutProps) {
}} }}
padding={{ base: 6, [Constants.layout.mobileBreakpointName]: "md" }} padding={{ base: 6, [Constants.layout.mobileBreakpointName]: "md" }}
> >
<AppShell.Header id="header"> <AppShell.Header id={Constants.dom.headerId}>{!headerInFooter && header}</AppShell.Header>
<OnMobile> <AppShell.Footer id={Constants.dom.footerId}>{headerInFooter && header}</AppShell.Footer>
{mobileMenuOpen && (
<Group justify="space-between" p="md">
<Box>{burger}</Box>
<Box>
<LogoAndTitle />
</Box>
<Box>{addButton}</Box>
</Group>
)}
{!mobileMenuOpen && (
<Group p="md">
<Box>{burger}</Box>
<Box style={{ flexGrow: 1 }}>{props.header}</Box>
</Group>
)}
</OnMobile>
<OnDesktop>
<Group p="md">
<Group justify="space-between" style={{ width: sidebarWidth - 16 }}>
<Box>
<LogoAndTitle />
</Box>
<Box>{addButton}</Box>
</Group>
<Box style={{ flexGrow: 1 }}>{props.header}</Box>
</Group>
</OnDesktop>
</AppShell.Header>
<AppShell.Navbar id="sidebar" p={sidebarPadding}> <AppShell.Navbar id="sidebar" p={sidebarPadding}>
<AppShell.Section grow component={ScrollArea} mx="-sm" px="sm"> <AppShell.Section grow component={ScrollArea} mx="-sm" px="sm">
<Box className={classes.sidebarContent}>{props.sidebar}</Box> <Box className={classes.sidebarContent}>{props.sidebar}</Box>
@@ -173,7 +185,7 @@ export default function Layout(props: LayoutProps) {
axis="x" axis="x"
defaultPosition={{ defaultPosition={{
x: sidebarWidth, x: sidebarWidth,
y: Constants.layout.headerHeight, y: 0,
}} }}
bounds={{ bounds={{
left: 120, left: 120,

View File

@@ -12,8 +12,8 @@ services:
postgresql: postgresql:
image: postgres image: postgres
environment: environment:
POSTGRES_USER: root - POSTGRES_USER=root
POSTGRES_PASSWORD: root - POSTGRES_PASSWORD=root
POSTGRES_DB: commafeed - POSTGRES_DB=commafeed
ports: ports:
- 5432:5432 - 5432:5432

View File

@@ -6,14 +6,14 @@
<parent> <parent>
<groupId>com.commafeed</groupId> <groupId>com.commafeed</groupId>
<artifactId>commafeed</artifactId> <artifactId>commafeed</artifactId>
<version>4.1.0</version> <version>4.3.0</version>
</parent> </parent>
<artifactId>commafeed-server</artifactId> <artifactId>commafeed-server</artifactId>
<name>CommaFeed Server</name> <name>CommaFeed Server</name>
<properties> <properties>
<guice.version>7.0.0</guice.version> <guice.version>7.0.0</guice.version>
<querydsl.version>5.0.0</querydsl.version> <querydsl.version>5.1.0</querydsl.version>
<rome.version>2.1.0</rome.version> <rome.version>2.1.0</rome.version>
</properties> </properties>
@@ -22,7 +22,7 @@
<dependency> <dependency>
<groupId>io.dropwizard</groupId> <groupId>io.dropwizard</groupId>
<artifactId>dropwizard-dependencies</artifactId> <artifactId>dropwizard-dependencies</artifactId>
<version>4.0.5</version> <version>4.0.6</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
@@ -36,12 +36,12 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.2.3</version> <version>3.2.5</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId> <artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.3</version> <version>3.2.5</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@@ -121,7 +121,7 @@
<plugin> <plugin>
<groupId>io.swagger.core.v3</groupId> <groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-maven-plugin-jakarta</artifactId> <artifactId>swagger-maven-plugin-jakarta</artifactId>
<version>2.2.19</version> <version>2.2.20</version>
<?m2e ignore?> <?m2e ignore?>
<configuration> <configuration>
<outputPath>${project.build.directory}/classes/assets</outputPath> <outputPath>${project.build.directory}/classes/assets</outputPath>
@@ -184,7 +184,7 @@
<plugin> <plugin>
<groupId>com.diffplug.spotless</groupId> <groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId> <artifactId>spotless-maven-plugin</artifactId>
<version>2.41.1</version> <version>2.43.0</version>
<?m2e ignore?> <?m2e ignore?>
<executions> <executions>
<execution> <execution>
@@ -211,7 +211,7 @@
<dependency> <dependency>
<groupId>com.commafeed</groupId> <groupId>com.commafeed</groupId>
<artifactId>commafeed-client</artifactId> <artifactId>commafeed-client</artifactId>
<version>4.1.0</version> <version>4.3.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -263,21 +263,20 @@
<groupId>io.dropwizard.metrics</groupId> <groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-json</artifactId> <artifactId>metrics-json</artifactId>
</dependency> </dependency>
<dependency>
<groupId>be.tomcools</groupId>
<artifactId>dropwizard-websocket-jsr356-bundle</artifactId>
<version>4.0.0</version>
</dependency>
<dependency> <dependency>
<groupId>io.whitfin</groupId> <groupId>io.whitfin</groupId>
<artifactId>dropwizard-environment-substitutor</artifactId> <artifactId>dropwizard-environment-substitutor</artifactId>
<version>1.1.1</version> <version>1.1.1</version>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jakarta-server</artifactId>
</dependency>
<dependency> <dependency>
<groupId>io.swagger.core.v3</groupId> <groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId> <artifactId>swagger-annotations</artifactId>
<version>2.2.19</version> <version>2.2.20</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -365,7 +364,7 @@
<dependency> <dependency>
<groupId>org.jsoup</groupId> <groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId> <artifactId>jsoup</artifactId>
<version>1.17.1</version> <version>1.17.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.ibm.icu</groupId> <groupId>com.ibm.icu</groupId>
@@ -385,7 +384,7 @@
<dependency> <dependency>
<groupId>org.gwtproject</groupId> <groupId>org.gwtproject</groupId>
<artifactId>gwt-servlet</artifactId> <artifactId>gwt-servlet</artifactId>
<version>2.10.0</version> <version>2.11.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents.client5</groupId> <groupId>org.apache.httpcomponents.client5</groupId>
@@ -394,30 +393,34 @@
<dependency> <dependency>
<groupId>io.github.hakky54</groupId> <groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-apache5</artifactId> <artifactId>sslcontext-kickstart-for-apache5</artifactId>
<version>8.2.0</version> <version>8.3.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.google.apis</groupId> <groupId>com.google.apis</groupId>
<artifactId>google-api-services-youtube</artifactId> <artifactId>google-api-services-youtube</artifactId>
<version>v3-rev20231011-2.0.0</version> <version>v3-rev20240123-2.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
<!-- stay on 2.1 because 2.2 file format changed to version '3' -->
<version>2.1.214</version><!--$NO-MVN-MAN-VER$ -->
</dependency> </dependency>
<dependency>
<groupId>com.manticore-projects.tools</groupId>
<artifactId>h2migrationtool</artifactId>
<version>1.4</version>
</dependency>
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version> <version>8.3.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mariadb.jdbc</groupId> <groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId> <artifactId>mariadb-java-client</artifactId>
<version>3.3.1</version> <version>3.3.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>
@@ -483,7 +486,7 @@
<dependency> <dependency>
<groupId>com.microsoft.playwright</groupId> <groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId> <artifactId>playwright</artifactId>
<version>1.40.0</version> <version>1.41.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>

View File

@@ -1,12 +1,15 @@
package com.commafeed; package com.commafeed;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant; import java.time.Instant;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import com.codahale.metrics.json.MetricsModule; import com.codahale.metrics.json.MetricsModule;
@@ -23,8 +26,9 @@ import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.User; import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserRole; import com.commafeed.backend.model.UserRole;
import com.commafeed.backend.model.UserSettings; import com.commafeed.backend.model.UserSettings;
import com.commafeed.backend.service.DatabaseStartupService;
import com.commafeed.backend.service.UserService; import com.commafeed.backend.service.UserService;
import com.commafeed.backend.service.db.DatabaseStartupService;
import com.commafeed.backend.service.db.H2MigrationService;
import com.commafeed.backend.task.ScheduledTask; import com.commafeed.backend.task.ScheduledTask;
import com.commafeed.frontend.auth.PasswordConstraintValidator; import com.commafeed.frontend.auth.PasswordConstraintValidator;
import com.commafeed.frontend.auth.SecurityCheckFactoryProvider; import com.commafeed.frontend.auth.SecurityCheckFactoryProvider;
@@ -52,12 +56,12 @@ import com.google.inject.Injector;
import com.google.inject.Key; import com.google.inject.Key;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
import be.tomcools.dropwizard.websocket.WebsocketBundle;
import io.dropwizard.assets.AssetsBundle; import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.configuration.DefaultConfigurationFactoryFactory; import io.dropwizard.configuration.DefaultConfigurationFactoryFactory;
import io.dropwizard.configuration.EnvironmentVariableSubstitutor; import io.dropwizard.configuration.EnvironmentVariableSubstitutor;
import io.dropwizard.configuration.SubstitutingSourceProvider; import io.dropwizard.configuration.SubstitutingSourceProvider;
import io.dropwizard.core.Application; import io.dropwizard.core.Application;
import io.dropwizard.core.ConfiguredBundle;
import io.dropwizard.core.setup.Bootstrap; import io.dropwizard.core.setup.Bootstrap;
import io.dropwizard.core.setup.Environment; import io.dropwizard.core.setup.Environment;
import io.dropwizard.db.DataSourceFactory; import io.dropwizard.db.DataSourceFactory;
@@ -82,7 +86,6 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
public static final Instant STARTUP_TIME = Instant.now(); public static final Instant STARTUP_TIME = Instant.now();
private HibernateBundle<CommaFeedConfiguration> hibernateBundle; private HibernateBundle<CommaFeedConfiguration> hibernateBundle;
private WebsocketBundle<CommaFeedConfiguration> websocketBundle;
@Override @Override
public String getName() { public String getName() {
@@ -94,7 +97,30 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
configureEnvironmentSubstitutor(bootstrap); configureEnvironmentSubstitutor(bootstrap);
configureObjectMapper(bootstrap.getObjectMapper()); configureObjectMapper(bootstrap.getObjectMapper());
bootstrap.addBundle(websocketBundle = new WebsocketBundle<>()); // run h2 migration as the first bundle because we need to migrate before hibernate is initialized
bootstrap.addBundle(new ConfiguredBundle<CommaFeedConfiguration>() {
@Override
public void run(CommaFeedConfiguration config, Environment environment) throws Exception {
DataSourceFactory dataSourceFactory = config.getDataSourceFactory();
String url = dataSourceFactory.getUrl();
if (isFileBasedH2(url)) {
Path path = getFilePath(url);
String user = dataSourceFactory.getUser();
String password = dataSourceFactory.getPassword();
new H2MigrationService().migrateIfNeeded(path, user, password);
}
}
private boolean isFileBasedH2(String url) {
return url.startsWith("jdbc:h2:") && !url.startsWith("jdbc:h2:mem:");
}
private Path getFilePath(String url) {
String name = url.substring("jdbc:h2:".length()).split(";")[0];
return Paths.get(name + ".mv.db");
}
});
bootstrap.addBundle(hibernateBundle = new HibernateBundle<>(AbstractModel.class, Feed.class, FeedCategory.class, FeedEntry.class, bootstrap.addBundle(hibernateBundle = new HibernateBundle<>(AbstractModel.class, Feed.class, FeedCategory.class, FeedEntry.class,
FeedEntryContent.class, FeedEntryStatus.class, FeedEntryTag.class, FeedSubscription.class, User.class, UserRole.class, FeedEntryContent.class, FeedEntryStatus.class, FeedEntryTag.class, FeedSubscription.class, User.class, UserRole.class,
UserSettings.class) { UserSettings.class) {
@@ -195,10 +221,13 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
} }
// WebSocket endpoint // WebSocket endpoint
ServerEndpointConfig serverEndpointConfig = ServerEndpointConfig.Builder.create(WebSocketEndpoint.class, "/ws") JakartaWebSocketServletContainerInitializer.configure(environment.getApplicationContext(), (context, container) -> {
.configurator(injector.getInstance(WebSocketConfigurator.class)) container.setDefaultMaxSessionIdleTimeout(config.getApplicationSettings().getWebsocketPingInterval().toMilliseconds() + 10000);
.build();
websocketBundle.addEndpoint(serverEndpointConfig); container.addEndpoint(ServerEndpointConfig.Builder.create(WebSocketEndpoint.class, "/ws")
.configurator(injector.getInstance(WebSocketConfigurator.class))
.build());
});
// Scheduled tasks // Scheduled tasks
Set<ScheduledTask> tasks = injector.getInstance(Key.get(new TypeLiteral<>() { Set<ScheduledTask> tasks = injector.getInstance(Key.get(new TypeLiteral<>() {

View File

@@ -10,8 +10,6 @@ import com.commafeed.backend.cache.RedisPoolFactory;
import com.commafeed.frontend.session.SessionHandlerFactory; import com.commafeed.frontend.session.SessionHandlerFactory;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import be.tomcools.dropwizard.websocket.WebsocketBundleConfiguration;
import be.tomcools.dropwizard.websocket.WebsocketConfiguration;
import io.dropwizard.core.Configuration; import io.dropwizard.core.Configuration;
import io.dropwizard.db.DataSourceFactory; import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.util.Duration; import io.dropwizard.util.Duration;
@@ -25,7 +23,7 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public class CommaFeedConfiguration extends Configuration implements WebsocketBundleConfiguration { public class CommaFeedConfiguration extends Configuration {
public enum CacheType { public enum CacheType {
NOOP, REDIS NOOP, REDIS
@@ -68,13 +66,6 @@ public class CommaFeedConfiguration extends Configuration implements WebsocketBu
this.gitCommit = properties.getProperty("git.commit.id.abbrev", "unknown"); this.gitCommit = properties.getProperty("git.commit.id.abbrev", "unknown");
} }
@Override
public WebsocketConfiguration getWebsocketConfiguration() {
WebsocketConfiguration config = new WebsocketConfiguration();
config.setMaxSessionIdleTimeout(getApplicationSettings().getWebsocketPingInterval().toMilliseconds() + 10000);
return config;
}
@Getter @Getter
@Setter @Setter
public static class ApplicationSettings { public static class ApplicationSettings {

View File

@@ -26,8 +26,8 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
super(sessionFactory); super(sessionFactory);
} }
public Long findExisting(String guidHash, Feed feed) { public FeedEntry findExisting(String guidHash, Feed feed) {
return query().select(entry.id).from(entry).where(entry.guidHash.eq(guidHash), entry.feed.eq(feed)).limit(1).fetchOne(); return query().select(entry).from(entry).where(entry.guidHash.eq(guidHash), entry.feed.eq(feed)).limit(1).fetchOne();
} }
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max) { public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max) {

View File

@@ -3,8 +3,11 @@ package com.commafeed.backend.feed;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
@@ -20,6 +23,7 @@ import com.commafeed.backend.dao.UnitOfWork;
import com.commafeed.backend.feed.parser.FeedParserResult.Content; import com.commafeed.backend.feed.parser.FeedParserResult.Content;
import com.commafeed.backend.feed.parser.FeedParserResult.Entry; import com.commafeed.backend.feed.parser.FeedParserResult.Entry;
import com.commafeed.backend.model.Feed; import com.commafeed.backend.model.Feed;
import com.commafeed.backend.model.FeedEntry;
import com.commafeed.backend.model.FeedSubscription; import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.User; import com.commafeed.backend.model.User;
import com.commafeed.backend.service.FeedEntryService; import com.commafeed.backend.service.FeedEntryService;
@@ -75,6 +79,7 @@ public class FeedRefreshUpdater {
private AddEntryResult addEntry(final Feed feed, final Entry entry, final List<FeedSubscription> subscriptions) { private AddEntryResult addEntry(final Feed feed, final Entry entry, final List<FeedSubscription> subscriptions) {
boolean processed = false; boolean processed = false;
boolean inserted = false; boolean inserted = false;
Set<FeedSubscription> subscriptionsForWhichEntryIsUnread = new HashSet<>();
// lock on feed, make sure we are not updating the same feed twice at // lock on feed, make sure we are not updating the same feed twice at
// the same time // the same time
@@ -96,10 +101,21 @@ public class FeedRefreshUpdater {
locked2 = lock2.tryLock(1, TimeUnit.MINUTES); locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
if (locked1 && locked2) { if (locked1 && locked2) {
processed = true; processed = true;
inserted = unitOfWork.call(() -> feedEntryService.addEntry(feed, entry, subscriptions)); inserted = unitOfWork.call(() -> {
if (inserted) { Instant now = Instant.now();
entryInserted.mark(); FeedEntry feedEntry = feedEntryService.findOrCreate(feed, entry);
} boolean newEntry = !feedEntry.getInserted().isBefore(now);
if (newEntry) {
entryInserted.mark();
for (FeedSubscription sub : subscriptions) {
boolean unread = feedEntryService.applyFilter(sub, feedEntry);
if (unread) {
subscriptionsForWhichEntryIsUnread.add(sub);
}
}
}
return newEntry;
});
} else { } else {
log.error("lock timeout for " + feed.getUrl() + " - " + key1); log.error("lock timeout for " + feed.getUrl() + " - " + key1);
} }
@@ -113,12 +129,13 @@ public class FeedRefreshUpdater {
lock2.unlock(); lock2.unlock();
} }
} }
return new AddEntryResult(processed, inserted); return new AddEntryResult(processed, inserted, subscriptionsForWhichEntryIsUnread);
} }
public boolean update(Feed feed, List<Entry> entries) { public boolean update(Feed feed, List<Entry> entries) {
boolean processed = true; boolean processed = true;
boolean insertedAtLeastOneEntry = false; long inserted = 0;
Map<FeedSubscription, Long> unreadCountBySubscription = new HashMap<>();
if (!entries.isEmpty()) { if (!entries.isEmpty()) {
Set<String> lastEntries = cache.getLastEntries(feed); Set<String> lastEntries = cache.getLastEntries(feed);
@@ -134,7 +151,8 @@ public class FeedRefreshUpdater {
} }
AddEntryResult addEntryResult = addEntry(feed, entry, subscriptions); AddEntryResult addEntryResult = addEntry(feed, entry, subscriptions);
processed &= addEntryResult.processed; processed &= addEntryResult.processed;
insertedAtLeastOneEntry |= addEntryResult.inserted; inserted += addEntryResult.inserted ? 1 : 0;
addEntryResult.subscriptionsForWhichEntryIsUnread.forEach(sub -> unreadCountBySubscription.merge(sub, 1L, Long::sum));
entryCacheMiss.mark(); entryCacheMiss.mark();
} else { } else {
@@ -148,22 +166,21 @@ public class FeedRefreshUpdater {
if (subscriptions == null) { if (subscriptions == null) {
feed.setMessage("No new entries found"); feed.setMessage("No new entries found");
} else if (insertedAtLeastOneEntry) { } else if (inserted > 0) {
List<User> users = subscriptions.stream().map(FeedSubscription::getUser).toList(); List<User> users = subscriptions.stream().map(FeedSubscription::getUser).toList();
cache.invalidateUnreadCount(subscriptions.toArray(new FeedSubscription[0])); cache.invalidateUnreadCount(subscriptions.toArray(new FeedSubscription[0]));
cache.invalidateUserRootCategory(users.toArray(new User[0])); cache.invalidateUserRootCategory(users.toArray(new User[0]));
// notify over websocket notifyOverWebsocket(unreadCountBySubscription);
subscriptions.forEach(sub -> webSocketSessions.sendMessage(sub.getUser(), WebSocketMessageBuilder.newFeedEntries(sub)));
} }
} }
if (!processed) { if (!processed) {
// requeue asap // requeue asap
feed.setDisabledUntil(Instant.EPOCH); feed.setDisabledUntil(Feed.MINIMUM_DISABLED_UNTIL);
} }
if (insertedAtLeastOneEntry) { if (inserted > 0) {
feedUpdated.mark(); feedUpdated.mark();
} }
@@ -172,10 +189,16 @@ public class FeedRefreshUpdater {
return processed; return processed;
} }
private void notifyOverWebsocket(Map<FeedSubscription, Long> unreadCountBySubscription) {
unreadCountBySubscription.forEach((sub, unreadCount) -> webSocketSessions.sendMessage(sub.getUser(),
WebSocketMessageBuilder.newFeedEntries(sub, unreadCount)));
}
@AllArgsConstructor @AllArgsConstructor
private static class AddEntryResult { private static class AddEntryResult {
private final boolean processed; private final boolean processed;
private final boolean inserted; private final boolean inserted;
private final Set<FeedSubscription> subscriptionsForWhichEntryIsUnread;
} }
} }

View File

@@ -15,6 +15,9 @@ import lombok.Setter;
@Setter @Setter
public class Feed extends AbstractModel { public class Feed extends AbstractModel {
// mariadb timestamp range starts at 1970-01-01 00:00:01
public static final Instant MINIMUM_DISABLED_UNTIL = Instant.EPOCH.plusSeconds(1);
/** /**
* The url of the feed * The url of the feed
*/ */

View File

@@ -35,6 +35,10 @@ public class UserSettings extends AbstractModel {
title, cozy, detailed, expanded title, cozy, detailed, expanded
} }
public enum ScrollMode {
always, never, if_needed
}
@OneToOne(fetch = FetchType.LAZY) @OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false, unique = true) @JoinColumn(name = "user_id", nullable = false, unique = true)
private User user; private User user;
@@ -66,9 +70,13 @@ public class UserSettings extends AbstractModel {
@Column(name = "scroll_speed") @Column(name = "scroll_speed")
private int scrollSpeed; private int scrollSpeed;
private boolean alwaysScrollToEntry; @Enumerated(EnumType.STRING)
@Column(nullable = false)
private ScrollMode scrollMode;
private boolean markAllAsReadConfirmation; private boolean markAllAsReadConfirmation;
private boolean customContextMenu; private boolean customContextMenu;
private boolean mobileFooter;
private boolean email; private boolean email;
private boolean gmail; private boolean gmail;

View File

@@ -17,6 +17,7 @@ import com.commafeed.backend.model.FeedEntry;
import com.commafeed.backend.model.FeedEntryStatus; import com.commafeed.backend.model.FeedEntryStatus;
import com.commafeed.backend.model.FeedSubscription; import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.User; import com.commafeed.backend.model.User;
import com.commafeed.backend.service.FeedEntryFilteringService.FeedEntryFilterException;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
@@ -38,33 +39,34 @@ public class FeedEntryService {
/** /**
* this is NOT thread-safe * this is NOT thread-safe
*/ */
public boolean addEntry(Feed feed, Entry entry, List<FeedSubscription> subscriptions) { public FeedEntry findOrCreate(Feed feed, Entry entry) {
String guid = FeedUtils.truncate(entry.guid(), 2048); String guid = FeedUtils.truncate(entry.guid(), 2048);
String guidHash = DigestUtils.sha1Hex(entry.guid()); String guidHash = DigestUtils.sha1Hex(entry.guid());
Long existing = feedEntryDAO.findExisting(guidHash, feed); FeedEntry existing = feedEntryDAO.findExisting(guidHash, feed);
if (existing != null) { if (existing != null) {
return false; return existing;
} }
FeedEntry feedEntry = buildEntry(feed, entry, guid, guidHash); FeedEntry feedEntry = buildEntry(feed, entry, guid, guidHash);
feedEntryDAO.saveOrUpdate(feedEntry); feedEntryDAO.saveOrUpdate(feedEntry);
return feedEntry;
}
// if filter does not match the entry, mark it as read public boolean applyFilter(FeedSubscription sub, FeedEntry entry) {
for (FeedSubscription sub : subscriptions) { boolean matches = true;
boolean matches = true; try {
try { matches = feedEntryFilteringService.filterMatchesEntry(sub.getFilter(), entry);
matches = feedEntryFilteringService.filterMatchesEntry(sub.getFilter(), feedEntry); } catch (FeedEntryFilterException e) {
} catch (FeedEntryFilteringService.FeedEntryFilterException e) { log.error("could not evaluate filter {}", sub.getFilter(), e);
log.error("could not evaluate filter {}", sub.getFilter(), e);
}
if (!matches) {
FeedEntryStatus status = new FeedEntryStatus(sub.getUser(), sub, feedEntry);
status.setRead(true);
feedEntryStatusDAO.saveOrUpdate(status);
}
} }
return true; if (!matches) {
FeedEntryStatus status = new FeedEntryStatus(sub.getUser(), sub, entry);
status.setRead(true);
feedEntryStatusDAO.saveOrUpdate(status);
}
return matches;
} }
private FeedEntry buildEntry(Feed feed, Entry e, String guid, String guidHash) { private FeedEntry buildEntry(Feed feed, Entry e, String guid, String guidHash) {

View File

@@ -45,7 +45,7 @@ public class FeedService {
feed.setUrl(url); feed.setUrl(url);
feed.setNormalizedUrl(normalizedUrl); feed.setNormalizedUrl(normalizedUrl);
feed.setNormalizedUrlHash(normalizedUrlHash); feed.setNormalizedUrlHash(normalizedUrlHash);
feed.setDisabledUntil(Instant.EPOCH); feed.setDisabledUntil(Feed.MINIMUM_DISABLED_UNTIL);
feedDAO.saveOrUpdate(feed); feedDAO.saveOrUpdate(feed);
} }
return feed; return feed;

View File

@@ -1,4 +1,4 @@
package com.commafeed.backend.service; package com.commafeed.backend.service.db;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;

View File

@@ -1,4 +1,4 @@
package com.commafeed.backend.service; package com.commafeed.backend.service.db;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -9,6 +9,7 @@ import org.hibernate.SessionFactory;
import com.commafeed.CommaFeedConfiguration; import com.commafeed.CommaFeedConfiguration;
import com.commafeed.backend.dao.UnitOfWork; import com.commafeed.backend.dao.UnitOfWork;
import com.commafeed.backend.dao.UserDAO; import com.commafeed.backend.dao.UserDAO;
import com.commafeed.backend.service.UserService;
import io.dropwizard.lifecycle.Managed; import io.dropwizard.lifecycle.Managed;
import jakarta.inject.Inject; import jakarta.inject.Inject;

View File

@@ -0,0 +1,84 @@
package com.commafeed.backend.service.db;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import com.manticore.h2.H2MigrationTool;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@RequiredArgsConstructor
@Slf4j
public class H2MigrationService {
public void migrateIfNeeded(Path path, String user, String password) {
if (Files.notExists(path)) {
return;
}
int format;
try {
format = getH2FileFormat(path);
} catch (IOException e) {
throw new RuntimeException("could not detect H2 format", e);
}
if (format == 2) {
try {
migrate(path, user, password, "2.1.214", "2.2.224");
} catch (Exception e) {
throw new RuntimeException("could not migrate H2 to format 3", e);
}
}
}
public int getH2FileFormat(Path path) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(path)) {
String headers = reader.readLine();
return Stream.of(headers.split(","))
.filter(h -> h.startsWith("format:"))
.map(h -> h.split(":")[1])
.map(Integer::parseInt)
.findFirst()
.orElseThrow(() -> new RuntimeException("could not find format in H2 file headers"));
}
}
private void migrate(Path path, String user, String password, String fromVersion, String toVersion) throws Exception {
log.info("migrating H2 database at {} from format {} to format {}", path, fromVersion, toVersion);
Path scriptPath = path.resolveSibling("script-" + System.currentTimeMillis() + ".sql");
Path newVersionPath = path.resolveSibling(path.getFileName() + "." + getPatchVersion(toVersion) + ".mv.db");
Path oldVersionBackupPath = path.resolveSibling(path.getFileName() + "." + getPatchVersion(fromVersion) + ".backup");
Files.deleteIfExists(scriptPath);
Files.deleteIfExists(newVersionPath);
Files.deleteIfExists(oldVersionBackupPath);
H2MigrationTool.readDriverRecords();
new H2MigrationTool().migrate(fromVersion, toVersion, path.toAbsolutePath().toString(), user, password,
scriptPath.toAbsolutePath().toString(), "", "", false, false, "");
if (!Files.exists(newVersionPath)) {
throw new RuntimeException("H2 migration failed, new version file not found");
}
Files.move(path, oldVersionBackupPath);
Files.move(newVersionPath, path);
Files.delete(oldVersionBackupPath);
Files.delete(scriptPath);
log.info("migrated H2 database from format {} to format {}", fromVersion, toVersion);
}
private String getPatchVersion(String version) {
return StringUtils.substringAfterLast(version, ".");
}
}

View File

@@ -3,7 +3,7 @@ package com.commafeed.backend.task;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.commafeed.CommaFeedConfiguration; import com.commafeed.CommaFeedConfiguration;
import com.commafeed.backend.service.DatabaseCleaningService; import com.commafeed.backend.service.db.DatabaseCleaningService;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;

View File

@@ -5,7 +5,7 @@ import java.time.Instant;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.commafeed.CommaFeedConfiguration; import com.commafeed.CommaFeedConfiguration;
import com.commafeed.backend.service.DatabaseCleaningService; import com.commafeed.backend.service.db.DatabaseCleaningService;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;

View File

@@ -4,7 +4,7 @@ import java.time.Instant;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.commafeed.CommaFeedConfiguration; import com.commafeed.CommaFeedConfiguration;
import com.commafeed.backend.service.DatabaseCleaningService; import com.commafeed.backend.service.db.DatabaseCleaningService;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;

View File

@@ -2,7 +2,7 @@ package com.commafeed.backend.task;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.commafeed.backend.service.DatabaseCleaningService; import com.commafeed.backend.service.db.DatabaseCleaningService;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;

View File

@@ -2,7 +2,7 @@ package com.commafeed.backend.task;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.commafeed.backend.service.DatabaseCleaningService; import com.commafeed.backend.service.db.DatabaseCleaningService;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;

View File

@@ -42,9 +42,10 @@ public class Settings implements Serializable {
private int scrollSpeed; private int scrollSpeed;
@Schema( @Schema(
description = "always scroll selected entry to the top of the page, even if it fits entirely on screen", description = "whether to scroll to the selected entry",
allowableValues = "always,never,if_needed",
requiredMode = RequiredMode.REQUIRED) requiredMode = RequiredMode.REQUIRED)
private boolean alwaysScrollToEntry; private String scrollMode;
@Schema(description = "ask for confirmation when marking all entries as read", requiredMode = RequiredMode.REQUIRED) @Schema(description = "ask for confirmation when marking all entries as read", requiredMode = RequiredMode.REQUIRED)
private boolean markAllAsReadConfirmation; private boolean markAllAsReadConfirmation;
@@ -52,6 +53,9 @@ public class Settings implements Serializable {
@Schema(description = "show commafeed's own context menu on right click", requiredMode = RequiredMode.REQUIRED) @Schema(description = "show commafeed's own context menu on right click", requiredMode = RequiredMode.REQUIRED)
private boolean customContextMenu; private boolean customContextMenu;
@Schema(description = "on mobile, show action buttons at the bottom of the screen", requiredMode = RequiredMode.REQUIRED)
private boolean mobileFooter;
@Schema(description = "sharing settings", requiredMode = RequiredMode.REQUIRED) @Schema(description = "sharing settings", requiredMode = RequiredMode.REQUIRED)
private SharingSettings sharingSettings = new SharingSettings(); private SharingSettings sharingSettings = new SharingSettings();

View File

@@ -24,6 +24,7 @@ import com.commafeed.backend.model.UserRole.Role;
import com.commafeed.backend.model.UserSettings; import com.commafeed.backend.model.UserSettings;
import com.commafeed.backend.model.UserSettings.ReadingMode; import com.commafeed.backend.model.UserSettings.ReadingMode;
import com.commafeed.backend.model.UserSettings.ReadingOrder; import com.commafeed.backend.model.UserSettings.ReadingOrder;
import com.commafeed.backend.model.UserSettings.ScrollMode;
import com.commafeed.backend.service.MailService; import com.commafeed.backend.service.MailService;
import com.commafeed.backend.service.PasswordEncryptionService; import com.commafeed.backend.service.PasswordEncryptionService;
import com.commafeed.backend.service.UserService; import com.commafeed.backend.service.UserService;
@@ -108,9 +109,10 @@ public class UserREST {
s.setCustomJs(settings.getCustomJs()); s.setCustomJs(settings.getCustomJs());
s.setLanguage(settings.getLanguage()); s.setLanguage(settings.getLanguage());
s.setScrollSpeed(settings.getScrollSpeed()); s.setScrollSpeed(settings.getScrollSpeed());
s.setAlwaysScrollToEntry(settings.isAlwaysScrollToEntry()); s.setScrollMode(settings.getScrollMode().name());
s.setMarkAllAsReadConfirmation(settings.isMarkAllAsReadConfirmation()); s.setMarkAllAsReadConfirmation(settings.isMarkAllAsReadConfirmation());
s.setCustomContextMenu(settings.isCustomContextMenu()); s.setCustomContextMenu(settings.isCustomContextMenu());
s.setMobileFooter(settings.isMobileFooter());
} else { } else {
s.setReadingMode(ReadingMode.unread.name()); s.setReadingMode(ReadingMode.unread.name());
s.setReadingOrder(ReadingOrder.desc.name()); s.setReadingOrder(ReadingOrder.desc.name());
@@ -128,9 +130,10 @@ public class UserREST {
s.setScrollMarks(true); s.setScrollMarks(true);
s.setLanguage("en"); s.setLanguage("en");
s.setScrollSpeed(400); s.setScrollSpeed(400);
s.setAlwaysScrollToEntry(false); s.setScrollMode(ScrollMode.if_needed.name());
s.setMarkAllAsReadConfirmation(true); s.setMarkAllAsReadConfirmation(true);
s.setCustomContextMenu(true); s.setCustomContextMenu(true);
s.setMobileFooter(false);
} }
return Response.ok(s).build(); return Response.ok(s).build();
} }
@@ -156,9 +159,10 @@ public class UserREST {
s.setCustomJs(CommaFeedApplication.USERNAME_DEMO.equals(user.getName()) ? "" : settings.getCustomJs()); s.setCustomJs(CommaFeedApplication.USERNAME_DEMO.equals(user.getName()) ? "" : settings.getCustomJs());
s.setLanguage(settings.getLanguage()); s.setLanguage(settings.getLanguage());
s.setScrollSpeed(settings.getScrollSpeed()); s.setScrollSpeed(settings.getScrollSpeed());
s.setAlwaysScrollToEntry(settings.isAlwaysScrollToEntry()); s.setScrollMode(ScrollMode.valueOf(settings.getScrollMode()));
s.setMarkAllAsReadConfirmation(settings.isMarkAllAsReadConfirmation()); s.setMarkAllAsReadConfirmation(settings.isMarkAllAsReadConfirmation());
s.setCustomContextMenu(settings.isCustomContextMenu()); s.setCustomContextMenu(settings.isCustomContextMenu());
s.setMobileFooter(settings.isMobileFooter());
s.setEmail(settings.getSharingSettings().isEmail()); s.setEmail(settings.getSharingSettings().isEmail());
s.setGmail(settings.getSharingSettings().isGmail()); s.setGmail(settings.getSharingSettings().isGmail());

View File

@@ -84,13 +84,6 @@ public class FeverREST {
private final FeedCategoryDAO feedCategoryDAO; private final FeedCategoryDAO feedCategoryDAO;
private final FeedEntryStatusDAO feedEntryStatusDAO; private final FeedEntryStatusDAO feedEntryStatusDAO;
@Path(PATH)
@GET
@Produces(MediaType.TEXT_PLAIN)
public String welcome() {
return "Welcome to the CommaFeed Fever API. Add this URL to your Fever-compatible reader.";
}
// expected Fever API // expected Fever API
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path(PATH) @Path(PATH)
@@ -116,6 +109,18 @@ public class FeverREST {
return handle(userId, params); return handle(userId, params);
} }
// workaround for some readers that use GET instead of POST
// e.g. Unread
@Path(PATH)
@GET
@UnitOfWork
@Timed
public FeverResponse get(@Context UriInfo uri, @PathParam("userId") Long userId) {
Map<String, String> params = new HashMap<>();
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.get(0)));
return handle(userId, params);
}
// workaround for some readers that post data using MultiPart FormData instead of the classic POST // workaround for some readers that post data using MultiPart FormData instead of the classic POST
// e.g. Raven Reader // e.g. Raven Reader
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)

View File

@@ -33,7 +33,7 @@ public class FeverResponse {
private boolean auth; private boolean auth;
@JsonProperty("last_refreshed_on_time") @JsonProperty("last_refreshed_on_time")
private long lastRefreshedOnTime; private Long lastRefreshedOnTime;
@JsonProperty("groups") @JsonProperty("groups")
private List<FeverGroup> groups; private List<FeverGroup> groups;

View File

@@ -7,8 +7,8 @@ import lombok.experimental.UtilityClass;
@UtilityClass @UtilityClass
public class WebSocketMessageBuilder { public class WebSocketMessageBuilder {
public static String newFeedEntries(FeedSubscription subscription) { public static String newFeedEntries(FeedSubscription subscription, long count) {
return String.format("%s:%s", "new-feed-entries", subscription.getId()); return String.format("%s:%s:%s", "new-feed-entries", subscription.getId(), count);
} }
} }

View File

@@ -3,7 +3,6 @@ package com.commafeed.frontend.ws;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import com.codahale.metrics.Gauge; import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
@@ -38,13 +37,8 @@ public class WebSocketSessions {
} }
public void sendMessage(User user, String text) { public void sendMessage(User user, String text) {
Set<Session> userSessions = sessions.entrySet() Set<Session> userSessions = sessions.get(user.getId());
.stream() if (userSessions != null && !userSessions.isEmpty()) {
.filter(e -> e.getKey().equals(user.getId()))
.flatMap(e -> e.getValue().stream())
.collect(Collectors.toSet());
if (!userSessions.isEmpty()) {
log.debug("sending '{}' to {} users via websocket", text, userSessions.size()); log.debug("sending '{}' to {} users via websocket", text, userSessions.size());
for (Session userSession : userSessions) { for (Session userSession : userSessions) {
if (userSession.isOpen()) { if (userSession.isOpen()) {

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="use-timestamps" author="athou">
<validCheckSum>9:bf66bf7def9ec3dab1f365f7230d92cf</validCheckSum>
<modifyDataType tableName="FEEDS" columnName="lastUpdated" newDataType="${timestamp_type}" />
<modifyDataType tableName="FEEDS" columnName="lastPublishedDate" newDataType="${timestamp_type}" />
<modifyDataType tableName="FEEDS" columnName="lastEntryDate" newDataType="${timestamp_type}" />
<modifyDataType tableName="FEEDS" columnName="disabledUntil" newDataType="${timestamp_type}" />
<modifyDataType tableName="FEEDENTRIES" columnName="inserted" newDataType="${timestamp_type}" />
<modifyDataType tableName="FEEDENTRIES" columnName="updated" newDataType="${timestamp_type}" />
<modifyDataType tableName="FEEDENTRYSTATUSES" columnName="entryInserted" newDataType="${timestamp_type}" />
<modifyDataType tableName="FEEDENTRYSTATUSES" columnName="entryUpdated" newDataType="${timestamp_type}" />
<modifyDataType tableName="USERS" columnName="lastLogin" newDataType="${timestamp_type}" />
<modifyDataType tableName="USERS" columnName="created" newDataType="${timestamp_type}" />
<modifyDataType tableName="USERS" columnName="recoverPasswordTokenDate" newDataType="${timestamp_type}" />
</changeSet>
<changeSet id="mobile-footer-setting" author="athou">
<addColumn tableName="USERSETTINGS">
<column name="mobileFooter" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false" />
</column>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="convert-alwaysScrollToEntry-to-scrollMode" author="athou">
<validCheckSum>9:663bcc7c6df5b832ec2109a3afcff5c6</validCheckSum>
<addColumn tableName="USERSETTINGS">
<column name="scrollMode" type="VARCHAR(32)" />
</addColumn>
<update tableName="USERSETTINGS">
<column name="scrollMode" value="always" />
<where>alwaysScrollToEntry = true</where>
</update>
<update tableName="USERSETTINGS">
<column name="scrollMode" value="if_needed" />
<where>alwaysScrollToEntry = false</where>
</update>
<addNotNullConstraint tableName="USERSETTINGS" columnName="scrollMode" columnDataType="VARCHAR(32)" />
<dropColumn tableName="USERSETTINGS" columnName="alwaysScrollToEntry" />
</changeSet>
</databaseChangeLog>

View File

@@ -4,9 +4,13 @@
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<property name="blob_type" value="bytea" dbms="postgresql" /> <property name="blob_type" value="bytea" dbms="postgresql" />
<property name="blob_type" value="blob" dbms="h2" /> <property name="blob_type" value="blob" dbms="h2,mysql,mariadb,mssql" />
<property name="blob_type" value="blob" dbms="mysql,mariadb" />
<property name="blob_type" value="blob" dbms="mssql" /> <!-- liquibase uses the 'TIMESTAMP WITHOUT TIME ZONE' type by default, which is not a UTC timestamp -->
<!-- postgresql UTC timestamp is actually 'TIMESTAMP WITH TIME ZONE' -->
<!-- see https://stackoverflow.com/a/48069726/1885506 -->
<property name="timestamp_type" value="timestamp with time zone" dbms="postgresql" />
<property name="timestamp_type" value="timestamp" dbms="h2,mysql,mariadb,mssql" />
<include file="changelogs/db.changelog-1.0.xml" /> <include file="changelogs/db.changelog-1.0.xml" />
<include file="changelogs/db.changelog-1.1.xml" /> <include file="changelogs/db.changelog-1.1.xml" />
@@ -24,5 +28,7 @@
<include file="changelogs/db.changelog-3.9.xml" /> <include file="changelogs/db.changelog-3.9.xml" />
<include file="changelogs/db.changelog-4.0.xml" /> <include file="changelogs/db.changelog-4.0.xml" />
<include file="changelogs/db.changelog-4.1.xml" /> <include file="changelogs/db.changelog-4.1.xml" />
<include file="changelogs/db.changelog-4.2.xml" />
<include file="changelogs/db.changelog-4.3.xml" />
</databaseChangeLog> </databaseChangeLog>

View File

@@ -0,0 +1,29 @@
package com.commafeed.backend.service.db;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
class H2MigrationServiceTest {
@TempDir
private Path root;
@Test
void testMigrateIfNeeded() throws IOException {
Path path = root.resolve("database.mv.db");
Files.copy(Objects.requireNonNull(getClass().getResourceAsStream("/h2-migration/database-v2.1.214.mv.db")), path);
H2MigrationService service = new H2MigrationService();
Assertions.assertEquals(2, service.getH2FileFormat(path));
service.migrateIfNeeded(path, "sa", "sa");
Assertions.assertEquals(3, service.getH2FileFormat(path));
}
}

View File

@@ -0,0 +1,82 @@
package com.commafeed.frontend.ws;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import com.codahale.metrics.MetricRegistry;
import com.commafeed.backend.model.User;
import jakarta.websocket.Session;
@ExtendWith(MockitoExtension.class)
class WebSocketSessionsTest {
@Mock
private MetricRegistry metrics;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Session session1;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Session session2;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Session session3;
private WebSocketSessions webSocketSessions;
@BeforeEach
void init() {
webSocketSessions = new WebSocketSessions(metrics);
}
@Test
void sendsMessageToUser() {
Mockito.when(session1.isOpen()).thenReturn(true);
Mockito.when(session2.isOpen()).thenReturn(true);
User user1 = newUser(1L);
webSocketSessions.add(user1.getId(), session1);
webSocketSessions.add(user1.getId(), session2);
User user2 = newUser(2L);
webSocketSessions.add(user2.getId(), session3);
webSocketSessions.sendMessage(user1, "Hello");
Mockito.verify(session1).getAsyncRemote();
Mockito.verify(session2).getAsyncRemote();
Mockito.verifyNoInteractions(session3);
}
@Test
void closedSessionsAreNotNotified() {
Mockito.when(session1.isOpen()).thenReturn(false);
User user1 = newUser(1L);
webSocketSessions.add(user1.getId(), session1);
webSocketSessions.sendMessage(user1, "Hello");
Mockito.verify(session1, Mockito.never()).getAsyncRemote();
}
@Test
void removedSessionsAreNotNotified() {
User user1 = newUser(1L);
webSocketSessions.add(user1.getId(), session1);
webSocketSessions.remove(session1);
webSocketSessions.sendMessage(user1, "Hello");
Mockito.verifyNoInteractions(session1);
}
private User newUser(Long userId) {
User user = new User();
user.setId(userId);
return user;
}
}

View File

@@ -38,6 +38,8 @@ import lombok.Getter;
@ExtendWith(MockServerExtension.class) @ExtendWith(MockServerExtension.class)
public abstract class BaseIT { public abstract class BaseIT {
private static final HttpRequest FEED_REQUEST = HttpRequest.request().withMethod("GET").withPath("/");
private final CommaFeedDropwizardAppExtension extension = buildExtension(); private final CommaFeedDropwizardAppExtension extension = buildExtension();
private Client client; private Client client;
@@ -50,6 +52,8 @@ public abstract class BaseIT {
private String webSocketUrl; private String webSocketUrl;
private MockServerClient mockServerClient;
protected CommaFeedDropwizardAppExtension buildExtension() { protected CommaFeedDropwizardAppExtension buildExtension() {
return new CommaFeedDropwizardAppExtension() { return new CommaFeedDropwizardAppExtension() {
@Override @Override
@@ -61,9 +65,10 @@ public abstract class BaseIT {
@BeforeEach @BeforeEach
void init(MockServerClient mockServerClient) throws IOException { void init(MockServerClient mockServerClient) throws IOException {
this.mockServerClient = mockServerClient;
URL resource = Objects.requireNonNull(getClass().getResource("/feed/rss.xml")); URL resource = Objects.requireNonNull(getClass().getResource("/feed/rss.xml"));
mockServerClient.when(HttpRequest.request().withMethod("GET").withPath("/")) mockServerClient.when(FEED_REQUEST).respond(HttpResponse.response().withBody(IOUtils.toString(resource, StandardCharsets.UTF_8)));
.respond(HttpResponse.response().withBody(IOUtils.toString(resource, StandardCharsets.UTF_8)));
this.client = extension.client(); this.client = extension.client();
this.feedUrl = "http://localhost:" + mockServerClient.getPort() + "/"; this.feedUrl = "http://localhost:" + mockServerClient.getPort() + "/";
@@ -77,6 +82,13 @@ public abstract class BaseIT {
this.client.close(); this.client.close();
} }
protected void feedNowReturnsMoreEntries() throws IOException {
mockServerClient.clear(FEED_REQUEST);
URL resource = Objects.requireNonNull(getClass().getResource("/feed/rss_2.xml"));
mockServerClient.when(FEED_REQUEST).respond(HttpResponse.response().withBody(IOUtils.toString(resource, StandardCharsets.UTF_8)));
}
protected String login() { protected String login() {
LoginRequest req = new LoginRequest(); LoginRequest req = new LoginRequest();
req.setName("admin"); req.setName("admin");
@@ -112,4 +124,8 @@ public abstract class BaseIT {
.get(); .get();
return response.readEntity(Entries.class); return response.readEntity(Entries.class);
} }
protected void forceRefreshAllFeeds() {
client.target(apiBaseUrl + "feed/refreshAll").request().get(Void.class);
}
} }

View File

@@ -13,6 +13,8 @@ import org.awaitility.Awaitility;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import com.commafeed.frontend.model.request.FeedModificationRequest;
import jakarta.websocket.ClientEndpointConfig; import jakarta.websocket.ClientEndpointConfig;
import jakarta.websocket.CloseReason; import jakarta.websocket.CloseReason;
import jakarta.websocket.ContainerProvider; import jakarta.websocket.ContainerProvider;
@@ -20,13 +22,12 @@ import jakarta.websocket.DeploymentException;
import jakarta.websocket.Endpoint; import jakarta.websocket.Endpoint;
import jakarta.websocket.EndpointConfig; import jakarta.websocket.EndpointConfig;
import jakarta.websocket.Session; import jakarta.websocket.Session;
import jakarta.ws.rs.client.Entity;
class WebSocketIT extends BaseIT { class WebSocketIT extends BaseIT {
@Test @Test
void sessionClosedIfNotLoggedIn() throws DeploymentException, IOException { void sessionClosedIfNotLoggedIn() throws DeploymentException, IOException {
ClientEndpointConfig config = buildConfig("fake-session-id");
AtomicBoolean connected = new AtomicBoolean(); AtomicBoolean connected = new AtomicBoolean();
AtomicReference<CloseReason> closeReasonRef = new AtomicReference<>(); AtomicReference<CloseReason> closeReasonRef = new AtomicReference<>();
try (Session ignored = ContainerProvider.getWebSocketContainer().connectToServer(new Endpoint() { try (Session ignored = ContainerProvider.getWebSocketContainer().connectToServer(new Endpoint() {
@@ -39,7 +40,7 @@ class WebSocketIT extends BaseIT {
public void onClose(Session session, CloseReason closeReason) { public void onClose(Session session, CloseReason closeReason) {
closeReasonRef.set(closeReason); closeReasonRef.set(closeReason);
} }
}, config, URI.create(getWebSocketUrl()))) { }, buildConfig("fake-session-id"), URI.create(getWebSocketUrl()))) {
Awaitility.await().atMost(15, TimeUnit.SECONDS).untilTrue(connected); Awaitility.await().atMost(15, TimeUnit.SECONDS).untilTrue(connected);
Awaitility.await().atMost(15, TimeUnit.SECONDS).until(() -> closeReasonRef.get() != null); Awaitility.await().atMost(15, TimeUnit.SECONDS).until(() -> closeReasonRef.get() != null);
@@ -50,7 +51,6 @@ class WebSocketIT extends BaseIT {
@Test @Test
void subscribeAndGetsNotified() throws DeploymentException, IOException { void subscribeAndGetsNotified() throws DeploymentException, IOException {
String sessionId = login(); String sessionId = login();
ClientEndpointConfig config = buildConfig(sessionId);
AtomicBoolean connected = new AtomicBoolean(); AtomicBoolean connected = new AtomicBoolean();
AtomicReference<String> messageRef = new AtomicReference<>(); AtomicReference<String> messageRef = new AtomicReference<>();
@@ -60,20 +60,50 @@ class WebSocketIT extends BaseIT {
session.addMessageHandler(String.class, messageRef::set); session.addMessageHandler(String.class, messageRef::set);
connected.set(true); connected.set(true);
} }
}, config, URI.create(getWebSocketUrl()))) { }, buildConfig(sessionId), URI.create(getWebSocketUrl()))) {
Awaitility.await().atMost(15, TimeUnit.SECONDS).untilTrue(connected); Awaitility.await().atMost(15, TimeUnit.SECONDS).untilTrue(connected);
Long subscriptionId = subscribe(getFeedUrl()); Long subscriptionId = subscribe(getFeedUrl());
Awaitility.await().atMost(15, TimeUnit.SECONDS).until(() -> messageRef.get() != null); Awaitility.await().atMost(15, TimeUnit.SECONDS).until(() -> messageRef.get() != null);
Assertions.assertEquals("new-feed-entries:" + subscriptionId, messageRef.get()); Assertions.assertEquals("new-feed-entries:" + subscriptionId + ":2", messageRef.get());
} }
} }
@Test
void notNotifiedForFilteredEntries() throws DeploymentException, IOException {
String sessionId = login();
Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
FeedModificationRequest req = new FeedModificationRequest();
req.setId(subscriptionId);
req.setName("feed-name");
req.setFilter("!title.contains('item 4')");
getClient().target(getApiBaseUrl() + "feed/modify").request().post(Entity.json(req), Void.class);
AtomicBoolean connected = new AtomicBoolean();
AtomicReference<String> messageRef = new AtomicReference<>();
try (Session ignored = ContainerProvider.getWebSocketContainer().connectToServer(new Endpoint() {
@Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(String.class, messageRef::set);
connected.set(true);
}
}, buildConfig(sessionId), URI.create(getWebSocketUrl()))) {
Awaitility.await().atMost(15, TimeUnit.SECONDS).untilTrue(connected);
feedNowReturnsMoreEntries();
forceRefreshAllFeeds();
Awaitility.await().atMost(15, TimeUnit.SECONDS).until(() -> messageRef.get() != null);
Assertions.assertEquals("new-feed-entries:" + subscriptionId + ":1", messageRef.get());
}
}
@Test @Test
void pingPong() throws DeploymentException, IOException { void pingPong() throws DeploymentException, IOException {
String sessionId = login(); String sessionId = login();
ClientEndpointConfig config = buildConfig(sessionId);
AtomicBoolean connected = new AtomicBoolean(); AtomicBoolean connected = new AtomicBoolean();
AtomicReference<String> messageRef = new AtomicReference<>(); AtomicReference<String> messageRef = new AtomicReference<>();
@@ -83,7 +113,7 @@ class WebSocketIT extends BaseIT {
session.addMessageHandler(String.class, messageRef::set); session.addMessageHandler(String.class, messageRef::set);
connected.set(true); connected.set(true);
} }
}, config, URI.create(getWebSocketUrl()))) { }, buildConfig(sessionId), URI.create(getWebSocketUrl()))) {
Awaitility.await().atMost(15, TimeUnit.SECONDS).untilTrue(connected); Awaitility.await().atMost(15, TimeUnit.SECONDS).untilTrue(connected);
session.getAsyncRemote().sendText("ping"); session.getAsyncRemote().sendText("ping");

View File

@@ -32,15 +32,6 @@ class FeverIT extends BaseIT {
this.userId = user.getId(); this.userId = user.getId();
} }
@Test
void get() {
String message = getClient().target(getApiBaseUrl() + "fever/user/${userId}")
.resolveTemplate("userId", 1)
.request()
.get(String.class);
Assertions.assertEquals("Welcome to the CommaFeed Fever API. Add this URL to your Fever-compatible reader.", message);
}
@Test @Test
void invalidApiKey() { void invalidApiKey() {
FeverResponse response = fetch("feeds", "invalid-key"); FeverResponse response = fetch("feeds", "invalid-key");

View File

@@ -5,13 +5,23 @@ import org.glassfish.jersey.client.ClientProperties;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import com.commafeed.CommaFeedDropwizardAppExtension;
import com.commafeed.frontend.model.UserModel;
import com.commafeed.integration.BaseIT; import com.commafeed.integration.BaseIT;
import jakarta.ws.rs.NotAuthorizedException;
import jakarta.ws.rs.client.Invocation.Builder;
import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
class LogoutIT extends BaseIT { class LogoutIT extends BaseIT {
@Override
protected CommaFeedDropwizardAppExtension buildExtension() {
// override so we don't add http basic auth
return new CommaFeedDropwizardAppExtension();
}
@Test @Test
void test() { void test() {
String cookie = login(); String cookie = login();
@@ -22,5 +32,8 @@ class LogoutIT extends BaseIT {
.get()) { .get()) {
Assertions.assertEquals(HttpStatus.FOUND_302, response.getStatus()); Assertions.assertEquals(HttpStatus.FOUND_302, response.getStatus());
} }
Builder req = getClient().target(getApiBaseUrl() + "user/profile").request().header(HttpHeaders.COOKIE, "JSESSIONID=" + cookie);
Assertions.assertThrows(NotAuthorizedException.class, () -> req.get(UserModel.class));
} }
} }

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>CommaFeed test feed</title>
<link>https://hostname.local/commafeed</link>
<description>CommaFeed test feed description</description>
<item>
<title>Item 4</title>
<link>https://hostname.local/commafeed/4</link>
<description>Item 4 description</description>
<pubDate>Sun, 31 Dec 2023 15:00:00 +0100</pubDate>
</item>
<item>
<title>Item 3</title>
<link>https://hostname.local/commafeed/3</link>
<description>Item 3 description</description>
<pubDate>Sat, 30 Dec 2023 15:00:00 +0100</pubDate>
</item>
<item>
<title>Item 2</title>
<link>https://hostname.local/commafeed/2</link>
<description>Item 2 description</description>
<pubDate>Fri, 29 Dec 2023 15:02:00 +0100</pubDate>
</item>
<item>
<title>Item 1</title>
<link>https://hostname.local/commafeed/1</link>
<description>Item 1 description</description>
<pubDate>Wed, 27 Dec 2023 22:24:00 +0100</pubDate>
</item>
</channel>
</rss>

View File

@@ -5,7 +5,7 @@
<groupId>com.commafeed</groupId> <groupId>com.commafeed</groupId>
<artifactId>commafeed</artifactId> <artifactId>commafeed</artifactId>
<version>4.1.0</version> <version>4.3.0</version>
<name>CommaFeed</name> <name>CommaFeed</name>
<packaging>pom</packaging> <packaging>pom</packaging>
@@ -20,7 +20,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version> <version>3.12.1</version>
<configuration> <configuration>
<parameters>true</parameters> <parameters>true</parameters>
</configuration> </configuration>