Compare commits

..

272 Commits

Author SHA1 Message Date
kolaente 4aad488707 chore: group return parameter
continuous-integration/drone/pr Build was killed Details
2023-05-31 14:18:58 +00:00
kolaente 61f0f5210a chore: make fuzzy matching a paramater 2023-05-31 14:18:58 +00:00
kolaente 8ea27a6655 fix: make type singular 2023-05-31 14:18:58 +00:00
kolaente 4993673d5c chore(i18n): clarify translation string 2023-05-31 14:18:58 +00:00
kolaente 1510807164 chore: use startsWith for prefix matching 2023-05-31 14:18:58 +00:00
kolaente a99eb820eb fix: clarify user search setting 2023-05-31 14:18:58 +00:00
kolaente ef65853278 chore: remove user margin from the component 2023-05-31 14:18:58 +00:00
kolaente 0bb6085fb1 chore: remove user margin from the component 2023-05-31 14:18:58 +00:00
kolaente ede1069577 feat(quick add magic): allow fuzzy matching of assignees when the api results are unambigous 2023-05-31 14:18:58 +00:00
kolaente 15a5aedcf9 fix: ensure all matched quick add magic parts are correctly removed from the task 2023-05-31 14:18:58 +00:00
kolaente 5f29624414 fix: lint 2023-05-31 14:18:58 +00:00
kolaente 502241a173 feat(assignees): show user avatar in search results 2023-05-31 14:18:58 +00:00
kolaente 7df5a0ba2e feat: show initial list of users when opening the assignees view 2023-05-31 14:18:58 +00:00
kolaente 1d05675cbd chore: clarify users when can still be found even if they disabled it 2023-05-31 14:18:58 +00:00
kolaente 0fcf949653 fix(quick add magic): cleanup all assignee properties 2023-05-31 14:18:58 +00:00
kolaente 22c10d935a fix(quick add magic): use the project user service to find assignees for quick add magic 2023-05-31 14:18:58 +00:00
kolaente 3d0753ebc8 fix(quick add magic): don't replace the prefix in every occurrence when it is present in the matched part 2023-05-31 14:18:58 +00:00
kolaente 8a75790453
chore: remove triggered notifications as it's not supported anywhere
continuous-integration/drone/push Build encountered an error Details
2023-05-31 15:21:09 +02:00
kolaente acb212ab24
feat: set the current language to the one saved by the user on login 2023-05-31 15:17:54 +02:00
kolaente 4ba02ebbb6
fix: don't try to convert a null date
continuous-integration/drone/push Build is passing Details
Resolves #3371
2023-05-31 15:07:23 +02:00
kolaente 244da46e38
fix(navigation): nav item width for items without sub projects
continuous-integration/drone/push Build is passing Details
2023-05-31 14:37:57 +02:00
kolaente f40035dc79
chore: update nix flake
continuous-integration/drone/push Build is passing Details
2023-05-31 13:44:14 +02:00
renovate 5f71e406fc fix(deps): update dependency marked to v5.0.4
continuous-integration/drone/push Build is passing Details
2023-05-31 05:15:46 +00:00
Frederick [Bot] 3d11a4f03a [skip ci] Updated translations via Crowdin 2023-05-31 00:30:36 +00:00
renovate 1dfd2dc4b7 fix(deps): update dependency vue-router to v4.2.2
continuous-integration/drone/push Build is passing Details
2023-05-30 22:46:00 +00:00
renovate e9701660d3 chore(deps): update dependency vite-plugin-pwa to v0.15.2
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-30 21:04:22 +00:00
renovate c8dbb4c7ef chore(deps): update typescript-eslint monorepo to v5.59.8
continuous-integration/drone/push Build is passing Details
2023-05-30 20:31:05 +00:00
renovate 1241d90268 chore(deps): update workbox monorepo to v6.6.1 (#3553)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #3553
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2023-05-30 20:30:46 +00:00
renovate 3de5b65977 chore(deps): update dependency vitest to v0.31.2
continuous-integration/drone/push Build is passing Details
2023-05-30 18:45:05 +00:00
renovate 4a353553c3 chore(deps): update pnpm to v8.6.0
continuous-integration/drone/push Build is passing Details
2023-05-30 18:42:51 +00:00
renovate 1240f31c0a chore(deps): update workbox monorepo to v6.6.0 (#3548)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #3548
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2023-05-30 18:12:03 +00:00
kolaente 01ac84ce1e
fix: don't require variant prop on loading component as it already has a default one set
continuous-integration/drone/push Build is passing Details
2023-05-30 20:00:02 +02:00
kolaente 4c969f0a42
fix: don't allow creating a new label from filter view
continuous-integration/drone/push Build is passing Details
Resolves #1035
2023-05-30 19:54:01 +02:00
kolaente 8e2c76a33e
feat: optimize print view for project views
continuous-integration/drone/push Build is passing Details
2023-05-30 19:50:37 +02:00
renovate b3666ec27e chore(deps): update dependency @vitejs/plugin-legacy to v4.0.4
continuous-integration/drone/push Build is failing Details
2023-05-30 16:36:54 +00:00
renovate 2c6862c509 chore(deps): update dependency vite-plugin-pwa to v0.15.1
continuous-integration/drone/push Build is failing Details
2023-05-30 16:36:44 +00:00
renovate 9f8c43818c chore(deps): update dependency @types/node to v18.16.16
continuous-integration/drone/push Build is failing Details
2023-05-30 16:36:17 +00:00
renovate 0debca91c8 chore(deps): update dependency @faker-js/faker to v8.0.2
continuous-integration/drone/push Build is passing Details
2023-05-30 16:36:08 +00:00
renovate 7b6c9fcd24 chore(deps): update dependency postcss to v8.4.24
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-30 15:05:47 +00:00
renovate 55675bf41b fix(deps): update sentry-javascript monorepo to v7.53.1
continuous-integration/drone/push Build is failing Details
2023-05-30 14:25:03 +00:00
renovate bb24b06031 chore(deps): update dependency vite to v4.3.9
continuous-integration/drone/push Build is passing Details
2023-05-30 14:24:37 +00:00
renovate dbce0376d5 fix(deps): update dependency marked to v5.0.3
continuous-integration/drone/push Build is failing Details
2023-05-30 14:24:15 +00:00
renovate 40db144a41 fix(deps): update dependency @intlify/unplugin-vue-i18n to v0.11.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-30 11:08:12 +00:00
kolaente f7ba3bd08f
fix: increase default auto-save timeout to 5 seconds
continuous-integration/drone/push Build is failing Details
Related discussion: https://community.vikunja.io/t/task-description-constantly-saving-loosing-content/1350
2023-05-30 12:19:14 +02:00
konrad ac1d374191 feat: remove namespaces, make projects infinitely nestable (#3323)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #3323
2023-05-30 10:09:39 +00:00
kolaente 391992effb
fix: missing await
continuous-integration/drone/pr Build is passing Details
2023-05-30 11:37:45 +02:00
kolaente 2e9ade11c3
fix: missing variant prop for loading component
continuous-integration/drone/pr Build was killed Details
2023-05-30 11:05:10 +02:00
kolaente f11a8c543b
fix(tests): project archived filter checkbox selector 2023-05-30 11:00:30 +02:00
kolaente e30a4452f2
fix(tests): new project input field 2023-05-30 10:57:08 +02:00
kolaente 6cc11e64ab
fix: undefined parent project when none was selected 2023-05-30 10:56:42 +02:00
kolaente 7b05ed9d3d
fix: avoid crashing browser processes during tests
continuous-integration/drone/pr Build was killed Details
2023-05-30 10:42:32 +02:00
Frederick [Bot] dba35c0107 [skip ci] Updated translations via Crowdin 2023-05-29 00:28:01 +00:00
Frederick [Bot] bfbc874b1d [skip ci] Updated translations via Crowdin 2023-05-28 00:29:34 +00:00
kolaente dbccdb239a
chore(tests): enable experimental memory managment for cypress tests
continuous-integration/drone/pr Build is failing Details
2023-05-24 18:32:23 +02:00
kolaente f13db9268a
fix: translation string 2023-05-24 17:41:14 +02:00
kolaente ed8de7e3eb
fix: lint
continuous-integration/drone/pr Build is failing Details
2023-05-24 15:54:37 +02:00
kolaente b34118485c
feat: allow creating a new project directly as a child project from another one 2023-05-24 15:54:37 +02:00
kolaente 9c3259c660
chore: don't recalculate everything 2023-05-24 15:54:37 +02:00
kolaente a3e289c06c
chore: remove type annotation for computed 2023-05-24 15:54:37 +02:00
kolaente 31b7c1f217
fix: don't set the current project when setting a project 2023-05-24 15:54:37 +02:00
kolaente c30dcff451
chore: don't show selection for parent project when no projects are available 2023-05-24 15:54:37 +02:00
kolaente 086f50d4fe
chore: re-add top menu spacing 2023-05-24 15:54:36 +02:00
kolaente 46e825820c
fix: sort in store 2023-05-24 15:54:36 +02:00
kolaente a3e2cbeb27
feat: replace color dot with handle icon on hover 2023-05-24 15:54:36 +02:00
kolaente a342ae67de
chore: use project id type 2023-05-24 15:54:36 +02:00
kolaente e4d97e0520
chore: don't set the current project to null if it's undefined already 2023-05-24 15:54:36 +02:00
kolaente b69a05689b
chore: move duplicate project logic to composable 2023-05-24 15:54:36 +02:00
kolaente 6b824a49ab
chore: redirect to new project after creating from store 2023-05-24 15:54:36 +02:00
kolaente 652db56d42
chore: remove unused code 2023-05-24 15:54:36 +02:00
kolaente afaf1846ec
chore: don't wrap a computed in another computed 2023-05-24 15:54:36 +02:00
kolaente ba452ab883
fix: move parent project handling out of useProject 2023-05-24 15:54:36 +02:00
kolaente 39f699a61a
fix: rename getParentProjects method to make it clear what it does 2023-05-24 15:54:36 +02:00
kolaente 4ab547810c
fix: return updated project instead of the old one 2023-05-24 15:54:35 +02:00
kolaente bbaddb9406
fix: remove leftovers of childIds 2023-05-24 15:54:35 +02:00
kolaente a2cc9ddc88
fix: properly determine if there are projects 2023-05-24 15:54:35 +02:00
kolaente 175e31ca62
fix: recreate project instead of editing before 2023-05-24 15:54:35 +02:00
kolaente d414b65e7d
fix: remove unnecessary fallback 2023-05-24 15:54:35 +02:00
kolaente 78158bcba5
fix: remove getProjectById and replace all usages of it 2023-05-24 15:54:35 +02:00
kolaente 9402344b7e
fix: add default for level 2023-05-24 15:54:35 +02:00
kolaente 3eca9f6180
fix: only bind child projects data down 2023-05-24 15:54:35 +02:00
kolaente 26e3d42ed5
fix: move parent project child id mutation to store 2023-05-24 15:54:35 +02:00
kolaente 6e095436e9
chore: rename flag 2023-05-24 15:54:35 +02:00
kolaente 1344026494
fix: move the collapsable placeholder to the button 2023-05-24 15:54:35 +02:00
kolaente 1a94496801
fix: bottom margin of project header 2023-05-24 15:54:34 +02:00
kolaente 48570808e5
fix: use the color bubble as handle if the project has a color 2023-05-24 15:54:34 +02:00
kolaente a7440ed296
chore: use stores directly 2023-05-24 15:54:34 +02:00
kolaente 12ebefd86a
chore: move v-if 2023-05-24 15:54:34 +02:00
kolaente 6c9cbaadc8
chore: set project id from the outside 2023-05-24 15:54:34 +02:00
kolaente 9b10693172
chore: replace section with a div 2023-05-24 15:54:34 +02:00
kolaente db1c6d6a41
chore: move all options to component props 2023-05-24 15:54:34 +02:00
kolaente c56787443f
chore: add types for emit 2023-05-24 15:54:34 +02:00
kolaente cb218ec0c3
feat: add setting for infinite nesting 2023-05-24 15:54:34 +02:00
kolaente 0dd6f82a0e
fix: use menu tag everywhere 2023-05-24 15:54:34 +02:00
kolaente 225091864f
fix: collapsing child projects 2023-05-24 15:54:34 +02:00
kolaente ebd9c4702e
feat: don't use child_projects property from api 2023-05-24 15:54:33 +02:00
kolaente 4ad9773022
chore: format 2023-05-24 15:54:33 +02:00
kolaente 0a17df87e9
fix: don't show child projects when the project is only a favorite 2023-05-24 15:54:33 +02:00
kolaente b567146d69
chore: move more logic to ProjectsNavigationItem.vue 2023-05-24 15:54:33 +02:00
kolaente 65522a57f1
chore: move ProjectsNavigationWrapper back to navigation.vue 2023-05-24 15:54:33 +02:00
kolaente 1d936618fa
feat: load all projects earlier than in the navigation and use the loading state of the store 2023-05-24 15:54:33 +02:00
kolaente 76814a2d3f
chore: move loading styles to variant into the component 2023-05-24 15:54:33 +02:00
kolaente 4134fcbd75
chore: remove old comment 2023-05-24 15:54:33 +02:00
kolaente 49fac7db1c
chore: use <menu> instead of <ul> 2023-05-24 15:54:33 +02:00
kolaente e25273df48
fix: indention 2023-05-24 15:54:33 +02:00
kolaente 638f6bea24
chore: improve prop type definition 2023-05-24 15:54:33 +02:00
kolaente ddcd6a17dc
chore: only apply padding where needed 2023-05-24 15:54:32 +02:00
kolaente 4e21b463df
chore: remove old todo 2023-05-24 15:54:32 +02:00
kolaente 3db4e011d4
feat: move navigation item to component 2023-05-24 15:54:32 +02:00
kolaente a0d39e6081
chore: use long variable name 2023-05-24 15:54:32 +02:00
kolaente a803bc637e
chore: rename alias 2023-05-24 15:54:32 +02:00
kolaente d4e452545a
chore: remove unused class 2023-05-24 15:54:32 +02:00
kolaente 9d73ac661f
fix: remove leftover suspense 2023-05-24 15:54:32 +02:00
kolaente 55e912221b
chore: use klona to clone project objet 2023-05-24 15:54:32 +02:00
kolaente d85be26761
fix: passing readonly projects data to navigation 2023-05-24 15:54:32 +02:00
kolaente ac78e85e17
chore: move loader class 2023-05-24 15:54:32 +02:00
kolaente 131022da42
chore: export favorite projects from store 2023-05-24 15:54:32 +02:00
kolaente 336db56316
chore: remove unnecessary map 2023-05-24 15:54:32 +02:00
kolaente b5d9afd0f7
chore: export not archived root projects 2023-05-24 15:54:31 +02:00
kolaente 0be83db40f
fix: show favorite on hover 2023-05-24 15:54:31 +02:00
kolaente 03f4d0b8bc
fix: don't show > for top-level projects 2023-05-24 15:54:31 +02:00
kolaente ee8f80cc70
feat: allow selecting a parent project when editing a project 2023-05-24 15:54:31 +02:00
kolaente ce887c38f3
feat: allow selecting a parent project when creating a project 2023-05-24 15:54:31 +02:00
kolaente 799c0be830
feat: allow selecting a parent project when duplicating a project 2023-05-24 15:54:31 +02:00
kolaente 760efa854d
feat: don't handle child projects and instead only save the ids 2023-05-24 15:54:31 +02:00
kolaente 26bec05174
fix: make computed side-effect free 2023-05-24 15:54:31 +02:00
kolaente c32a198a34
chore: refactor get parents project and move to projects store 2023-05-24 15:54:31 +02:00
kolaente 6a8c656dbb
feat: show all parent projects in project search 2023-05-24 15:54:31 +02:00
kolaente 63ba2982c9
feat: show all parent projects in task detail view 2023-05-24 15:54:30 +02:00
kolaente 9d9fb959d8
fix: add await 2023-05-24 15:54:30 +02:00
kolaente 8ed201c83f
fix(filters): load projects after updating a filter 2023-05-24 15:54:30 +02:00
kolaente bfb40c9166
fix(filters): load projects after deleting a filter 2023-05-24 15:54:30 +02:00
kolaente 5ea450844c
fix(filters): load projects after creating a filter 2023-05-24 15:54:30 +02:00
kolaente 36bec9e64f
chore(task): move toggleFavorite to store 2023-05-24 15:54:30 +02:00
kolaente a95014dc5d
feat(projects): move hasProjects check to store 2023-05-24 15:54:30 +02:00
kolaente 2579c33ee1
feat: wrap projects navigation in a <Suspense> so that we can use top level await 2023-05-24 15:54:30 +02:00
kolaente 6f1baa3219
chore: use long variable name 2023-05-24 15:54:30 +02:00
kolaente 4dee3a90e9
chore: rename archived message key 2023-05-24 15:54:30 +02:00
kolaente 326b6eda6f
fix: use correct shortcut to open projects overview 2023-05-24 15:54:30 +02:00
kolaente 85e882cc59
fix: simplify sort 2023-05-24 15:54:29 +02:00
kolaente e4379f0a22
chore: export projects as array directly from projects store 2023-05-24 15:54:29 +02:00
kolaente 2bb7ff1803
chore: rename prop 2023-05-24 15:54:29 +02:00
kolaente 5dd6e9a077
feat(tests): add project tests derived from old namespace tests 2023-05-24 15:54:29 +02:00
kolaente f7629c28f4
fix(projects): make sure the project hierarchy is properly updated when moving projects between parents 2023-05-24 15:54:29 +02:00
kolaente be2a38b48e
feat(navigation): show favorite projects on top 2023-05-24 15:54:29 +02:00
kolaente 3ba5f531bb
fix(navigation): make sure updating a project's state works for sub projects as well. 2023-05-24 15:54:29 +02:00
kolaente 10f1e69bc3
fix(navigation): make marking a project as favorite work 2023-05-24 15:54:29 +02:00
kolaente fd7d90b017
fix(navigation): make sure the Favorites project shows up when marking or unmarking a task as favorite 2023-05-24 15:54:29 +02:00
kolaente d898316918
fix(navigation): favorites project 2023-05-24 15:54:29 +02:00
kolaente a6f524e7af
fix(task detail view): make project display show the task's project 2023-05-24 15:54:29 +02:00
kolaente 5e65814b8c
fix: make check if projects are available work again 2023-05-24 15:54:28 +02:00
kolaente aaa9d553d0
fix: cleanup unused translation strings 2023-05-24 15:54:28 +02:00
kolaente 5685890493
fix: make tests work again 2023-05-24 15:54:28 +02:00
kolaente 2e336150e0
chore: cleanup namespace leftovers 2023-05-24 15:54:28 +02:00
kolaente 749dcdcd70
fix(navigation): hide left ul border 2023-05-24 15:54:28 +02:00
kolaente ab94343d07
feat(navigation): make dragging a project under another project work 2023-05-24 15:54:28 +02:00
kolaente fa71cec5c8
feat(navigation): allow dragging a project out from its parent project 2023-05-24 15:54:28 +02:00
kolaente c6f3829387
feat(navigation): make dragging a project to a parent work 2023-05-24 15:54:28 +02:00
kolaente 7171b63947
fix(navigation): hover state of other menu items 2023-05-24 15:54:28 +02:00
kolaente 06c4c0d921
feat(navigation): add hiding child projects 2023-05-24 15:54:28 +02:00
kolaente f2ca2d850d
feat: translate inbox project title 2023-05-24 15:54:28 +02:00
kolaente 638d187a24
chore: format 2023-05-24 15:54:28 +02:00
kolaente b188d40d3c
feat(navigation): correctly show child projects 2023-05-24 15:54:27 +02:00
kolaente 3ad948305f
fix(navigation): make the styles work again 2023-05-24 15:54:27 +02:00
kolaente be1f1d94c9
fix(navigation): watcher 2023-05-24 15:54:27 +02:00
kolaente 06e8cdb9d2
feat: rebuild main navigation so that it works recursively with projects 2023-05-24 15:54:27 +02:00
kolaente 10311b79df
fix: remove namespace routes 2023-05-24 15:54:27 +02:00
kolaente ad2690b21c
fix: remove namespace store reference 2023-05-24 15:54:27 +02:00
kolaente 1bd17d6e50
feat: remove all namespace leftovers 2023-05-24 15:54:27 +02:00
kolaente a5e710bfe5
fix: route to create new project 2023-05-24 15:54:27 +02:00
kolaente e1bdabc8d6
feat: move namespaces list to projects list 2023-05-24 15:54:27 +02:00
renovate c6ef99dde2 chore(deps): update dependency cypress to v12.13.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-24 00:04:34 +00:00
renovate 49b508a783 fix(deps): update sentry-javascript monorepo to v7.53.0
continuous-integration/drone/push Build is passing Details
2023-05-23 15:50:03 +00:00
renovate 52128925f5 chore(deps): update typescript-eslint monorepo to v5.59.7
continuous-integration/drone/push Build is passing Details
2023-05-23 15:49:52 +00:00
renovate cf0c7f9d08 chore(deps): update dependency rollup to v3.23.0
continuous-integration/drone/push Build is failing Details
2023-05-23 15:49:28 +00:00
renovate 57d5140301 chore(deps): update dependency @types/node to v18.16.14
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-23 12:04:31 +00:00
renovate dbd9106621 chore(deps): update dependency postcss-preset-env to v8.4.1
continuous-integration/drone/push Build is passing Details
2023-05-23 11:17:17 +00:00
renovate e4fef0e88e chore(deps): update dependency eslint to v8.41.0
continuous-integration/drone/push Build is passing Details
2023-05-23 11:16:31 +00:00
renovate 7ef0074ecc chore(deps): update dependency caniuse-lite to v1.0.30001489
continuous-integration/drone/push Build is passing Details
2023-05-23 11:16:09 +00:00
renovate 17c35f6d42 chore(deps): update dependency happy-dom to v9.20.1
continuous-integration/drone/push Build is failing Details
2023-05-23 11:15:58 +00:00
renovate 3a0844adba chore(deps): update dependency @rushstack/eslint-patch to v1.3.0
continuous-integration/drone/push Build is failing Details
2023-05-23 11:15:13 +00:00
renovate 5b5b9022e0 chore(deps): update dependency vite-plugin-pwa to v0.15.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-23 01:09:13 +00:00
Frederick [Bot] 0b0bd7dff6 [skip ci] Updated translations via Crowdin 2023-05-23 00:29:34 +00:00
renovate 079e3782d1 chore(deps): update dependency rollup to v3.22.0
continuous-integration/drone/push Build is failing Details
2023-05-19 10:30:44 +00:00
renovate a0ae9ae54c chore(deps): update dependency @types/marked to v5
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-19 09:06:04 +00:00
renovate a1b9a0ec4c fix(deps): update dependency @kyvg/vue3-notification to v2.9.1
continuous-integration/drone/push Build is failing Details
2023-05-19 08:07:44 +00:00
renovate 1fa690670d fix(deps): update dependency vue-router to v4.2.1
continuous-integration/drone/push Build is failing Details
2023-05-19 08:06:23 +00:00
renovate 3f0a87a5ec chore(deps): update dependency vite to v4.3.8
continuous-integration/drone/push Build is failing Details
2023-05-19 08:05:46 +00:00
renovate caf02f78bf chore(deps): update dependency @types/marked to v4.3.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-18 23:05:09 +00:00
renovate 9b9fd14d27 chore(deps): update dependency vitest to v0.31.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-17 15:05:09 +00:00
renovate 7f77efbfab chore(deps): update dependency @types/node to v18.16.11
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-16 20:04:54 +00:00
renovate 53967d20cc chore(deps): update dependency vite to v4.3.7
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-16 17:05:08 +00:00
renovate ef3411f39a chore(deps): update dependency @types/node to v18.16.10
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-16 11:04:50 +00:00
renovate 66e63f1363 chore(deps): update typescript-eslint monorepo to v5.59.6
continuous-integration/drone/push Build is passing Details
2023-05-16 10:46:23 +00:00
renovate 2fe21f6b28 fix(deps): update sentry-javascript monorepo to v7.52.1
continuous-integration/drone/push Build is passing Details
2023-05-16 10:46:09 +00:00
renovate 67df372636 chore(deps): update dependency eslint-plugin-vue to v9.13.0
continuous-integration/drone/push Build is failing Details
2023-05-16 10:45:49 +00:00
renovate df80e9da23 chore(deps): update dependency rollup to v3.21.8
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-16 08:04:56 +00:00
renovate 13ab2efd0f chore(deps): update dependency @faker-js/faker to v8.0.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-15 17:04:44 +00:00
renovate 0ffe96cf59 chore(deps): update dependency vite to v4.3.6
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-15 16:04:58 +00:00
renovate 1808d0971d fix(deps): update sentry-javascript monorepo to v7.52.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-15 14:05:00 +00:00
renovate ec83a28d78 chore(deps): update pnpm to v8.5.1
continuous-integration/drone/push Build is passing Details
2023-05-15 10:33:06 +00:00
renovate f0320b3a58 chore(deps): update dependency caniuse-lite to v1.0.30001487
continuous-integration/drone/push Build is passing Details
2023-05-15 10:30:51 +00:00
renovate d93a1a4f4f chore(deps): update dependency happy-dom to v9.18.3
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-15 00:05:29 +00:00
renovate a9f9ddf6b9 chore(deps): update dependency @types/node to v18.16.9
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-13 15:05:04 +00:00
renovate 6a8fe35fcf chore(deps): update dependency rollup to v3.21.7
continuous-integration/drone/push Build is passing Details
2023-05-13 14:48:00 +00:00
renovate 94661e9e09 chore(deps): update dependency vue-tsc to v1.6.5
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-13 08:04:55 +00:00
renovate 318f63d098 chore(deps): update dependency esbuild to v0.17.19
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-13 01:04:45 +00:00
renovate e2c9e83c2a chore(deps): update dependency @vitejs/plugin-vue to v4.2.3
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-12 11:04:45 +00:00
renovate cd434a0e3e chore(deps): update dependency @types/node to v18.16.8
continuous-integration/drone/push Build is passing Details
2023-05-12 07:06:52 +00:00
renovate 9f293af804 chore(deps): update dependency @vue/tsconfig to v0.4.0
continuous-integration/drone/push Build is failing Details
2023-05-12 07:06:24 +00:00
renovate b175e00cfe chore(deps): update dependency @tsconfig/node18 to v2.0.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-12 05:04:41 +00:00
Frederick [Bot] 19dd82d62a [skip ci] Updated translations via Crowdin 2023-05-12 00:29:44 +00:00
renovate b3ddc9465a chore(deps): update dependency @vitejs/plugin-vue to v4.2.2
continuous-integration/drone/push Build is passing Details
2023-05-11 19:57:40 +00:00
renovate 6b38f17d32 fix(deps): update dependency vue-router to v4.2.0
continuous-integration/drone/push Build is passing Details
2023-05-11 19:57:25 +00:00
renovate 86449d4912 fix(deps): update dependency marked to v5.0.2
continuous-integration/drone/push Build is failing Details
2023-05-11 19:57:07 +00:00
renovate 145d756251 chore(deps): update dependency @faker-js/faker to v8
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-11 18:05:10 +00:00
renovate 838a11a2f6 chore(deps): update dependency eslint-plugin-vue to v9.12.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-10 14:04:39 +00:00
renovate 3bfd3210b0 chore(deps): update dependency @types/node to v18.16.7
continuous-integration/drone/push Build is failing Details
2023-05-10 09:46:06 +00:00
renovate e933bfa99e fix(deps): update sentry-javascript monorepo to v7.51.2
continuous-integration/drone/push Build is failing Details
2023-05-10 09:14:43 +00:00
renovate f6a37a54d0 fix(deps): update dependency pinia to v2.0.36
continuous-integration/drone/push Build is failing Details
2023-05-10 09:14:33 +00:00
primeapple e00c9bb1af feat: add hotkeys for priority, delete and favorite on the `TaskDetailView` (#3400)
continuous-integration/drone/push Build is failing Details
Reviewed-on: #3400
Reviewed-by: konrad <k@knt.li>
Co-authored-by: primeapple <toni.mueller.web@mailbox.org>
Co-committed-by: primeapple <toni.mueller.web@mailbox.org>
2023-05-10 09:14:07 +00:00
kolaente 018707c3d5
fix(ci): disable puppeteer chrome download
continuous-integration/drone/push Build is failing Details
2023-05-10 10:42:44 +02:00
renovate 386727f6c5 chore(deps): update dependency @types/node to v18.16.6
continuous-integration/drone/push Build is passing Details
2023-05-10 08:09:35 +00:00
renovate a29ce36d6c chore(deps): update typescript-eslint monorepo to v5.59.5
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-10 07:05:09 +00:00
renovate 7aed16bd6f chore(deps): update dependency rollup to v3.21.6
continuous-integration/drone/push Build is failing Details
2023-05-10 06:03:37 +00:00
renovate b1f3ca6e59 chore(deps): update pnpm to v8.5.0
continuous-integration/drone/push Build is failing Details
2023-05-10 06:03:09 +00:00
renovate 4c0b8a06c5 chore(deps): update dependency cypress to v12.12.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-09 23:05:25 +00:00
renovate 60647c50ac chore(deps): update dependency caniuse-lite to v1.0.30001486
continuous-integration/drone/push Build is failing Details
2023-05-08 07:11:25 +00:00
renovate 59eaf1849e chore(deps): update dependency happy-dom to v9.10.9
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-08 00:05:41 +00:00
renovate fb57339050 chore(deps): update dependency eslint-plugin-vue to v9.11.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-07 17:04:47 +00:00
renovate f9831a6ad8 fix(deps): update dependency marked to v5.0.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-06 21:04:51 +00:00
renovate f25c67f80a chore(deps): update dependency eslint to v8.40.0
continuous-integration/drone/push Build is passing Details
2023-05-06 15:26:02 +00:00
renovate d3b0b97192 chore(deps): update dependency @types/node to v18.16.5
continuous-integration/drone/push Build is passing Details
2023-05-06 15:25:42 +00:00
renovate fa3be219a8 fix(deps): update dependency dompurify to v3.0.3
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2023-05-06 13:04:56 +00:00
renovate c22702d911 chore(deps): update dependency @types/node to v18.16.4
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-05 14:04:43 +00:00
renovate b25c5ff547 chore(deps): update dependency vite to v4.3.5
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-05 11:04:43 +00:00
renovate 2e0a097806 chore(deps): update dependency rollup to v3.21.5
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-05 05:04:46 +00:00
renovate c2083f7924 fix(deps): update sentry-javascript monorepo to v7.51.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-04 16:05:24 +00:00
renovate 8923261e5b fix(deps): update dependency ufo to v1.1.2
continuous-integration/drone/push Build is passing Details
2023-05-04 07:35:00 +00:00
renovate 5391df56b0 chore(deps): update dependency vue-tsc to v1.6.4
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-04 01:04:54 +00:00
renovate d2b1f5780e chore(deps): update dependency vitest to v0.31.0
continuous-integration/drone/push Build is passing Details
2023-05-03 19:52:49 +00:00
renovate 1717e968e1 chore(deps): update dependency rollup to v3.21.4
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-03 19:04:31 +00:00
renovate 2c29bb3971 chore(deps): update pnpm to v8.4.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-02 14:04:09 +00:00
renovate 37b8218a0a chore(deps): update node.js to v20 (#3411)
continuous-integration/drone/push Build is passing Details
Reviewed-on: #3411
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2023-05-02 13:35:04 +00:00
konrad ca7bbb5b91 chore(ci): remove netlify dependency (#3459)
continuous-integration/drone/push Build is passing Details
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: #3459
2023-05-02 10:10:14 +00:00
renovate 2f3c008d2b chore(deps): update dependency vite to v4.3.4
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-02 08:04:40 +00:00
renovate c2722b7c3d fix(deps): update dependency @vueuse/core to v10.1.2
continuous-integration/drone/push Build is failing Details
2023-05-02 07:18:12 +00:00
renovate 312abd907f chore(deps): update dependency rollup to v3.21.3
continuous-integration/drone/push Build is passing Details
2023-05-02 07:18:02 +00:00
renovate 1b73c1ed64 chore(deps): update dependency vue-tsc to v1.6.3
continuous-integration/drone/push Build is passing Details
2023-05-02 07:17:43 +00:00
renovate d442d6653b fix(deps): update dependency marked to v5
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-02 05:05:40 +00:00
renovate 758b8d6e2b chore(deps): update typescript-eslint monorepo to v5.59.2
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-01 18:04:39 +00:00
renovate 416fd2e2a7 chore(deps): update dependency @types/marked to v4.3.0
continuous-integration/drone/push Build is passing Details
2023-05-01 16:45:51 +00:00
renovate 15a8335f1a chore(deps): update dependency vue-tsc to v1.6.2
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-01 14:04:42 +00:00
renovate c689583669 chore(deps): update dependency netlify-cli to v14.3.1
continuous-integration/drone/push Build is passing Details
2023-05-01 10:44:11 +00:00
renovate 7a43a7acc9 chore(deps): update dependency happy-dom to v9.10.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-01 00:04:51 +00:00
renovate 8843418161 fix(deps): update dependency date-fns to v2.30.0
continuous-integration/drone/push Build is passing Details
2023-04-30 06:57:42 +00:00
renovate 7c1eab13ae chore(deps): update dependency rollup to v3.21.2
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-30 06:04:44 +00:00
renovate 5a69036da7 fix(deps): update dependency highlight.js to v11.8.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-29 14:04:50 +00:00
renovate 2ad3458873 chore(deps): update dependency @types/node to v18.16.3
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-29 07:04:40 +00:00
renovate eb464343e8 chore(deps): update dependency rollup to v3.21.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-29 06:04:42 +00:00
kolaente 2f18d0cbad
fix(docker): don't set nginx worker rlimit
continuous-integration/drone/push Build is passing Details
Resolves https://community.vikunja.io/t/helm-chart-frontend-pod-does-not-start-because-of-permission-issues-in-raspberry-pie-4-k3s/1286
2023-04-28 10:31:15 +02:00
renovate 6cd463a514 chore(deps): pin dependency @tsconfig/node18 to 2.0.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-28 08:04:35 +00:00
kolaente 05b70632c5
fix: tsconfig as per https://github.com/vuejs/tsconfig#configuration-for-node-environments
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-28 09:30:45 +02:00
kolaente ca9fe6ff21
fix: tsconfig as per https://github.com/vuejs/tsconfig#configuration-for-node-environments
continuous-integration/drone/pr Build is failing Details
2023-04-28 09:16:54 +02:00
renovate e5754300de chore(deps): update dependency @vue/tsconfig to v0.3.2
continuous-integration/drone/pr Build is failing Details
2023-04-28 07:04:31 +00:00
renovate 65134048bf chore(deps): update dependency @vitejs/plugin-vue to v4.2.1
continuous-integration/drone/push Build is passing Details
2023-04-28 06:04:35 +00:00
renovate 8339a99747 chore(deps): update dependency @types/node to v18.16.2
continuous-integration/drone/push Build is passing Details
2023-04-28 05:17:36 +00:00
renovate 3e1ae41e70 fix(deps): update dependency axios to v1.4.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-28 00:04:55 +00:00
renovate f757ba3441 chore(deps): update dependency vue-tsc to v1.6.1
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-27 19:04:37 +00:00
renovate 6499c9cb5b fix(deps): update sentry-javascript monorepo to v7.50.0
continuous-integration/drone/push Build is passing Details
2023-04-27 09:39:32 +00:00
renovate 28e5440d8b fix(deps): update dependency codemirror to v5.65.13
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-27 09:04:38 +00:00
renovate fef8c4d0f4 chore(deps): update dependency vue-tsc to v1.6.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-26 21:06:27 +00:00
renovate 99e5059c64 chore(deps): update dependency cypress to v12.11.0
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-04-26 18:04:42 +00:00
128 changed files with 3745 additions and 12134 deletions

View File

@ -42,11 +42,12 @@ steps:
# - .cache
- name: dependencies
image: node:18-alpine
image: node:20-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
CYPRESS_CACHE_FOLDER: .cache/cypress
PUPPETEER_SKIP_DOWNLOAD: true
commands:
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm install --fetch-timeout 100000
@ -54,7 +55,7 @@ steps:
# - restore-cache
- name: lint
image: node:18-alpine
image: node:20-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -65,7 +66,7 @@ steps:
- dependencies
- name: build-prod
image: node:18-alpine
image: node:20-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -76,7 +77,7 @@ steps:
- dependencies
- name: test-unit
image: node:18-alpine
image: node:20-alpine
pull: always
commands:
- corepack enable && pnpm config set store-dir .cache/pnpm
@ -86,7 +87,7 @@ steps:
- name: typecheck
failure: ignore
image: node:18-alpine
image: node:20-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -136,8 +137,9 @@ steps:
# - dependencies
- name: deploy-preview
image: node:18-alpine
image: williamjackson/netlify-cli
pull: always
user: root # The rest runs as root and thus the permissions wouldn't work
environment:
NETLIFY_AUTH_TOKEN:
from_secret: netlify_auth_token
@ -200,7 +202,7 @@ steps:
# - .cache
- name: build
image: node:18-alpine
image: node:20-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -277,7 +279,7 @@ steps:
# - .cache
- name: build
image: node:18-alpine
image: node:20-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -522,6 +524,6 @@ steps:
from_secret: crowdin_key
---
kind: signature
hmac: 303afeb09b75a57ba88720b45dc06c8bf2c7320e19d738d8299f325438246f75
hmac: 511c2a090e9efd4c942980d971204adb6321540bb01c92409dd9bf8463b7f6f4
...

View File

@ -3,7 +3,7 @@
# │─││ │││ │ │
# ┘─┘┘─┘┘┘─┘┘─┘
FROM --platform=$BUILDPLATFORM node:18-alpine AS builder
FROM --platform=$BUILDPLATFORM node:20-alpine AS builder
WORKDIR /build
@ -54,6 +54,7 @@ ENV VIKUNJA_LOG_FORMAT main
ENV VIKUNJA_API_URL /api/v1
ENV VIKUNJA_SENTRY_ENABLED false
ENV VIKUNJA_SENTRY_DSN https://85694a2d757547cbbc90cd4b55c5a18d@o1047380.ingest.sentry.io/6024480
ENV VIKUNJA_PROJECT_INFINITE_NESTING_ENABLED false
COPY docker/injector.sh /docker-entrypoint.d/50-injector.sh
COPY docker/ipv6-disable.sh /docker-entrypoint.d/60-ipv6-disable.sh

View File

@ -24,4 +24,5 @@ export default defineConfig({
},
viewportWidth: 1600,
viewportHeight: 900,
experimentalMemoryManagement: true,
})

View File

@ -2,7 +2,6 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser'
import {TaskFactory} from '../../factories/task'
import {ProjectFactory} from '../../factories/project'
import {NamespaceFactory} from '../../factories/namespace'
import {UserProjectFactory} from '../../factories/users_project'
import {BucketFactory} from '../../factories/bucket'
@ -10,7 +9,6 @@ describe('Editor', () => {
createFakeUserAndLogin()
beforeEach(() => {
NamespaceFactory.create(1)
ProjectFactory.create(1)
BucketFactory.create(1)
TaskFactory.truncate()

View File

@ -8,20 +8,20 @@ describe('The Menu', () => {
})
it('Is visible by default on desktop', () => {
cy.get('.namespace-container')
cy.get('.menu-container')
.should('have.class', 'is-active')
})
it('Can be hidden on desktop', () => {
cy.get('button.menu-show-button:visible')
.click()
cy.get('.namespace-container')
cy.get('.menu-container')
.should('not.have.class', 'is-active')
})
it('Is hidden by default on mobile', () => {
cy.viewport('iphone-8')
cy.get('.namespace-container')
cy.get('.menu-container')
.should('not.have.class', 'is-active')
})
@ -29,7 +29,7 @@ describe('The Menu', () => {
cy.viewport('iphone-8')
cy.get('button.menu-show-button:visible')
.click()
cy.get('.namespace-container')
cy.get('.menu-container')
.should('have.class', 'is-active')
})
})

View File

@ -1,145 +0,0 @@
import {createFakeUserAndLogin} from '../../support/authenticateUser'
import {ProjectFactory} from '../../factories/project'
import {NamespaceFactory} from '../../factories/namespace'
describe('Namepaces', () => {
createFakeUserAndLogin()
let namespaces
beforeEach(() => {
namespaces = NamespaceFactory.create(1)
ProjectFactory.create(1)
})
it('Should be all there', () => {
cy.visit('/namespaces')
cy.get('[data-cy="namespace-title"]')
.should('contain', namespaces[0].title)
})
it('Should create a new Namespace', () => {
const newNamespaceTitle = 'New Namespace'
cy.visit('/namespaces')
cy.get('[data-cy="new-namespace"]')
.should('contain', 'New namespace')
.click()
cy.url()
.should('contain', '/namespaces/new')
cy.get('.card-header-title')
.should('contain', 'New namespace')
cy.get('input.input')
.type(newNamespaceTitle)
cy.get('.button')
.contains('Create')
.click()
cy.get('.global-notification')
.should('contain', 'Success')
cy.get('.namespace-container')
.should('contain', newNamespaceTitle)
cy.url()
.should('contain', '/namespaces')
})
it('Should rename the namespace all places', () => {
const newNamespaces = NamespaceFactory.create(5)
const newNamespaceName = 'New namespace name'
cy.visit('/namespaces')
cy.get(`.namespace-container .menu.namespaces-lists .namespace-title:contains(${newNamespaces[0].title}) .dropdown .dropdown-trigger`)
.click()
cy.get('.namespace-container .menu.namespaces-lists .namespace-title .dropdown .dropdown-content')
.contains('Edit')
.click()
cy.url()
.should('contain', '/settings/edit')
cy.get('#namespacetext')
.invoke('val')
.should('equal', newNamespaces[0].title) // wait until the namespace data is loaded
cy.get('#namespacetext')
.type(`{selectall}${newNamespaceName}`)
cy.get('footer.card-footer .button')
.contains('Save')
.click()
cy.get('.global-notification', { timeout: 1000 })
.should('contain', 'Success')
cy.get('.namespace-container .menu.namespaces-lists')
.should('contain', newNamespaceName)
.should('not.contain', newNamespaces[0].title)
cy.get('[data-cy="namespaces-list"]')
.should('contain', newNamespaceName)
.should('not.contain', newNamespaces[0].title)
})
it('Should remove a namespace when deleting it', () => {
const newNamespaces = NamespaceFactory.create(5)
cy.visit('/')
cy.get(`.namespace-container .menu.namespaces-lists .namespace-title:contains(${newNamespaces[0].title}) .dropdown .dropdown-trigger`)
.click()
cy.get('.namespace-container .menu.namespaces-lists .namespace-title .dropdown .dropdown-content')
.contains('Delete')
.click()
cy.url()
.should('contain', '/settings/delete')
cy.get('[data-cy="modalPrimary"]')
.contains('Do it')
.click()
cy.get('.global-notification')
.should('contain', 'Success')
cy.get('.namespace-container .menu.namespaces-lists')
.should('not.contain', newNamespaces[0].title)
})
it('Should not show archived projects & namespaces if the filter is not checked', () => {
const n = NamespaceFactory.create(1, {
id: 2,
is_archived: true,
}, false)
ProjectFactory.create(1, {
id: 2,
namespace_id: n[0].id,
}, false)
ProjectFactory.create(1, {
id: 3,
is_archived: true,
}, false)
// Initial
cy.visit('/namespaces')
cy.get('.namespace')
.should('not.contain', 'Archived')
// Show archived
cy.get('[data-cy="show-archived-check"] .fancycheckbox__content')
.should('be.visible')
.click()
cy.get('[data-cy="show-archived-check"] input')
.should('be.checked')
cy.get('.namespace')
.should('contain', 'Archived')
// Don't show archived
cy.get('[data-cy="show-archived-check"] .fancycheckbox__content')
.should('be.visible')
.click()
cy.get('[data-cy="show-archived-check"] input')
.should('not.be.checked')
// Second time visiting after unchecking
cy.visit('/namespaces')
cy.get('[data-cy="show-archived-check"] input')
.should('not.be.checked')
cy.get('.namespace')
.should('not.contain', 'Archived')
})
})

View File

@ -1,9 +1,7 @@
import {ProjectFactory} from '../../factories/project'
import {NamespaceFactory} from '../../factories/namespace'
import {TaskFactory} from '../../factories/task'
export function createProjects() {
NamespaceFactory.create(1)
const projects = ProjectFactory.create(1, {
title: 'First Project'
})

View File

@ -8,37 +8,30 @@ describe('Project History', () => {
prepareProjects()
it('should show a project history on the home page', () => {
cy.intercept(Cypress.env('API_URL') + '/namespaces*').as('loadNamespaces')
cy.intercept(Cypress.env('API_URL') + '/projects*').as('loadProjectArray')
cy.intercept(Cypress.env('API_URL') + '/projects/*').as('loadProject')
const projects = ProjectFactory.create(6)
cy.visit('/')
cy.wait('@loadNamespaces')
cy.wait('@loadProjectArray')
cy.get('body')
.should('not.contain', 'Last viewed')
cy.visit(`/projects/${projects[0].id}`)
cy.wait('@loadNamespaces')
cy.wait('@loadProject')
cy.visit(`/projects/${projects[1].id}`)
cy.wait('@loadNamespaces')
cy.wait('@loadProject')
cy.visit(`/projects/${projects[2].id}`)
cy.wait('@loadNamespaces')
cy.wait('@loadProject')
cy.visit(`/projects/${projects[3].id}`)
cy.wait('@loadNamespaces')
cy.wait('@loadProject')
cy.visit(`/projects/${projects[4].id}`)
cy.wait('@loadNamespaces')
cy.wait('@loadProject')
cy.visit(`/projects/${projects[5].id}`)
cy.wait('@loadNamespaces')
cy.wait('@loadProject')
// cy.visit('/')
// cy.wait('@loadNamespaces')
// Not using cy.visit here to work around the redirect issue fixed in #1337
cy.get('nav.menu.top-menu a')
.contains('Overview')

View File

@ -58,7 +58,6 @@ describe('Project View Project', () => {
})
const projects = ProjectFactory.create(2, {
owner_id: '{increment}',
namespace_id: '{increment}',
})
cy.visit(`/projects/${projects[1].id}/`)

View File

@ -1,6 +1,7 @@
import {createFakeUserAndLogin} from '../../support/authenticateUser'
import {TaskFactory} from '../../factories/task'
import {ProjectFactory} from '../../factories/project'
import {prepareProjects} from './prepareProjects'
describe('Projects', () => {
@ -10,23 +11,20 @@ describe('Projects', () => {
prepareProjects((newProjects) => (projects = newProjects))
it('Should create a new project', () => {
cy.visit('/')
cy.get('.namespace-title .dropdown-trigger')
.click()
cy.get('.namespace-title .dropdown .dropdown-item')
.contains('New project')
cy.visit('/projects')
cy.get('.project-header [data-cy=new-project]')
.click()
cy.url()
.should('contain', '/projects/new/1')
.should('contain', '/projects/new')
cy.get('.card-header-title')
.contains('New project')
cy.get('input.input')
cy.get('input[name=projectTitle]')
.type('New Project')
cy.get('.button')
.contains('Create')
.click()
cy.get('.global-notification', { timeout: 1000 }) // Waiting until the request to create the new project is done
cy.get('.global-notification', {timeout: 1000}) // Waiting until the request to create the new project is done
.should('contain', 'Success')
cy.url()
.should('contain', '/projects/')
@ -56,9 +54,9 @@ describe('Projects', () => {
cy.get('.project-title')
.should('contain', 'First Project')
cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child .dropdown .menu-list-dropdown-trigger')
cy.get('.menu-container .menu-list li:first-child .dropdown .menu-list-dropdown-trigger')
.click()
cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child .dropdown .dropdown-content')
cy.get('.menu-container .menu-list li:first-child .dropdown .dropdown-content')
.contains('Edit')
.click()
cy.get('#title')
@ -72,21 +70,21 @@ describe('Projects', () => {
cy.get('.project-title')
.should('contain', newProjectName)
.should('not.contain', projects[0].title)
cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child')
cy.get('.menu-container .menu-list li:first-child')
.should('contain', newProjectName)
.should('not.contain', projects[0].title)
cy.visit('/')
cy.get('.card-content')
cy.get('.project-grid')
.should('contain', newProjectName)
.should('not.contain', projects[0].title)
})
it('Should remove a project', () => {
it('Should remove a project when deleting it', () => {
cy.visit(`/projects/${projects[0].id}`)
cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child .dropdown .menu-list-dropdown-trigger')
cy.get('.menu-container .menu-list li:first-child .dropdown .menu-list-dropdown-trigger')
.click()
cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child .dropdown .dropdown-content')
cy.get('.menu-container .menu-list li:first-child .dropdown .dropdown-content')
.contains('Delete')
.click()
cy.url()
@ -97,15 +95,15 @@ describe('Projects', () => {
cy.get('.global-notification')
.should('contain', 'Success')
cy.get('.namespace-container .menu.namespaces-lists .menu-list')
cy.get('.menu-container .menu-list')
.should('not.contain', projects[0].title)
cy.location('pathname')
.should('equal', '/')
})
it('Should archive a project', () => {
cy.visit(`/projects/${projects[0].id}`)
cy.get('.project-title-dropdown')
.click()
cy.get('.project-title-dropdown .dropdown-menu .dropdown-item')
@ -115,10 +113,59 @@ describe('Projects', () => {
.should('contain.text', 'Archive this project')
cy.get('.modal-content [data-cy=modalPrimary]')
.click()
cy.get('.namespace-container .menu.namespaces-lists .menu-list')
cy.get('.menu-container .menu-list')
.should('not.contain', projects[0].title)
cy.get('main.app-content')
.should('contain.text', 'This project is archived. It is not possible to create new or edit tasks for it.')
})
it('Should show all projects on the projects page', () => {
const projects = ProjectFactory.create(10)
cy.visit('/projects')
projects.forEach(p => {
cy.get('[data-cy="projects-list"]')
.should('contain', p.title)
})
})
it('Should not show archived projects if the filter is not checked', () => {
ProjectFactory.create(1, {
id: 2,
}, false)
ProjectFactory.create(1, {
id: 3,
is_archived: true,
}, false)
// Initial
cy.visit('/projects')
cy.get('.project-grid')
.should('not.contain', 'Archived')
// Show archived
cy.get('[data-cy="show-archived-check"] label span')
.should('be.visible')
.click()
cy.get('[data-cy="show-archived-check"] input')
.should('be.checked')
cy.get('.project-grid')
.should('contain', 'Archived')
// Don't show archived
cy.get('[data-cy="show-archived-check"] label span')
.should('be.visible')
.click()
cy.get('[data-cy="show-archived-check"] input')
.should('not.be.checked')
// Second time visiting after unchecking
cy.visit('/projects')
cy.get('[data-cy="show-archived-check"] input')
.should('not.be.checked')
cy.get('.project-grid')
.should('not.contain', 'Archived')
})
})

View File

@ -3,12 +3,10 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser'
import {ProjectFactory} from '../../factories/project'
import {seed} from '../../support/seed'
import {TaskFactory} from '../../factories/task'
import {NamespaceFactory} from '../../factories/namespace'
import {BucketFactory} from '../../factories/bucket'
import {updateUserSettings} from '../../support/updateUserSettings'
function seedTasks(numberOfTasks = 50, startDueDate = new Date()) {
NamespaceFactory.create(1)
const project = ProjectFactory.create()[0]
BucketFactory.create(1, {
project_id: project.id,
@ -137,8 +135,7 @@ describe('Home Page Task Overview', () => {
cy.visit('/')
cy.get('.home.app-content .content')
.should('contain.text', 'You can create a new project for your new tasks:')
.should('contain.text', 'Or import your projects and tasks from other services into Vikunja:')
.should('contain.text', 'Import your projects and tasks from other services into Vikunja:')
})
it('Should not show the cta buttons for new project when there are tasks', () => {

View File

@ -4,7 +4,6 @@ import {TaskFactory} from '../../factories/task'
import {ProjectFactory} from '../../factories/project'
import {TaskCommentFactory} from '../../factories/task_comment'
import {UserFactory} from '../../factories/user'
import {NamespaceFactory} from '../../factories/namespace'
import {UserProjectFactory} from '../../factories/users_project'
import {TaskAssigneeFactory} from '../../factories/task_assignee'
import {LabelFactory} from '../../factories/labels'
@ -47,13 +46,11 @@ function uploadAttachmentAndVerify(taskId: number) {
describe('Task', () => {
createFakeUserAndLogin()
let namespaces
let projects
let buckets
beforeEach(() => {
// UserFactory.create(1)
namespaces = NamespaceFactory.create(1)
projects = ProjectFactory.create(1)
buckets = BucketFactory.create(1, {
project_id: projects[0].id,
@ -110,7 +107,7 @@ describe('Task', () => {
cy.get('.tasks .task .favorite')
.first()
.click()
cy.get('.menu.namespaces-lists')
cy.get('.menu-container')
.should('contain', 'Favorites')
})
@ -133,7 +130,6 @@ describe('Task', () => {
cy.get('.task-view h1.title.task-id')
.should('contain', '#1')
cy.get('.task-view h6.subtitle')
.should('contain', namespaces[0].title)
.should('contain', projects[0].title)
cy.get('.task-view .details.content.description')
.should('contain', tasks[0].description)
@ -260,7 +256,6 @@ describe('Task', () => {
.click()
cy.get('.task-view h6.subtitle')
.should('contain', namespaces[0].title)
.should('contain', projects[1].title)
cy.get('.global-notification')
.should('contain', 'Success')

View File

@ -1,5 +1,5 @@
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["./**/*", "../support/**/*", "../factories/**/*"],
"compilerOptions": {
"baseUrl": ".",

View File

@ -1,18 +0,0 @@
import {faker} from '@faker-js/faker'
import {Factory} from '../support/factory'
export class NamespaceFactory extends Factory {
static table = 'namespaces'
static factory() {
const now = new Date()
return {
id: '{increment}',
title: faker.lorem.words(3),
owner_id: 1,
created: now.toISOString(),
updated: now.toISOString(),
}
}
}

View File

@ -11,7 +11,6 @@ export class ProjectFactory extends Factory {
id: '{increment}',
title: faker.lorem.words(3),
owner_id: 1,
namespace_id: 1,
created: now.toISOString(),
updated: now.toISOString(),
}

1
docker/injector.sh Normal file → Executable file
View File

@ -11,5 +11,6 @@ VIKUNJA_SENTRY_DSN="$(echo "$VIKUNJA_SENTRY_DSN" | sed -r 's/([:;])/\\\1/g')"
sed -ri "s:^(\s*window.API_URL\s*=)\s*.+:\1 '${VIKUNJA_API_URL}':g" /usr/share/nginx/html/index.html
sed -ri "s:^(\s*window.SENTRY_ENABLED\s*=)\s*.+:\1 ${VIKUNJA_SENTRY_ENABLED}:g" /usr/share/nginx/html/index.html
sed -ri "s:^(\s*window.SENTRY_DSN\s*=)\s*.+:\1 '${VIKUNJA_SENTRY_DSN}':g" /usr/share/nginx/html/index.html
sed -ri "s:^(\s*window.PROJECT_INFINITE_NESTING_ENABLED\s*=)\s*.+:\1 '${VIKUNJA_PROJECT_INFINITE_NESTING_ENABLED}':g" /usr/share/nginx/html/index.html
date -uIseconds | xargs echo 'info: started at'

0
docker/ipv6-disable.sh Normal file → Executable file
View File

View File

@ -4,7 +4,6 @@
pid /tmp/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;
events {
multi_accept on;

View File

@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1680030621,
"narHash": "sha256-qQa1NeS5Rvk2lgK5lSk986PC6I72yIHejzM8PFu+dHs=",
"lastModified": 1685498995,
"narHash": "sha256-rdyjnkq87tJp+T2Bm1OD/9NXKSsh/vLlPeqCc/mm7qs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "402cc3633cc60dfc50378197305c984518b30773",
"rev": "9cfaa8a1a00830d17487cb60a19bb86f96f09b27",
"type": "github"
},
"original": {

View File

@ -27,6 +27,9 @@
// our sentry instance to notify us of potential problems.
window.SENTRY_ENABLED = false
window.SENTRY_DSN = 'https://85694a2d757547cbbc90cd4b55c5a18d@o1047380.ingest.sentry.io/6024480'
// If enabled, allows the user to nest projects infinitely, instead of the default 2 levels.
// This setting might change in the future or be removed completely.
window.PROJECT_INFINITE_NESTING_ENABLED = false
</script>
</body>
</html>

View File

@ -13,7 +13,7 @@
},
"homepage": "https://vikunja.io/",
"funding": "https://opencollective.com/vikunja",
"packageManager": "pnpm@8.3.1",
"packageManager": "pnpm@8.6.0",
"keywords": [
"todo",
"productivity",
@ -51,96 +51,96 @@
"@fortawesome/vue-fontawesome": "3.0.3",
"@github/hotkey": "2.0.1",
"@infectoone/vue-ganttastic": "2.1.4",
"@intlify/unplugin-vue-i18n": "0.10.0",
"@kyvg/vue3-notification": "2.9.0",
"@sentry/tracing": "7.49.0",
"@sentry/vue": "7.49.0",
"@vueuse/core": "10.1.0",
"axios": "1.3.6",
"@intlify/unplugin-vue-i18n": "0.11.0",
"@kyvg/vue3-notification": "2.9.1",
"@sentry/tracing": "7.53.1",
"@sentry/vue": "7.53.1",
"@vueuse/core": "10.1.2",
"axios": "1.4.0",
"blurhash": "2.0.5",
"bulma-css-variables": "0.9.33",
"camel-case": "4.1.2",
"codemirror": "5.65.12",
"date-fns": "2.29.3",
"codemirror": "5.65.13",
"date-fns": "2.30.0",
"dayjs": "1.11.7",
"dompurify": "3.0.2",
"dompurify": "3.0.3",
"easymde": "2.18.0",
"fast-deep-equal": "3.1.3",
"flatpickr": "4.6.13",
"flexsearch": "0.7.31",
"floating-vue": "2.0.0-beta.20",
"highlight.js": "11.7.0",
"highlight.js": "11.8.0",
"is-touch-device": "1.0.1",
"klona": "2.0.6",
"lodash.debounce": "4.0.8",
"marked": "4.3.0",
"pinia": "2.0.35",
"marked": "5.0.4",
"pinia": "2.0.36",
"register-service-worker": "1.7.2",
"snake-case": "3.0.4",
"sortablejs": "1.15.0",
"ufo": "1.1.1",
"ufo": "1.1.2",
"vue": "3.2.47",
"vue-advanced-cropper": "2.8.8",
"vue-flatpickr-component": "11.0.3",
"vue-i18n": "9.2.2",
"vue-router": "4.1.6",
"workbox-precaching": "6.5.4",
"vue-router": "4.2.2",
"workbox-precaching": "6.6.1",
"zhyswan-vuedraggable": "4.1.3"
},
"devDependencies": {
"@4tw/cypress-drag-drop": "2.2.3",
"@cypress/vite-dev-server": "5.0.5",
"@cypress/vue": "5.0.5",
"@faker-js/faker": "7.6.0",
"@faker-js/faker": "8.0.2",
"@histoire/plugin-screenshot": "0.16.1",
"@histoire/plugin-vue": "0.16.1",
"@rushstack/eslint-patch": "1.2.0",
"@rushstack/eslint-patch": "1.3.0",
"@tsconfig/node18": "2.0.1",
"@types/codemirror": "5.60.7",
"@types/dompurify": "3.0.2",
"@types/flexsearch": "0.7.3",
"@types/is-touch-device": "1.0.0",
"@types/lodash.debounce": "4.0.7",
"@types/marked": "4.0.8",
"@types/node": "18.16.1",
"@types/marked": "5.0.0",
"@types/node": "18.16.16",
"@types/postcss-preset-env": "7.7.0",
"@types/sortablejs": "1.15.1",
"@typescript-eslint/eslint-plugin": "5.59.1",
"@typescript-eslint/parser": "5.59.1",
"@vitejs/plugin-legacy": "4.0.3",
"@vitejs/plugin-vue": "4.2.0",
"@typescript-eslint/eslint-plugin": "5.59.8",
"@typescript-eslint/parser": "5.59.8",
"@vitejs/plugin-legacy": "4.0.4",
"@vitejs/plugin-vue": "4.2.3",
"@vue/eslint-config-typescript": "11.0.3",
"@vue/test-utils": "2.3.2",
"@vue/tsconfig": "0.1.3",
"@vue/tsconfig": "0.4.0",
"autoprefixer": "10.4.14",
"browserslist": "4.21.5",
"caniuse-lite": "1.0.30001481",
"caniuse-lite": "1.0.30001489",
"css-has-pseudo": "5.0.2",
"csstype": "3.1.2",
"cypress": "12.10.0",
"esbuild": "0.17.18",
"eslint": "8.39.0",
"eslint-plugin-vue": "9.11.0",
"happy-dom": "9.9.2",
"cypress": "12.13.0",
"esbuild": "0.17.19",
"eslint": "8.41.0",
"eslint-plugin-vue": "9.13.0",
"happy-dom": "9.20.1",
"histoire": "0.16.1",
"netlify-cli": "14.2.1",
"postcss": "8.4.23",
"postcss": "8.4.24",
"postcss-easing-gradients": "3.0.1",
"postcss-easings": "3.0.1",
"postcss-focus-within": "7.0.2",
"postcss-preset-env": "8.3.2",
"rollup": "3.21.0",
"postcss-preset-env": "8.4.1",
"rollup": "3.23.0",
"rollup-plugin-visualizer": "5.9.0",
"sass": "1.62.1",
"start-server-and-test": "2.0.0",
"typescript": "5.0.4",
"vite": "4.3.3",
"vite": "4.3.9",
"vite-plugin-inject-preload": "1.3.1",
"vite-plugin-pwa": "0.14.7",
"vite-plugin-pwa": "0.15.2",
"vite-svg-loader": "4.0.0",
"vitest": "0.30.1",
"vue-tsc": "1.4.4",
"vitest": "0.31.2",
"vue-tsc": "1.6.5",
"wait-on": "7.0.1",
"workbox-cli": "6.5.4"
"workbox-cli": "6.6.1"
},
"pnpm": {
"patchedDependencies": {

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
],
"packageRules": [
{
"matchPackageNames": ["netlify-cli", "happy-dom"],
"matchPackageNames": ["happy-dom"],
"extends": ["schedule:weekly"]
},
{

View File

@ -33,9 +33,9 @@ const promiseExec = cmd => {
}
(async function () {
let stdout = await promiseExec(`./node_modules/.bin/netlify link --id ${siteId}`)
let stdout = await promiseExec(`/home/node/docker-netlify-cli/node_modules/.bin/netlify link --id ${siteId}`)
console.log(stdout)
stdout = await promiseExec(`./node_modules/.bin/netlify deploy --alias ${alias}`)
stdout = await promiseExec(`/home/node/docker-netlify-cli/node_modules/.bin/netlify deploy --alias ${alias}`)
console.log(stdout)
const data = await fetch(prIssueCommentsUrl).then(response => response.json())

View File

@ -1 +1 @@
57af69409e66bc87f4f2fc5822dd8d3c2eb47c601f81af1ac4a56f3e2d80837b1a2de06f4ff57695ec379b7c15b881e3 ./scripts/deploy-preview-netlify.mjs
4a7c1293c7b12e9ab476cdf35251a407c6a1cd005d22c06df994222cccfb25cde5f47d15866a098c9d739778fee4dc19 ./scripts/deploy-preview-netlify.mjs

View File

@ -0,0 +1,107 @@
<template>
<draggable
v-model="availableProjects"
animation="100"
ghostClass="ghost"
group="projects"
@start="() => drag = true"
@end="saveProjectPosition"
handle=".handle"
tag="menu"
item-key="id"
:disabled="!canEditOrder"
:component-data="{
type: 'transition-group',
name: !drag ? 'flip-list' : null,
class: [
'menu-list can-be-hidden',
{ 'dragging-disabled': !canEditOrder }
]
}"
>
<template #item="{element: project}">
<ProjectsNavigationItem
:project="project"
:is-loading="projectUpdating[project.id]"
:can-collapse="canCollapse"
:level="level"
:data-project-id="project.id"
/>
</template>
</draggable>
</template>
<script lang="ts" setup>
import {ref, watch} from 'vue'
import draggable from 'zhyswan-vuedraggable'
import type {SortableEvent} from 'sortablejs'
import ProjectsNavigationItem from '@/components/home/ProjectsNavigationItem.vue'
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import type {IProject} from '@/modelTypes/IProject'
import {useProjectStore} from '@/stores/projects'
const props = defineProps<{
modelValue?: IProject[],
canEditOrder: boolean,
canCollapse?: boolean,
level?: number,
}>()
const emit = defineEmits<{
(e: 'update:modelValue', projects: IProject[]): void
}>()
const drag = ref(false)
const projectStore = useProjectStore()
// Vue draggable will modify the projects list as it changes their position which will not work on a prop.
// Hence, we'll clone the prop and work on the clone.
const availableProjects = ref<IProject[]>([])
watch(
() => props.modelValue,
projects => {
availableProjects.value = projects || []
},
{immediate: true},
)
const projectUpdating = ref<{ [id: IProject['id']]: boolean }>({})
async function saveProjectPosition(e: SortableEvent) {
if (!e.newIndex && e.newIndex !== 0) return
const projectsActive = availableProjects.value
// If the project was dragged to the last position, Safari will report e.newIndex as the size of the projectsActive
// array instead of using the position. Because the index is wrong in that case, dragging the project will fail.
// To work around that we're explicitly checking that case here and decrease the index.
const newIndex = e.newIndex === projectsActive.length ? e.newIndex - 1 : e.newIndex
const projectId = parseInt(e.item.dataset.projectId)
const project = projectStore.projects[projectId]
const parentProjectId = e.to.parentNode.dataset.projectId ? parseInt(e.to.parentNode.dataset.projectId) : 0
const projectBefore = projectsActive[newIndex - 1] ?? null
const projectAfter = projectsActive[newIndex + 1] ?? null
projectUpdating.value[project.id] = true
const position = calculateItemPosition(
projectBefore !== null ? projectBefore.position : null,
projectAfter !== null ? projectAfter.position : null,
)
try {
// create a copy of the project in order to not violate pinia manipulation
await projectStore.updateProject({
...project,
position,
parentProjectId,
})
emit('update:modelValue', availableProjects.value)
} finally {
projectUpdating.value[project.id] = false
}
}
</script>

View File

@ -0,0 +1,156 @@
<template>
<li
class="list-menu loader-container is-loading-small"
:class="{'is-loading': isLoading}"
>
<div>
<BaseButton
v-if="canCollapse && childProjects?.length > 0"
@click="childProjectsOpen = !childProjectsOpen"
class="collapse-project-button"
>
<icon icon="chevron-down" :class="{ 'project-is-collapsed': !childProjectsOpen }"/>
</BaseButton>
<BaseButton
:to="{ name: 'project.index', params: { projectId: project.id} }"
class="list-menu-link"
:class="{'router-link-exact-active': currentProject?.id === project.id}"
>
<span
v-if="!canCollapse || childProjects?.length === 0"
class="collapse-project-button-placeholder"
></span>
<div class="color-bubble-handle-wrapper">
<ColorBubble
v-if="project.hexColor !== ''"
:color="project.hexColor"
/>
<span
class="icon menu-item-icon handle lines-handle"
:class="{'has-color-bubble': project.hexColor !== ''}"
>
<icon icon="grip-lines"/>
</span>
</div>
<span class="list-menu-title">{{ getProjectTitle(project) }}</span>
</BaseButton>
<BaseButton
v-if="project.id > 0"
class="favorite"
:class="{'is-favorite': project.isFavorite}"
@click="projectStore.toggleProjectFavorite(project)"
>
<icon :icon="project.isFavorite ? 'star' : ['far', 'star']"/>
</BaseButton>
<ProjectSettingsDropdown
v-if="project.id > 0"
class="menu-list-dropdown"
:project="project"
:level="level"
>
<template #trigger="{toggleOpen}">
<BaseButton class="menu-list-dropdown-trigger" @click="toggleOpen">
<icon icon="ellipsis-h" class="icon"/>
</BaseButton>
</template>
</ProjectSettingsDropdown>
<span class="list-setting-spacer" v-else></span>
</div>
<ProjectsNavigation
v-if="canNestDeeper && childProjectsOpen && canCollapse"
:model-value="childProjects"
:can-edit-order="true"
:can-collapse="canCollapse"
:level="level + 1"
/>
</li>
</template>
<script setup lang="ts">
import {computed, ref} from 'vue'
import {useProjectStore} from '@/stores/projects'
import {useBaseStore} from '@/stores/base'
import type {IProject} from '@/modelTypes/IProject'
import BaseButton from '@/components/base/BaseButton.vue'
import ProjectSettingsDropdown from '@/components/project/project-settings-dropdown.vue'
import {getProjectTitle} from '@/helpers/getProjectTitle'
import ColorBubble from '@/components/misc/colorBubble.vue'
import ProjectsNavigation from '@/components/home/ProjectsNavigation.vue'
import {canNestProjectDeeper} from '@/helpers/canNestProjectDeeper'
const props = withDefaults(defineProps<{
project: IProject,
isLoading?: boolean,
canCollapse?: boolean,
level?: number,
}>(), {
level: 0,
})
const projectStore = useProjectStore()
const baseStore = useBaseStore()
const currentProject = computed(() => baseStore.currentProject)
const childProjectsOpen = ref(true)
const childProjects = computed(() => {
if (!canNestDeeper.value) {
return []
}
return projectStore.getChildProjects(props.project.id)
.sort((a, b) => a.position - b.position)
})
const canNestDeeper = computed(() => canNestProjectDeeper(props.level))
</script>
<style lang="scss" scoped>
.list-setting-spacer {
width: 5rem;
flex-shrink: 0;
}
.project-is-collapsed {
transform: rotate(-90deg);
}
.favorite {
transition: opacity $transition, color $transition;
opacity: 0;
&:hover,
&.is-favorite {
opacity: 1;
color: var(--warning);
}
}
.list-menu:hover > div > .favorite {
opacity: 1;
}
.list-menu:hover > div > a > .color-bubble-handle-wrapper > .color-bubble {
opacity: 0;
}
.color-bubble-handle-wrapper {
position: relative;
width: 1rem;
height: 1rem;
display: flex;
align-items: center;
justify-content: flex-start;
margin-right: .25rem;
.color-bubble, .icon {
transition: all $transition;
position: absolute;
width: 12px;
margin: 0 !important;
padding: 0 !important;
}
}
</style>

View File

@ -7,8 +7,9 @@
<MenuButton class="menu-button" />
<div v-if="currentProject.id" class="project-title-wrapper">
<h1 class="project-title">{{ currentProject.title === '' ? $t('misc.loading') : getProjectTitle(currentProject) }}
<div v-if="currentProject?.id" class="project-title-wrapper">
<h1 class="project-title">
{{ currentProject.title === '' ? $t('misc.loading') : getProjectTitle(currentProject) }}
</h1>
<BaseButton :to="{ name: 'project.info', params: { projectId: currentProject.id } }" class="project-title-button">
@ -89,7 +90,7 @@ import { useAuthStore } from '@/stores/auth'
const baseStore = useBaseStore()
const currentProject = computed(() => baseStore.currentProject)
const background = computed(() => baseStore.background)
const canWriteCurrentProject = computed(() => baseStore.currentProject.maxRight > Rights.READ)
const canWriteCurrentProject = computed(() => baseStore.currentProject?.maxRight > Rights.READ)
const menuActive = computed(() => baseStore.menuActive)
const authStore = useAuthStore()

View File

@ -69,6 +69,7 @@ import BaseButton from '@/components/base/BaseButton.vue'
import {useBaseStore} from '@/stores/base'
import {useLabelStore} from '@/stores/labels'
import {useProjectStore} from '@/stores/projects'
import {useRouteWithModal} from '@/composables/useRouteWithModal'
import {useRenewTokenOnFocus} from '@/composables/useRenewTokenOnFocus'
@ -94,14 +95,13 @@ watch(() => route.name as string, (routeName) => {
(
[
'home',
'namespace.edit',
'teams.index',
'teams.edit',
'tasks.range',
'labels.index',
'migrate.start',
'migrate.wunderlist',
'namespaces.index',
'projects.index',
].includes(routeName) ||
routeName.startsWith('user.settings')
)
@ -116,6 +116,9 @@ useRenewTokenOnFocus()
const labelStore = useLabelStore()
labelStore.loadAllLabels()
const projectStore = useProjectStore()
projectStore.loadProjects()
</script>
<style lang="scss" scoped>

View File

@ -9,9 +9,9 @@
<Logo class="logo" v-if="logoVisible"/>
<h1
:class="{'m-0': !logoVisible}"
:style="{ 'opacity': currentProject.title === '' ? '0': '1' }"
:style="{ 'opacity': currentProject?.title === '' ? '0': '1' }"
class="title">
{{ currentProject.title === '' ? $t('misc.loading') : currentProject.title }}
{{ currentProject?.title === '' ? $t('misc.loading') : currentProject?.title }}
</h1>
<div class="box has-text-left view">
<router-view/>

View File

@ -1,10 +1,10 @@
<template>
<aside :class="{'is-active': menuActive}" class="namespace-container">
<aside :class="{'is-active': baseStore.menuActive}" class="menu-container">
<nav class="menu top-menu">
<router-link :to="{name: 'home'}" class="logo">
<Logo width="164" height="48"/>
</router-link>
<ul class="menu-list">
<menu class="menu-list other-menu-items">
<li>
<router-link :to="{ name: 'home'}" v-shortcut="'g o'">
<span class="menu-item-icon icon">
@ -22,11 +22,11 @@
</router-link>
</li>
<li>
<router-link :to="{ name: 'namespaces.index'}" v-shortcut="'g n'">
<router-link :to="{ name: 'projects.index'}" v-shortcut="'g p'">
<span class="menu-item-icon icon">
<icon icon="layer-group"/>
</span>
{{ $t('namespace.title') }}
{{ $t('project.projects') }}
</router-link>
</li>
<li>
@ -45,238 +45,51 @@
{{ $t('team.title') }}
</router-link>
</li>
</ul>
</menu>
</nav>
<nav class="menu namespaces-lists loader-container is-loading-small" :class="{'is-loading': loading}">
<template v-for="(n, nk) in namespaces" :key="n.id">
<div class="namespace-title" :class="{'has-menu': n.id > 0}">
<BaseButton
@click="toggleProjects(n.id)"
class="menu-label"
v-tooltip="namespaceTitles[nk]"
>
<ColorBubble
v-if="n.hexColor !== ''"
:color="n.hexColor"
class="mr-1"
/>
<span class="name">{{ namespaceTitles[nk] }}</span>
<div
class="icon menu-item-icon is-small toggle-lists-icon pl-2"
:class="{'active': typeof projectsVisible[n.id] !== 'undefined' ? projectsVisible[n.id] : true}"
>
<icon icon="chevron-down"/>
</div>
<span class="count" :class="{'ml-2 mr-0': n.id > 0}">
({{ namespaceProjectsCount[nk] }})
</span>
</BaseButton>
<namespace-settings-dropdown class="menu-list-dropdown" :namespace="n" v-if="n.id > 0"/>
</div>
<!--
NOTE: a v-model / computed setter is not possible, since the updateActiveProjects function
triggered by the change needs to have access to the current namespace
-->
<draggable
v-if="projectsVisible[n.id] ?? true"
v-bind="dragOptions"
:modelValue="activeProjects[nk]"
@update:modelValue="(projects) => updateActiveProjects(n, projects)"
group="namespace-lists"
@start="() => drag = true"
@end="saveListPosition"
handle=".handle"
:disabled="n.id < 0 || undefined"
tag="ul"
item-key="id"
:data-namespace-id="n.id"
:data-namespace-index="nk"
:component-data="{
type: 'transition-group',
name: !drag ? 'flip-list' : null,
class: [
'menu-list can-be-hidden',
{ 'dragging-disabled': n.id < 0 }
]
}"
>
<template #item="{element: l}">
<li
class="list-menu loader-container is-loading-small"
:class="{'is-loading': projectUpdating[l.id]}"
>
<BaseButton
:to="{ name: 'project.index', params: { projectId: l.id} }"
class="list-menu-link"
:class="{'router-link-exact-active': currentProject.id === l.id}"
>
<span class="icon menu-item-icon handle">
<icon icon="grip-lines"/>
</span>
<ColorBubble
v-if="l.hexColor !== ''"
:color="l.hexColor"
class="mr-1"
/>
<span class="list-menu-title">{{ getProjectTitle(l) }}</span>
</BaseButton>
<BaseButton
v-if="l.id > 0"
class="favorite"
:class="{'is-favorite': l.isFavorite}"
@click="projectStore.toggleProjectFavorite(l)"
>
<icon :icon="l.isFavorite ? 'star' : ['far', 'star']"/>
</BaseButton>
<ProjectSettingsDropdown class="menu-list-dropdown" :project="l" v-if="l.id > 0">
<template #trigger="{toggleOpen}">
<BaseButton class="menu-list-dropdown-trigger" @click="toggleOpen">
<icon icon="ellipsis-h" class="icon"/>
</BaseButton>
</template>
</ProjectSettingsDropdown>
<span class="list-setting-spacer" v-else></span>
</li>
</template>
</draggable>
</template>
</nav>
<Loading
v-if="projectStore.isLoading"
variant="small"
/>
<template v-else>
<nav class="menu" v-if="favoriteProjects">
<ProjectsNavigation :model-value="favoriteProjects" :can-edit-order="false" :can-collapse="false"/>
</nav>
<nav class="menu">
<ProjectsNavigation
:model-value="projects"
:can-edit-order="true"
:can-collapse="true"
:level="1"
/>
</nav>
</template>
<PoweredByLink/>
</aside>
</template>
<script setup lang="ts">
import {ref, computed, onBeforeMount} from 'vue'
import draggable from 'zhyswan-vuedraggable'
import type {SortableEvent} from 'sortablejs'
import {computed} from 'vue'
import BaseButton from '@/components/base/BaseButton.vue'
import ProjectSettingsDropdown from '@/components/project/project-settings-dropdown.vue'
import NamespaceSettingsDropdown from '@/components/namespace/namespace-settings-dropdown.vue'
import PoweredByLink from '@/components/home/PoweredByLink.vue'
import Logo from '@/components/home/Logo.vue'
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import {getNamespaceTitle} from '@/helpers/getNamespaceTitle'
import {getProjectTitle} from '@/helpers/getProjectTitle'
import type {IProject} from '@/modelTypes/IProject'
import type {INamespace} from '@/modelTypes/INamespace'
import ColorBubble from '@/components/misc/colorBubble.vue'
import Loading from '@/components/misc/loading.vue'
import {useBaseStore} from '@/stores/base'
import {useProjectStore} from '@/stores/projects'
import {useNamespaceStore} from '@/stores/namespaces'
const drag = ref(false)
const dragOptions = {
animation: 100,
ghostClass: 'ghost',
}
import ProjectsNavigation from '@/components/home/ProjectsNavigation.vue'
const baseStore = useBaseStore()
const namespaceStore = useNamespaceStore()
const currentProject = computed(() => baseStore.currentProject)
const menuActive = computed(() => baseStore.menuActive)
const loading = computed(() => namespaceStore.isLoading)
const namespaces = computed(() => {
return namespaceStore.namespaces.filter(n => !n.isArchived)
})
const activeProjects = computed(() => {
return namespaces.value.map(({projects}) => {
return projects?.filter(item => {
return typeof item !== 'undefined' && !item.isArchived
})
})
})
const namespaceTitles = computed(() => {
return namespaces.value.map((namespace) => getNamespaceTitle(namespace))
})
const namespaceProjectsCount = computed(() => {
return namespaces.value.map((_, index) => activeProjects.value[index]?.length ?? 0)
})
const projectStore = useProjectStore()
function toggleProjects(namespaceId: INamespace['id']) {
projectsVisible.value[namespaceId] = !projectsVisible.value[namespaceId]
}
const projectsVisible = ref<{ [id: INamespace['id']]: boolean }>({})
// FIXME: async action will be unfinished when component mounts
onBeforeMount(async () => {
const namespaces = await namespaceStore.loadNamespaces()
namespaces.forEach(n => {
if (typeof projectsVisible.value[n.id] === 'undefined') {
projectsVisible.value[n.id] = true
}
})
})
function updateActiveProjects(namespace: INamespace, activeProjects: IProject[]) {
// This is a bit hacky: since we do have to filter out the archived items from the list
// for vue draggable updating it is not as simple as replacing it.
// To work around this, we merge the active projects with the archived ones. Doing so breaks the order
// because now all archived projects are sorted after the active ones. This is fine because they are sorted
// later when showing them anyway, and it makes the merging happening here a lot easier.
const projects = [
...activeProjects,
...namespace.projects.filter(l => l.isArchived),
]
namespaceStore.setNamespaceById({
...namespace,
projects,
})
}
const projectUpdating = ref<{ [id: INamespace['id']]: boolean }>({})
async function saveListPosition(e: SortableEvent) {
if (!e.newIndex && e.newIndex !== 0) return
const namespaceId = parseInt(e.to.dataset.namespaceId as string)
const newNamespaceIndex = parseInt(e.to.dataset.namespaceIndex as string)
const projectsActive = activeProjects.value[newNamespaceIndex]
// If the project was dragged to the last position, Safari will report e.newIndex as the size of the projectsActive
// array instead of using the position. Because the index is wrong in that case, dragging the project will fail.
// To work around that we're explicitly checking that case here and decrease the index.
const newIndex = e.newIndex === projectsActive.length ? e.newIndex - 1 : e.newIndex
const project = projectsActive[newIndex]
const projectBefore = projectsActive[newIndex - 1] ?? null
const projectAfter = projectsActive[newIndex + 1] ?? null
projectUpdating.value[project.id] = true
const position = calculateItemPosition(
projectBefore !== null ? projectBefore.position : null,
projectAfter !== null ? projectAfter.position : null,
)
try {
// create a copy of the project in order to not violate pinia manipulation
await projectStore.updateProject({
...project,
position,
namespaceId,
})
} finally {
projectUpdating.value[project.id] = false
}
}
const projects = computed(() => projectStore.notArchivedRootProjects)
const favoriteProjects = computed(() => projectStore.favoriteProjects)
</script>
<style lang="scss" scoped>
$navbar-padding: 2rem;
$vikunja-nav-background: var(--site-background);
$vikunja-nav-color: var(--grey-700);
$vikunja-nav-selected-width: 0.4rem;
.logo {
display: block;
@ -289,8 +102,8 @@ $vikunja-nav-selected-width: 0.4rem;
}
}
.namespace-container {
background: $vikunja-nav-background;
.menu-container {
background: var(--site-background);
color: $vikunja-nav-color;
padding: 0 0 1rem;
transition: transform $transition-duration ease-in;
@ -301,6 +114,7 @@ $vikunja-nav-selected-width: 0.4rem;
transform: translateX(-100%);
overflow-x: auto;
width: $navbar-width;
margin-top: 1rem;
@media screen and (max-width: $tablet) {
top: 0;
@ -314,252 +128,24 @@ $vikunja-nav-selected-width: 0.4rem;
}
}
// these are general menu styles
// should be in own components
.menu {
.menu-label,
.menu-list .list-menu-link,
.menu-list a {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
.color-bubble {
height: 12px;
flex: 0 0 12px;
}
}
.menu-list {
li {
height: 44px;
display: flex;
align-items: center;
&:hover {
background: var(--white);
}
.menu-list-dropdown {
opacity: 1;
transition: $transition;
}
@media(hover: hover) and (pointer: fine) {
.menu-list-dropdown {
opacity: 0;
}
&:hover .menu-list-dropdown {
opacity: 1;
}
}
}
.menu-item-icon {
color: var(--grey-400);
}
.menu-list-dropdown-trigger {
display: flex;
padding: 0.5rem;
}
.flip-list-move {
transition: transform $transition-duration;
}
.ghost {
background: var(--grey-200);
* {
opacity: 0;
}
}
a:hover {
background: transparent;
}
.list-menu-link,
li > a {
color: $vikunja-nav-color;
padding: 0.75rem .5rem 0.75rem ($navbar-padding * 1.5 - 1.75rem);
transition: all 0.2s ease;
border-radius: 0;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
border-left: $vikunja-nav-selected-width solid transparent;
&:hover {
border-left: $vikunja-nav-selected-width solid var(--primary);
}
&.router-link-exact-active {
color: var(--primary);
border-left: $vikunja-nav-selected-width solid var(--primary);
}
.icon {
height: 1rem;
vertical-align: middle;
padding-right: 0.5rem;
}
&.router-link-exact-active .icon:not(.handle) {
color: var(--primary);
}
.handle {
opacity: 0;
transition: opacity $transition;
margin-right: .25rem;
}
&:hover .handle {
opacity: 1;
}
}
&:not(.dragging-disabled) .handle {
cursor: grab;
}
}
}
.top-menu {
margin-top: math.div($navbar-padding, 2);
.menu-list {
li {
font-weight: 600;
font-family: $vikunja-font;
}
.list-menu-link,
li > a {
padding-left: 2rem;
display: inline-block;
.icon {
padding-bottom: .25rem;
}
}
}
}
.namespaces-lists {
padding-top: math.div($navbar-padding, 2);
.menu-label {
font-size: 1rem;
font-weight: 700;
font-weight: bold;
font-family: $vikunja-font;
color: $vikunja-nav-color;
.top-menu .menu-list {
li {
font-weight: 600;
min-height: 2.5rem;
padding-top: 0;
padding-left: $navbar-padding;
overflow: hidden;
margin-bottom: 0;
flex: 1 1 auto;
.name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: auto;
}
.count {
color: var(--grey-500);
margin-right: .5rem;
// align brackets with number
font-feature-settings: "case";
}
font-family: $vikunja-font;
}
.favorite {
margin-left: .25rem;
transition: opacity $transition, color $transition;
opacity: 1;
.list-menu-link,
li > a {
padding-left: 2rem;
display: inline-block;
&.is-favorite {
color: var(--warning);
opacity: 1;
.icon {
padding-bottom: .25rem;
}
}
@media(hover: hover) and (pointer: fine) {
.list-menu .favorite {
opacity: 0;
}
.list-menu:hover .favorite,
.favorite.is-favorite {
opacity: 1;
}
}
.list-menu-title {
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
}
.color-bubble {
width: 14px;
height: 14px;
flex-basis: auto;
}
.is-archived {
min-width: 85px;
}
}
.namespace-title {
display: flex;
align-items: center;
justify-content: space-between;
color: $vikunja-nav-color;
padding: 0 .25rem;
.toggle-lists-icon {
svg {
transition: all $transition;
transform: rotate(90deg);
opacity: 1;
}
&.active svg {
transform: rotate(0deg);
opacity: 0;
}
}
&:hover .toggle-lists-icon svg {
opacity: 1;
}
&:not(.has-menu) .toggle-lists-icon {
padding-right: 1rem;
}
}
.list-setting-spacer {
width: 2.5rem;
flex-shrink: 0;
}
.namespaces-list.loader-container.is-loading {
min-height: calc(100vh - #{$navbar-height + 1.5rem + 1rem + 1.5rem});
.menu + .menu {
padding-top: math.div($navbar-padding, 2);
}
</style>

View File

@ -1,63 +0,0 @@
<template>
<multiselect
v-model="selectedNamespaces"
:search-results="foundNamespaces"
:loading="namespaceService.loading"
:multiple="true"
:placeholder="$t('namespace.search')"
label="namespace"
@search="findNamespaces"
/>
</template>
<script setup lang="ts">
import {computed, ref, shallowReactive, watchEffect, type PropType} from 'vue'
import Multiselect from '@/components/input/multiselect.vue'
import type {INamespace} from '@/modelTypes/INamespace'
import NamespaceService from '@/services/namespace'
import {includesById} from '@/helpers/utils'
const props = defineProps({
modelValue: {
type: Array as PropType<INamespace[]>,
default: () => [],
},
})
const emit = defineEmits<{
(e: 'update:modelValue', value: INamespace[]): void
}>()
const namespaces = ref<INamespace[]>([])
watchEffect(() => {
namespaces.value = props.modelValue
})
const selectedNamespaces = computed({
get() {
return namespaces.value
},
set: (value) => {
namespaces.value = value
emit('update:modelValue', value)
},
})
const namespaceService = shallowReactive(new NamespaceService())
const foundNamespaces = ref<INamespace[]>([])
async function findNamespaces(query: string) {
if (query === '') {
foundNamespaces.value = []
return
}
const response = await namespaceService.getAll({}, {s: query}) as INamespace[]
// Filter selected items from the results
foundNamespaces.value = response.filter(({id}) => !includesById(namespaces.value, id))
}
</script>

View File

@ -158,7 +158,12 @@ const flatPickerConfig = computed(() => ({
// Since flatpickr dates are strings, we need to convert them to native date objects.
// To make that work, we need a separate variable since flatpickr does not have a change event.
const flatPickrDate = computed({
set(newValue: string | Date) {
set(newValue: string | Date | null) {
if (newValue === null) {
date.value = null
return
}
date.value = createDateFromString(newValue)
updateData()
},

View File

@ -211,7 +211,7 @@ function handleInput(val: string) {
bubble(1000)
}
function bubble(timeout = 500) {
function bubble(timeout = 5000) {
if (changeTimeout.value !== null) {
clearTimeout(changeTimeout.value)
}

View File

@ -24,12 +24,12 @@
}"
>
<div :class="{'content': hasContent}">
<slot />
<slot/>
</div>
</div>
<footer v-if="$slots.footer" class="card-footer">
<slot name="footer" />
<slot name="footer"/>
</footer>
</div>
</template>
@ -76,22 +76,27 @@ defineEmits(['close'])
<style lang="scss" scoped>
.card {
background-color: var(--white);
border-radius: $radius;
margin-bottom: 1rem;
border: 1px solid var(--card-border-color);
box-shadow: var(--shadow-sm);
background-color: var(--white);
border-radius: $radius;
margin-bottom: 1rem;
border: 1px solid var(--card-border-color);
box-shadow: var(--shadow-sm);
@media print {
box-shadow: none;
border: none;
}
}
.card-header {
box-shadow: none;
border-bottom: 1px solid var(--card-border-color);
border-radius: $radius $radius 0 0;
box-shadow: none;
border-bottom: 1px solid var(--card-border-color);
border-radius: $radius $radius 0 0;
}
.card-footer {
background-color: var(--grey-50);
border-top: 0;
background-color: var(--grey-50);
border-top: 0;
padding: var(--modal-card-head-padding);
display: flex;
justify-content: flex-end;

View File

@ -44,8 +44,8 @@ export const KEYBOARD_SHORTCUTS : ShortcutGroup[] = [
combination: 'then',
},
{
title: 'keyboardShortcuts.navigation.namespaces',
keys: ['g', 'n'],
title: 'keyboardShortcuts.navigation.projects',
keys: ['g', 'p'],
combination: 'then',
},
{
@ -140,6 +140,18 @@ export const KEYBOARD_SHORTCUTS : ShortcutGroup[] = [
title: 'keyboardShortcuts.task.description',
keys: ['e'],
},
{
title: 'keyboardShortcuts.task.priority',
keys: ['p'],
},
{
title: 'keyboardShortcuts.task.delete',
keys: ['shift', 'delete'],
},
{
title: 'keyboardShortcuts.task.favorite',
keys: ['s'],
},
],
},
]
]

View File

@ -1,13 +1,21 @@
<template>
<div class="loader-container is-loading"></div>
<div class="loader-container is-loading" :class="{'is-small': variant === 'small'}"></div>
</template>
<script lang="ts">
export default {
inheritAttrs: false,
inheritAttrs: true,
}
</script>
<script lang="ts" setup>
const {
variant = 'default',
} = defineProps<{
variant?: 'default' | 'small'
}>()
</script>
<style scoped lang="scss">
.loader-container {
height: 100%;
@ -20,5 +28,18 @@ export default {
min-height: 50px;
min-width: 100px;
}
&.is-small {
min-width: 100%;
height: 150px;
&.is-loading::after {
width: 3rem;
height: 3rem;
top: calc(50% - 1.5rem);
left: calc(50% - 1.5rem);
border-width: 3px;
}
}
}
</style>

View File

@ -47,7 +47,7 @@ import {success} from '@/message'
import type { IconProp } from '@fortawesome/fontawesome-svg-core'
const props = defineProps({
entity: String,
entity: String as ISubscription['entity'],
entityId: Number,
isButton: {
type: Boolean,
@ -73,12 +73,6 @@ const {t} = useI18n({useScope: 'global'})
const tooltipText = computed(() => {
if (disabled.value) {
if (props.entity === 'project' && subscriptionEntity.value === 'namespace') {
return t('task.subscription.subscribedProjectThroughParentNamespace')
}
if (props.entity === 'task' && subscriptionEntity.value === 'namespace') {
return t('task.subscription.subscribedTaskThroughParentNamespace')
}
if (props.entity === 'task' && subscriptionEntity.value === 'project') {
return t('task.subscription.subscribedTaskThroughParentProject')
}
@ -87,10 +81,6 @@ const tooltipText = computed(() => {
}
switch (props.entity) {
case 'namespace':
return props.modelValue !== null ?
t('task.subscription.subscribedNamespace') :
t('task.subscription.notSubscribedNamespace')
case 'project':
return props.modelValue !== null ?
t('task.subscription.subscribedProject') :
@ -130,9 +120,6 @@ async function subscribe() {
let message = ''
switch (props.entity) {
case 'namespace':
message = t('task.subscription.subscribeSuccessNamespace')
break
case 'project':
message = t('task.subscription.subscribeSuccessProject')
break
@ -153,9 +140,6 @@ async function unsubscribe() {
let message = ''
switch (props.entity) {
case 'namespace':
message = t('task.subscription.unsubscribeSuccessNamespace')
break
case 'project':
message = t('task.subscription.unsubscribeSuccessProject')
break

View File

@ -1,103 +0,0 @@
<template>
<dropdown>
<template #trigger="triggerProps">
<slot name="trigger" v-bind="triggerProps">
<BaseButton class="dropdown-trigger" @click="triggerProps.toggleOpen">
<icon icon="ellipsis-h" class="icon"/>
</BaseButton>
</slot>
</template>
<template v-if="namespace.isArchived">
<dropdown-item
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id } }"
icon="archive"
>
{{ $t('menu.unarchive') }}
</dropdown-item>
</template>
<template v-else>
<dropdown-item
:to="{ name: 'namespace.settings.edit', params: { id: namespace.id } }"
icon="pen"
>
{{ $t('menu.edit') }}
</dropdown-item>
<dropdown-item
:to="{ name: 'namespace.settings.share', params: { namespaceId: namespace.id } }"
icon="share-alt"
>
{{ $t('menu.share') }}
</dropdown-item>
<dropdown-item
:to="{ name: 'project.create', params: { namespaceId: namespace.id } }"
icon="plus"
>
{{ $t('menu.newProject') }}
</dropdown-item>
<dropdown-item
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id } }"
icon="archive"
>
{{ $t('menu.archive') }}
</dropdown-item>
<Subscription
class="has-no-shadow"
:is-button="false"
entity="namespace"
:entity-id="namespace.id"
:model-value="subscription"
@update:model-value="setSubscriptionInStore"
type="dropdown"
/>
<dropdown-item
:to="{ name: 'namespace.settings.delete', params: { id: namespace.id } }"
icon="trash-alt"
class="has-text-danger"
>
{{ $t('menu.delete') }}
</dropdown-item>
</template>
</dropdown>
</template>
<script setup lang="ts">
import {ref, onMounted, type PropType} from 'vue'
import BaseButton from '@/components/base/BaseButton.vue'
import Dropdown from '@/components/misc/dropdown.vue'
import DropdownItem from '@/components/misc/dropdown-item.vue'
import Subscription from '@/components/misc/subscription.vue'
import type {INamespace} from '@/modelTypes/INamespace'
import type {ISubscription} from '@/modelTypes/ISubscription'
import {useNamespaceStore} from '@/stores/namespaces'
const props = defineProps({
namespace: {
type: Object as PropType<INamespace>,
required: true,
},
})
const namespaceStore = useNamespaceStore()
const subscription = ref<ISubscription | null>(null)
onMounted(() => {
subscription.value = props.namespace.subscription
})
function setSubscriptionInStore(sub: ISubscription) {
subscription.value = sub
namespaceStore.setNamespaceById({
...props.namespace,
subscription: sub,
})
}
</script>
<style scoped lang="scss">
.dropdown-trigger {
padding: 0.5rem;
display: flex;
}
</style>

View File

@ -1,9 +1,13 @@
<template>
<div
:class="{ 'is-loading': projectService.loading, 'is-archived': currentProject.isArchived}"
:class="{ 'is-loading': projectService.loading, 'is-archived': currentProject?.isArchived}"
class="loader-container"
>
<div class="switch-view-container">
<h1 class="project-title-print">
{{ getProjectTitle(currentProject) }}
</h1>
<div class="switch-view-container d-print-none">
<div class="switch-view">
<BaseButton
v-shortcut="'g l'"
@ -45,8 +49,8 @@
<slot name="header" />
</div>
<CustomTransition name="fade">
<Message variant="warning" v-if="currentProject.isArchived" class="mb-4">
{{ $t('project.archived') }}
<Message variant="warning" v-if="currentProject?.isArchived" class="mb-4">
{{ $t('project.archivedMessage') }}
</Message>
</CustomTransition>
@ -98,7 +102,7 @@ const currentProject = computed(() => {
maxRight: null,
} : baseStore.currentProject
})
useTitle(() => currentProject.value.id ? getProjectTitle(currentProject.value) : '')
useTitle(() => currentProject.value?.id ? getProjectTitle(currentProject.value) : '')
// watchEffect would be called every time the prop would get a value assigned, even if that value was the same as before.
// This resulted in loading and setting the project multiple times, even when navigating away from it.
@ -118,7 +122,7 @@ watch(
(
projectIdToLoad === loadedProjectId.value ||
typeof projectIdToLoad === 'undefined' ||
projectIdToLoad === currentProject.value.id
projectIdToLoad === currentProject.value?.id
)
&& typeof currentProject.value !== 'undefined' && currentProject.value.maxRight !== null
) {
@ -130,8 +134,8 @@ watch(
// Set the current project to the one we're about to load so that the title is already shown at the top
loadedProjectId.value = 0
const projectFromStore = projectStore.getProjectById(projectData.id)
if (projectFromStore !== null) {
const projectFromStore = projectStore.projects[projectData.id]
if (projectFromStore) {
baseStore.setBackground(null)
baseStore.setBlurHash(null)
baseStore.handleSetCurrentProject({project: projectFromStore})
@ -197,4 +201,15 @@ watch(
.is-archived .notification.is-warning {
margin-bottom: 1rem;
}
.project-title-print {
display: none;
font-size: 1.75rem;
text-align: center;
margin-bottom: .5rem;
@media print {
display: block;
}
}
</style>

View File

@ -15,7 +15,7 @@
:class="{'is-visible': background}"
:style="{'background-image': background !== null ? `url(${background})` : undefined}"
/>
<span v-if="project.isArchived" class="is-archived" >{{ $t('namespace.archived') }}</span>
<span v-if="project.isArchived" class="is-archived" >{{ $t('project.archived') }}</span>
<div class="project-title" aria-hidden="true">{{ project.title }}</div>
<BaseButton

View File

@ -147,6 +147,7 @@
<label class="label">{{ $t('task.attributes.labels') }}</label>
<div class="control labels-list">
<edit-labels
:creatable="false"
v-model="entities.labels"
@update:model-value="changeLabelFilter"
/>
@ -165,16 +166,6 @@
/>
</div>
</div>
<div class="field">
<label class="label">{{ $t('namespace.namespaces') }}</label>
<div class="control">
<SelectNamespace
v-model="entities.namespace"
@select="changeMultiselectFilter('namespace', 'namespace')"
@remove="changeMultiselectFilter('namespace', 'namespace')"
/>
</div>
</div>
</template>
</card>
</template>
@ -189,7 +180,6 @@ import {camelCase} from 'camel-case'
import type {ILabel} from '@/modelTypes/ILabel'
import type {IUser} from '@/modelTypes/IUser'
import type {INamespace} from '@/modelTypes/INamespace'
import type {IProject} from '@/modelTypes/IProject'
import {useLabelStore} from '@/stores/labels'
@ -201,7 +191,6 @@ import EditLabels from '@/components/tasks/partials/editLabels.vue'
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
import SelectUser from '@/components/input/SelectUser.vue'
import SelectProject from '@/components/input/SelectProject.vue'
import SelectNamespace from '@/components/input/SelectNamespace.vue'
import {parseDateOrString} from '@/helpers/time/parseDateOrString'
import {dateIsValid, formatISO} from '@/helpers/time/formatDate'
@ -209,7 +198,6 @@ import {objectToSnakeCase} from '@/helpers/case'
import UserService from '@/services/user'
import ProjectService from '@/services/project'
import NamespaceService from '@/services/namespace'
// FIXME: do not use this here for now. instead create new version from DEFAULT_PARAMS
import {getDefaultParams} from '@/composables/useTaskList'
@ -240,7 +228,6 @@ const DEFAULT_FILTERS = {
assignees: '',
labels: '',
project_id: '',
namespace: '',
} as const
const props = defineProps({
@ -265,23 +252,20 @@ const filters = ref({...DEFAULT_FILTERS})
const services = {
users: shallowReactive(new UserService()),
projects: shallowReactive(new ProjectService()),
namespace: shallowReactive(new NamespaceService()),
}
interface Entities {
users: IUser[]
labels: ILabel[]
projects: IProject[]
namespace: INamespace[]
}
type EntityType = 'users' | 'labels' | 'projects' | 'namespace'
type EntityType = 'users' | 'labels' | 'projects'
const entities: Entities = reactive({
users: [],
labels: [],
projects: [],
namespace: [],
})
onMounted(() => {
@ -328,7 +312,6 @@ function prepareFilters() {
prepareDate('reminders')
prepareRelatedObjectFilter('users', 'assignees')
prepareRelatedObjectFilter('projects', 'project_id')
prepareRelatedObjectFilter('namespace')
prepareSingleValue('labels')

View File

@ -72,6 +72,13 @@
@update:model-value="setSubscriptionInStore"
type="dropdown"
/>
<dropdown-item
v-if="level < 2"
:to="{ name: 'project.createFromParent', params: { parentProjectId: project.id } }"
icon="layer-group"
>
{{ $t('menu.createProject') }}
</dropdown-item>
<dropdown-item
:to="{ name: 'project.settings.delete', params: { projectId: project.id } }"
icon="trash-alt"
@ -96,17 +103,18 @@ import type {ISubscription} from '@/modelTypes/ISubscription'
import {isSavedFilter} from '@/services/savedFilter'
import {useConfigStore} from '@/stores/config'
import {useProjectStore} from '@/stores/projects'
import {useNamespaceStore} from '@/stores/namespaces'
const props = defineProps({
project: {
type: Object as PropType<IProject>,
required: true,
},
level: {
type: Number,
},
})
const projectStore = useProjectStore()
const namespaceStore = useNamespaceStore()
const subscription = ref<ISubscription | null>(null)
watchEffect(() => {
subscription.value = props.project.subscription ?? null
@ -122,6 +130,5 @@ function setSubscriptionInStore(sub: ISubscription) {
subscription: sub,
}
projectStore.setProject(updatedProject)
namespaceStore.setProjectInNamespaceById(updatedProject)
}
</script>

View File

@ -61,7 +61,6 @@ import {useRouter} from 'vue-router'
import TaskService from '@/services/task'
import TeamService from '@/services/team'
import NamespaceModel from '@/models/namespace'
import TeamModel from '@/models/team'
import ProjectModel from '@/models/project'
@ -70,7 +69,6 @@ import QuickAddMagic from '@/components/tasks/partials/quick-add-magic.vue'
import {useBaseStore} from '@/stores/base'
import {useProjectStore} from '@/stores/projects'
import {useNamespaceStore} from '@/stores/namespaces'
import {useLabelStore} from '@/stores/labels'
import {useTaskStore} from '@/stores/tasks'
@ -81,7 +79,6 @@ import {success} from '@/message'
import type {ITeam} from '@/modelTypes/ITeam'
import type {ITask} from '@/modelTypes/ITask'
import type {INamespace} from '@/modelTypes/INamespace'
import type {IProject} from '@/modelTypes/IProject'
const {t} = useI18n({useScope: 'global'})
@ -89,7 +86,6 @@ const router = useRouter()
const baseStore = useBaseStore()
const projectStore = useProjectStore()
const namespaceStore = useNamespaceStore()
const labelStore = useLabelStore()
const taskStore = useTaskStore()
@ -105,7 +101,6 @@ enum ACTION_TYPE {
enum COMMAND_TYPE {
NEW_TASK = 'newTask',
NEW_PROJECT = 'newProject',
NEW_NAMESPACE = 'newNamespace',
NEW_TEAM = 'newTeam',
}
@ -147,24 +142,15 @@ const foundProjects = computed(() => {
return []
}
const ncache: { [id: ProjectModel['id']]: INamespace } = {}
const history = getHistory()
const allProjects = [
...new Set([
...history.map((l) => projectStore.getProjectById(l.id)),
...history.map((l) => projectStore.projects[l.id]),
...projectStore.searchProject(project),
]),
]
return allProjects.filter((l) => {
if (typeof l === 'undefined' || l === null) {
return false
}
if (typeof ncache[l.namespaceId] === 'undefined') {
ncache[l.namespaceId] = namespaceStore.getNamespaceById(l.namespaceId)
}
return !ncache[l.namespaceId].isArchived
})
return allProjects.filter(l => Boolean(l))
})
// FIXME: use fuzzysearch
@ -205,7 +191,6 @@ const results = computed<Result[]>(() => {
const loading = computed(() =>
taskService.loading ||
namespaceStore.isLoading ||
projectStore.isLoading ||
teamService.loading,
)
@ -230,12 +215,6 @@ const commands = computed<{ [key in COMMAND_TYPE]: Command }>(() => ({
placeholder: t('quickActions.newProject'),
action: newProject,
},
newNamespace: {
type: COMMAND_TYPE.NEW_NAMESPACE,
title: t('quickActions.cmds.newNamespace'),
placeholder: t('quickActions.newNamespace'),
action: newNamespace,
},
newTeam: {
type: COMMAND_TYPE.NEW_TEAM,
title: t('quickActions.cmds.newTeam'),
@ -252,7 +231,6 @@ const currentProject = computed(() => Object.keys(baseStore.currentProject).leng
)
const hintText = computed(() => {
let namespace
if (selectedCmd.value !== null && currentProject.value !== null) {
switch (selectedCmd.value.type) {
case COMMAND_TYPE.NEW_TASK:
@ -260,12 +238,7 @@ const hintText = computed(() => {
title: currentProject.value.title,
})
case COMMAND_TYPE.NEW_PROJECT:
namespace = namespaceStore.getNamespaceById(
currentProject.value.namespaceId,
)
return t('quickActions.createProject', {
title: namespace?.title,
})
return t('quickActions.createProject')
}
}
const prefixes =
@ -278,7 +251,7 @@ const availableCmds = computed(() => {
if (currentProject.value !== null) {
cmds.push(commands.value.newTask, commands.value.newProject)
}
cmds.push(commands.value.newNamespace, commands.value.newTeam)
cmds.push(commands.value.newTeam)
return cmds
})
@ -396,7 +369,7 @@ function searchTasks() {
const r = await taskService.getAll({}, params) as DoAction<ITask>[]
foundTasks.value = r.map((t) => {
t.type = ACTION_TYPE.TASK
const project = projectStore.getProjectById(t.projectId)
const project = projectStore.projects[t.projectId]
if (project !== null) {
t.title = `${t.title} (${project.title})`
}
@ -504,21 +477,10 @@ async function newProject() {
if (currentProject.value === null) {
return
}
const newProject = await projectStore.createProject(new ProjectModel({
await projectStore.createProject(new ProjectModel({
title: query.value,
namespaceId: currentProject.value.namespaceId,
}))
success({ message: t('project.create.createdSuccess')})
await router.push({
name: 'project.index',
params: { projectId: newProject.id },
})
}
async function newNamespace() {
const newNamespace = new NamespaceModel({ title: query.value })
await namespaceStore.createNamespace(newNamespace)
success({ message: t('namespace.create.success') })
}
async function newTeam() {

View File

@ -139,10 +139,6 @@ import {ref, reactive, computed, shallowReactive, type Ref} from 'vue'
import type {PropType} from 'vue'
import {useI18n} from 'vue-i18n'
import UserNamespaceService from '@/services/userNamespace'
import UserNamespaceModel from '@/models/userNamespace'
import type {IUserNamespace} from '@/modelTypes/IUserNamespace'
import UserProjectService from '@/services/userProject'
import UserProjectModel from '@/models/userProject'
import type {IUserProject} from '@/modelTypes/IUserProject'
@ -151,10 +147,6 @@ import UserService from '@/services/user'
import UserModel, { getDisplayName } from '@/models/user'
import type {IUser} from '@/modelTypes/IUser'
import TeamNamespaceService from '@/services/teamNamespace'
import TeamNamespaceModel from '@/models/teamNamespace'
import type { ITeamNamespace } from '@/modelTypes/ITeamNamespace'
import TeamProjectService from '@/services/teamProject'
import TeamProjectModel from '@/models/teamProject'
import type { ITeamProject } from '@/modelTypes/ITeamProject'
@ -170,13 +162,15 @@ import Nothing from '@/components/misc/nothing.vue'
import {success} from '@/message'
import {useAuthStore} from '@/stores/auth'
// FIXME: I think this whole thing can now only manage user/team sharing for projects? Maybe remove a little generalization?
const props = defineProps({
type: {
type: String as PropType<'project' | 'namespace'>,
type: String as PropType<'project'>,
default: '',
},
shareType: {
type: String as PropType<'user' | 'team' | 'namespace'>,
type: String as PropType<'user' | 'team'>,
default: '',
},
id: {
@ -191,9 +185,9 @@ const props = defineProps({
const {t} = useI18n({useScope: 'global'})
// This user service is either a userNamespaceService or a userProjectService, depending on the type we are using
let stuffService: UserNamespaceService | UserProjectService | TeamProjectService | TeamNamespaceService
let stuffModel: IUserNamespace | IUserProject | ITeamProject | ITeamNamespace
// This user service is a userProjectService, depending on the type we are using
let stuffService: UserProjectService | TeamProjectService
let stuffModel: IUserProject | ITeamProject
let searchService: UserService | TeamService
let sharable: Ref<IUser | ITeam>
@ -231,10 +225,6 @@ const sharableName = computed(() => {
return t('project.list.title')
}
if (props.shareType === 'namespace') {
return t('namespace.namespace')
}
return ''
})
@ -247,11 +237,6 @@ if (props.shareType === 'user') {
if (props.type === 'project') {
stuffService = shallowReactive(new UserProjectService())
stuffModel = reactive(new UserProjectModel({projectId: props.id}))
} else if (props.type === 'namespace') {
stuffService = shallowReactive(new UserNamespaceService())
stuffModel = reactive(new UserNamespaceModel({
namespaceId: props.id,
}))
} else {
throw new Error('Unknown type: ' + props.type)
}
@ -264,11 +249,6 @@ if (props.shareType === 'user') {
if (props.type === 'project') {
stuffService = shallowReactive(new TeamProjectService())
stuffModel = reactive(new TeamProjectModel({projectId: props.id}))
} else if (props.type === 'namespace') {
stuffService = shallowReactive(new TeamNamespaceService())
stuffModel = reactive(new TeamNamespaceModel({
namespaceId: props.id,
}))
} else {
throw new Error('Unknown type: ' + props.type)
}

View File

@ -7,7 +7,7 @@
:search-results="foundLabels"
@select="addLabel"
label="title"
:creatable="true"
:creatable="creatable"
@create="createAndAddLabel"
:create-placeholder="$t('task.label.createPlaceholder')"
v-model="labels"
@ -65,6 +65,10 @@ const props = defineProps({
disabled: {
default: false,
},
creatable: {
type: Boolean,
default: true,
},
})
const emit = defineEmits(['update:modelValue'])

View File

@ -11,8 +11,10 @@
@search="findProjects"
>
<template #searchResult="{option}">
<span class="project-namespace-title search-result">{{ namespace((option as IProject).namespaceId) }} ></span>
{{ (option as IProject).title }}
<span class="has-text-grey" v-if="projectStore.getAncestors(option).length > 1">
{{ projectStore.getAncestors(option).filter(p => p.id !== option.id).map(p => getProjectTitle(p)).join(' &gt; ') }} &gt;
</span>
{{ getProjectTitle(option) }}
</template>
</Multiselect>
</template>
@ -20,13 +22,11 @@
<script lang="ts" setup>
import {reactive, ref, watch} from 'vue'
import type {PropType} from 'vue'
import {useI18n} from 'vue-i18n'
import type {IProject} from '@/modelTypes/IProject'
import type {INamespace} from '@/modelTypes/INamespace'
import {useProjectStore} from '@/stores/projects'
import {useNamespaceStore} from '@/stores/namespaces'
import {getProjectTitle} from '@/helpers/getProjectTitle'
import ProjectModel from '@/models/project'
@ -40,8 +40,6 @@ const props = defineProps({
})
const emit = defineEmits(['update:modelValue'])
const {t} = useI18n({useScope: 'global'})
const project: IProject = reactive(new ProjectModel())
watch(
@ -54,7 +52,6 @@ watch(
)
const projectStore = useProjectStore()
const namespaceStore = useNamespaceStore()
const foundProjects = ref<IProject[]>([])
function findProjects(query: string) {
if (query === '') {
@ -70,17 +67,4 @@ function select(l: IProject | null) {
Object.assign(project, l)
emit('update:modelValue', project)
}
function namespace(namespaceId: INamespace['id']) {
const namespace = namespaceStore.getNamespaceById(namespaceId)
return namespace !== null
? namespace.title
: t('project.shared')
}
</script>
<style lang="scss" scoped>
.project-namespace-title {
color: var(--grey-500);
}
</style>

View File

@ -46,11 +46,6 @@
class="different-project"
v-if="task.projectId !== projectId"
>
<span
v-if="task.differentNamespace !== null"
v-tooltip="$t('task.relation.differentNamespace')">
{{ task.differentNamespace }} >
</span>
<span
v-if="task.differentProject !== null"
v-tooltip="$t('task.relation.differentProject')">
@ -101,11 +96,6 @@
class="different-project"
v-if="t.projectId !== projectId"
>
<span
v-if="t.differentNamespace !== null"
v-tooltip="$t('task.relation.differentNamespace')">
{{ t.differentNamespace }} >
</span>
<span
v-if="t.differentProject !== null"
v-tooltip="$t('task.relation.differentProject')">
@ -168,10 +158,9 @@ import BaseButton from '@/components/base/BaseButton.vue'
import Multiselect from '@/components/input/multiselect.vue'
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
import {useNamespaceStore} from '@/stores/namespaces'
import {error, success} from '@/message'
import {useTaskStore} from '@/stores/tasks'
import {useProjectStore} from '@/stores/projects'
const props = defineProps({
taskId: {
@ -196,7 +185,7 @@ const props = defineProps({
})
const taskStore = useTaskStore()
const namespaceStore = useNamespaceStore()
const projectStore = useProjectStore()
const route = useRoute()
const {t} = useI18n({useScope: 'global'})
@ -230,26 +219,15 @@ async function findTasks(newQuery: string) {
foundTasks.value = await taskService.getAll({}, {s: newQuery})
}
const getProjectAndNamespaceById = (projectId: number) => namespaceStore.getProjectAndNamespaceById(projectId, true)
const namespace = computed(() => getProjectAndNamespaceById(props.projectId)?.namespace)
function mapRelatedTasks(tasks: ITask[]) {
return tasks.map(task => {
// by doing this here once we can save a lot of duplicate calls in the template
const {
project,
namespace: taskNamespace,
} = getProjectAndNamespaceById(task.projectId) || {project: null, namespace: null}
const project = projectStore.projects[task.ProjectId]
return {
...task,
differentNamespace:
(taskNamespace !== null &&
taskNamespace.id !== namespace.value.id &&
taskNamespace?.title) || null,
differentProject:
(project !== null &&
(project &&
task.projectId !== props.projectId &&
project?.title) || null,
}

View File

@ -7,19 +7,19 @@
/>
<ColorBubble
v-if="showProjectColor && projectColor !== '' && currentProject.id !== task.projectId"
v-if="showProjectColor && projectColor !== '' && currentProject?.id !== task.projectId"
:color="projectColor"
class="mr-1"
/>
<router-link
:to="taskDetailRoute"
:class="{ 'done': task.done, 'show-project': showProject && project !== null}"
:class="{ 'done': task.done, 'show-project': showProject && project}"
class="tasktext"
>
<span>
<router-link
v-if="showProject && project !== null"
v-if="showProject && typeof project !== 'undefined'"
:to="{ name: 'project.list', params: { projectId: task.projectId } }"
class="task-project"
:class="{'mr-2': task.hexColor !== ''}"
@ -34,7 +34,7 @@
/>
<!-- Show any parent tasks to make it clear this task is a sub task of something -->
<span class="parent-tasks" v-if="typeof task.relatedTasks.parenttask !== 'undefined'">
<span class="parent-tasks" v-if="typeof task.relatedTasks?.parenttask !== 'undefined'">
<template v-for="(pt, i) in task.relatedTasks.parenttask">
{{ pt.title }}<template v-if="(i + 1) < task.relatedTasks.parenttask.length">,&nbsp;</template>
</template>
@ -105,7 +105,7 @@
</progress>
<router-link
v-if="!showProject && currentProject.id !== task.projectId && project !== null"
v-if="!showProject && currentProject?.id !== task.projectId && project"
:to="{ name: 'project.list', params: { projectId: task.projectId } }"
class="task-project"
v-tooltip="$t('task.detail.belongsToProject', {project: project.title})"
@ -150,7 +150,6 @@ import {formatDateSince, formatISO, formatDateLong} from '@/helpers/time/formatD
import {success} from '@/message'
import {useProjectStore} from '@/stores/projects'
import {useNamespaceStore} from '@/stores/namespaces'
import {useBaseStore} from '@/stores/base'
import {useTaskStore} from '@/stores/tasks'
@ -210,10 +209,9 @@ onBeforeUnmount(() => {
const baseStore = useBaseStore()
const projectStore = useProjectStore()
const taskStore = useTaskStore()
const namespaceStore = useNamespaceStore()
const project = computed(() => projectStore.getProjectById(task.value.projectId))
const projectColor = computed(() => project.value !== null ? project.value.hexColor : '')
const project = computed(() => projectStore.projects[task.value.projectId])
const projectColor = computed(() => project.value ? project.value?.hexColor : '')
const currentProject = computed(() => {
return typeof baseStore.currentProject === 'undefined' ? {
@ -258,10 +256,8 @@ function undoDone(checked: boolean) {
}
async function toggleFavorite() {
task.value.isFavorite = !task.value.isFavorite
task.value = await taskService.update(task.value)
task.value = await taskStore.toggleFavorite(task.value)
emit('task-updated', task.value)
namespaceStore.loadNamespacesIfFavoritesDontExist()
}
const deferDueDate = ref<typeof DeferTask | null>(null)

View File

@ -1,19 +0,0 @@
import {ref, computed} from 'vue'
import {useNamespaceStore} from '@/stores/namespaces'
export function useNamespaceSearch() {
const query = ref('')
const namespaceStore = useNamespaceStore()
const namespaces = computed(() => namespaceStore.searchNamespace(query.value))
function findNamespaces(newQuery: string) {
query.value = newQuery
}
return {
namespaces,
findNamespaces,
}
}

View File

@ -0,0 +1,7 @@
export function canNestProjectDeeper(level: number) {
if (level < 2) {
return true
}
return level >= 2 && window.PROJECT_INFINITE_NESTING_ENABLED
}

View File

@ -1,15 +0,0 @@
import {i18n} from '@/i18n'
import type {INamespace} from '@/modelTypes/INamespace'
export const getNamespaceTitle = (n: INamespace) => {
if (n.id === -1) {
return i18n.global.t('namespace.pseudo.sharedProjects.title')
}
if (n.id === -2) {
return i18n.global.t('namespace.pseudo.favorites.title')
}
if (n.id === -3) {
return i18n.global.t('namespace.pseudo.savedFilters.title')
}
return n.title
}

View File

@ -1,9 +1,14 @@
import {i18n} from '@/i18n'
import type {IProject} from '@/modelTypes/IProject'
export function getProjectTitle(l: IProject) {
if (l.id === -1) {
export function getProjectTitle(project: IProject) {
if (project.id === -1) {
return i18n.global.t('project.pseudo.favorites.title')
}
return l.title
if (project.title === 'Inbox') {
return i18n.global.t('project.inboxTitle')
}
return project.title
}

View File

@ -894,7 +894,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -1053,4 +1056,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -894,7 +894,10 @@
"color": "Změnit barvu tohoto úkolu",
"move": "Move this task to another project",
"reminder": "Spravovat připomenutí této úlohy",
"description": "Přepnout úpravy popisu úkolu"
"description": "Přepnout úpravy popisu úkolu",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -1053,4 +1056,4 @@
"frontendVersion": "Verze frontendu: {version}",
"apiVersion": "Verze API: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Godaften {username}!",
"lastViewed": "Sidst vist",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Slet din Vikunja konto",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "For at fortsætte, skal du indtaste din adgangskode. Du vil modtage en e-mail med yderligere instruktioner.",
"confirm": "Slet min konto",
"requestSuccess": "Anmodningen blev gennemført. Du vil modtage en e-mail med yderligere instruktioner.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Eksporter dine Vikunja-data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Indtast venligst din adgangskode for at fortsætte:",
"request": "Anmod om en kopi af mine Vikunja-data",
"success": "Du har anmodet om dine Vikunja-data! Vi sender dig en e-mail, når den er klar til hentning.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Navneområde",
"showArchived": "Vis arkiverede",
"noneAvailable": "Du har ingen navneområder lige nu.",
"unarchive": "Tilbagekald",
"archived": "Arkiveret",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Navneområder",
"search": "Skriv for at søge efter et navneområde…",
"create": {
"title": "Nyt navneområde",
"titleRequired": "Angiv venligst en titel.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "Hvad er et navneområde?",
"success": "Navneområdet blev oprettet."
},
"archive": {
"titleArchive": "Arkiver \"{namespace}\"",
"titleUnarchive": "Fjern arkivering \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "Navneområdet blev arkiveret.",
"unarchiveSuccess": "Navneområdet blev tilbagekaldt.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Slet \"{namespace}\"",
"text1": "Er du sikker på, at du vil slette dette navneområde og alt dets indhold?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "Navneområdet blev slettet."
},
"edit": {
"title": "Rediger \"{namespace}\"",
"success": "Navneområdet blev opdateret."
},
"share": {
"title": "Del \"{namespace}\""
},
"attributes": {
"title": "Navneområde Titel",
"titlePlaceholder": "Navneområdets titel skrives her…",
"description": "Beskrivelse",
"descriptionPlaceholder": "Navneområdets beskrivelse skrives her…",
"color": "Farve",
"archived": "Er Arkiveret",
"isArchived": "Dette navneområde er arkiveret"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favoritter"
},
"savedFilters": {
"title": "Filtre"
}
}
},
"filters": {
"title": "Filtre",
"clear": "Ryd Filtre",
@ -403,7 +344,7 @@
},
"create": {
"title": "Nyt Gemt Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Opret nyt gemt filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Opdateret"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "Du kan ikke afmelde dig her, fordi du abonnerer på denne opgave gennem dens navneområde.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "Du abonnerer i øjeblikket på dette navneområde og vil modtage notifikationer om ændringer.",
"notSubscribedNamespace": "Du abonnerer ikke på dette navneområde og modtager ikke notifikationer om ændringer.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "Du abonnerer på denne opgave og vil modtage notifikationer om ændringer.",
"notSubscribedTask": "Du abonnerer ikke på denne opgave og modtager ikke notifikationer om ændringer.",
"subscribe": "Abonner",
"unsubscribe": "Afmeld",
"subscribeSuccessNamespace": "Du abonnerer nu på dette navneområde",
"unsubscribeSuccessNamespace": "Du er nu afmeldt dette navneområde",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "Du abonnerer nu på denne opgave",
@ -763,7 +698,6 @@
"searchPlaceholder": "Indtast søgning efter en ny opgave der tilføjes som relateret…",
"createPlaceholder": "Tilføj dette som en ny relateret opgave",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "Denne opgave hører til et andet navneområde.",
"noneYet": "Ingen opgaverelationer endnu.",
"delete": "Slet Opgaverelation",
"deleteText1": "Er du sikker på, at du vil slette denne opgaverelation?",
@ -848,19 +782,19 @@
"delete": {
"header": "Slet holdet",
"text1": "Er du sikker på du vil slette dette hold og alle dets medlemmer?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "Holdet blev slettet."
},
"deleteUser": {
"header": "Fjern en bruger fra holdet",
"text1": "Er du sikker på du vil fjerne denne bruger fra holdet?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "Brugeren blev fjernet fra holdet."
},
"leave": {
"title": "Forlad hold",
"text1": "Er du sikker på du vil forlade dette hold?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "Du har forladt holdet."
}
},
@ -894,7 +828,10 @@
"color": "Skift farven på denne opgave",
"move": "Move this task to another project",
"reminder": "Administrer påmindelser om denne opgave",
"description": "Slå redigering af opgavebeskrivelse til/fra"
"description": "Slå redigering af opgavebeskrivelse til/fra",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Gå til oversigt",
"upcoming": "Gå til kommende opgaver",
"namespaces": "Navigate to namespaces & projects",
"labels": "Naviger til etiketter",
"teams": "Naviger til hold"
"teams": "Naviger til hold",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Tilbagekald",
"setBackground": "Indstil baggrund",
"share": "Del",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Notifikationer",
"none": "Du har ingen notifikationer. Hav en dejlig dag!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Kommandoer",
@ -954,14 +892,12 @@
"teams": "Hold",
"newProject": "Enter the title of the new project…",
"newTask": "Indtast titlen på den nye opgave…",
"newNamespace": "Indtast titlen på det nye navneområde…",
"newTeam": "Indtast navnet på det nye hold…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"cmds": {
"newTask": "Ny Opgave",
"newProject": "New project",
"newNamespace": "Nyt navneområde",
"newTeam": "Nyt hold"
}
},
@ -1017,13 +953,6 @@
"4017": "Ugyldig komparator til opgavefilter.",
"4018": "Ugyldig sammenkædning til opgavefilter.",
"4019": "Ugyldig værdi til opgavefilter.",
"5001": "Navneområdet findes ikke.",
"5003": "Du har ikke adgang til det angivne navneområde.",
"5006": "Navneområdets navn må ikke være tomt.",
"5009": "Du skal have navneområde læseadgang for at udføre denne handling.",
"5010": "Dette hold har ikke adgang til dette navneområde.",
"5011": "Denne bruger har allerede adgang til dette navneområde.",
"5012": "Navneområdet er arkiveret og kan derfor kun læses.",
"6001": "Holdnavnet må ikke være tomt.",
"6002": "Holdet findes ikke.",
"6004": "The team already has access to that namespace or project.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Guten Abend, {username}!",
"lastViewed": "Zuletzt angesehen",
"project": {
"newText": "Du kannst ein neues Projekt für deine neuen Aufgaben erstellen:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Lösche deinen Vikunja-Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Zum Fortfahren gib bitte dein Passwort ein. Du erhältst eine E-Mail mit weiteren Anweisungen.",
"confirm": "Meinen Account löschen",
"requestSuccess": "Die Anfrage war erfolgreich. Du erhältst eine E-Mail mit weiteren Anweisungen.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Exportiere deine Vikunja-Daten",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Bitte gib dein Passwort ein, um fortzufahren:",
"request": "Eine Kopie meiner Vikunja Daten anfordern",
"success": "Du hast deine Daten bei Vikunja erfolgreich angefordert! Wir schicken dir eine E-Mail, sobald sie zum Download bereitstehen.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Archivierte anzeigen",
"noneAvailable": "Du hast momentan keine Namespaces.",
"unarchive": "Archivierung aufheben",
"archived": "Archiviert",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Beginne zu schreiben, um einen Namespace zu suchen…",
"create": {
"title": "Neuer Namespace",
"titleRequired": "Bitte gebe einen Titel an.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "Was ist ein Namespace?",
"success": "Der Namespace wurde erfolgreich erstellt."
},
"archive": {
"titleArchive": "„{namespace}“ archivieren",
"titleUnarchive": "Archivierung von \"{namespace}\" aufheben",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "Der Namespace wurde erfolgreich archiviert.",
"unarchiveSuccess": "Der Namespace wurde erfolgreich wiederhergestellt.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "„{namespace}“ löschen",
"text1": "Diesen Namespace mit sämtlichem Inhalt löschen?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "Der Namespace wurde erfolgreich gelöscht."
},
"edit": {
"title": "„{namespace}“ bearbeiten",
"success": "Der Namespace wurde erfolgreich aktualisiert."
},
"share": {
"title": "„{namespace}“ teilen"
},
"attributes": {
"title": "Namespace Titel",
"titlePlaceholder": "Titel des Namespace angeben…",
"description": "Beschreibung",
"descriptionPlaceholder": "Beschreibung für den Namespace eingeben…",
"color": "Farbe",
"archived": "Ist archiviert",
"isArchived": "Dieser Namespace ist archiviert"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favoriten"
},
"savedFilters": {
"title": "Filter"
}
}
},
"filters": {
"title": "Filter",
"clear": "Filter zurücksetzen",
@ -403,7 +344,7 @@
},
"create": {
"title": "Neuer gespeicherter Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Neuen gespeicherten Filter erstellen",
"titleRequired": "Bitte gib den Titel für den Filter an."
},
@ -674,19 +615,13 @@
"updated": "Aktualisiert"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "Du kannst hier nicht de-abonnieren, da du diese Aufgabe über ihren Namespace abonniert hast.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "Du hast diesen Namespace abonniert und erhältst Benachrichtigungen über Änderungen.",
"notSubscribedNamespace": "Du hast diesen Namespace nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "Du hast diese Aufgabe abonniert und erhältst Benachrichtigungen über Änderungen.",
"notSubscribedTask": "Du hast diese Aufgabe nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
"subscribe": "Abonnieren",
"unsubscribe": "Abbestellen",
"subscribeSuccessNamespace": "Du hast diesen Namespace jetzt abonniert",
"unsubscribeSuccessNamespace": "Du hast diesen Namespace jetzt nicht mehr abonniert",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "Du hast diese Aufgabe jetzt abonniert",
@ -763,7 +698,6 @@
"searchPlaceholder": "Beginne zu schreiben, um eine Aufgabe zu suchen, die als Beziehung hinzugefügt werden soll…",
"createPlaceholder": "Füge diese Aufgabe als neue Aufgabenbeziehung hinzu",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "Diese Aufgabe gehört zu einem anderen Namespace.",
"noneYet": "Keine Aufgabenbeziehung vorhanden.",
"delete": "Aufgabenbeziehung entfernen",
"deleteText1": "Willst du diese Aufgabenbeziehung wirklich entfernen?",
@ -848,19 +782,19 @@
"delete": {
"header": "Team löschen",
"text1": "Bist du sicher, dass du dieses Team und alle seine Mitglieder löschen willst?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "Das Team wurde erfolgreich gelöscht."
},
"deleteUser": {
"header": "Benutzer:innen aus dem Team entfernen",
"text1": "Bist du sicher, dass du diese:n Benutzer:in aus dem Team entfernen willst?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "Der:die Benutzer:in wurde erfolgreich aus dem Team gelöscht."
},
"leave": {
"title": "Team verlassen",
"text1": "Bist du sicher, dass du dieses Team verlassen willst?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "Du hast das Team erfolgreich verlassen."
}
},
@ -894,7 +828,10 @@
"color": "Die Farbe dieser Aufgabe ändern",
"move": "Move this task to another project",
"reminder": "Erinnerungen für diese Aufgabe verwalten",
"description": "Aufgabenbeschreibung bearbeiten"
"description": "Aufgabenbeschreibung bearbeiten",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Die Startseite aufrufen",
"upcoming": "Anstehende Aufgaben aufrufen",
"namespaces": "Navigate to namespaces & projects",
"labels": "Labels aufrufen",
"teams": "Teams aufrufen"
"teams": "Teams aufrufen",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Archivierung aufheben",
"setBackground": "Hintergrund einstellen",
"share": "Teilen",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja-URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Benachrichtigungen",
"none": "Du hast keine Benachrichtigungen. Einen schönen Tag noch!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Befehle",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Gib den Titel der neuen Aufgabe ein …",
"newNamespace": "Gib den Titel des neuen Namespaces ein…",
"newTeam": "Gib den Namen des neuen Teams ein …",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Neue Aufgabe",
"newProject": "New project",
"newNamespace": "Neuer Namespace",
"newTeam": "Neues Team"
}
},
@ -1017,16 +953,9 @@
"4017": "Ungültiger Aufgabenfilter (Vergleichskriterium).",
"4018": "Ungültige Verkettung von Aufgabenfiltern.",
"4019": "Ungültiger Aufgabenfilter (Wert).",
"5001": "Dieser Namespace existiert nicht.",
"5003": "Du hast keinen Zugriff auf den Namespace.",
"5006": "Der Namespace Titel kann nicht leer sein.",
"5009": "Du benötigst Leserechte in diesem Namespace, um diese Aktion durchzuführen.",
"5010": "Dieses Team hat keinen Zugriff auf diesen Namespace.",
"5011": "Diese:r Benutzer:in hat bereits Zugriff auf diesen Namespace.",
"5012": "Dieser Namespace ist archiviert und kann deshalb nur gelesen werden.",
"6001": "Der Teamname kann nicht leer sein.",
"6002": "Das Team existiert nicht.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "Diese:r Benutzer:in ist bereits dem Team beigetreten.",
"6006": "Du kannst den:die letzten Benutzer:in dieses Teams nicht löschen.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend-Version: {version}",
"apiVersion": "API-Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Guten Abend, {username}!",
"lastViewed": "Zletscht ahglueget",
"project": {
"newText": "Du kannst ein neues Projekt für deine neuen Aufgaben erstellen:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Lösche deinen Vikunja-Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Zum Fortfahren gib bitte dein Passwort ein. Du erhältst eine E-Mail mit weiteren Anweisungen.",
"confirm": "Meinen Account löschen",
"requestSuccess": "Die Anfrage war erfolgreich. Du erhältst eine E-Mail mit weiteren Anweisungen.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Exportiere deine Vikunja-Daten",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Bitte gib dein Passwort ein, um fortzufahren:",
"request": "Eine Kopie meiner Vikunja Daten anfordern",
"success": "Du hast deine Daten bei Vikunja erfolgreich angefordert! Wir schicken dir eine E-Mail, sobald sie zum Download bereitstehen.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namensruum",
"showArchived": "Archivierti aahzeige",
"noneAvailable": "Du hesch momentan kein Namensruuim.",
"unarchive": "Ent-archiviere",
"archived": "Archiviert",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namensrüüm",
"search": "Schriib, um nachemne Namensruum z'sueche…",
"create": {
"title": "Neuer Namespace",
"titleRequired": "Bitte gib en Titl ah.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "Was isch en Namensruum?",
"success": "Namensruum erstellt."
},
"archive": {
"titleArchive": "\"{namespace}\" archiviere",
"titleUnarchive": "\"{namespace}\" ent-archiviere",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "De Namensruum isch erfolgriich archiviert worde.",
"unarchiveSuccess": "Der Namespace wurde erfolgreich wiederhergestellt.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "\"{namespace}\" chüble",
"text1": "Bisch du dir sicher, dass du de Namensruum und all ihren Inhalt chüble wetsch?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "Namensruum g'chüblet."
},
"edit": {
"title": "\"{namespace}\" bearbeite",
"success": "Namensruum aktualisiert."
},
"share": {
"title": "\"{namespace}\" teile"
},
"attributes": {
"title": "Namensruumtitl",
"titlePlaceholder": "De Namensruumtitl chunt da ahne…",
"description": "Beschriibig",
"descriptionPlaceholder": "D'Namensruum Beschriibig chunt da ahne…",
"color": "Farb",
"archived": "Isch archiviert",
"isArchived": "De Namensruum isch archiviert"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favorite"
},
"savedFilters": {
"title": "Filter"
}
}
},
"filters": {
"title": "Filter",
"clear": "Filter zurücksetzen",
@ -403,7 +344,7 @@
},
"create": {
"title": "Neuer gespeicherter Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Neue gspeicherete Filter erstelle",
"titleRequired": "Bitte gib den Titel für den Filter an."
},
@ -674,19 +615,13 @@
"updated": "Aktualisiert"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "Du kannst hier nicht de-abonnieren, da du diese Aufgabe über ihren Namespace abonniert hast.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "Du hast diesen Namespace abonniert und erhältst Benachrichtigungen über Änderungen.",
"notSubscribedNamespace": "Du hast diesen Namespace nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "Du hast diese Aufgabe abonniert und erhältst Benachrichtigungen über Änderungen.",
"notSubscribedTask": "Du hast diese Aufgabe nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
"subscribe": "Abooniere",
"unsubscribe": "Deabonniere",
"subscribeSuccessNamespace": "Du hast diesen Namespace jetzt abonniert",
"unsubscribeSuccessNamespace": "Du hast diesen Namespace jetzt nicht mehr abonniert",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "Du hast diese Aufgabe jetzt abonniert",
@ -763,7 +698,6 @@
"searchPlaceholder": "Schriib, um e neui Uufgab als Zueghörigkeit hinzuezfüege…",
"createPlaceholder": "Das als en neui Zueghörigkeit hinzuefüege",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "Diese Aufgabe gehört zu einem anderen Namespace.",
"noneYet": "S'git kei Uufgabe Beziehige.",
"delete": "Uufgabe Beziehig chüble",
"deleteText1": "Bisch du dir sicher, dass du die Zueghörigkeit chüblä wetsch?",
@ -848,19 +782,19 @@
"delete": {
"header": "Das Team chüble",
"text1": "Bischder sicher, dasst wetsch da Team mit allne Mitglieder lösche?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "Da Team isch erfolgriich g'chüblet wore."
},
"deleteUser": {
"header": "Benutzer usem Team entferne",
"text1": "Bisch du dir sicher, dass du de Benutzer usm Team werfe wetsch?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "Benutzer erfolgriich usegworfe."
},
"leave": {
"title": "Team verlassen",
"text1": "Bist du sicher, dass du dieses Team verlassen willst?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "Du hast das Team erfolgreich verlassen."
}
},
@ -894,7 +828,10 @@
"color": "Die Farbe dieser Aufgabe ändern",
"move": "Move this task to another project",
"reminder": "Erinnerungen für diese Aufgabe verwalten",
"description": "Aufgabenbeschreibung bearbeiten"
"description": "Aufgabenbeschreibung bearbeiten",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Die Startseite aufrufen",
"upcoming": "Anstehende Aufgaben aufrufen",
"namespaces": "Navigate to namespaces & projects",
"labels": "Labels aufrufen",
"teams": "Teams aufrufen"
"teams": "Teams aufrufen",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Ent-archiviere",
"setBackground": "Hintergrund iihstelle",
"share": "Teilä",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Benachrichtigunge",
"none": "Du hesch kei neui Benachrichtunge. Heb e schös Tägli!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Befehl",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Gib en Titl für die neu Uufgab iih…",
"newNamespace": "Gib en Titl für de neu Namensruum iih…",
"newTeam": "Gib en Name für da neui Team iih…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Neui Uufgab",
"newProject": "New project",
"newNamespace": "Neue Namensruum",
"newTeam": "Neus Team"
}
},
@ -1017,16 +953,9 @@
"4017": "Ungültige Uufgabefilter vergliich.",
"4018": "Ungültige Verkettung von Aufgabenfiltern.",
"4019": "Ungültigi Uufgabe Filter Wert.",
"5001": "De Namensruum existiert nid.",
"5003": "Du hesch kei Zuegriff zu dem Namensruum.",
"5006": "De Namensruum Name cha nid leer sii.",
"5009": "Du bruuchsch Läsezuegriff uf de Namensruum, um das durezfüehre.",
"5010": "Da Team hett kei zuegriff uf de Namensruum.",
"5011": "De Benutzer hett bereits zuegriff uf de Namensruum.",
"5012": "De Namensruum isch momentan schriibgschützt weil er archiviert isch.",
"6001": "Der Teamname kann nicht leer sein.",
"6002": "Da Team giz nid.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "De Benutzer isch scho bi dem Team.",
"6006": "Du chasch nid de letschti Benutzer vom Team lösche.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Last viewed",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "To proceed, please enter your password. You will receive an email with further instructions.",
"confirm": "Delete my account",
"requestSuccess": "The request was successful. You'll receive an email with further instructions.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Export your Vikunja data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Please enter your password to proceed:",
"request": "Request a copy of my Vikunja Data",
"success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Show Archived",
"noneAvailable": "You don't have any namespaces right now.",
"unarchive": "Un-Archive",
"archived": "Archived",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Type to search for a namespace…",
"create": {
"title": "New namespace",
"titleRequired": "Please specify a title.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "What's a namespace?",
"success": "The namespace was successfully created."
},
"archive": {
"titleArchive": "Archive \"{namespace}\"",
"titleUnarchive": "Un-Archive \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "The namespace was successfully archived.",
"unarchiveSuccess": "The namespace was successfully un-archived.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Delete \"{namespace}\"",
"text1": "Are you sure you want to delete this namespace and all of its contents?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "The namespace was successfully deleted."
},
"edit": {
"title": "Edit \"{namespace}\"",
"success": "The namespace was successfully updated."
},
"share": {
"title": "Share \"{namespace}\""
},
"attributes": {
"title": "Namespace Title",
"titlePlaceholder": "The namespace title goes here…",
"description": "Description",
"descriptionPlaceholder": "The namespaces description goes here…",
"color": "Color",
"archived": "Is Archived",
"isArchived": "This namespace is archived"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favorites"
},
"savedFilters": {
"title": "Filters"
}
}
},
"filters": {
"title": "Filters",
"clear": "Clear Filters",
@ -403,7 +344,7 @@
},
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -677,19 +618,13 @@
"updated": "Updated"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -766,7 +701,6 @@
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Add this as new related task",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "This task belongs to a different namespace.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
"deleteText1": "Are you sure you want to delete this task relation?",
@ -851,19 +785,19 @@
"delete": {
"header": "Delete the team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "The team was successfully deleted."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "The user was successfully deleted from the team."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -897,7 +831,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -910,9 +847,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Navigate to labels",
"teams": "Navigate to teams"
"teams": "Navigate to teams",
"projects": "Navigate to projects"
}
},
"update": {
@ -927,7 +864,8 @@
"unarchive": "Un-Archive",
"setBackground": "Set background",
"share": "Share",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -946,7 +884,7 @@
"notification": {
"title": "Notifications",
"none": "You don't have any notifications. Have a nice day!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commands",
@ -957,14 +895,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "New task",
"newProject": "New project",
"newNamespace": "New namespace",
"newTeam": "New team"
}
},
@ -1020,16 +956,9 @@
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatenator.",
"4019": "Invalid task filter value.",
"5001": "The namespace does not exist.",
"5003": "You do not have access to the specified namespace.",
"5006": "The namespace name cannot be empty.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "The user is already a member of that team.",
"6006": "Cannot delete the last team member.",
"6007": "The team does not have access to the project to perform that action.",
@ -1056,4 +985,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "¡Buenas Tardes {username}!",
"lastViewed": "Visto por última vez",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Eliminar tu Cuenta de Vikunja",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Para continuar, por favor, introduce tu contraseña. Recibirás un correo electrónico con más instrucciones.",
"confirm": "Eliminar mi cuenta",
"requestSuccess": "La solicitud ha sido exitosa. Recibirás un correo electrónico con más instrucciones.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Exportar tus datos de Vikunja",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Por favor, introduce tu contraseña para continuar:",
"request": "Solicitar una copia de mis datos de Vikunja",
"success": "Tu petición de datos de Vikunja ha sido procesada correctamente. Te enviaremos un correo una vez esté lista para descargar.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Proyecto",
"showArchived": "Mostrar Archivados",
"noneAvailable": "No tienes ningún proyecto en este momento.",
"unarchive": "Desarchivar",
"archived": "Archivado",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Proyectos",
"search": "Escribe para buscar un proyecto…",
"create": {
"title": "Nuevo proyecto",
"titleRequired": "Por favor, especifica un título.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "¿Qué es un proyecto?",
"success": "El proyecto se ha creado correctamente."
},
"archive": {
"titleArchive": "Archivar \"{namespace}\"",
"titleUnarchive": "Desarchivar \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "El proyecto fue archivado con éxito.",
"unarchiveSuccess": "El proyecto se ha desarchivado con éxito.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Eliminar \"{namespace}\"",
"text1": "¿Estás seguro de que deseas eliminar este proyecto y todo su contenido?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "El proyecto se ha eliminado con éxito."
},
"edit": {
"title": "Editar \"{namespace}\"",
"success": "El proyecto se actualizó con éxito."
},
"share": {
"title": "Compartir \"{namespace}\""
},
"attributes": {
"title": "Título del proyecto",
"titlePlaceholder": "El título del proyecto va aquí…",
"description": "Descripción",
"descriptionPlaceholder": "La descripción del proyecto va aquí…",
"color": "Color",
"archived": "Está archivado",
"isArchived": "Este proyecto está archivado"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favoritos"
},
"savedFilters": {
"title": "Filtros"
}
}
},
"filters": {
"title": "Filtros",
"clear": "Limpiar Filtros",
@ -403,7 +344,7 @@
},
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Actualizado"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "No puede cancelar la suscripción aquí porque está suscrito a esta tarea a través de su proyecto.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "Actualmente está suscrito a este proyecto y recibirás notificaciones de cambios.",
"notSubscribedNamespace": "No está suscrito a este proyecto y no recibirá notificaciones de cambios.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "Actualmente estás suscrito a esta tarea y recibirás notificaciones de cambios.",
"notSubscribedTask": "No estás suscrito a esta tarea y no recibirás notificaciones de cambios.",
"subscribe": "Suscribirse",
"unsubscribe": "Desuscribirse",
"subscribeSuccessNamespace": "Ahora está suscrito a este proyecto",
"unsubscribeSuccessNamespace": "Ya no está suscrito a este proyecto",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Escriba para buscar una nueva tarea a añadir como relacionada…",
"createPlaceholder": "Añadir esto como nueva tarea relacionada",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "Esta tarea pertenece a un proyecto diferente.",
"noneYet": "Aún no hay tareas relacionadas.",
"delete": "Eliminar Relación de Tarea",
"deleteText1": "¿Está seguro que desea eliminar esta relación de la tarea?",
@ -848,19 +782,19 @@
"delete": {
"header": "Delete the team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "El equipo fue eliminado con éxito."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "El usuario fue quitado del equipo con éxito."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "Has abandonado el equipo con éxito."
}
},
@ -894,7 +828,10 @@
"color": "Cambia el color de esta tarea",
"move": "Move this task to another project",
"reminder": "Administrar recordatorios de esta tarea",
"description": "Editar la descripción de la tarea"
"description": "Editar la descripción de la tarea",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Secciones",
"overview": "Ir a resumen",
"upcoming": "Ir a tareas próximas",
"namespaces": "Navigate to namespaces & projects",
"labels": "Ir a etiquetas",
"teams": "Ir a equipos"
"teams": "Ir a equipos",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Desarchivar",
"setBackground": "Establecer fondo",
"share": "Compartir",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "URL de Vikunja",
@ -943,7 +881,7 @@
"notification": {
"title": "Notificaciones",
"none": "No tienes notificaciones. ¡Que tengas un buen día!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commands",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "New task",
"newProject": "New project",
"newNamespace": "New namespace",
"newTeam": "New team"
}
},
@ -1017,16 +953,9 @@
"4017": "Comparador de filtro de tarea inválido.",
"4018": "Concatenador de filtro de tarea inválido.",
"4019": "Valor de filtro de tarea inválido.",
"5001": "El proyecto no existe.",
"5003": "No tiene acceso al proyecto especificado.",
"5006": "El nombre del proyecto no puede estar vacío.",
"5009": "Necesita tener acceso de lectura al proyecto para realizar esa acción.",
"5010": "Este equipo no tiene acceso a ese proyecto.",
"5011": "Este usuario ya tiene acceso a ese proyecto.",
"5012": "El proyecto está archivado y por lo tanto solo podrá acceder en modo solo lectura.",
"6001": "El nombre del equipo no puede estar vacío.",
"6002": "Este equipo no existe.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "El usuario ya es miembro de ese equipo.",
"6006": "No se puede quitar al último miembro del equipo.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "Versión de la API: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Dernière consultation",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Supprimer ton compte Vikunja",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Pour continuer, entre ton mot de passe. Tu recevras un courriel contenant les instructions suivantes.",
"confirm": "Supprimer mon compte",
"requestSuccess": "La demande a réussi. Tu recevras un courriel avec des instructions supplémentaires.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Exporter tes données Vikunja",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Entre ton mot de passe pour continuer :",
"request": "Demander une copie de mes données Vikunja",
"success": "Tu as bien demandé tes données Vikunja ! Nous t'enverrons un courriel dès qu'elles seront prêtes à être téléchargées.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Espace de noms",
"showArchived": "Montrer les archivés",
"noneAvailable": "Tu nas pas despace de noms pour le moment.",
"unarchive": "Désarchiver",
"archived": "Archivé",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Espaces de noms",
"search": "Écris pour rechercher un espace de noms…",
"create": {
"title": "Nouvel espace de noms",
"titleRequired": "Indique un nom.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "Quest-ce quun espace de noms ?",
"success": "Espace de noms créé."
},
"archive": {
"titleArchive": "Archiver « {namespace} »",
"titleUnarchive": "Désarchiver « {namespace} »",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "Espace de noms archivé.",
"unarchiveSuccess": "Espace de noms archivé.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Supprimer « {namespace} »",
"text1": "Supprimer cet espace de noms et tout son contenu ?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "Espace de noms supprimé."
},
"edit": {
"title": "Modifier « {namespace} »",
"success": "Espace de noms mis à jour."
},
"share": {
"title": "Partager « {namespace} »"
},
"attributes": {
"title": "Nom de lespace de noms",
"titlePlaceholder": "Entre le nom de lespace de noms…",
"description": "Description",
"descriptionPlaceholder": "Entre la description de lespace de noms…",
"color": "Couleur",
"archived": "Est archivé",
"isArchived": "Cet espace de noms est archivé"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favoris"
},
"savedFilters": {
"title": "Filtres"
}
}
},
"filters": {
"title": "Filtres",
"clear": "Effacer les filtres",
@ -403,7 +344,7 @@
},
"create": {
"title": "Nouveau filtre enregistré",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Créer un nouveau filtre enregistré",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Mis à jour"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Sabonner",
"unsubscribe": "Se désabonner",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Écris la recherche dune nouvelle tâche à ajouter comme connexe…",
"createPlaceholder": "Ajouter cette tâche comme nouvelle tâche connexe",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "Cette tâche fait partie d'un espace de noms différent.",
"noneYet": "Pas encore de relations de tâches.",
"delete": "Supprimer la relation de tâche",
"deleteText1": "Supprimer cette relation de tâche ?",
@ -848,19 +782,19 @@
"delete": {
"header": "Supprimer léquipe",
"text1": "Supprimer cette équipe et tous ses membres ?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "Équipe supprimée."
},
"deleteUser": {
"header": "Retirer un·e utilisateur·rice de léquipe",
"text1": "Retirer cette personne de léquipe ?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "Utilisateur·rice retiré·e de léquipe."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Changer la couleur de cette tâche",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Accéder aux étiquettes",
"teams": "Accéder aux équipes"
"teams": "Accéder aux équipes",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Désarchiver",
"setBackground": "Définir larrière-plan",
"share": "Partager",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "URL Vikunja",
@ -943,7 +881,7 @@
"notification": {
"title": "Notifications",
"none": "Tu nas pas de notifications. Passe une bonne journée !",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commandes",
@ -954,14 +892,12 @@
"teams": "Équipes",
"newProject": "Enter the title of the new project…",
"newTask": "Entre le nom de la tâche…",
"newNamespace": "Entre le nom de lespace de noms…",
"newTeam": "Entre le nom de la nouvelle équipe…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Nouvelle tâche",
"newProject": "New project",
"newNamespace": "Nouvel espace de noms",
"newTeam": "Nouvelle équipe"
}
},
@ -1017,16 +953,9 @@
"4017": "Comparateur de filtre de tâche invalide.",
"4018": "Concaténateur de filtre de tâche invalide.",
"4019": "Valeur de filtre de tâche invalide.",
"5001": "Lespace de noms nexiste pas.",
"5003": "Tu nas pas accès à lespace de noms indiqué.",
"5006": "Le nom de lespace de noms ne peut pas être vide.",
"5009": "Accès en lecture à lespace de noms nécessaire pour effectuer cette action.",
"5010": "Cette équipe na pas accès à cet espace de noms.",
"5011": "Cet·e utilisateur·rice a déjà accès à cet espace de noms.",
"5012": "Lespace de noms est archivé et ne peut donc être consulté quen lecture seule.",
"6001": "Le nom de l'équipe ne peut pas être vide.",
"6002": "Léquipe nexiste pas.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "Lutilisateur·rice est déjà membre de cette équipe.",
"6006": "Impossible de supprimer le dernier membre de léquipe.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Version : {version}",
"apiVersion": "Version de lAPI : {version}"
}
}
}

View File

@ -6,10 +6,8 @@
"welcomeEvening": "Buonasera {username}!",
"lastViewed": "Ultima visualizzazione",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Importa i tuoi dati in Vikunja"
}
},
"404": {
@ -85,7 +83,7 @@
"weekStartSunday": "Domenica",
"weekStartMonday": "Lunedì",
"language": "Lingua",
"defaultProject": "Default Project",
"defaultProject": "Progetto Predefinito",
"timezone": "Fuso Orario",
"overdueTasksRemindersTime": "Orario email attività in scadute"
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Elimina il tuo Account Vikunja",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Per continuare, inserisci la tua password. Riceverai un'e-mail con ulteriori istruzioni.",
"confirm": "Elimina il mio profilo",
"requestSuccess": "Richiesta riuscita. Riceverai un'e-mail con ulteriori istruzioni.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Esporta i tuoi dati Vikunja",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Inserisci la tua password per procedere:",
"request": "Richiedi una copia dei miei dati Vikunja",
"success": "Hai richiesto con successo i tuoi dati Vikunja! Ti invieremo un'e-mail una volta che saranno pronti da scaricare.",
@ -165,42 +163,46 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Titolo Progetto",
"color": "Colore",
"projects": "Progetti",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"shared": "Progetti Condivisi",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
"addTitleRequired": "Please specify a title.",
"createdSuccess": "The project was successfully created.",
"header": "Nuovo progetto",
"titlePlaceholder": "Titolo del progetto…",
"addTitleRequired": "Specifica un titolo.",
"createdSuccess": "Progetto creato.",
"addProjectRequired": "Please specify a project or set a default project in the settings."
},
"archive": {
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"title": "Archivia \"{project}\"",
"archive": "Archivia questo progetto",
"unarchive": "Estrai questo progetto dall'archivio",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"success": "The project was successfully archived."
"success": "Progetto archiviato."
},
"background": {
"title": "Set project background",
"remove": "Remove Background",
"upload": "Choose a background from your pc",
"searchPlaceholder": "Search for a background…",
"poweredByUnsplash": "Powered by Unsplash",
"loadMore": "Load more photos",
"title": "Imposta lo sfondo del progetto",
"remove": "Rimuovi lo sfondo",
"upload": "Scegli uno sfondo dal tuo PC",
"searchPlaceholder": "Cerca uno sfondo…",
"poweredByUnsplash": "Alimentato da Unsplash",
"loadMore": "Carica altre foto",
"success": "The background has been set successfully!",
"removeSuccess": "The background has been removed successfully!"
},
"delete": {
"title": "Delete \"{project}\"",
"header": "Delete this project",
"title": "Elimina \"{project}\"",
"header": "Elimina questo progetto",
"text1": "Are you sure you want to delete this project and all of its contents?",
"text2": "This includes all tasks and CANNOT BE UNDONE!",
"success": "The project was successfully deleted.",
@ -208,27 +210,27 @@
"noTasksToDelete": "This project does not contain any tasks, it should be safe to delete."
},
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"title": "Duplica il progetto",
"label": "Duplica",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
"header": "Edit This Project",
"title": "Edit \"{project}\"",
"titlePlaceholder": "The project title goes here…",
"header": "Modifica Questo Progetto",
"title": "Modifica \"{project}\"",
"titlePlaceholder": "Titolo del progetto…",
"identifierTooltip": "The project identifier can be used to uniquely identify a task across projects. You can set it to empty to disable it.",
"identifier": "Project Identifier",
"identifierPlaceholder": "The project identifier goes here…",
"description": "Description",
"descriptionPlaceholder": "The projects description goes here…",
"color": "Color",
"description": "Descrizione",
"descriptionPlaceholder": "Descrizione del progetto…",
"color": "Colore",
"success": "The project was successfully updated."
},
"share": {
"header": "Share this project",
"title": "Share \"{project}\"",
"share": "Share",
"header": "Condividi questo progetto",
"title": "Condividi \"{project}\"",
"share": "Condividi",
"links": {
"title": "Share Links",
"what": "What is a share link?",
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Mostra Archiviati",
"noneAvailable": "Non hai alcun namespace in questo momento.",
"unarchive": "De-Archivia",
"archived": "Archiviato",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespace",
"search": "Digita per cercare un namespace…",
"create": {
"title": "Nuovo namespace",
"titleRequired": "Specifica un titolo.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "Che cos'è un namespace?",
"success": "Namespace creato."
},
"archive": {
"titleArchive": "Archivia \"{namespace}\"",
"titleUnarchive": "Disarchivia \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "Namespace creato.",
"unarchiveSuccess": "Namespace estratto dall'archivio.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Elimina \"{namespace}\"",
"text1": "Sei sicuro di voler rimuovere questo namespace e tutto il relativo contenuto?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "Namespace eliminato."
},
"edit": {
"title": "Modifica \"{namespace}\"",
"success": "Namespace aggiornato."
},
"share": {
"title": "Condividi \"{namespace}\""
},
"attributes": {
"title": "Titolo del Namespace",
"titlePlaceholder": "Il titolo del namespace va qui…",
"description": "Descrizione",
"descriptionPlaceholder": "La descrizione del namespace va qui…",
"color": "Colore",
"archived": "Archiviato",
"isArchived": "Questo namespace è archiviato"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Preferiti"
},
"savedFilters": {
"title": "Filtri"
}
}
},
"filters": {
"title": "Filtri",
"clear": "Pulisci Filtri",
@ -403,7 +344,7 @@
},
"create": {
"title": "Nuovo Filtro Salvato",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Crea nuovo filtro salvato",
"titleRequired": "È necessario un titolo per il filtro."
},
@ -674,19 +615,13 @@
"updated": "Aggiornato"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "Non puoi annullare l'iscrizione perché sei iscritto al namespace di questa attività.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "Sei iscritto a questo namespace e verrai notificato delle modifiche.",
"notSubscribedNamespace": "Non sei iscritto a questo namespace e non verrai notificato delle modifiche.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "Sei iscritto a questa attività e verrai notificato delle modifiche.",
"notSubscribedTask": "Non sei iscritto a questa attività e non verrai notificato delle modifiche.",
"subscribe": "Iscriviti",
"unsubscribe": "Disiscriviti",
"subscribeSuccessNamespace": "Sei iscritto a questo namespace",
"unsubscribeSuccessNamespace": "Non sei più iscritto a questo namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "Sei iscritto a questa attività",
@ -763,7 +698,6 @@
"searchPlaceholder": "Digita per cercare un'attività da aggiungere come collegata…",
"createPlaceholder": "Aggiungi come attività collegata",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "Questa attività appartiene ad un namespace diverso.",
"noneYet": "Nessuna attività collegata.",
"delete": "Elimina Collegamento Attività",
"deleteText1": "Confermi di voler eliminare questo collegamento attività?",
@ -848,19 +782,19 @@
"delete": {
"header": "Elimina il gruppo",
"text1": "Sei sicuro di voler eliminare questo gruppo e tutti i suoi membri?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "Gruppo eliminato."
},
"deleteUser": {
"header": "Rimuovi un utente dal gruppo",
"text1": "Confermi di voler rimuovere questo utente dal gruppo?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "Utente rimosso dal gruppo."
},
"leave": {
"title": "Abbandona il gruppo",
"text1": "Sei sicuro di voler abbandonare questo gruppo?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "Hai abbandonato il gruppo."
}
},
@ -894,7 +828,10 @@
"color": "Cambia il colore di questa attività",
"move": "Move this task to another project",
"reminder": "Gestisci i promemoria di questa attività",
"description": "Attiva/Disattiva modifica della descrizione dell'attività"
"description": "Attiva/Disattiva modifica della descrizione dell'attività",
"delete": "Elimina questa attività",
"priority": "Modifica la priorità di questa attività",
"favorite": "Segna questa attività come preferita o non preferita"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigazione",
"overview": "Passa a \"Panoramica\"",
"upcoming": "Passa a \"Prossimamente\"",
"namespaces": "Navigate to namespaces & projects",
"labels": "Passa a \"Etichette\"",
"teams": "Passa a \"Gruppi\""
"teams": "Passa a \"Gruppi\"",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Disarchivia",
"setBackground": "Imposta sfondo",
"share": "Condividi",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "URL Vikunja",
@ -943,7 +881,7 @@
"notification": {
"title": "Notifiche",
"none": "Nessuna notifica. Buona giornata!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Comandi",
@ -954,14 +892,12 @@
"teams": "Gruppi",
"newProject": "Enter the title of the new project…",
"newTask": "Inserisci il titolo della nuova attività…",
"newNamespace": "Inserisci il titolo del nuovo namespace…",
"newTeam": "Inserisci il nome del nuovo gruppo…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Nuova attività",
"newProject": "New project",
"newNamespace": "Nuovo Namespace",
"newTeam": "Nuovo gruppo"
}
},
@ -1017,16 +953,9 @@
"4017": "Comparatore di filtri attività non valido.",
"4018": "Concatenatore filtro attività non valido.",
"4019": "Filtro attività non valido.",
"5001": "Il namespace non esiste.",
"5003": "Non hai accesso a questo namespace.",
"5006": "Il nome del namespace non può essere vuoto.",
"5009": "Devi avere accesso in lettura al namespace per effettuare questa operazione.",
"5010": "Il tuo gruppo non ha accesso a questo namespace.",
"5011": "Questo utente ha già accesso a quel namespace.",
"5012": "Il namespace è archiviato e può quindi essere accessibile solo in sola lettura.",
"6001": "Il nome del gruppo non può essere vuoto.",
"6002": "Gruppo non esistente.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "L'utente è già membro di quel gruppo.",
"6006": "Non è possibile eliminare l'ultimo membro del gruppo.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Versione Frontend: {version}",
"apiVersion": "Versione API: {version}"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Laatst bekeken",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Verwijder je Vikunja account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Graag je wachtwoord invullen om verder te gaan. Je zult een e-mail ontvangen met verdere instructies.",
"confirm": "Verwijder mijn account",
"requestSuccess": "Het verzoek was succesvol. Je ontvangt een e-mail met verdere instructies.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Je Vikunja gegevens exporteren",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Voer je wachtwoord in om door te gaan:",
"request": "Een kopie van mijn Vikunja gegevens opvragen",
"success": "Je hebt met succes je Vikunja Data aangevraagd! We sturen je een e-mail zodra het klaar is om te downloaden.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Toon gearchiveerd",
"noneAvailable": "Je hebt op dit moment geen Namespaces.",
"unarchive": "Archivering opheffen",
"archived": "Gearchiveerd",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Begin met typen om een Namespace te zoeken…",
"create": {
"title": "Nieuwe namespace",
"titleRequired": "Voer een titel in.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "Wat is een namespace?",
"success": "De Namespace is succesvol gemaakt."
},
"archive": {
"titleArchive": "Archiveer \"{namespace}\"",
"titleUnarchive": "Archivering \"{namespace}\" ongedaan maken",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "The namespace was successfully archived.",
"unarchiveSuccess": "The namespace was successfully un-archived.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "\"{namespace}\" verwijderen",
"text1": "Weet je zeker dat je deze Namespace en alle inhoud ervan wilt verwijderen?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "De Namespace is succesvol verwijderd."
},
"edit": {
"title": "Bewerk \"{namespace}\"",
"success": "The namespace was successfully updated."
},
"share": {
"title": "\"{namespace}\" delen"
},
"attributes": {
"title": "Namespace titel",
"titlePlaceholder": "The namespace title goes here…",
"description": "Beschrijving",
"descriptionPlaceholder": "The namespaces description goes here…",
"color": "Kleur",
"archived": "Is gearchiveerd",
"isArchived": "This namespace is archived"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favorieten"
},
"savedFilters": {
"title": "Filters"
}
}
},
"filters": {
"title": "Filters",
"clear": "Clear Filters",
@ -403,7 +344,7 @@
},
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Bijgewerkt"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Voeg dit toe als nieuwe gerelateerde taak",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "This task belongs to a different namespace.",
"noneYet": "Nog geen taakrelaties.",
"delete": "Taak relatie verwijderen",
"deleteText1": "Weet je zeker dat je deze taakrelatie wilt verwijderen?",
@ -848,19 +782,19 @@
"delete": {
"header": "Verwijder het team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "The team was successfully deleted."
},
"deleteUser": {
"header": "Verwijder een gebruiker uit het team",
"text1": "Weet je zeker dat je deze gebruiker wilt verwijderen uit het team?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "The user was successfully deleted from the team."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Navigate to labels",
"teams": "Navigate to teams"
"teams": "Navigate to teams",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Archivering opheffen",
"setBackground": "Achtergrond instellen",
"share": "Delen",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Notificaties",
"none": "Je hebt geen meldingen. Fijne dag!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commands",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Nieuwe taak",
"newProject": "New project",
"newNamespace": "Nieuwe namespace",
"newTeam": "Nieuw team"
}
},
@ -1017,16 +953,9 @@
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatenator.",
"4019": "Ongeldige taakfilter waarde.",
"5001": "Deze Namespace bestaat niet.",
"5003": "Je hebt geen toegang tot de opgegeven Namespace.",
"5006": "De naam van de namespace mag niet leeg zijn.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be empty.",
"6002": "Het team bestaat niet.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "The user is already a member of that team.",
"6006": "Kan het laatste teamlid niet verwijderen.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend versie: {version}",
"apiVersion": "API Versie: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "God Morgen {username}!",
"lastViewed": "Sist sett",
"project": {
"newText": "Du kan opprette en ny liste for dine nye oppgaver:",
"new": "Nytt prosjekt",
"importText": "Eller importer lister og oppgaver fra andre tjenester til Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Importer dine data til Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Slett kontoen din",
"text1": "Sletting av din konto er permanent og kan ikke angres. Vi vil slette alle dine navneområder og prosjekter, oppgaver og alt forbundet med den.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "For å fortsette, skriv inn passordet ditt. Du vil motta en e-post med ytterligere instruksjoner.",
"confirm": "Slett min konto",
"requestSuccess": "Forespørselen var vellykket. Du vil motta en e-post med ytterligere instruksjoner.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Eksporter dine kontodata",
"description": "Du kan be om en kopi av alle Vikunja dataene dine. Dette inkluderer navneområder, lister, oppgaver og alt tilknyttet dem.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Skriv inn passordet for å fortsette:",
"request": "Be om kopi av mine Vikunja Data",
"success": "Du har spurt om dine Vikunja data! Vi sender deg en e-post når den er klar til å laste ned.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "Dette prosjektet er arkivert. Det er ikke mulig å opprette nye eller redigere oppgaver for det.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Prosjekt tittel",
"color": "Farger",
"projects": "Prosjekter",
"parent": "Parent Project",
"search": "Tast for å søke etter et prosjekt…",
"searchSelect": "Klikk eller trykk enter for å velge dette prosjektet",
"shared": "Delte prosjekter",
"noDescriptionAvailable": "Ingen prosjektbeskrivelse er tilgjengelig.",
"inboxTitle": "Inbox",
"create": {
"header": "Nytt prosjekt",
"titlePlaceholder": "Prosjektets tittel er her…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Dupliser dette prosjektet",
"label": "Dupliser",
"text": "Velg et navneområde som skal holde det dupliserte prosjektet:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "Prosjektet ble duplisert."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Navneområder & lister",
"namespace": "Navneområde",
"showArchived": "Vis arkiverte",
"noneAvailable": "Du har ingen navneområder akkurat nå.",
"unarchive": "Av-arkiver",
"archived": "Arkivert",
"noProjects": "Dette navneområdet inneholder ikke noen prosjekter.",
"createProject": "Opprett et nytt prosjekt i dette navneområdet.",
"namespaces": "Navnerom",
"search": "Skriv for å søke etter en etikett…",
"create": {
"title": "Nytt navneområde",
"titleRequired": "Angi den nye tittelen.",
"explanation": "Et navneområde er en samling av lister du kan dele og bruke til å organisere listene dine med. I realiteten hører hver liste til et navneområde.",
"tooltip": "Hva er et navneområde?",
"success": "Navneområdet ble opprettet."
},
"archive": {
"titleArchive": "Arkiv \"{namespace}\"",
"titleUnarchive": "Av-Arkiv \"{namespace}\"",
"archiveText": "Du vil ikke kunne redigere dette navneområdet eller opprette nye lister før du avlaster arkivet. Dette vil også arkivere alle lister i dette navneområdet.",
"unarchiveText": "Du vil kunne opprette nye oppgaver eller redigere den.",
"success": "Navnerommet ble arkivert.",
"unarchiveSuccess": "Navnerommet ble vellykket fjernet fra arkivet.",
"description": "Hvis navneområdet er arkivert, kan du ikke opprette nye lister eller redigere det."
},
"delete": {
"title": "Slett \"{namespace}",
"text1": "Er du sikker på at du vil slette dette navneområdet og alt innholdet?",
"text2": "Dette inkluderer alle oppgaver og KAN IKKE ANGRES!",
"success": "Navnområdet ble slettet."
},
"edit": {
"title": "Rediger \"{namespace}",
"success": "Navnerommet ble oppdatert."
},
"share": {
"title": "Del \"{namespace}"
},
"attributes": {
"title": "Navneområdes Tittel",
"titlePlaceholder": "Navneområdets tittel går her…",
"description": "Beskrivelse",
"descriptionPlaceholder": "Beskrivelsen av navneområdene gis her…",
"color": "Farger",
"archived": "Arkivert",
"isArchived": "Dette navneområdet er arkivert"
},
"pseudo": {
"sharedProjects": {
"title": "Delte prosjekter"
},
"favorites": {
"title": "Favoritter"
},
"savedFilters": {
"title": "Filtre"
}
}
},
"filters": {
"title": "Filtre",
"clear": "Fjern filtre",
@ -403,7 +344,7 @@
},
"create": {
"title": "Nytt lagret filter",
"description": "Et lagret filter er en virtuell liste som beregnes fra et sett med filtre hver gang det åpnes. Når du er opprettet, vil det vises i et eget navneområde.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Opprett nytt filter",
"titleRequired": "Skriv inn en tittel for filteret."
},
@ -674,19 +615,13 @@
"updated": "Oppdatert"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "Du kan ikke slutte å abonnere her fordi du abonnerer på denne listen gjennom dens navneområde.",
"subscribedTaskThroughParentNamespace": "Du kan ikke slutte å abonnere her fordi du abonnerer på denne oppgaven gjennom navneområdet.",
"subscribedTaskThroughParentProject": "Du kan ikke melde deg ut her fordi du abonnerer på denne oppgaven gjennom prosjektet.",
"subscribedNamespace": "Du abonnerer for øyeblikket på dette navneområdet og vil motta varsler for endringer.",
"notSubscribedNamespace": "Du abonnerer ikke på dette navneområdet og vil ikke motta varsler for endringer.",
"subscribedProject": "Du abonnerer for øyeblikket på dette prosjektet og vil motta varsler for endringer.",
"notSubscribedProject": "Du abonnerer ikke på dette prosjektet og vil ikke motta varsler for endringer.",
"subscribedTask": "Du abonnerer for øyeblikket på denne oppgaven og vil motta varsler for endringer.",
"notSubscribedTask": "Du abonnerer ikke på denne oppgaven og vil ikke motta varsler for endringer.",
"subscribe": "Abonnerer",
"unsubscribe": "Avslutt abonnement",
"subscribeSuccessNamespace": "Du abonnerer nå på dette navneområdet",
"unsubscribeSuccessNamespace": "Du blir nå avmeldt dette navneområdet",
"subscribeSuccessProject": "Du abonnerer nå på dette prosjektet",
"unsubscribeSuccessProject": "Du har nå avsluttet abonnementet for dette prosjektet",
"subscribeSuccessTask": "Du abonnerer nå på denne oppgaven",
@ -763,7 +698,6 @@
"searchPlaceholder": "Skriv søk etter en ny oppgave å legge til som relatert…",
"createPlaceholder": "Legg til denne som ny relatert oppgave",
"differentProject": "Denne oppgaven tilhører et annet prosjekt.",
"differentNamespace": "Denne oppgaven tilhører en annen navneområde.",
"noneYet": "Ingen arbeidsrelasjoner ennå.",
"delete": "Slett relasjon",
"deleteText1": "Er du sikker på at du vil slette denne relasjonen?",
@ -848,19 +782,19 @@
"delete": {
"header": "Slett gruppen",
"text1": "Er du sikker på at du vil slette denne gruppen og alle dets medlemmer?",
"text2": "Alle teammedlemmer vil miste tilgang til prosjekter og navneområder som deles med dette teamet. KAN IKKE ANGRES!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "Gruppen ble slettet."
},
"deleteUser": {
"header": "Fjerne en bruker fra gruppen",
"text1": "Er du sikker på at du vil fjerne bruker fra denne gruppen?",
"text2": "De vil miste tilgang til alle prosjekter og namespaces dette teamet har tilgang til. Dette KAN IKKE ANGRES!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "Brukeren ble slettet fra gruppen."
},
"leave": {
"title": "Forlat gruppen",
"text1": "Er du sikker på at du vil forlate denne gruppen?",
"text2": "Du vil miste tilgang til alle prosjekter og namespaces dette teamet har tilgang til. Hvis du ombestemmer deg, må du ha en lagadministrator for å legge deg til igjen.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "Du har forlatt gruppen."
}
},
@ -894,7 +828,10 @@
"color": "Endre fargen på denne oppgaven",
"move": "Flytt denne oppgaven til et annet prosjekt",
"reminder": "Behandle påminnelser om denne oppgaven",
"description": "Veksle redigering av oppgavebeskrivelsen"
"description": "Veksle redigering av oppgavebeskrivelsen",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Prosjektvisning",
@ -907,9 +844,9 @@
"title": "Navigasjon",
"overview": "Naviger til oversikt",
"upcoming": "Gå til kommende oppgaver",
"namespaces": "Gå til navneområder & prosjekter",
"labels": "Naviger til etiketter",
"teams": "Naviger til gruppe"
"teams": "Naviger til gruppe",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Av-arkiver",
"setBackground": "Bruk som bakgrunn",
"share": "Del",
"newProject": "Nytt prosjekt"
"newProject": "Nytt prosjekt",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Varsler",
"none": "Du har ingen varsler på dette tidspunktet!",
"explainer": "Varsler vil vises her når handlinger på navneområder, prosjekter, lister eller oppgaver du abonnerer på."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Kommandoer",
@ -954,14 +892,12 @@
"teams": "Grupper",
"newProject": "Skriv tittelen på det nye prosjektet…",
"newTask": "Skriv tittelen på den nye oppgaven…",
"newNamespace": "Skriv inn tittelen på det nye navneområdet…",
"newTeam": "Skriv inn navnet på den nye gruppen…",
"createTask": "Opprett en oppgave i det gjeldende prosjektet ({title})",
"createProject": "Opprett et prosjekt i gjeldende navneområde ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Ny oppgave",
"newProject": "Nytt prosjekt",
"newNamespace": "Nytt navneområde",
"newTeam": "Ny gruppe"
}
},
@ -1017,16 +953,9 @@
"4017": "Ugyldig oppgave filter.",
"4018": "Ugyldig oppgave filter.",
"4019": "Ugyldig oppgave filterverdi.",
"5001": "Navneområdet finnes ikke.",
"5003": "Du har ikke tilgang til det angitte navneområdet.",
"5006": "Navneområde-navnet kan ikke være tomt.",
"5009": "Du må ha lesetilgang til navneområdet for å utføre den handlingen.",
"5010": "Denne gruppen har ikke tilgang til det navneområdet.",
"5011": "Denne brukeren har allerede tilgang til det navneområdet.",
"5012": "Navneområdet er arkivert og kan derfor kun leses på.",
"6001": "Gruppe nanvet kan ikke være tomt.",
"6002": "Gruppen finnes ikke.",
"6004": "Teamet har allerede tilgang til det navneområdet eller prosjektet.",
"6004": "The team already has access to that project.",
"6005": "Brukeren er allerede medlem av gruppen.",
"6006": "Kan ikke slette siste gruppemedlem.",
"6007": "Gruppen har ikke tilgang til prosjektet for å utføre den handlingen.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend versjon: {version}",
"apiVersion": "API versjon: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Ostatnio oglądane",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Usuń swoje konto Vikunja",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Aby kontynuować, wprowadź swoje hasło. Otrzymasz wiadomość e-mail z dalszymi instrukcjami.",
"confirm": "Usuń moje konto",
"requestSuccess": "Żądanie powiodło się. Otrzymasz wiadomość e-mail z dalszymi instrukcjami.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Eksportuj swoje dane Vikunja",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Wprowadź hasło, aby kontynuować:",
"request": "Generuj kopię moich danych Vikunja",
"success": "Pomyślnie zażądałeś danych Vikunja! Wyślemy Ci e-mail, gdy będą gotowe do pobrania.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Sekcja",
"showArchived": "Pokaż zarchiwizowane",
"noneAvailable": "W tej chwili nie masz żadnych sekcji.",
"unarchive": "Cofnij archiwizację",
"archived": "Zarchiwizowane",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Sekcje",
"search": "Wpisz, aby wyszukać sekcję…",
"create": {
"title": "Nowa sekcja",
"titleRequired": "Proszę, podaj tytuł.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "Co to jest sekcja?",
"success": "Sekcja została pomyślnie utworzona."
},
"archive": {
"titleArchive": "Archiwizuj \"{namespace}\"",
"titleUnarchive": "Cofnij archiwizację \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "Sekcja została pomyślnie zarchiwizowana.",
"unarchiveSuccess": "Archiwizacja sekcji została pomyślnie cofnięta.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Usuń \"{namespace}\"",
"text1": "Czy na pewno chcesz usunąć tę sekcję i całą jej zawartość?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "Sekcja została pomyślnie usunięta."
},
"edit": {
"title": "Edytuj \"{namespace}\"",
"success": "Sekcja została pomyślnie zaktualizowana."
},
"share": {
"title": "Udostępnij \"{namespace}\""
},
"attributes": {
"title": "Tytuł sekcji",
"titlePlaceholder": "Tu wpisz tytuł sekcji…",
"description": "Opis",
"descriptionPlaceholder": "Tu wpisz opis sekcji…",
"color": "Kolor",
"archived": "Archiwizacja",
"isArchived": "Ta sekcja jest zarchiwizowana"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Ulubione"
},
"savedFilters": {
"title": "Filtry"
}
}
},
"filters": {
"title": "Filtry",
"clear": "Wyczyść filtry",
@ -403,7 +344,7 @@
},
"create": {
"title": "Nowy filtr stały",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Utwórz nowy filtr stały",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Zaktualizowano"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Subskrybuj",
"unsubscribe": "Anuluj subskrypcję",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Wpisz, aby wyszukać zadanie, które chcesz dodać jako powiązane…",
"createPlaceholder": "Dodaj jako nowe powiązane zadanie",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "To zadanie należy do innej sekcji.",
"noneYet": "Nie ma jeszcze powiązanych zadań.",
"delete": "Usuń powiązane zadanie",
"deleteText1": "Czy na pewno chcesz usunąć to powiązane zadanie?",
@ -848,19 +782,19 @@
"delete": {
"header": "Usuń zespół",
"text1": "Czy na pewno chcesz usunąć ten zespół i wszystkich jego członków?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "Zespół został pomyślnie usunięty."
},
"deleteUser": {
"header": "Usuń użytkownika z zespołu",
"text1": "Czy na pewno chcesz usunąć tego użytkownika z zespołu?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "Użytkownik został pomyślnie usunięty z zespołu."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Zmień kolor tego zadania",
"move": "Move this task to another project",
"reminder": "Zarządzaj przypomnieniami o tym zadaniu",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Nawigacja",
"overview": "Przejdź do przeglądu",
"upcoming": "Przejdź do nadchodzących zadań",
"namespaces": "Navigate to namespaces & projects",
"labels": "Przejdź do etykiet",
"teams": "Przejdź do zespołów"
"teams": "Przejdź do zespołów",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Cofnij archiwizację",
"setBackground": "Ustaw tło",
"share": "Udostępnij",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "URL Vikunji",
@ -943,7 +881,7 @@
"notification": {
"title": "Powiadomienia",
"none": "Nie masz żadnych powiadomień. Miłego dnia!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Polecenia",
@ -954,14 +892,12 @@
"teams": "Zespoły",
"newProject": "Enter the title of the new project…",
"newTask": "Wpisz tytuł nowego zadania…",
"newNamespace": "Wpisz tytuł nowej sekcji…",
"newTeam": "Wpisz nazwę nowego zespołu…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Nowe zadanie",
"newProject": "New project",
"newNamespace": "Nowa sekcja",
"newTeam": "Nowy zespół"
}
},
@ -1017,16 +953,9 @@
"4017": "Nieprawidłowe porównanie filtra zadań.",
"4018": "Nieprawidłowe połączenie filtra zadań.",
"4019": "Nieprawidłowa wartość filtra zadań.",
"5001": "Sekcja nie istnieje.",
"5003": "Nie masz dostępu do określonej sekcji.",
"5006": "Nazwa sekcji nie może być pusta.",
"5009": "Aby wykonać tę akcję, musisz mieć uprawnienia do odczytu sekcji.",
"5010": "Ten zespół nie ma dostępu do tej sekcji.",
"5011": "Ten użytkownik ma już dostęp do tej sekcji.",
"5012": "Sekcja jest zarchiwizowana, dlatego może być dostępna tylko do odczytu.",
"6001": "Nazwa zespołu nie może być pusta.",
"6002": "Zespół nie istnieje.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "Użytkownik jest już członkiem tego zespołu.",
"6006": "Nie można usunąć ostatniego członka zespołu.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Wersja frontendu: {version}",
"apiVersion": "Wersja API: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Boa noite, {username}!",
"lastViewed": "Visto por último",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "To proceed, please enter your password. You will receive an email with further instructions.",
"confirm": "Delete my account",
"requestSuccess": "The request was successful. You'll receive an email with further instructions.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Export your Vikunja data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Please enter your password to proceed:",
"request": "Request a copy of my Vikunja Data",
"success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Show Archived",
"noneAvailable": "Você não tem nenhum namespace no momento.",
"unarchive": "Desarquivar",
"archived": "Arquivado",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Digite para procurar por um namespace…",
"create": {
"title": "Novo namespace",
"titleRequired": "Por favor, especifique um título.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "O que é um namespace?",
"success": "O namespace foi criado com sucesso."
},
"archive": {
"titleArchive": "Arquivar \"{namespace}\"",
"titleUnarchive": "Desarquivar \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "O namespace foi arquivado com sucesso.",
"unarchiveSuccess": "O namespace foi desarquivado com sucesso.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Excluir \"{namespace}\"",
"text1": "Are you sure you want to delete this namespace and all of its contents?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "O namespace foi excluído com sucesso."
},
"edit": {
"title": "Editar \"{namespace}\"",
"success": "O namespace foi atualizado com sucesso."
},
"share": {
"title": "Compartilhar \"{namespace}\""
},
"attributes": {
"title": "Título do Namespace",
"titlePlaceholder": "O título do namespace fica aqui…",
"description": "Descrição",
"descriptionPlaceholder": "A descrição do namespace fica aqui…",
"color": "Cor",
"archived": "Está arquivado",
"isArchived": "Este namespace está arquivado"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favoritos"
},
"savedFilters": {
"title": "Filtros"
}
}
},
"filters": {
"title": "Filtros",
"clear": "Limpar Filtros",
@ -403,7 +344,7 @@
},
"create": {
"title": "Novo filtro salvo",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Atualizado"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Inscrever-se",
"unsubscribe": "Desinscrever-se",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Add this as new related task",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "This task belongs to a different namespace.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
"deleteText1": "Are you sure you want to delete this task relation?",
@ -848,19 +782,19 @@
"delete": {
"header": "Excluir a equipe",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "A equipe foi excluída com sucesso."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "O usuário foi removido da equipe com sucesso."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Navigate to labels",
"teams": "Navigate to teams"
"teams": "Navigate to teams",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Un-Archive",
"setBackground": "Set background",
"share": "Share",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Notificações",
"none": "You don't have any notifications. Have a nice day!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Comandos",
@ -954,14 +892,12 @@
"teams": "Equipes",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Nova tarefa",
"newProject": "New project",
"newNamespace": "Novo namespace",
"newTeam": "Nova equipe"
}
},
@ -1017,16 +953,9 @@
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatenator.",
"4019": "Invalid task filter value.",
"5001": "The namespace does not exist.",
"5003": "You do not have access to the specified namespace.",
"5006": "The namespace name cannot be empty.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "The user is already a member of that team.",
"6006": "Cannot delete the last team member.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Boa Tarde {username}!",
"lastViewed": "Visto recentemente",
"project": {
"newText": "Podes criar um novo projeto para as tuas novas tarefas:",
"new": "Novo projeto",
"importText": "Ou importar os teus projetos e tarefas de outros serviços para o Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Importar os teus dados para o Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Eliminar a tua conta Vikunja",
"text1": "A eliminação da tua conta é permanente e não pode ser revertida. Vão ser eliminados todos os teus espaços, projetos, tarefas e tudo o que lhes está associado.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Para prosseguires, introduz por favor a tua palavra-passe. Receberás um e-mail com mais instruções.",
"confirm": "Eliminar a minha conta",
"requestSuccess": "A solicitação foi bem sucedida. Receberás um e-mail com mais instruções.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Exportar os teus dados do Vikunja",
"description": "Podes solicitar uma cópia de todos os teus dados do Vikunja. Isso inclui Espaços, Projetos, Tarefas e tudo o que lhes está associado. Podes importar esses dados em qualquer instância do Vikunja através da função de migração.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Por favor, introduz a tua palavra-passe para continuar:",
"request": "Solicitar uma cópia dos meus dados do Vikunja",
"success": "Solicitaste com sucesso os teus dados do Vikunja! Enviaremos um e-mail assim que estiverem prontos para download.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "Este projeto está arquivado. Não é possível editar ou criar novas tarefas para ele.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Título do Projeto",
"color": "Cor",
"projects": "Projetos",
"parent": "Parent Project",
"search": "Escreve para pesquisar por um projeto…",
"searchSelect": "Clica ou pressiona Enter para selecionar este projeto",
"shared": "Projetos Partilhados",
"noDescriptionAvailable": "Não está disponível nenhuma descrição do projeto.",
"inboxTitle": "Inbox",
"create": {
"header": "Novo projeto",
"titlePlaceholder": "O título do projeto será aqui…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicar este projeto",
"label": "Duplicar",
"text": "Selecione um espaço para colocar o projeto duplicado:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "O projeto foi duplicado com sucesso."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Espaços e Projetos",
"namespace": "Espaço",
"showArchived": "Mostrar Arquivados",
"noneAvailable": "Por enquanto não tens nenhum espaço.",
"unarchive": "Desarquivar",
"archived": "Arquivado",
"noProjects": "Este espaço não contém qualquer projeto.",
"createProject": "Criar uma novo projeto neste espaço.",
"namespaces": "Espaços",
"search": "Escreva para pesquisar por um espaço…",
"create": {
"title": "Novo espaço",
"titleRequired": "Por favor, especifica um título.",
"explanation": "Um espaço é uma coleção de projetos que podes partilhar e utilizar para organizar as tuas listas. De facto, cada projeto pertence a um espaço.",
"tooltip": "O que é um espaço?",
"success": "O espaço foi criado com sucesso."
},
"archive": {
"titleArchive": "Arquivar \"{namespace}\"",
"titleUnarchive": "Desarquivar \"{namespace}\"",
"archiveText": "Não será possível editar este espaço nem criar novos projetos enquanto não o desarquivares. Isto também irá arquivar todas os projetos existentes neste espaço.",
"unarchiveText": "Poderás criar novos projetos ou editá-los.",
"success": "O espaço foi arquivado com sucesso.",
"unarchiveSuccess": "O espaço foi desarquivado com sucesso.",
"description": "Se um espaço estiver arquivado, não poderás criar novos projetos ou editá-los."
},
"delete": {
"title": "Eliminar \"{namespace}\"",
"text1": "Tens a certeza que pretendes eliminar este espaço e todo o seu conteúdo?",
"text2": "Isto inclui todas os projetos e tarefas, e NÃO PODE SER REVERTIDO!",
"success": "O espaço foi eliminado com sucesso."
},
"edit": {
"title": "Editar \"{namespace}\"",
"success": "O espaço foi atualizado com sucesso."
},
"share": {
"title": "Partilhar \"{namespace}\""
},
"attributes": {
"title": "Título do Espaço",
"titlePlaceholder": "O título do espaço será aqui…",
"description": "Descrição",
"descriptionPlaceholder": "A descrição do espaço será aqui…",
"color": "Cor",
"archived": "Arquivado",
"isArchived": "O espaço está arquivado"
},
"pseudo": {
"sharedProjects": {
"title": "Projetos Partilhados"
},
"favorites": {
"title": "Favoritos"
},
"savedFilters": {
"title": "Filtros"
}
}
},
"filters": {
"title": "Filtros",
"clear": "Limpar Filtros",
@ -403,7 +344,7 @@
},
"create": {
"title": "Novo Filtro Memorizado",
"description": "Um filtro memorizado é uma lista virtual que é compilada a partir de um conjunto de filtros de cada vez que é acedido. Uma vez criado, irá aparecer num espaço especial.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Criar novo filtro memorizado",
"titleRequired": "Por favor, insere um título para o filtro."
},
@ -674,19 +615,13 @@
"updated": "Atualizado"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "Não podes cancelar a tua subscrição aqui porque estás subscrito neste projeto através do seu espaço.",
"subscribedTaskThroughParentNamespace": "Não podes cancelar a tua subscrição aqui porque estás subscrito nesta tarefa através do seu espaço.",
"subscribedTaskThroughParentProject": "Não podes cancelar a tua subscrição aqui porque estás subscrito nesta tarefa através do seu projeto.",
"subscribedNamespace": "Estás atualmente subscrito a este espaço e serás notificado de alterações.",
"notSubscribedNamespace": "Não estás subscrito a este espaço e não serás notificado de alterações.",
"subscribedProject": "Estás atualmente subscrito a este projeto e serás notificado de alterações.",
"notSubscribedProject": "Não estás subscrito a este projeto e não serás notificado de alterações.",
"subscribedTask": "Estás atualmente subscrito a esta tarefa e serás notificado de alterações.",
"notSubscribedTask": "Não estás subscrito a esta tarefa e não serás notificado de alterações.",
"subscribe": "Subscrever",
"unsubscribe": "Remover Subscrição",
"subscribeSuccessNamespace": "Estás agora subscrito a este espaço",
"unsubscribeSuccessNamespace": "Não estás mais subcrito a este espaço",
"subscribeSuccessProject": "Estás agora subscrito a este projeto",
"unsubscribeSuccessProject": "Não estás mais subcrito a este projeto",
"subscribeSuccessTask": "Estás agora subscrito a esta tarefa",
@ -763,7 +698,6 @@
"searchPlaceholder": "Escreve para pesquisar uma tarefa a adicionar como relacionada…",
"createPlaceholder": "Adicionar como nova tarefa relacionada",
"differentProject": "Esta tarefa pertence a um projeto diferente.",
"differentNamespace": "Esta tarefa pertence a um espaço diferente.",
"noneYet": "Ainda sem tarefas relacionadas.",
"delete": "Eliminar Relação Entre Tarefas",
"deleteText1": "Tens a certeza que pretendes eliminar esta relação entre tarefas?",
@ -848,19 +782,19 @@
"delete": {
"header": "Eliminar equipa",
"text1": "Tens a certeza que pretendes eliminar esta equipa e todos os seus membros?",
"text2": "Todos os membros da equipa perderão acesso aos projetos e espaços partilhados com esta equipa. Isto NÃO PODE SER REVERTIDO!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "A equipa foi eliminada com sucesso."
},
"deleteUser": {
"header": "Remover utilizador da equipa",
"text1": "Tens a certeza que pretendes remover este utilizador da equipa?",
"text2": "Eles perderão o acesso a todos os projetos e espaços a que esta equipa tem acesso. Isto NÃO PODER SER REVERTIDO!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "O utilizador foi removido da equipa com sucesso."
},
"leave": {
"title": "Sair da equipa",
"text1": "Tens a certeza de que queres sair desta equipa?",
"text2": "Vais perder o acesso a todos os projetos e espaços a que esta equipa tem acesso. Se mudares de ideias, vais necessitar que um administrador da equipa te adicione novamente.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "Saíste da equipa com sucesso."
}
},
@ -894,7 +828,10 @@
"color": "Alterar a cor desta tarefa",
"move": "Mover esta tarefa para outro projeto",
"reminder": "Gerir lembretes desta tarefa",
"description": "Alternar edição da descrição da tarefa"
"description": "Alternar edição da descrição da tarefa",
"delete": "Eliminar esta tarefa",
"priority": "Alterar a prioridade desta tarefa",
"favorite": "Marcar / Desmarcar esta tarefa como favorita"
},
"project": {
"title": "Vista do Projeto",
@ -907,9 +844,9 @@
"title": "Navegação",
"overview": "Ir para a vista geral",
"upcoming": "Ir para próximas tarefas",
"namespaces": "Ir para espaços e projetos",
"labels": "Navegar para etiquetas",
"teams": "Navegar para equipas"
"teams": "Navegar para equipas",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Desarquivar",
"setBackground": "Definir Fundo",
"share": "Partilhar",
"newProject": "Novo projeto"
"newProject": "Novo projeto",
"createProject": "Create project"
},
"apiConfig": {
"url": "URL do Vikunja",
@ -943,7 +881,7 @@
"notification": {
"title": "Notificações",
"none": "Não tens nenhuma notificação. Tem um bom dia!",
"explainer": "As notificações aparecerão aqui quando ocorrem ações em espaços, projetos ou tarefas às quais estejas subscrito."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Comandos",
@ -954,14 +892,12 @@
"teams": "Equipas",
"newProject": "Insere o título do novo espaço…",
"newTask": "Insere o título da nova tarefa…",
"newNamespace": "Insere o título do novo espaço…",
"newTeam": "Insere o nome da nova equipa…",
"createTask": "Cria uma tarefa no projeto atual ({title})",
"createProject": "Cria um projeto no espaço atual ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Nova tarefa",
"newProject": "Novo projeto",
"newNamespace": "Novo espaço",
"newTeam": "Nova equipa"
}
},
@ -1017,16 +953,9 @@
"4017": "Filtro de comparação de tarefas inválido.",
"4018": "Filtro de encademanto de tarefas inválido.",
"4019": "Valor de filtro de tarefas inválido.",
"5001": "O espaço não existe.",
"5003": "Não tens acesso ao espaço especificado.",
"5006": "O nome do espaço não pode estar vazio.",
"5009": "Precisas ter permissão de leitura deste espaço para executar essa ação.",
"5010": "Esta equipa não tem acesso a esse espaço.",
"5011": "Este utilizador já tem acesso a esse espaço.",
"5012": "O espaço está arquivado, portanto, só pode ser acedido para leitura.",
"6001": "O nome da equipa não pode estar vazio.",
"6002": "A equipa não existe.",
"6004": "A equipa tem já acesso a esse espaço ou projeto.",
"6004": "The team already has access to that project.",
"6005": "O utilizador é já membro dessa equipa.",
"6006": "Não podes eliminar o último membro da equipa.",
"6007": "A equipa não tem acesso ao projeto para executar essa ação.",
@ -1053,4 +982,4 @@
"frontendVersion": "Versão Atual: {version}",
"apiVersion": "Versão da API: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Last viewed",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "To proceed, please enter your password. You will receive an email with further instructions.",
"confirm": "Delete my account",
"requestSuccess": "The request was successful. You'll receive an email with further instructions.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Export your Vikunja data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Please enter your password to proceed:",
"request": "Request a copy of my Vikunja Data",
"success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Show Archived",
"noneAvailable": "You don't have any namespaces right now.",
"unarchive": "Un-Archive",
"archived": "Archived",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Type to search for a namespace…",
"create": {
"title": "New namespace",
"titleRequired": "Please specify a title.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "What's a namespace?",
"success": "The namespace was successfully created."
},
"archive": {
"titleArchive": "Archive \"{namespace}\"",
"titleUnarchive": "Un-Archive \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "The namespace was successfully archived.",
"unarchiveSuccess": "The namespace was successfully un-archived.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Delete \"{namespace}\"",
"text1": "Are you sure you want to delete this namespace and all of its contents?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "The namespace was successfully deleted."
},
"edit": {
"title": "Edit \"{namespace}\"",
"success": "The namespace was successfully updated."
},
"share": {
"title": "Share \"{namespace}\""
},
"attributes": {
"title": "Namespace Title",
"titlePlaceholder": "The namespace title goes here…",
"description": "Description",
"descriptionPlaceholder": "The namespaces description goes here…",
"color": "Color",
"archived": "Is Archived",
"isArchived": "This namespace is archived"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favorites"
},
"savedFilters": {
"title": "Filters"
}
}
},
"filters": {
"title": "Filters",
"clear": "Clear Filters",
@ -403,7 +344,7 @@
},
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Updated"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Add this as new related task",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "This task belongs to a different namespace.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
"deleteText1": "Are you sure you want to delete this task relation?",
@ -848,19 +782,19 @@
"delete": {
"header": "Delete the team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "The team was successfully deleted."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "The user was successfully deleted from the team."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Navigate to labels",
"teams": "Navigate to teams"
"teams": "Navigate to teams",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Un-Archive",
"setBackground": "Set background",
"share": "Share",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Notifications",
"none": "You don't have any notifications. Have a nice day!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commands",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "New task",
"newProject": "New project",
"newNamespace": "New namespace",
"newTeam": "New team"
}
},
@ -1017,16 +953,9 @@
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatenator.",
"4019": "Invalid task filter value.",
"5001": "The namespace does not exist.",
"5003": "You do not have access to the specified namespace.",
"5006": "The namespace name cannot be empty.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "The user is already a member of that team.",
"6006": "Cannot delete the last team member.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Добрый вечер, {username}!",
"lastViewed": "Последние просмотренные",
"project": {
"newText": "Вы можете создать новый проект для своих задач:",
"new": "Создать проект",
"importText": "Или импортировать проекты и задачи из других сервисов в Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Импорт данных в Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Удалить свой аккаунт VIkunja",
"text1": "Удаление аккаунта необратимо. Мы удалим все ваши пространства имён, проекты, задачи и всё связанное с ними.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Для продолжения введите свой пароль. На почту будет отправлено письмо с дальнейшими инструкциями.",
"confirm": "Удалить мой аккаунт",
"requestSuccess": "Запрос успешно выполнен. На почту будет отправлено письмо с дальнейшими инструкциями.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Экспорт данных Vikunja",
"description": "Вы можете запросить копию всех своих данных Vikunja. Это включает в себя пространства имён, проекты, задачи и всё связанное с ними. Эти данные можно будет импортировать на любом экземпляре Vikunja через функцию миграции.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Для продолжения введите свой пароль:",
"request": "Запросить копию моих данных Vikunja",
"success": "Данные Vikunja успешно запрошены! На почту придёт письмо, когда они будут готовы для скачивания.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "Этот проект архивирован. В нём нельзя создавать или изменять задачи.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Название проекта",
"color": "Цвет",
"projects": "Проекты",
"parent": "Parent Project",
"search": "Введите запрос для поиска проекта…",
"searchSelect": "Кликните или нажмите Enter для выбора этого проекта",
"shared": "Shared Projects",
"noDescriptionAvailable": "Описание проекта отсутствует.",
"inboxTitle": "Inbox",
"create": {
"header": "Создать проект",
"titlePlaceholder": "Введите название проекта…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Создание копии проекта",
"label": "Создать копию",
"text": "Пространство имён, в которое поместить копию проекта:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "Копия проекта создана."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Пространства имён и проекты",
"namespace": "Пространство имён",
"showArchived": "Показать архив",
"noneAvailable": "Пространств имён сейчас нет.",
"unarchive": "Вернуть из архива",
"archived": "Архивировано",
"noProjects": "В этом пространстве имён нет ни одного проекта.",
"createProject": "Создать новый проект в этом пространстве имён.",
"namespaces": "Пространства имён",
"search": "Введите запрос для поиска пространства имён…",
"create": {
"title": "Создать пространство имён",
"titleRequired": "Пожалуйста, укажите название.",
"explanation": "Это коллекция проектов, которым можно поделиться и который можно использовать для упорядочивания проектов. Фактически, каждый проект принадлежит какому-нибудь пространству имён.",
"tooltip": "Что такое пространство имён?",
"success": "Пространство имён создано."
},
"archive": {
"titleArchive": "Архивировать «{namespace}»",
"titleUnarchive": "Вернуть «{namespace}» из архива",
"archiveText": "Вы не сможете изменять это пространство имён, пока не вернёте его из архива. Это также касается всех проектов в этом пространстве имён.",
"unarchiveText": "Вы сможете создавать новые проекты или изменять их.",
"success": "Пространство имён архивировано.",
"unarchiveSuccess": "Пространство имён разархивировано.",
"description": "Архивирование пространства имён означает, что вы не сможете создавать в нём новые проекты или изменять их."
},
"delete": {
"title": "Удалить «{namespace}»",
"text1": "Удалить это пространство имён вместе со всем содержимым?",
"text2": "Это включает в себя все проекты и задачи, и отменить это будет нельзя!",
"success": "Пространство имён удалено."
},
"edit": {
"title": "Изменить «{namespace}»",
"success": "Пространство имён обновлено."
},
"share": {
"title": "Поделиться пространством имён «{namespace}»"
},
"attributes": {
"title": "Название пространства имён",
"titlePlaceholder": "Введи название пространства имён…",
"description": "Описание",
"descriptionPlaceholder": "Введи описание пространства имён…",
"color": "Цвет",
"archived": "Архивировано",
"isArchived": "Это пространство имён архивировано"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Избранное"
},
"savedFilters": {
"title": "Фильтры"
}
}
},
"filters": {
"title": "Фильтры",
"clear": "Сбросить фильтры",
@ -403,7 +344,7 @@
},
"create": {
"title": "Создать сохранённый фильтр",
"description": "Сохранённый фильтр — это виртуальный проект, построенный из набора фильтров. При создании отображается в специальном пространстве имён.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Создать новый сохранённый фильтр",
"titleRequired": "Укажите название фильтра."
},
@ -674,19 +615,13 @@
"updated": "Дата изменения"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "Вы не можете отписаться здесь, потому что вы подписаны на проект через его пространство имён.",
"subscribedTaskThroughParentNamespace": "Вы не можете отписаться здесь, потому что вы подписаны на эту задачу через её пространство имён.",
"subscribedTaskThroughParentProject": "Вы не можете отписаться здесь, потому что вы подписаны эту задачу через её проект.",
"subscribedNamespace": "Вы подписаны на это пространство имён и будете получать уведомления об изменениях.",
"notSubscribedNamespace": "Вы не подписаны на это пространство имён и не будете получать уведомления об изменениях.",
"subscribedProject": "Вы подписаны на этот проект и будете получать уведомления об изменениях.",
"notSubscribedProject": "Вы не подписаны на этот проект и не будете получать уведомления об изменениях.",
"subscribedTask": "Вы подписаны на эту задачу и будете получать уведомления об изменениях.",
"notSubscribedTask": "Вы не подписаны на эту задачу и не будете получать уведомления об изменениях.",
"subscribe": "Подписаться",
"unsubscribe": "Отписаться",
"subscribeSuccessNamespace": "Подписка на пространство имён оформлена",
"unsubscribeSuccessNamespace": "Подписка на пространство имён удалена",
"subscribeSuccessProject": "Подписка на проект оформлена",
"unsubscribeSuccessProject": "Подписка на проект удалена",
"subscribeSuccessTask": "Подписка на задачу оформлена",
@ -763,7 +698,6 @@
"searchPlaceholder": "Введи запрос для поиска задачи, чтобы добавить связь…",
"createPlaceholder": "Добавить как связанную задачу",
"differentProject": "Эта задача принадлежит другому проекту.",
"differentNamespace": "Эта задача принадлежит другому пространству имён.",
"noneYet": "Ещё нет связанных задач.",
"delete": "Удалить связь",
"deleteText1": "Удалить эту связь с задачей?",
@ -848,19 +782,19 @@
"delete": {
"header": "Удалить команду",
"text1": "Удалить эту команду вместе с участниками?",
"text2": "Все участники команды потеряют доступ к проектам и пространствам имён, которыми поделились с этой командой. Это действие отменить НЕЛЬЗЯ!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "Команда удалена."
},
"deleteUser": {
"header": "Удалить пользователя из команды",
"text1": "Удалить этого пользователя из команды?",
"text2": "Пользователь потеряет доступ ко всем проектам и пространствам имён, к которым есть доступ у команды. Это действие отменить нельзя!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "Пользователь удалён из команды."
},
"leave": {
"title": "Покинуть команду",
"text1": "Покинуть эту команду?",
"text2": "Вы потеряете доступ ко всем проектам и пространствам имён, к которым есть доступ у команды. Если вы передумаете, придётся просить администратора команды добавить вас снова.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "Вы покинули команду."
}
},
@ -894,7 +828,10 @@
"color": "Изменить цвет этой задачи",
"move": "Переместить эту задачу в другой проект",
"reminder": "Управление напоминаниями об этой задаче",
"description": "Включить изменение описания задачи"
"description": "Включить изменение описания задачи",
"delete": "Удалить задачу",
"priority": "Изменить приоритет задачи",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Просмотр проекта",
@ -907,9 +844,9 @@
"title": "Навигация",
"overview": "Перейти к странице обзора",
"upcoming": "Перейти к предстоящим задачам",
"namespaces": "Перейти к пространствам имён и проектам",
"labels": "Перейти к меткам",
"teams": "Перейти к командам"
"teams": "Перейти к командам",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Вернуть из архива",
"setBackground": "Задать фон",
"share": "Поделиться",
"newProject": "Создать проект"
"newProject": "Создать проект",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Уведомления",
"none": "Уведомлений нет. Хорошего дня!",
"explainer": "Здесь появятся уведомления, когда что-нибудь произойдёт с пространствами имён, проектами или задачами, на которые вы подписаны."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Команды",
@ -954,14 +892,12 @@
"teams": "Команды",
"newProject": "Введите название проекта…",
"newTask": "Введите название задачи…",
"newNamespace": "Введите название пространства имён…",
"newTeam": "Введите название новой команды…",
"createTask": "Создать задачу в текущем проекте ({title})",
"createProject": "Создать проект в текущем пространстве имён ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Новая задача",
"newProject": "Создать проект",
"newNamespace": "Новое пространство имён",
"newTeam": "Новая команда"
}
},
@ -1017,16 +953,9 @@
"4017": "Неверный сравнитель фильтров задач.",
"4018": "Неверный соединитель фильтров задач.",
"4019": "Неверное значение фильтра задач.",
"5001": "Пространство имён не существует.",
"5003": "Нет доступа к указанному пространству имён.",
"5006": "Название пространства имён не может быть пустым.",
"5009": "Для этого действия необходим доступ на чтение пространства имён.",
"5010": "У этой команды нет доступа к этому пространству имён.",
"5011": "Этот пользователь уже имеет доступ к этому пространству имён.",
"5012": "Это пространство имён архивировано и поэтому доступно только для чтения.",
"6001": "Имя команды не может быть пустым.",
"6002": "Команда не существует.",
"6004": "Эта команда уже имеет доступ к этому пространству имён или проекту.",
"6004": "The team already has access to that project.",
"6005": "Пользователь уже является участником этой команды.",
"6006": "Нельзя удалить последнего участника команды.",
"6007": "У команды нет доступа к проекту, чтобы выполнить это действие.",
@ -1053,4 +982,4 @@
"frontendVersion": "Версия фронтенда: {version}",
"apiVersion": "Версия API: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Last viewed",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "To proceed, please enter your password. You will receive an email with further instructions.",
"confirm": "Delete my account",
"requestSuccess": "The request was successful. You'll receive an email with further instructions.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Export your Vikunja data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Please enter your password to proceed:",
"request": "Request a copy of my Vikunja Data",
"success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Show Archived",
"noneAvailable": "You don't have any namespaces right now.",
"unarchive": "Un-Archive",
"archived": "Archived",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Type to search for a namespace…",
"create": {
"title": "New namespace",
"titleRequired": "Please specify a title.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "What's a namespace?",
"success": "The namespace was successfully created."
},
"archive": {
"titleArchive": "Archive \"{namespace}\"",
"titleUnarchive": "Un-Archive \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "The namespace was successfully archived.",
"unarchiveSuccess": "The namespace was successfully un-archived.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Delete \"{namespace}\"",
"text1": "Are you sure you want to delete this namespace and all of its contents?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "The namespace was successfully deleted."
},
"edit": {
"title": "Edit \"{namespace}\"",
"success": "The namespace was successfully updated."
},
"share": {
"title": "Share \"{namespace}\""
},
"attributes": {
"title": "Namespace Title",
"titlePlaceholder": "The namespace title goes here…",
"description": "Description",
"descriptionPlaceholder": "The namespaces description goes here…",
"color": "Color",
"archived": "Is Archived",
"isArchived": "This namespace is archived"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favorites"
},
"savedFilters": {
"title": "Filters"
}
}
},
"filters": {
"title": "Filters",
"clear": "Clear Filters",
@ -403,7 +344,7 @@
},
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Updated"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Add this as new related task",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "This task belongs to a different namespace.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
"deleteText1": "Are you sure you want to delete this task relation?",
@ -848,19 +782,19 @@
"delete": {
"header": "Delete the team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "The team was successfully deleted."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "The user was successfully deleted from the team."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Navigate to labels",
"teams": "Navigate to teams"
"teams": "Navigate to teams",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Un-Archive",
"setBackground": "Set background",
"share": "Share",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Notifications",
"none": "You don't have any notifications. Have a nice day!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commands",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "New task",
"newProject": "New project",
"newNamespace": "New namespace",
"newTeam": "New team"
}
},
@ -1017,16 +953,9 @@
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatenator.",
"4019": "Invalid task filter value.",
"5001": "The namespace does not exist.",
"5003": "You do not have access to the specified namespace.",
"5006": "The namespace name cannot be empty.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "The user is already a member of that team.",
"6006": "Cannot delete the last team member.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Last viewed",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "To proceed, please enter your password. You will receive an email with further instructions.",
"confirm": "Delete my account",
"requestSuccess": "The request was successful. You'll receive an email with further instructions.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Export your Vikunja data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Please enter your password to proceed:",
"request": "Request a copy of my Vikunja Data",
"success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Show Archived",
"noneAvailable": "You don't have any namespaces right now.",
"unarchive": "Un-Archive",
"archived": "Archived",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Type to search for a namespace…",
"create": {
"title": "New namespace",
"titleRequired": "Please specify a title.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "What's a namespace?",
"success": "The namespace was successfully created."
},
"archive": {
"titleArchive": "Archive \"{namespace}\"",
"titleUnarchive": "Un-Archive \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "The namespace was successfully archived.",
"unarchiveSuccess": "The namespace was successfully un-archived.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Delete \"{namespace}\"",
"text1": "Are you sure you want to delete this namespace and all of its contents?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "The namespace was successfully deleted."
},
"edit": {
"title": "Edit \"{namespace}\"",
"success": "The namespace was successfully updated."
},
"share": {
"title": "Share \"{namespace}\""
},
"attributes": {
"title": "Namespace Title",
"titlePlaceholder": "The namespace title goes here…",
"description": "Description",
"descriptionPlaceholder": "The namespaces description goes here…",
"color": "Color",
"archived": "Is Archived",
"isArchived": "This namespace is archived"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favorites"
},
"savedFilters": {
"title": "Filters"
}
}
},
"filters": {
"title": "Filters",
"clear": "Clear Filters",
@ -403,7 +344,7 @@
},
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Updated"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Add this as new related task",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "This task belongs to a different namespace.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
"deleteText1": "Are you sure you want to delete this task relation?",
@ -848,19 +782,19 @@
"delete": {
"header": "Delete the team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "The team was successfully deleted."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "The user was successfully deleted from the team."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Navigate to labels",
"teams": "Navigate to teams"
"teams": "Navigate to teams",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Un-Archive",
"setBackground": "Set background",
"share": "Share",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Notifications",
"none": "You don't have any notifications. Have a nice day!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commands",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "New task",
"newProject": "New project",
"newNamespace": "New namespace",
"newTeam": "New team"
}
},
@ -1017,16 +953,9 @@
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatenator.",
"4019": "Invalid task filter value.",
"5001": "The namespace does not exist.",
"5003": "You do not have access to the specified namespace.",
"5006": "The namespace name cannot be empty.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "The user is already a member of that team.",
"6006": "Cannot delete the last team member.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Last viewed",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "To proceed, please enter your password. You will receive an email with further instructions.",
"confirm": "Delete my account",
"requestSuccess": "The request was successful. You'll receive an email with further instructions.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Export your Vikunja data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Please enter your password to proceed:",
"request": "Request a copy of my Vikunja Data",
"success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Show Archived",
"noneAvailable": "You don't have any namespaces right now.",
"unarchive": "Un-Archive",
"archived": "Archived",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Type to search for a namespace…",
"create": {
"title": "New namespace",
"titleRequired": "Please specify a title.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "What's a namespace?",
"success": "The namespace was successfully created."
},
"archive": {
"titleArchive": "Archive \"{namespace}\"",
"titleUnarchive": "Un-Archive \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "The namespace was successfully archived.",
"unarchiveSuccess": "The namespace was successfully un-archived.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Delete \"{namespace}\"",
"text1": "Are you sure you want to delete this namespace and all of its contents?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "The namespace was successfully deleted."
},
"edit": {
"title": "Edit \"{namespace}\"",
"success": "The namespace was successfully updated."
},
"share": {
"title": "Share \"{namespace}\""
},
"attributes": {
"title": "Namespace Title",
"titlePlaceholder": "The namespace title goes here…",
"description": "Description",
"descriptionPlaceholder": "The namespaces description goes here…",
"color": "Color",
"archived": "Is Archived",
"isArchived": "This namespace is archived"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favorites"
},
"savedFilters": {
"title": "Filters"
}
}
},
"filters": {
"title": "Filters",
"clear": "Clear Filters",
@ -403,7 +344,7 @@
},
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Updated"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Add this as new related task",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "This task belongs to a different namespace.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
"deleteText1": "Are you sure you want to delete this task relation?",
@ -848,19 +782,19 @@
"delete": {
"header": "Delete the team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "The team was successfully deleted."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "The user was successfully deleted from the team."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Navigate to labels",
"teams": "Navigate to teams"
"teams": "Navigate to teams",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Un-Archive",
"setBackground": "Set background",
"share": "Share",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Notifications",
"none": "You don't have any notifications. Have a nice day!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commands",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "New task",
"newProject": "New project",
"newNamespace": "New namespace",
"newTeam": "New team"
}
},
@ -1017,16 +953,9 @@
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatenator.",
"4019": "Invalid task filter value.",
"5001": "The namespace does not exist.",
"5003": "You do not have access to the specified namespace.",
"5006": "The namespace name cannot be empty.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "The user is already a member of that team.",
"6006": "Cannot delete the last team member.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Last viewed",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "To proceed, please enter your password. You will receive an email with further instructions.",
"confirm": "Delete my account",
"requestSuccess": "The request was successful. You'll receive an email with further instructions.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Export your Vikunja data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Please enter your password to proceed:",
"request": "Request a copy of my Vikunja Data",
"success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Show Archived",
"noneAvailable": "You don't have any namespaces right now.",
"unarchive": "Un-Archive",
"archived": "Archived",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Type to search for a namespace…",
"create": {
"title": "New namespace",
"titleRequired": "Please specify a title.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "What's a namespace?",
"success": "The namespace was successfully created."
},
"archive": {
"titleArchive": "Archive \"{namespace}\"",
"titleUnarchive": "Un-Archive \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "The namespace was successfully archived.",
"unarchiveSuccess": "The namespace was successfully un-archived.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Delete \"{namespace}\"",
"text1": "Are you sure you want to delete this namespace and all of its contents?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "The namespace was successfully deleted."
},
"edit": {
"title": "Edit \"{namespace}\"",
"success": "The namespace was successfully updated."
},
"share": {
"title": "Share \"{namespace}\""
},
"attributes": {
"title": "Namespace Title",
"titlePlaceholder": "The namespace title goes here…",
"description": "Description",
"descriptionPlaceholder": "The namespaces description goes here…",
"color": "Color",
"archived": "Is Archived",
"isArchived": "This namespace is archived"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favorites"
},
"savedFilters": {
"title": "Filters"
}
}
},
"filters": {
"title": "Filters",
"clear": "Clear Filters",
@ -403,7 +344,7 @@
},
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Updated"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Add this as new related task",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "This task belongs to a different namespace.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
"deleteText1": "Are you sure you want to delete this task relation?",
@ -848,19 +782,19 @@
"delete": {
"header": "Delete the team",
"text1": "Are you sure you want to delete this team and all of its members?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "The team was successfully deleted."
},
"deleteUser": {
"header": "Remove a user from the team",
"text1": "Are you sure you want to remove this user from the team?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "The user was successfully deleted from the team."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Navigate to labels",
"teams": "Navigate to teams"
"teams": "Navigate to teams",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Un-Archive",
"setBackground": "Set background",
"share": "Share",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -943,7 +881,7 @@
"notification": {
"title": "Notifications",
"none": "You don't have any notifications. Have a nice day!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Commands",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "New task",
"newProject": "New project",
"newNamespace": "New namespace",
"newTeam": "New team"
}
},
@ -1017,16 +953,9 @@
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatenator.",
"4019": "Invalid task filter value.",
"5001": "The namespace does not exist.",
"5003": "You do not have access to the specified namespace.",
"5006": "The namespace name cannot be empty.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "The user is already a member of that team.",
"6006": "Cannot delete the last team member.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Xem gần đây",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Xóa tài khoản của bạn",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "Để tiếp tục, vui lòng nhập mật khẩu của bạn. Bạn sẽ nhận được một email hướng dẫn thêm.",
"confirm": "Xóa tài khoản của tôi",
"requestSuccess": "Yêu cầu đã thành công. Bạn sẽ nhận được một email hướng dẫn thêm.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Xuất dữ liệu Vikunja của bạn",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Vui lòng nhập mật khẩu của bạn để tiếp tục:",
"request": "Yêu cầu một bản sao Dữ liệu Vikunja của tôi",
"success": "Bạn đã yêu cầu dữ liệu Vikunja của mình thành công! Chúng tôi sẽ gửi cho bạn một email sau khi nó sẵn sàng để tải xuống.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Góc làm việc",
"showArchived": "Hiển thị đã lưu trữ",
"noneAvailable": "Bạn không có bất kỳ góc làm việc nào.",
"unarchive": "Bỏ lưu trữ",
"archived": "Đã lưu trữ",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Góc làm việc",
"search": "Gõ để tìm kiếm một góc làm việc…",
"create": {
"title": "Góc làm việc mới",
"titleRequired": "Hãy đặt một tiêu đề.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "Góc làm việc là gì?",
"success": "Góc làm việc đã được tạo."
},
"archive": {
"titleArchive": "Lưu trữ \"{namespace}\"",
"titleUnarchive": "Bỏ lưu trữ \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "Góc làm việc đã lưu trữ thành công.",
"unarchiveSuccess": "Góc làm việc đã được bỏ lưu trữ thành công.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Xóa \"{namespace}\"",
"text1": "Bạn có chắc muốn loại bỏ góc làm việc này và tất cả nội dung của nó không?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "Góc làm việc đã được loại bỏ."
},
"edit": {
"title": "Chỉnh sửa \"{namespace}\"",
"success": "Góc làm việc đã được làm mới."
},
"share": {
"title": "Chia sẻ \"{namespace}\""
},
"attributes": {
"title": "Tên Góc làm việc",
"titlePlaceholder": "Tên góc làm việc ở đây…",
"description": "Mô tả",
"descriptionPlaceholder": "Mô tả góc làm việc ở đây…",
"color": "Màu sắc",
"archived": "Được lưu trữ",
"isArchived": "Góc làm việc này đã được lưu trữ"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Ưa thích"
},
"savedFilters": {
"title": "Bộ lọc"
}
}
},
"filters": {
"title": "Bộ lọc",
"clear": "Xoá các bộ lọc",
@ -403,7 +344,7 @@
},
"create": {
"title": "Bộ lọc đã lưu mới",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Tạo thêm bộ lọc sẵn",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Đã cập nhật"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Theo dõi",
"unsubscribe": "Bỏ theo dõi",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Gõ tìm kiếm một công việc để thêm dưới dạng liên quan…",
"createPlaceholder": "Thêm điều này làm công việc liên quan mới",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "Công việc này thuộc về một Góc làm việc khác.",
"noneYet": "Không có công việc liên quan nào.",
"delete": "Xóa công việc liên quan",
"deleteText1": "Bạn có chắc muốn xóa công việc liên quan này không?",
@ -848,19 +782,19 @@
"delete": {
"header": "Giải tán Team",
"text1": "Bạn có chắc giải tán Team này không?",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"text2": "All team members will lose access to projects shared with this team. This CANNOT BE UNDONE!",
"success": "Team đã giải tán."
},
"deleteUser": {
"header": "Đưa thành viên ra khỏi Team",
"text1": "Bạn có chắc muốn đưa thành viên này ra khỏi Team không?",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"text2": "They will lose access to all projects this team has access to. This CANNOT BE UNDONE!",
"success": "Thành viên đã rời khỏi Team."
},
"leave": {
"title": "Leave team",
"text1": "Are you sure you want to leave this team?",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"text2": "You will lose access to all projects this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "You have successfully left the team."
}
},
@ -894,7 +828,10 @@
"color": "Thay đổi màu công việc này",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Điều hướng",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Điều hướng đến nhãn",
"teams": "Điều hướng đến Team"
"teams": "Điều hướng đến Team",
"projects": "Navigate to projects"
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Bỏ lưu trữ",
"setBackground": "Cài hình nền",
"share": "Chia sẻ",
"newProject": "New project"
"newProject": "New project",
"createProject": "Create project"
},
"apiConfig": {
"url": "URL Vikunja",
@ -943,7 +881,7 @@
"notification": {
"title": "Thông báo",
"none": "Bạn không có thông báo nào. Chúc một ngày tốt lành!",
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
"explainer": "Notifications will appear here when actions projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Các lệnh",
@ -954,14 +892,12 @@
"teams": "Team",
"newProject": "Enter the title of the new project…",
"newTask": "Đặt tên cho tác vụ mới…",
"newNamespace": "Nhập tên của Góc làm việc mới…",
"newTeam": "Đặt tên cho đội nhóm mới…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"createProject": "Create a project",
"cmds": {
"newTask": "Tác vụ mới",
"newProject": "New project",
"newNamespace": "Góc làm việc mới",
"newTeam": "Team mới"
}
},
@ -1017,16 +953,9 @@
"4017": "Bộ so sánh bộ lọc công việc không hợp lệ.",
"4018": "Bộ lọc kết hợp không hợp lệ.",
"4019": "Giá trị bộ lọc công việc không hợp lệ.",
"5001": "Góc làm việc không có nữa.",
"5003": "Bạn chưa được phép bước vào vào góc làm việc được chỉ định.",
"5006": "Góc làm việc cần có một cái tên.",
"5009": "Bạn cần có quyền đọc với góc làm việc để thực hiện hành động đó.",
"5010": "Team này không có quyền bước vào góc làm việc đó.",
"5011": "Người này đã có quyền bước vào góc làm việc đó.",
"5012": "Góc làm việc đã được lưu trữ nên chỉ có thể vào đó để đọc.",
"6001": "Tên của Team không được để trống.",
"6002": "Team không tồn tại.",
"6004": "The team already has access to that namespace or project.",
"6004": "The team already has access to that project.",
"6005": "Người này đã là thành viên của Team đó rồi.",
"6006": "Không thể loại bỏ thành viên cuối cùng của Team.",
"6007": "The team does not have access to the project to perform that action.",
@ -1053,4 +982,4 @@
"frontendVersion": "Phiên bản giao diện người dùng: {version}",
"apiVersion": "Phiên bản API: {version}"
}
}
}

View File

@ -894,7 +894,10 @@
"color": "更改此任务的颜色",
"move": "Move this task to another project",
"reminder": "管理此任务的提醒",
"description": "切换编辑时的任务描述"
"description": "切换编辑时的任务描述",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -1053,4 +1056,4 @@
"frontendVersion": "前端版本:{version}",
"apiVersion": "API 版本:{version}"
}
}
}

View File

@ -6,9 +6,7 @@
"welcomeEvening": "Good Evening {username}!",
"lastViewed": "Last viewed",
"project": {
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"importText": "Import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
@ -143,7 +141,7 @@
},
"deletion": {
"title": "Delete your Vikunja Account",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your projects, tasks and everything associated with it.",
"text2": "To proceed, please enter your password. You will receive an email with further instructions.",
"confirm": "Delete my account",
"requestSuccess": "The request was successful. You'll receive an email with further instructions.",
@ -157,7 +155,7 @@
},
"export": {
"title": "Export your Vikunja data",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"description": "You can request a copy of all your Vikunja data. This includes Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Please enter your password to proceed:",
"request": "Request a copy of my Vikunja Data",
"success": "You've successfully requested your Vikunja Data! We will send you an email once it's ready to download.",
@ -165,14 +163,18 @@
}
},
"project": {
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"archivedMessage": "This project is archived. It is not possible to create new or edit tasks for it.",
"archived": "Archived",
"showArchived": "Show Archived",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"parent": "Parent Project",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"inboxTitle": "Inbox",
"create": {
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
@ -210,7 +212,7 @@
"duplicate": {
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"text": "Select a parent project which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
@ -321,67 +323,6 @@
}
}
},
"namespace": {
"title": "Namespaces & Projects",
"namespace": "Namespace",
"showArchived": "Show Archived",
"noneAvailable": "You don't have any namespaces right now.",
"unarchive": "Un-Archive",
"archived": "Archived",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Namespaces",
"search": "Type to search for a namespace…",
"create": {
"title": "New namespace",
"titleRequired": "Please specify a title.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "What's a namespace?",
"success": "The namespace was successfully created."
},
"archive": {
"titleArchive": "Archive \"{namespace}\"",
"titleUnarchive": "Un-Archive \"{namespace}\"",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "The namespace was successfully archived.",
"unarchiveSuccess": "The namespace was successfully un-archived.",
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Delete \"{namespace}\"",
"text1": "Are you sure you want to delete this namespace and all of its contents?",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "The namespace was successfully deleted."
},
"edit": {
"title": "Edit \"{namespace}\"",
"success": "The namespace was successfully updated."
},
"share": {
"title": "Share \"{namespace}\""
},
"attributes": {
"title": "Namespace Title",
"titlePlaceholder": "The namespace title goes here…",
"description": "Description",
"descriptionPlaceholder": "The namespaces description goes here…",
"color": "Color",
"archived": "Is Archived",
"isArchived": "This namespace is archived"
},
"pseudo": {
"sharedProjects": {
"title": "Shared Projects"
},
"favorites": {
"title": "Favorites"
},
"savedFilters": {
"title": "Filters"
}
}
},
"filters": {
"title": "Filters",
"clear": "Clear Filters",
@ -403,7 +344,7 @@
},
"create": {
"title": "New Saved Filter",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed.",
"action": "Create new saved filter",
"titleRequired": "Please provide a title for the filter."
},
@ -674,19 +615,13 @@
"updated": "Updated"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "You are now subscribed to this task",
@ -763,7 +698,6 @@
"searchPlaceholder": "Type search for a new task to add as related…",
"createPlaceholder": "Add this as new related task",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "This task belongs to a different namespace.",
"noneYet": "No task relations yet.",
"delete": "Delete Task Relation",
"deleteText1": "Are you sure you want to delete this task relation?",
@ -894,7 +828,10 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description"
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
},
"project": {
"title": "Project Views",
@ -907,9 +844,9 @@
"title": "Navigation",
"overview": "Navigate to overview",
"upcoming": "Navigate to upcoming tasks",
"namespaces": "Navigate to namespaces & projects",
"labels": "Navigate to labels",
"teams": "Navigate to teams"
"teams": "Navigate to teams",
"projects": ""
}
},
"update": {
@ -924,7 +861,8 @@
"unarchive": "Un-Archive",
"setBackground": "Set background",
"share": "Share",
"newProject": "New project"
"newProject": "New project",
"createProject": ""
},
"apiConfig": {
"url": "Vikunja URL",
@ -954,14 +892,12 @@
"teams": "Teams",
"newProject": "Enter the title of the new project…",
"newTask": "Enter the title of the new task…",
"newNamespace": "Enter the title of the new namespace…",
"newTeam": "Enter the name of the new team…",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"cmds": {
"newTask": "New task",
"newProject": "New project",
"newNamespace": "New namespace",
"newTeam": "New team"
}
},
@ -1017,13 +953,6 @@
"4017": "Invalid task filter comparator.",
"4018": "Invalid task filter concatenator.",
"4019": "Invalid task filter value.",
"5001": "The namespace does not exist.",
"5003": "You do not have access to the specified namespace.",
"5006": "The namespace name cannot be empty.",
"5009": "You need to have namespace read access to perform that action.",
"5010": "This team does not have access to that namespace.",
"5011": "This user has already access to that namespace.",
"5012": "The namespace is archived and can therefore only be accessed read only.",
"6001": "The team name cannot be empty.",
"6002": "The team does not exist.",
"6004": "The team already has access to that namespace or project.",
@ -1053,4 +982,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -23,6 +23,7 @@ declare global {
API_URL: string;
SENTRY_ENABLED: boolean;
SENTRY_DSN: string;
PROJECT_INFINITE_NESTING_ENABLED: boolean;
}
}

View File

@ -1,18 +0,0 @@
import type {IAbstract} from './IAbstract'
import type {IProject} from './IProject'
import type {IUser} from './IUser'
import type {ISubscription} from './ISubscription'
export interface INamespace extends IAbstract {
id: number
title: string
description: string
owner: IUser
projects: IProject[]
isArchived: boolean
hexColor: string
subscription: ISubscription
created: Date
updated: Date
}

View File

@ -2,7 +2,6 @@ import type {IAbstract} from './IAbstract'
import type {ITask} from './ITask'
import type {IUser} from './IUser'
import type {ISubscription} from './ISubscription'
import type {INamespace} from './INamespace'
export interface IProject extends IAbstract {
@ -11,7 +10,6 @@ export interface IProject extends IAbstract {
description: string
owner: IUser
tasks: ITask[]
namespaceId: INamespace['id']
isArchived: boolean
hexColor: string
identifier: string
@ -20,6 +18,7 @@ export interface IProject extends IAbstract {
subscription: ISubscription
position: number
backgroundBlurHash: string
parentProjectId: number
created: Date
updated: Date

View File

@ -1,9 +1,8 @@
import type {IAbstract} from './IAbstract'
import type {IProject} from './IProject'
import type {INamespace} from './INamespace'
export interface IProjectDuplicate extends IAbstract {
projectId: number
namespaceId: INamespace['id']
project: IProject
parentProjectId: IProject['id']
}

View File

@ -1,6 +0,0 @@
import type {ITeamShareBase} from './ITeamShareBase'
import type {INamespace} from './INamespace'
export interface ITeamNamespace extends ITeamShareBase {
namespaceId: INamespace['id']
}

View File

@ -1,6 +0,0 @@
import type {IUserShareBase} from './IUserShareBase'
import type {INamespace} from './INamespace'
export interface IUserNamespace extends IUserShareBase {
namespaceId: INamespace['id']
}

View File

@ -1,45 +0,0 @@
import AbstractModel from './abstractModel'
import ProjectModel from './project'
import UserModel from './user'
import SubscriptionModel from '@/models/subscription'
import type {INamespace} from '@/modelTypes/INamespace'
import type {IUser} from '@/modelTypes/IUser'
import type {IProject} from '@/modelTypes/IProject'
import type {ISubscription} from '@/modelTypes/ISubscription'
export default class NamespaceModel extends AbstractModel<INamespace> implements INamespace {
id = 0
title = ''
description = ''
owner: IUser = UserModel
projects: IProject[] = []
isArchived = false
hexColor = ''
subscription: ISubscription = null
created: Date = null
updated: Date = null
constructor(data: Partial<INamespace> = {}) {
super()
this.assignData(data)
if (this.hexColor !== '' && this.hexColor.substring(0, 1) !== '#') {
this.hexColor = '#' + this.hexColor
}
this.projects = this.projects.map(l => {
return new ProjectModel(l)
})
this.owner = new UserModel(this.owner)
if(typeof this.subscription !== 'undefined' && this.subscription !== null) {
this.subscription = new SubscriptionModel(this.subscription)
}
this.created = new Date(this.created)
this.updated = new Date(this.updated)
}
}

View File

@ -6,7 +6,6 @@ import SubscriptionModel from '@/models/subscription'
import type {IProject} from '@/modelTypes/IProject'
import type {IUser} from '@/modelTypes/IUser'
import type {ITask} from '@/modelTypes/ITask'
import type {INamespace} from '@/modelTypes/INamespace'
import type {ISubscription} from '@/modelTypes/ISubscription'
export default class ProjectModel extends AbstractModel<IProject> implements IProject {
@ -15,7 +14,6 @@ export default class ProjectModel extends AbstractModel<IProject> implements IPr
description = ''
owner: IUser = UserModel
tasks: ITask[] = []
namespaceId: INamespace['id'] = 0
isArchived = false
hexColor = ''
identifier = ''
@ -24,6 +22,7 @@ export default class ProjectModel extends AbstractModel<IProject> implements IPr
subscription: ISubscription = null
position = 0
backgroundBlurHash = ''
parentProjectId = 0
created: Date = null
updated: Date = null
@ -46,7 +45,7 @@ export default class ProjectModel extends AbstractModel<IProject> implements IPr
if (typeof this.subscription !== 'undefined' && this.subscription !== null) {
this.subscription = new SubscriptionModel(this.subscription)
}
this.created = new Date(this.created)
this.updated = new Date(this.updated)
}

View File

@ -2,13 +2,12 @@ import AbstractModel from './abstractModel'
import ProjectModel from './project'
import type {IProjectDuplicate} from '@/modelTypes/IProjectDuplicate'
import type {INamespace} from '@/modelTypes/INamespace'
import type {IProject} from '@/modelTypes/IProject'
export default class ProjectDuplicateModel extends AbstractModel<IProjectDuplicate> implements IProjectDuplicate {
projectId = 0
namespaceId: INamespace['id'] = 0
project: IProject = ProjectModel
parentProjectId = 0
constructor(data : Partial<IProjectDuplicate>) {
super()

View File

@ -23,11 +23,6 @@ import SubscriptionModel from './subscription'
export const TASK_DEFAULT_COLOR = '#1973ff'
const SUPPORTS_TRIGGERED_NOTIFICATION = 'Notification' in window && 'showTrigger' in Notification.prototype
if (!SUPPORTS_TRIGGERED_NOTIFICATION) {
console.debug('This browser does not support triggered notifications')
}
export function getHexColor(hexColor: string): string {
if (hexColor === '' || hexColor === '#') {
return TASK_DEFAULT_COLOR
@ -122,12 +117,6 @@ export default class TaskModel extends AbstractModel<ITask> implements ITask {
this.reminderDates = this.reminderDates.map(d => new Date(d))
// Cancel all scheduled notifications for this task to be sure to only have available notifications
this.cancelScheduledNotifications().then(() => {
// Every time we see a reminder, we schedule a notification for it
this.reminderDates.forEach(d => this.scheduleNotification(d))
})
if (this.hexColor !== '' && this.hexColor.substring(0, 1) !== '#') {
this.hexColor = '#' + this.hexColor
}
@ -169,83 +158,5 @@ export default class TaskModel extends AbstractModel<ITask> implements ITask {
getHexColor() {
return getHexColor(this.hexColor)
}
/////////////////
// Helper functions
///////////////
async cancelScheduledNotifications() {
if (!SUPPORTS_TRIGGERED_NOTIFICATION) {
return
}
if (typeof navigator.serviceWorker === 'undefined') {
console.debug('Service Worker not available')
return
}
const registration = await navigator.serviceWorker.getRegistration()
if (typeof registration === 'undefined') {
return
}
// Get all scheduled notifications for this task and cancel them
const scheduledNotifications = await registration.getNotifications({
tag: `vikunja-task-${this.id}`,
includeTriggered: true,
})
console.debug('Already scheduled notifications:', scheduledNotifications)
scheduledNotifications.forEach(n => n.close())
}
async scheduleNotification(date) {
if (typeof navigator.serviceWorker === 'undefined') {
console.debug('Service Worker not available')
return
}
if (date < new Date()) {
console.debug('Date is in the past, not scheduling a notification. Date is ', date)
return
}
if (!SUPPORTS_TRIGGERED_NOTIFICATION) {
return
}
const {state} = await navigator.permissions.request({name: 'notifications'})
if (state !== 'granted') {
console.debug('Notification permission not granted, not showing notifications')
return
}
const registration = await navigator.serviceWorker.getRegistration()
if (typeof registration === 'undefined') {
console.error('No service worker registration available')
return
}
// Register the actual notification
try {
registration.showNotification('Vikunja Reminder', {
tag: `vikunja-task-${this.id}`, // Group notifications by task id so we're only showing one notification per task
body: this.title,
// eslint-disable-next-line no-undef
showTrigger: new TimestampTrigger(date),
badge: '/images/icons/badge-monochrome.png',
icon: '/images/icons/android-chrome-512x512.png',
data: {taskId: this.id},
actions: [
{
action: 'show-task',
title: 'Show task',
},
],
})
console.debug('Notification scheduled for ' + date)
} catch (e) {
throw new Error('Error scheduling notification', e)
}
}
}

View File

@ -1,13 +0,0 @@
import TeamShareBaseModel from './teamShareBase'
import type {ITeamNamespace} from '@/modelTypes/ITeamNamespace'
import type {INamespace} from '@/modelTypes/INamespace'
export default class TeamNamespaceModel extends TeamShareBaseModel implements ITeamNamespace {
namespaceId: INamespace['id'] = 0
constructor(data: Partial<ITeamNamespace>) {
super(data)
this.assignData(data)
}
}

View File

@ -6,7 +6,7 @@ import type {ITeam} from '@/modelTypes/ITeam'
/**
* This class is a base class for common team sharing model.
* It is extended in a way so it can be used for namespaces as well for projects.
* It is extended in a way, so it can be used for projects.
*/
export default class TeamShareBaseModel extends AbstractModel<ITeamShareBase> implements ITeamShareBase {
teamId: ITeam['id'] = 0

View File

@ -1,14 +0,0 @@
import UserShareBaseModel from './userShareBase'
import type {INamespace} from '@/modelTypes/INamespace'
import type {IUserNamespace} from '@/modelTypes/IUserNamespace'
// This class extends the user share model with a 'rights' parameter which is used in sharing
export default class UserNamespaceModel extends UserShareBaseModel implements IUserNamespace {
namespaceId: INamespace['id'] = 0
constructor(data: Partial<IUserNamespace>) {
super(data)
this.assignData(data)
}
}

View File

@ -22,7 +22,6 @@ const DataExportDownload = () => import('@/views/user/DataExportDownload.vue')
// Tasks
import UpcomingTasksComponent from '@/views/tasks/ShowTasks.vue'
import LinkShareAuthComponent from '@/views/sharing/LinkSharingAuth.vue'
const ListNamespaces = () => import('@/views/namespaces/ListNamespaces.vue')
const TaskDetailView = () => import('@/views/tasks/TaskDetailView.vue')
// Team Handling
@ -41,6 +40,7 @@ const ProjectKanban = () => import('@/views/project/ProjectKanban.vue')
const ProjectInfo = () => import('@/views/project/ProjectInfo.vue')
// Project Settings
const ListProjects = () => import('@/views/project/ListProjects.vue')
const ProjectSettingEdit = () => import('@/views/project/settings/edit.vue')
const ProjectSettingBackground = () => import('@/views/project/settings/background.vue')
const ProjectSettingDuplicate = () => import('@/views/project/settings/duplicate.vue')
@ -48,12 +48,6 @@ const ProjectSettingShare = () => import('@/views/project/settings/share.vue')
const ProjectSettingDelete = () => import('@/views/project/settings/delete.vue')
const ProjectSettingArchive = () => import('@/views/project/settings/archive.vue')
// Namespace Settings
const NamespaceSettingEdit = () => import('@/views/namespaces/settings/edit.vue')
const NamespaceSettingShare = () => import('@/views/namespaces/settings/share.vue')
const NamespaceSettingArchive = () => import('@/views/namespaces/settings/archive.vue')
const NamespaceSettingDelete = () => import('@/views/namespaces/settings/delete.vue')
// Saved Filters
const FilterNew = () => import('@/views/filters/FilterNew.vue')
const FilterEdit = () => import('@/views/filters/FilterEdit.vue')
@ -74,9 +68,6 @@ const UserSettingsTOTPComponent = () => import('@/views/user/settings/TOTP.vue')
// Project Handling
const NewProjectComponent = () => import('@/views/project/NewProject.vue')
// Namespace Handling
const NewNamespaceComponent = () => import('@/views/namespaces/NewNamespace.vue')
const EditTeamComponent = () => import('@/views/teams/EditTeam.vue')
const NewTeamComponent = () => import('@/views/teams/NewTeam.vue')
@ -203,54 +194,6 @@ const router = createRouter({
name: 'link-share.auth',
component: LinkShareAuthComponent,
},
{
path: '/namespaces',
name: 'namespaces.index',
component: ListNamespaces,
},
{
path: '/namespaces/new',
name: 'namespace.create',
component: NewNamespaceComponent,
meta: {
showAsModal: true,
},
},
{
path: '/namespaces/:id/settings/edit',
name: 'namespace.settings.edit',
component: NamespaceSettingEdit,
meta: {
showAsModal: true,
},
props: route => ({ namespaceId: Number(route.params.id as string) }),
},
{
path: '/namespaces/:namespaceId/settings/share',
name: 'namespace.settings.share',
component: NamespaceSettingShare,
meta: {
showAsModal: true,
},
},
{
path: '/namespaces/:id/settings/archive',
name: 'namespace.settings.archive',
component: NamespaceSettingArchive,
meta: {
showAsModal: true,
},
props: route => ({ namespaceId: parseInt(route.params.id as string) }),
},
{
path: '/namespaces/:id/settings/delete',
name: 'namespace.settings.delete',
component: NamespaceSettingDelete,
meta: {
showAsModal: true,
},
props: route => ({ namespaceId: Number(route.params.id as string) }),
},
{
path: '/tasks/:id',
name: 'task.detail',
@ -282,13 +225,27 @@ const router = createRouter({
},
},
{
path: '/projects/new/:namespaceId/',
path: '/projects',
name: 'projects.index',
component: ListProjects,
},
{
path: '/projects/new',
name: 'project.create',
component: NewProjectComponent,
meta: {
showAsModal: true,
},
},
{
path: '/projects/:parentProjectId/new',
name: 'project.createFromParent',
component: NewProjectComponent,
props: route => ({ parentProjectId: Number(route.params.parentProjectId as string) }),
meta: {
showAsModal: true,
},
},
{
path: '/projects/:projectId/settings/edit',
name: 'project.settings.edit',
@ -412,7 +369,7 @@ const router = createRouter({
saveProjectView(to.params.projectId, to.name)
// Properly set the page title when a task popup is closed
const projectStore = useProjectStore()
const projectFromStore = projectStore.getProjectById(Number(to.params.projectId))
const projectFromStore = projectStore.projects[Number(to.params.projectId)]
if(projectFromStore) {
setTitle(projectFromStore.title)
}

View File

@ -1,30 +0,0 @@
import AbstractService from './abstractService'
import NamespaceModel from '../models/namespace'
import type {INamespace} from '@/modelTypes/INamespace'
import {colorFromHex} from '@/helpers/color/colorFromHex'
export default class NamespaceService extends AbstractService<INamespace> {
constructor() {
super({
create: '/namespaces',
get: '/namespaces/{id}',
getAll: '/namespaces',
update: '/namespaces/{id}',
delete: '/namespaces/{id}',
})
}
modelFactory(data) {
return new NamespaceModel(data)
}
beforeUpdate(namespace) {
namespace.hexColor = colorFromHex(namespace.hexColor)
return namespace
}
beforeCreate(namespace) {
namespace.hexColor = colorFromHex(namespace.hexColor)
return namespace
}
}

View File

@ -7,7 +7,7 @@ import {colorFromHex} from '@/helpers/color/colorFromHex'
export default class ProjectService extends AbstractService<IProject> {
constructor() {
super({
create: '/namespaces/{namespaceId}/projects',
create: '/projects',
get: '/projects/{id}',
getAll: '/projects',
update: '/projects/{id}',

View File

@ -12,7 +12,7 @@ import AbstractService from '@/services/abstractService'
import SavedFilterModel from '@/models/savedFilter'
import {useBaseStore} from '@/stores/base'
import {useNamespaceStore} from '@/stores/namespaces'
import {useProjectStore} from '@/stores/projects'
import {objectToSnakeCase, objectToCamelCase} from '@/helpers/case'
import {success} from '@/message'
@ -40,7 +40,7 @@ export function getSavedFilterIdFromProjectId(projectId: IProject['id']) {
}
export function isSavedFilter(project: IProject) {
return getSavedFilterIdFromProjectId(project.id) > 0
return getSavedFilterIdFromProjectId(project?.id) > 0
}
export default class SavedFilterService extends AbstractService<ISavedFilter> {
@ -81,7 +81,7 @@ export default class SavedFilterService extends AbstractService<ISavedFilter> {
export function useSavedFilter(projectId?: MaybeRef<IProject['id']>) {
const router = useRouter()
const {t} = useI18n({useScope:'global'})
const namespaceStore = useNamespaceStore()
const projectStore = useProjectStore()
const filterService = shallowReactive(new SavedFilterService())
@ -110,13 +110,13 @@ export function useSavedFilter(projectId?: MaybeRef<IProject['id']>) {
async function createFilter() {
filter.value = await filterService.create(filter.value)
await namespaceStore.loadNamespaces()
await projectStore.loadProjects()
router.push({name: 'project.index', params: {projectId: getProjectId(filter.value)}})
}
async function saveFilter() {
const response = await filterService.update(filter.value)
await namespaceStore.loadNamespaces()
await projectStore.loadProjects()
success({message: t('filters.edit.success')})
response.filters = objectToSnakeCase(response.filters)
filter.value = response
@ -129,9 +129,9 @@ export function useSavedFilter(projectId?: MaybeRef<IProject['id']>) {
async function deleteFilter() {
await filterService.delete(filter.value)
await namespaceStore.loadNamespaces()
await projectStore.loadProjects()
success({message: t('filters.delete.success')})
router.push({name: 'namespaces.index'})
router.push({name: 'projects.index'})
}
const titleValid = ref(true)

View File

@ -1,23 +0,0 @@
import AbstractService from './abstractService'
import TeamNamespaceModel from '@/models/teamNamespace'
import type {ITeamNamespace} from '@/modelTypes/ITeamNamespace'
import TeamModel from '@/models/team'
export default class TeamNamespaceService extends AbstractService<ITeamNamespace> {
constructor() {
super({
create: '/namespaces/{namespaceId}/teams',
getAll: '/namespaces/{namespaceId}/teams',
update: '/namespaces/{namespaceId}/teams/{teamId}',
delete: '/namespaces/{namespaceId}/teams/{teamId}',
})
}
modelFactory(data) {
return new TeamNamespaceModel(data)
}
modelGetAllFactory(data) {
return new TeamModel(data)
}
}

View File

@ -1,23 +0,0 @@
import AbstractService from './abstractService'
import UserNamespaceModel from '@/models/userNamespace'
import type {IUserNamespace} from '@/modelTypes/IUserNamespace'
import UserModel from '@/models/user'
export default class UserNamespaceService extends AbstractService<IUserNamespace> {
constructor() {
super({
create: '/namespaces/{namespaceId}/users',
getAll: '/namespaces/{namespaceId}/users',
update: '/namespaces/{namespaceId}/users/{userId}',
delete: '/namespaces/{namespaceId}/users/{userId}',
})
}
modelFactory(data) {
return new UserNamespaceModel(data)
}
modelGetAllFactory(data) {
return new UserModel(data)
}
}

View File

@ -2,7 +2,7 @@ import {computed, readonly, ref} from 'vue'
import {defineStore, acceptHMRUpdate} from 'pinia'
import {HTTPFactory, AuthenticatedHTTPFactory} from '@/helpers/fetcher'
import {i18n, getCurrentLanguage, saveLanguage} from '@/i18n'
import {i18n, getCurrentLanguage, saveLanguage, setLanguage} from '@/i18n'
import {objectToSnakeCase} from '@/helpers/case'
import UserModel, { getAvatarUrl, getDisplayName } from '@/models/user'
import UserSettingsService from '@/services/userSettings'
@ -250,6 +250,7 @@ export const useAuthStore = defineStore('auth', () => {
...(info.value?.exp && {exp: info.value?.exp}),
})
await setLanguage(newUser.settings.language)
setUser(newUser)
updateLastUserRefresh()

View File

@ -81,7 +81,7 @@ export const useBaseStore = defineStore('base', () => {
async function handleSetCurrentProject(
{project, forceUpdate = false}: {project: IProject | null, forceUpdate?: boolean},
) {
if (project === null) {
if (project === null || typeof project === 'undefined') {
setCurrentProject({})
setBackground('')
setBlurHash('')

View File

@ -1,236 +0,0 @@
import {computed, readonly, ref} from 'vue'
import {defineStore, acceptHMRUpdate} from 'pinia'
import NamespaceService from '../services/namespace'
import {setModuleLoading} from '@/stores/helper'
import {createNewIndexer} from '@/indexes'
import type {INamespace} from '@/modelTypes/INamespace'
import type {IProject} from '@/modelTypes/IProject'
import {useProjectStore} from '@/stores/projects'
const {add, remove, search, update} = createNewIndexer('namespaces', ['title', 'description'])
export const useNamespaceStore = defineStore('namespace', () => {
const projectStore = useProjectStore()
const isLoading = ref(false)
// FIXME: should be object with id as key
const namespaces = ref<INamespace[]>([])
const getProjectAndNamespaceById = computed(() => (projectId: IProject['id'], ignorePseudoNamespaces = false) => {
for (const n in namespaces.value) {
if (ignorePseudoNamespaces && namespaces.value[n].id < 0) {
continue
}
for (const l in namespaces.value[n].projects) {
if (namespaces.value[n].projects[l].id === projectId) {
return {
project: namespaces.value[n].projects[l],
namespace: namespaces.value[n],
}
}
}
}
return null
})
const getNamespaceById = computed(() => (namespaceId: INamespace['id']) => {
return namespaces.value.find(({id}) => id == namespaceId) || null
})
const searchNamespace = computed(() => {
return (query: string) => (
search(query)
?.filter(value => value > 0)
.map(getNamespaceById.value)
.filter(n => n !== null)
|| []
)
})
function setIsLoading(newIsLoading: boolean) {
isLoading.value = newIsLoading
}
function setNamespaces(newNamespaces: INamespace[]) {
namespaces.value = newNamespaces
newNamespaces.forEach(n => {
add(n)
// Check for each project in that namespace if it has a subscription and set it if not
n.projects.forEach(l => {
if (l.subscription === null || l.subscription.entity !== 'project') {
l.subscription = n.subscription
}
})
})
}
function setNamespaceById(namespace: INamespace) {
const namespaceIndex = namespaces.value.findIndex(n => n.id === namespace.id)
if (namespaceIndex === -1) {
return
}
if (!namespace.projects || namespace.projects.length === 0) {
namespace.projects = namespaces.value[namespaceIndex].projects
}
// Check for each project in that namespace if it has a subscription and set it if not
namespace.projects.forEach(l => {
if (l.subscription === null || l.subscription.entity !== 'project') {
l.subscription = namespace.subscription
}
})
namespaces.value[namespaceIndex] = namespace
update(namespace)
}
function setProjectInNamespaceById(project: IProject) {
for (const n in namespaces.value) {
// We don't have the namespace id on the project which means we need to loop over all projects until we find it.
// FIXME: Not ideal at all - we should fix that at the api level.
if (namespaces.value[n].id === project.namespaceId) {
for (const l in namespaces.value[n].projects) {
if (namespaces.value[n].projects[l].id === project.id) {
const namespace = namespaces.value[n]
namespace.projects[l] = project
namespaces.value[n] = namespace
return
}
}
}
}
}
function addNamespace(namespace: INamespace) {
namespaces.value.push(namespace)
add(namespace)
}
function removeNamespaceById(namespaceId: INamespace['id']) {
for (const n in namespaces.value) {
if (namespaces.value[n].id === namespaceId) {
remove(namespaces.value[n])
namespaces.value.splice(n, 1)
return
}
}
}
function addProjectToNamespace(project: IProject) {
for (const n in namespaces.value) {
if (namespaces.value[n].id === project.namespaceId) {
namespaces.value[n].projects.push(project)
return
}
}
}
function removeProjectFromNamespaceById(project: IProject) {
for (const n in namespaces.value) {
// We don't have the namespace id on the project which means we need to loop over all projects until we find it.
// FIXME: Not ideal at all - we should fix that at the api level.
if (namespaces.value[n].id === project.namespaceId) {
for (const l in namespaces.value[n].projects) {
if (namespaces.value[n].projects[l].id === project.id) {
namespaces.value[n].projects.splice(l, 1)
return
}
}
}
}
}
async function loadNamespaces() {
const cancel = setModuleLoading(setIsLoading)
const namespaceService = new NamespaceService()
try {
// We always load all namespaces and filter them on the frontend
const namespaces = await namespaceService.getAll({}, {is_archived: true}) as INamespace[]
setNamespaces(namespaces)
// Put all projects in the project state
const projects = namespaces.flatMap(({projects}) => projects)
projectStore.setProjects(projects)
return namespaces
} finally {
cancel()
}
}
function loadNamespacesIfFavoritesDontExist() {
// The first or second namespace should be the one holding all favorites
if (namespaces.value[0].id === -2 || namespaces.value[1]?.id === -2) {
return
}
return loadNamespaces()
}
function removeFavoritesNamespaceIfEmpty() {
if (namespaces.value[0].id === -2 && namespaces.value[0].projects.length === 0) {
namespaces.value.splice(0, 1)
}
}
async function deleteNamespace(namespace: INamespace) {
const cancel = setModuleLoading(setIsLoading)
const namespaceService = new NamespaceService()
try {
const response = await namespaceService.delete(namespace)
removeNamespaceById(namespace.id)
return response
} finally {
cancel()
}
}
async function createNamespace(namespace: INamespace) {
const cancel = setModuleLoading(setIsLoading)
const namespaceService = new NamespaceService()
try {
const createdNamespace = await namespaceService.create(namespace)
addNamespace(createdNamespace)
return createdNamespace
} finally {
cancel()
}
}
return {
isLoading: readonly(isLoading),
namespaces: readonly(namespaces),
getProjectAndNamespaceById,
getNamespaceById,
searchNamespace,
setNamespaces,
setNamespaceById,
setProjectInNamespaceById,
addNamespace,
removeNamespaceById,
addProjectToNamespace,
removeProjectFromNamespaceById,
loadNamespaces,
loadNamespacesIfFavoritesDontExist,
removeFavoritesNamespaceIfEmpty,
deleteNamespace,
createNamespace,
}
})
// support hot reloading
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useNamespaceStore, import.meta.hot))
}

View File

@ -1,12 +1,14 @@
import {watch, reactive, shallowReactive, unref, toRefs, readonly, ref, computed} from 'vue'
import {watch, reactive, shallowReactive, unref, readonly, ref, computed} from 'vue'
import {acceptHMRUpdate, defineStore} from 'pinia'
import {useI18n} from 'vue-i18n'
import {useRouter} from 'vue-router'
import ProjectService from '@/services/project'
import ProjectDuplicateService from '@/services/projectDuplicateService'
import ProjectDuplicateModel from '@/models/projectDuplicateModel'
import {setModuleLoading} from '@/stores/helper'
import {removeProjectFromHistory} from '@/modules/projectHistory'
import {createNewIndexer} from '@/indexes'
import {useNamespaceStore} from './namespaces'
import type {IProject} from '@/modelTypes/IProject'
@ -16,9 +18,7 @@ import ProjectModel from '@/models/project'
import {success} from '@/message'
import {useBaseStore} from '@/stores/base'
const {add, remove, search, update} = createNewIndexer('projects', ['title', 'description'])
const FavoriteProjectsNamespace = -2
const {remove, search, update} = createNewIndexer('projects', ['title', 'description'])
export interface ProjectState {
[id: IProject['id']]: IProject
@ -26,16 +26,22 @@ export interface ProjectState {
export const useProjectStore = defineStore('project', () => {
const baseStore = useBaseStore()
const namespaceStore = useNamespaceStore()
const router = useRouter()
const isLoading = ref(false)
// The projects are stored as an object which has the project ids as keys.
const projects = ref<ProjectState>({})
const projectsArray = computed(() => Object.values(projects.value)
.sort((a, b) => a.position - b.position))
const notArchivedRootProjects = computed(() => projectsArray.value
.filter(p => p.parentProjectId === 0 && !p.isArchived))
const favoriteProjects = computed(() => projectsArray.value
.filter(p => !p.isArchived && p.isFavorite))
const hasProjects = computed(() => projectsArray.value.length > 0)
const getProjectById = computed(() => {
return (id: IProject['id']) => typeof projects.value[id] !== 'undefined' ? projects.value[id] : null
const getChildProjects = computed(() => {
return (id: IProject['id']) => projectsArray.value.filter(p => p.parentProjectId === id)
})
const findProjectByExactname = computed(() => {
@ -53,7 +59,7 @@ export const useProjectStore = defineStore('project', () => {
?.filter(value => value > 0)
.map(id => projects.value[id])
.filter(project => project.isArchived === includeArchived)
|| []
|| []
}
})
@ -65,16 +71,15 @@ export const useProjectStore = defineStore('project', () => {
projects.value[project.id] = project
update(project)
// FIXME: This should be a watcher, but using a watcher instead will sometimes crash browser processes.
// Reverted from 31b7c1f217532bf388ba95a03f469508bee46f6a
if (baseStore.currentProject?.id === project.id) {
baseStore.setCurrentProject(project)
}
}
function setProjects(newProjects: IProject[]) {
newProjects.forEach(l => {
projects.value[l.id] = l
add(l)
})
newProjects.forEach(p => setProject(p))
}
function removeProjectById(project: IProject) {
@ -100,9 +105,11 @@ export const useProjectStore = defineStore('project', () => {
try {
const createdProject = await projectService.create(project)
createdProject.namespaceId = project.namespaceId
namespaceStore.addProjectToNamespace(createdProject)
setProject(createdProject)
router.push({
name: 'project.index',
params: { projectId: createdProject.id },
})
return createdProject
} finally {
cancel()
@ -112,26 +119,14 @@ export const useProjectStore = defineStore('project', () => {
async function updateProject(project: IProject) {
const cancel = setModuleLoading(setIsLoading)
const projectService = new ProjectService()
try {
await projectService.update(project)
const updatedProject = await projectService.update(project)
setProject(project)
namespaceStore.setProjectInNamespaceById(project)
// the returned project from projectService.update is the same!
// in order to not create a manipulation in pinia store we have to create a new copy
const newProject = {
...project,
namespaceId: FavoriteProjectsNamespace,
}
namespaceStore.removeProjectFromNamespaceById(newProject)
if (project.isFavorite) {
namespaceStore.addProjectToNamespace(newProject)
}
namespaceStore.loadNamespacesIfFavoritesDontExist()
namespaceStore.removeFavoritesNamespaceIfEmpty()
return newProject
return updatedProject
} catch (e) {
// Reset the project state to the initial one to avoid confusion for the user
setProject({
@ -151,7 +146,6 @@ export const useProjectStore = defineStore('project', () => {
try {
const response = await projectService.delete(project)
removeProjectById(project)
namespaceStore.removeProjectFromNamespaceById(project)
removeProjectFromHistory({id: project.id})
return response
} finally {
@ -159,11 +153,42 @@ export const useProjectStore = defineStore('project', () => {
}
}
async function loadProjects() {
const cancel = setModuleLoading(setIsLoading)
const projectService = new ProjectService()
try {
const loadedProjects = await projectService.getAll({}, {is_archived: true}) as IProject[]
projects.value = {}
setProjects(loadedProjects)
return loadedProjects
} finally {
cancel()
}
}
function getAncestors(project: IProject): IProject[] {
if (!project?.parentProjectId) {
return [project]
}
const parentProject = projects.value[project.parentProjectId]
return [
...getAncestors(parentProject),
project,
]
}
return {
isLoading: readonly(isLoading),
projects: readonly(projects),
projectsArray: readonly(projectsArray),
notArchivedRootProjects: readonly(notArchivedRootProjects),
favoriteProjects: readonly(favoriteProjects),
hasProjects: readonly(hasProjects),
getProjectById,
getChildProjects,
findProjectByExactname,
searchProject,
@ -171,17 +196,24 @@ export const useProjectStore = defineStore('project', () => {
setProjects,
removeProjectById,
toggleProjectFavorite,
loadProjects,
createProject,
updateProject,
deleteProject,
getAncestors,
}
})
export function useProject(projectId: MaybeRef<IProject['id']>) {
const projectService = shallowReactive(new ProjectService())
const {loading: isLoading} = toRefs(projectService)
const projectDuplicateService = shallowReactive(new ProjectDuplicateService())
const isLoading = computed(() => projectService.loading || projectDuplicateService.loading)
const project: IProject = reactive(new ProjectModel())
const {t} = useI18n({useScope: 'global'})
const router = useRouter()
const projectStore = useProjectStore()
watch(
() => unref(projectId),
@ -192,20 +224,34 @@ export function useProject(projectId: MaybeRef<IProject['id']>) {
{immediate: true},
)
const projectStore = useProjectStore()
async function save() {
await projectStore.updateProject(project)
const updatedProject = await projectStore.updateProject(project)
Object.assign(project, updatedProject)
success({message: t('project.edit.success')})
}
async function duplicateProject(parentProjectId: IProject['id']) {
const projectDuplicate = new ProjectDuplicateModel({
projectId: unref(projectId),
parentProjectId,
})
const duplicate = await projectDuplicateService.create(projectDuplicate)
projectStore.setProject(duplicate.project)
success({message: t('project.duplicate.success')})
router.push({name: 'project.index', params: {projectId: duplicate.project.id}})
}
return {
isLoading: readonly(isLoading),
project,
save,
duplicateProject,
}
}
// support hot reloading
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useProjectStore, import.meta.hot))
import.meta.hot.accept(acceptHMRUpdate(useProjectStore, import.meta.hot))
}

Some files were not shown because too many files have changed in this diff Show More