Compare commits

..

1 Commits

Author SHA1 Message Date
Julius Härtl
011488d63b ci: Add query count for integration tests
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2023-02-16 23:33:31 +01:00
119 changed files with 32707 additions and 34104 deletions

View File

@@ -148,7 +148,7 @@ jobs:
tar -zcvf ${{ env.APP_NAME }}.tar.gz ${{ env.APP_NAME }}
- name: Attach tarball to github release
uses: svenstaro/upload-release-action@7319e4733ec7a184d739a6f412c40ffc339b69c7 # v2
uses: svenstaro/upload-release-action@cc92c9093e5f785e23a3d654fe2671640b851b5f # v2
id: attach_to_release
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -23,7 +23,7 @@ jobs:
# containers: [1, 2, 3]
php-versions: [ '8.0' ]
databases: [ 'sqlite' ]
server-versions: [ 'stable26' ]
server-versions: [ 'master' ]
steps:
- name: Use Node.js ${{ matrix.node-version }}

View File

@@ -28,7 +28,7 @@ jobs:
matrix:
php-versions: ['8.1']
databases: ['sqlite', 'mysql', 'pgsql']
server-versions: ['stable26']
server-versions: ['master']
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}
@@ -74,12 +74,11 @@ jobs:
uses: shivammathur/setup-php@2.24.0
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, mysql, pdo_mysql, pgsql, pdo_pgsql, apcu
ini-values:
apc.enable_cli=on
tools: phpunit
extensions: mbstring, iconv, fileinfo, intl, sqlite, pdo_sqlite, mysql, pdo_mysql, pgsql, pdo_pgsql,
coverage: none
- name: Set up dependencies
- name: Set up PHPUnit
working-directory: apps/${{ env.APP_NAME }}
run: composer i --no-dev
@@ -92,9 +91,6 @@ jobs:
fi
mkdir data
./occ maintenance:install --verbose --database=${{ matrix.databases }} --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
./occ config:system:set hashing_default_password --value=true --type=boolean
./occ config:system:set memcache.local --value="\\OC\\Memcache\\APCu"
./occ config:system:set memcache.distributed --value="\\OC\\Memcache\\APCu"
cat config/config.php
./occ user:list
./occ app:enable --force ${{ env.APP_NAME }}
@@ -107,7 +103,7 @@ jobs:
- name: Query count
if: ${{ matrix.databases == 'mysql' }}
uses: actions/github-script@v6
uses: actions/github-script@v5
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
@@ -151,4 +147,4 @@ jobs:
repo: context.repo.repo,
body: comment
})
}
}

View File

@@ -26,9 +26,9 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['8.0', '8.1', '8.2']
php-versions: ['8.0', '8.1']
databases: ['sqlite', 'mysql', 'pgsql']
server-versions: ['stable26']
server-versions: ['master']
name: php${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }}

View File

@@ -1,63 +1,6 @@
# Changelog
All notable changes to this project will be documented in this file.
## 1.9.2
### Fixed
- fix: Properly overwrite z-index of datepicker above modal [#4665](https://github.com/nextcloud/deck/pull/4665)
## 1.9.1
### Fixed
- Gracefully handle not found card for a share [#4567](https://github.com/nextcloud/deck/pull/4567)
- fix: Adapt NcEmptyContent usages to new slots [#4562](https://github.com/nextcloud/deck/pull/4562)
- allow user to toggle visibility of the calendar for a deck board [#4625](https://github.com/nextcloud/deck/pull/4625)
- fix: Append datetime picker to body to avoid cut off [#4644](https://github.com/nextcloud/deck/pull/4644)
- chore: Remove unused @nextcloud/vue-dashboard @juliushaertl [#4650](https://github.com/nextcloud/deck/pull/4650)
- fix: Bring back overdue column by removing faulty condition [#4662](https://github.com/nextcloud/deck/pull/4662)
- Fix : Overlapping expiry dates on tags [#4537](https://github.com/nextcloud/deck/pull/4537)
- Better display of card dates (creation and change dates) [#4619](https://github.com/nextcloud/deck/pull/4619)
- Update dependencies
## 1.9.0
### Added
- Live updates on board collaboration using notify_push @alangecker [#4273](https://github.com/nextcloud/deck/pull/4273)
- Basic notify_push usage with session handling @alangecker [#3876](https://github.com/nextcloud/deck/pull/3876)
- Use text as editor if available [#4399](https://github.com/nextcloud/deck/pull/4399)
- Improve reference provider and add reference widgets @julien-nc [#4422](https://github.com/nextcloud/deck/pull/4422)
- Tag creation from card view @juliushaertl [#4344](https://github.com/nextcloud/deck/pull/4344)
- Optimize query performance with larger board or card count @[#4452](https://github.com/nextcloud/deck/pull/4452)
- Export Board as CSV @david-loe [#3065](https://github.com/nextcloud/deck/pull/3065)
### Fixed
- fix(cards): Fix card sizing by limiting too wide style rules [#4521](https://github.com/nextcloud/deck/pull/4521)
- fix(references): Mute NoPermissionException as it is expected to happen for references [#4516](https://github.com/nextcloud/deck/pull/4516)
- fix(API): Fix board API details parameter to work as expected [#4519](https://github.com/nextcloud/deck/pull/4519)
- fix(sessions): Do not send close request without token [#4525](https://github.com/nextcloud/deck/pull/4525)
- fix: Avoid mutating the due date when calculating days @juliushaertl [#4488](https://github.com/nextcloud/deck/pull/4488)
- fix: Pass user id along to properly check permissions in background jobs @juliushaertl [#4485](https://github.com/nextcloud/deck/pull/4485)
- fix: Use passed userid when getting attachment folder @juliushaertl [#4487](https://github.com/nextcloud/deck/pull/4487)
- fix: Use proper z-index for text menubar @juliushaertl [#4490](https://github.com/nextcloud/deck/pull/4490)
- fix(dashboard): Fix undefined array index @marcelklehr [#4492](https://github.com/nextcloud/deck/pull/4492)
- fix: Always return sorted index array to make sure a json array is the result @juliushaertl [#4493](https://github.com/nextcloud/deck/pull/4493)
- Fix component renaming so that acl works on shares again @small1 [#4315](https://github.com/nextcloud/deck/pull/4315)
- fix(Sidebar): Only close sidebar on v-click-outside for specific targets @juliushaertl [#4350](https://github.com/nextcloud/deck/pull/4350)
- add basic e2e tests for stack title @shoetten [#4206](https://github.com/nextcloud/deck/pull/4206)
- App metadata: add links to user and developer documentation @p-bo [#4356](https://github.com/nextcloud/deck/pull/4356)
- Update signature of Entity::markFieldUpdated @nickvergessen [#4398](https://github.com/nextcloud/deck/pull/4398)
- Remove updated nightly information @xf- [#4419](https://github.com/nextcloud/deck/pull/4419)
- perf: Register notifier and resource listener lazy @juliushaertl [#4439](https://github.com/nextcloud/deck/pull/4439)
- perf: Lazy load dashboard components @juliushaertl [#4440](https://github.com/nextcloud/deck/pull/4440)
- Optimise upcomming overview creation @Raudius [#3793](https://github.com/nextcloud/deck/pull/3793)
## 1.8.0-beta.1
### Enhancements

View File

@@ -16,7 +16,7 @@
- 🚀 Get your project organized
</description>
<version>1.9.2</version>
<version>1.9.0-beta.1</version>
<licence>agpl</licence>
<author>Julius Härtl</author>
<documentation>

View File

@@ -19,7 +19,7 @@
"symfony/event-dispatcher": "^4.0",
"vimeo/psalm": "^5.4",
"php-parallel-lint/php-parallel-lint": "^1.2",
"nextcloud/ocp": "dev-stable26"
"nextcloud/ocp": "dev-master"
},
"config": {
"optimize-autoloader": true,

114
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7f234626b3fd062832a6387b9434427c",
"content-hash": "22d201a4569de6d4fafbc13277ae91a6",
"packages": [
{
"name": "cogpowered/finediff",
@@ -952,16 +952,16 @@
},
{
"name": "fidry/cpu-core-counter",
"version": "0.5.1",
"version": "0.4.1",
"source": {
"type": "git",
"url": "https://github.com/theofidry/cpu-core-counter.git",
"reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623"
"reference": "79261cc280aded96d098e1b0e0ba0c4881b432c2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/b58e5a3933e541dc286cc91fc4f3898bbc6f1623",
"reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623",
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/79261cc280aded96d098e1b0e0ba0c4881b432c2",
"reference": "79261cc280aded96d098e1b0e0ba0c4881b432c2",
"shasum": ""
},
"require": {
@@ -1001,7 +1001,7 @@
],
"support": {
"issues": "https://github.com/theofidry/cpu-core-counter/issues",
"source": "https://github.com/theofidry/cpu-core-counter/tree/0.5.1"
"source": "https://github.com/theofidry/cpu-core-counter/tree/0.4.1"
},
"funding": [
{
@@ -1009,7 +1009,7 @@
"type": "github"
}
],
"time": "2022-12-24T12:35:10+00:00"
"time": "2022-12-16T22:01:02+00:00"
},
{
"name": "friendsofphp/php-cs-fixer",
@@ -1253,24 +1253,26 @@
},
{
"name": "nextcloud/ocp",
"version": "dev-stable26",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/nextcloud-deps/ocp.git",
"reference": "8ad3d190cc7fa4210e5121c36d40d0de9dcc343f"
"reference": "5636b942e35ee391b1103150261d83d3d753d657"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/8ad3d190cc7fa4210e5121c36d40d0de9dcc343f",
"reference": "8ad3d190cc7fa4210e5121c36d40d0de9dcc343f",
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/5636b942e35ee391b1103150261d83d3d753d657",
"reference": "5636b942e35ee391b1103150261d83d3d753d657",
"shasum": ""
},
"require": {
"php": "^7.4 || ~8.0 || ~8.1",
"psr/clock": "^1.0",
"psr/container": "^1.1.1",
"psr/event-dispatcher": "^1.0",
"psr/log": "^1.1"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
@@ -1290,9 +1292,9 @@
"description": "Composer package containing Nextcloud's public API (classes, interfaces)",
"support": {
"issues": "https://github.com/nextcloud-deps/ocp/issues",
"source": "https://github.com/nextcloud-deps/ocp/tree/stable26"
"source": "https://github.com/nextcloud-deps/ocp/tree/master"
},
"time": "2023-04-04T00:35:10+00:00"
"time": "2023-02-08T00:37:37+00:00"
},
{
"name": "nikic/php-parser",
@@ -2204,6 +2206,54 @@
},
"time": "2021-02-03T23:26:27+00:00"
},
{
"name": "psr/clock",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/clock.git",
"reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
"reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Psr\\Clock\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for reading the clock.",
"homepage": "https://github.com/php-fig/clock",
"keywords": [
"clock",
"now",
"psr",
"psr-20",
"time"
],
"support": {
"issues": "https://github.com/php-fig/clock/issues",
"source": "https://github.com/php-fig/clock/tree/1.0.0"
},
"time": "2022-11-25T14:36:26+00:00"
},
{
"name": "psr/container",
"version": "1.1.2",
@@ -3750,25 +3800,26 @@
},
{
"name": "spatie/array-to-xml",
"version": "3.1.5",
"version": "2.17.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/array-to-xml.git",
"reference": "13f76acef5362d15c71ae1ac6350cc3df5e25e43"
"reference": "5cbec9c6ab17e320c58a259f0cebe88bde4a7c46"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/array-to-xml/zipball/13f76acef5362d15c71ae1ac6350cc3df5e25e43",
"reference": "13f76acef5362d15c71ae1ac6350cc3df5e25e43",
"url": "https://api.github.com/repos/spatie/array-to-xml/zipball/5cbec9c6ab17e320c58a259f0cebe88bde4a7c46",
"reference": "5cbec9c6ab17e320c58a259f0cebe88bde4a7c46",
"shasum": ""
},
"require": {
"ext-dom": "*",
"php": "^8.0"
"php": "^7.4|^8.0"
},
"require-dev": {
"mockery/mockery": "^1.2",
"pestphp/pest": "^1.21",
"phpunit/phpunit": "^9.0",
"spatie/pest-plugin-snapshots": "^1.1"
},
"type": "library",
@@ -3797,7 +3848,7 @@
"xml"
],
"support": {
"source": "https://github.com/spatie/array-to-xml/tree/3.1.5"
"source": "https://github.com/spatie/array-to-xml/tree/2.17.1"
},
"funding": [
{
@@ -3809,7 +3860,7 @@
"type": "github"
}
],
"time": "2022-12-24T13:43:51+00:00"
"time": "2022-12-26T08:22:07+00:00"
},
{
"name": "symfony/console",
@@ -5252,16 +5303,16 @@
},
{
"name": "vimeo/psalm",
"version": "5.7.7",
"version": "5.6.0",
"source": {
"type": "git",
"url": "https://github.com/vimeo/psalm.git",
"reference": "e028ba46ba0d7f9a78bc3201c251e137383e145f"
"reference": "e784128902dfe01d489c4123d69918a9f3c1eac5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vimeo/psalm/zipball/e028ba46ba0d7f9a78bc3201c251e137383e145f",
"reference": "e028ba46ba0d7f9a78bc3201c251e137383e145f",
"url": "https://api.github.com/repos/vimeo/psalm/zipball/e784128902dfe01d489c4123d69918a9f3c1eac5",
"reference": "e784128902dfe01d489c4123d69918a9f3c1eac5",
"shasum": ""
},
"require": {
@@ -5280,12 +5331,12 @@
"ext-tokenizer": "*",
"felixfbecker/advanced-json-rpc": "^3.1",
"felixfbecker/language-server-protocol": "^1.5.2",
"fidry/cpu-core-counter": "^0.4.1 || ^0.5.1",
"fidry/cpu-core-counter": "^0.4.0",
"netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
"nikic/php-parser": "^4.13",
"php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0",
"sebastian/diff": "^4.0 || ^5.0",
"spatie/array-to-xml": "^2.17.0 || ^3.0",
"spatie/array-to-xml": "^2.17.0",
"symfony/console": "^4.1.6 || ^5.0 || ^6.0",
"symfony/filesystem": "^5.4 || ^6.0"
},
@@ -5294,13 +5345,13 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
"brianium/paratest": "^6.9",
"brianium/paratest": "^6.0",
"ext-curl": "*",
"mockery/mockery": "^1.5",
"nunomaduro/mock-final-classes": "^1.1",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpdoc-parser": "^1.6",
"phpunit/phpunit": "^9.6",
"phpunit/phpunit": "^9.5",
"psalm/plugin-mockery": "^1.1",
"psalm/plugin-phpunit": "^0.18",
"slevomat/coding-standard": "^8.4",
@@ -5346,14 +5397,13 @@
"keywords": [
"code",
"inspection",
"php",
"static analysis"
"php"
],
"support": {
"issues": "https://github.com/vimeo/psalm/issues",
"source": "https://github.com/vimeo/psalm/tree/5.7.7"
"source": "https://github.com/vimeo/psalm/tree/5.6.0"
},
"time": "2023-02-25T01:05:07+00:00"
"time": "2023-01-23T20:32:47+00:00"
},
{
"name": "webmozart/assert",

View File

@@ -79,12 +79,8 @@ OC.L10N.register(
"The board \"%s\" has been shared with you by %s." : "Таблото \"%s\" е споделено с вас от%s.",
"{user} has shared {deck-board} with you." : "{user} сподели {deck-board} с Вас.",
"Deck board" : "Deck табло",
"Owned by %1$s" : "Притежаван от %1$s",
"Deck boards, cards and comments" : "Табла, карти и коментари",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "От %1$s, в %2$s/%3$s, притежание на %4$s",
"Card comments" : "Коментари на карти",
"%s on %s" : "%s на %s",
"Deck boards and cards" : "Табла и карти",
"No data was provided to create an attachment." : "Не бяха предоставени данни за създаване на прикачен файл.",
"Finished" : "Готово",
"To review" : "За преглед",
@@ -295,7 +291,6 @@ OC.L10N.register(
"No due" : "Не се дължи",
"Search for {searchQuery} in all boards" : "Търсене на {searchQuery} във всички табла",
"No results found" : "Няма намерени резултати",
"Deck board {name}\n* Last modified on {lastMod}" : "Табло {name}\n* Последна промяна на {lastMod}",
"{stack} in {board}" : "{stack} в {board}",
"Click to expand description" : "Кликване за разширяване на описанието",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Създаден на {created}\n* Последна промяна на {lastMod} \n* {nbAttachments} прикачени файлове \n* {nbComments} коментара",
@@ -303,7 +298,6 @@ OC.L10N.register(
"Click to expand comment" : "Кликване за разширяване на коментара",
"No upcoming cards" : "Няма предстоящи карти",
"upcoming cards" : "предстоящи карти",
"New card" : "Нова карта",
"Due on {date}" : "Краен срок до {date}",
"Link to a board" : "Линк към табло",
"Link to a card" : "Линк към карта",

View File

@@ -77,12 +77,8 @@
"The board \"%s\" has been shared with you by %s." : "Таблото \"%s\" е споделено с вас от%s.",
"{user} has shared {deck-board} with you." : "{user} сподели {deck-board} с Вас.",
"Deck board" : "Deck табло",
"Owned by %1$s" : "Притежаван от %1$s",
"Deck boards, cards and comments" : "Табла, карти и коментари",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "От %1$s, в %2$s/%3$s, притежание на %4$s",
"Card comments" : "Коментари на карти",
"%s on %s" : "%s на %s",
"Deck boards and cards" : "Табла и карти",
"No data was provided to create an attachment." : "Не бяха предоставени данни за създаване на прикачен файл.",
"Finished" : "Готово",
"To review" : "За преглед",
@@ -293,7 +289,6 @@
"No due" : "Не се дължи",
"Search for {searchQuery} in all boards" : "Търсене на {searchQuery} във всички табла",
"No results found" : "Няма намерени резултати",
"Deck board {name}\n* Last modified on {lastMod}" : "Табло {name}\n* Последна промяна на {lastMod}",
"{stack} in {board}" : "{stack} в {board}",
"Click to expand description" : "Кликване за разширяване на описанието",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Създаден на {created}\n* Последна промяна на {lastMod} \n* {nbAttachments} прикачени файлове \n* {nbComments} коментара",
@@ -301,7 +296,6 @@
"Click to expand comment" : "Кликване за разширяване на коментара",
"No upcoming cards" : "Няма предстоящи карти",
"upcoming cards" : "предстоящи карти",
"New card" : "Нова карта",
"Due on {date}" : "Краен срок до {date}",
"Link to a board" : "Линк към табло",
"Link to a card" : "Линк към карта",

View File

@@ -79,12 +79,8 @@ OC.L10N.register(
"The board \"%s\" has been shared with you by %s." : "El tauler \"%s\" se us ha compartit per %s.",
"{user} has shared {deck-board} with you." : "{user} us ha compartit {board}.",
"Deck board" : "Tauler de Deck",
"Owned by %1$s" : "Propietat de %1$s",
"Deck boards, cards and comments" : "Taulers, targetes i comentaris",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "De %1$s, a %2$s/%3$s, propietat de %4$s",
"Card comments" : "Comentaris de la targeta",
"%s on %s" : "%s a %s",
"Deck boards and cards" : "Taulers de piles i targetes",
"No data was provided to create an attachment." : "No sha proporcionat cap dada per crear un fitxer adjunt.",
"Finished" : "Acabat",
"To review" : "Per revisar",
@@ -157,7 +153,6 @@ OC.L10N.register(
"Toggle compact mode" : "Commuta el mode compacte",
"Open details" : "Obre els detalls",
"Details" : "Detalls",
"Currently present people" : "Persones presents actuals",
"Loading board" : "S'està carregant el tauler",
"No lists available" : "No hi ha cap llista disponible",
"Create a new list to add cards to this board" : "Crea una llista nova per afegir targetes a aquest tauler",
@@ -186,7 +181,6 @@ OC.L10N.register(
"Transfer" : "Transferència",
"The board has been transferred to {user}" : "El tauler s'ha transferit a {user}",
"Failed to transfer the board to {user}" : "No s'ha pogut transferir el tauler a {user}",
"Edit list title" : "Edita el títol de la llista",
"Archive all cards" : "Arxiva totes les targetes",
"Unarchive all cards" : "Desarxivar totes les targetes",
"Delete list" : "Suprimeix la llista",
@@ -277,7 +271,6 @@ OC.L10N.register(
"Clone board" : "Clonar tauler",
"Unarchive board" : "Desarxiva el tauler",
"Archive board" : "Arxiva el tauler",
"Export board" : "Exportació de tauler",
"Turn on due date reminders" : "Activa els recordatoris de data de venciment",
"Turn off due date reminders" : "Desactiva els recordatoris de data de venciment",
"Due date reminders" : "Recordatoris de data de venciment",
@@ -295,15 +288,12 @@ OC.L10N.register(
"No due" : "Sense venciment",
"Search for {searchQuery} in all boards" : "Busca {searchQuery} a tots els taulers",
"No results found" : "No s'han trobat resultats",
"Deck board {name}\n* Last modified on {lastMod}" : "Tauler de piles {name}\n* Última modificació el dia {lastMod}",
"{stack} in {board}" : "{stack} a {board}",
"Click to expand description" : "Feu clic per ampliar la descripció",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Creat el {created}\n* Última modificació el dia {lastMod}\n* {nbAttachments} fitxers adjunts\n* {nbComments} comentaris",
"{nbCards} cards" : "{nbCards} targetes",
"Click to expand comment" : "Feu clic per ampliar el comentari",
"No upcoming cards" : "No hi ha pròximes targetes",
"upcoming cards" : "pròximes targetes",
"New card" : "Nova targeta",
"Due on {date}" : "Venciment el dia {date}",
"Link to a board" : "Enllaça a un tauler",
"Link to a card" : "Enllaç una targeta",

View File

@@ -77,12 +77,8 @@
"The board \"%s\" has been shared with you by %s." : "El tauler \"%s\" se us ha compartit per %s.",
"{user} has shared {deck-board} with you." : "{user} us ha compartit {board}.",
"Deck board" : "Tauler de Deck",
"Owned by %1$s" : "Propietat de %1$s",
"Deck boards, cards and comments" : "Taulers, targetes i comentaris",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "De %1$s, a %2$s/%3$s, propietat de %4$s",
"Card comments" : "Comentaris de la targeta",
"%s on %s" : "%s a %s",
"Deck boards and cards" : "Taulers de piles i targetes",
"No data was provided to create an attachment." : "No sha proporcionat cap dada per crear un fitxer adjunt.",
"Finished" : "Acabat",
"To review" : "Per revisar",
@@ -155,7 +151,6 @@
"Toggle compact mode" : "Commuta el mode compacte",
"Open details" : "Obre els detalls",
"Details" : "Detalls",
"Currently present people" : "Persones presents actuals",
"Loading board" : "S'està carregant el tauler",
"No lists available" : "No hi ha cap llista disponible",
"Create a new list to add cards to this board" : "Crea una llista nova per afegir targetes a aquest tauler",
@@ -184,7 +179,6 @@
"Transfer" : "Transferència",
"The board has been transferred to {user}" : "El tauler s'ha transferit a {user}",
"Failed to transfer the board to {user}" : "No s'ha pogut transferir el tauler a {user}",
"Edit list title" : "Edita el títol de la llista",
"Archive all cards" : "Arxiva totes les targetes",
"Unarchive all cards" : "Desarxivar totes les targetes",
"Delete list" : "Suprimeix la llista",
@@ -275,7 +269,6 @@
"Clone board" : "Clonar tauler",
"Unarchive board" : "Desarxiva el tauler",
"Archive board" : "Arxiva el tauler",
"Export board" : "Exportació de tauler",
"Turn on due date reminders" : "Activa els recordatoris de data de venciment",
"Turn off due date reminders" : "Desactiva els recordatoris de data de venciment",
"Due date reminders" : "Recordatoris de data de venciment",
@@ -293,15 +286,12 @@
"No due" : "Sense venciment",
"Search for {searchQuery} in all boards" : "Busca {searchQuery} a tots els taulers",
"No results found" : "No s'han trobat resultats",
"Deck board {name}\n* Last modified on {lastMod}" : "Tauler de piles {name}\n* Última modificació el dia {lastMod}",
"{stack} in {board}" : "{stack} a {board}",
"Click to expand description" : "Feu clic per ampliar la descripció",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Creat el {created}\n* Última modificació el dia {lastMod}\n* {nbAttachments} fitxers adjunts\n* {nbComments} comentaris",
"{nbCards} cards" : "{nbCards} targetes",
"Click to expand comment" : "Feu clic per ampliar el comentari",
"No upcoming cards" : "No hi ha pròximes targetes",
"upcoming cards" : "pròximes targetes",
"New card" : "Nova targeta",
"Due on {date}" : "Venciment el dia {date}",
"Link to a board" : "Enllaça a un tauler",
"Link to a card" : "Enllaç una targeta",

View File

@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "Komentář rozbalíte kliknutím",
"No upcoming cards" : "Žádné nadcházející karty",
"upcoming cards" : "nadcházející karty",
"New card" : "Nová karta",
"Due on {date}" : "Termín {date}",
"Link to a board" : "Propojit s tabulí",
"Link to a card" : "Propojit s kartou",

View File

@@ -301,7 +301,6 @@
"Click to expand comment" : "Komentář rozbalíte kliknutím",
"No upcoming cards" : "Žádné nadcházející karty",
"upcoming cards" : "nadcházející karty",
"New card" : "Nová karta",
"Due on {date}" : "Termín {date}",
"Link to a board" : "Propojit s tabulí",
"Link to a card" : "Propojit s kartou",

View File

@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "Klicken, um den Kommentar zu erweitern",
"No upcoming cards" : "Keine anstehenden Karten",
"upcoming cards" : "Anstehende Karten",
"New card" : "Neue Karte",
"Due on {date}" : "Fällig am {date}",
"Link to a board" : "Mit einem Board verknüpfen",
"Link to a card" : "Mit einer Karte verknüpfen",

View File

@@ -301,7 +301,6 @@
"Click to expand comment" : "Klicken, um den Kommentar zu erweitern",
"No upcoming cards" : "Keine anstehenden Karten",
"upcoming cards" : "Anstehende Karten",
"New card" : "Neue Karte",
"Due on {date}" : "Fällig am {date}",
"Link to a board" : "Mit einem Board verknüpfen",
"Link to a card" : "Mit einer Karte verknüpfen",

View File

@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "Klicken, um den Kommentar zu erweitern",
"No upcoming cards" : "Keine anstehenden Karten",
"upcoming cards" : "Anstehende Karten",
"New card" : "Neue Karte",
"Due on {date}" : "Fällig am {date}",
"Link to a board" : "Mit einem Board verknüpfen",
"Link to a card" : "Mit einer Karte verknüpfen",

View File

@@ -301,7 +301,6 @@
"Click to expand comment" : "Klicken, um den Kommentar zu erweitern",
"No upcoming cards" : "Keine anstehenden Karten",
"upcoming cards" : "Anstehende Karten",
"New card" : "Neue Karte",
"Due on {date}" : "Fällig am {date}",
"Link to a board" : "Mit einem Board verknüpfen",
"Link to a card" : "Mit einer Karte verknüpfen",

View File

@@ -79,11 +79,8 @@ OC.L10N.register(
"The board \"%s\" has been shared with you by %s." : "Ο πίνακας \"%s\" είναι σε κοινή χρήση μαζί σας από %s.",
"{user} has shared {deck-board} with you." : "Ο/Η διαμοιράστηκε μαζί σας το {deck-board}",
"Deck board" : "Πίνακας του Deck",
"Owned by %1$s" : "Ανήκει στον/στην %1$s",
"Deck boards, cards and comments" : "Πίνακες, κάρτες και σχόλια Deck",
"Card comments" : "Σχόλια καρτέλας",
"%s on %s" : "%s στο %s",
"Deck boards and cards" : "Πίνακες και κάρτες Deck",
"No data was provided to create an attachment." : "Δεν δόθηκαν στοιχεία για δημιουργία συνημμένου.",
"Finished" : "Ολοκληρώθηκε",
"To review" : "Προς επισκόπηση",
@@ -139,7 +136,6 @@ OC.L10N.register(
"Archived cards" : "Αρχειοθετημένες καρτέλες",
"Add list" : "Προσθήκη λίστας",
"List name" : "Όνομα λίστας",
"Active filters" : "Ενεργά φίλτρα",
"Apply filter" : "Εφαρμογή φίλτρου",
"Filter by tag" : "Φίλτρο ανά ετικέτα",
"Filter by assigned user" : "Φίλτρο ανά χρήστη",
@@ -156,7 +152,6 @@ OC.L10N.register(
"Toggle compact mode" : "Εναλλαγή λειτουργίας μικρού μεγέθους",
"Open details" : "Άνοιγμα λεπτομερειών",
"Details" : "Λεπτομέρειες",
"Currently present people" : "Παρόντες αυτή τη στιγμή",
"Loading board" : "Φόρτωση πίνακα",
"No lists available" : "Δεν υπάρχουν διαθέσιμες λίστες",
"Create a new list to add cards to this board" : "Δημιουργήστε νέα λίστα για να προσθέσετε καρτέλες σε αυτό τον πίνακα.",
@@ -180,17 +175,10 @@ OC.L10N.register(
"Owner" : "Κάτοχος",
"Delete" : "Διαγραφή",
"Failed to create share with {displayName}" : "Αποτυχία δημιουργίας κοινής χρήσης με το {displayName}",
"Are you sure you want to transfer the board {title} to {user}?" : "Είστε σίγουροι ότι θέλετε να μεταφέρετε τον πίνακα {title} στον {user}? ",
"Transfer the board." : "Μεταφορά του πίνακα.",
"Transfer" : "Μεταφορά",
"The board has been transferred to {user}" : "Ο πίνακας έχει μεταφερθεί στον/στην {user}",
"Failed to transfer the board to {user}" : "Απέτυχε η μεταφορά του πίνακα στον χρήστη {user}",
"Edit list title" : "Επεξεργασία τίτλου λίστας",
"Archive all cards" : "Αρχειοθέτηση όλων των καρτελών.",
"Unarchive all cards" : "Κατάργηση αρχειοθέτησης όλων των καρτών",
"Delete list" : "Διαγραφή λίστας",
"Archive all cards in this list" : "Αρχειοθέτηση όλων των καρτελών σε αυτή τη λίστα.",
"Unarchive all cards in this list" : "Κατάργηση αρχειοθέτησης όλων των καρτών σε αυτή τη λίστα",
"Add a new card" : "Προσθήκη νέας καρτέλας",
"Card name" : "Όνομα καρτέλας",
"List deleted" : "Η λίστα διαγράφηκε",
@@ -248,9 +236,7 @@ OC.L10N.register(
"Write a description …" : "Γράψτε μια περιγραφή…",
"Choose attachment" : "Επιλογή συνημμένου",
"(group)" : "(ομάδα)",
"Todo items" : "Στοιχεία todo",
"{count} comments, {unread} unread" : "{count} σχόλια, {unread} μη αναγνωσμένα",
"Edit card title" : "Επεξεργασία τίτλου κάρτας",
"Assign to me" : "Ανάθεση σε εμένα",
"Unassign myself" : "Αποδέσμευσή μου",
"Move card" : "Μετακίνηση καρτέλας",
@@ -265,7 +251,6 @@ OC.L10N.register(
"All boards" : "Όλοι οι πίνακες",
"Archived boards" : "Αρχειοθέτηση πινάκων ",
"Shared with you" : "Διαμοιρασμένα μαζί σας",
"Deck settings" : "Ρυθμίσεις Deck",
"Use bigger card view" : "Χρησιμοποιήστε μεγαλύτερη προβολή καρτέλας",
"Show boards in calendar/tasks" : "Εμφάνιση πινάκων στο ημερολόγιο / εργασίες",
"Limit deck usage of groups" : "Περιορίστε τη χρήση της εφαρμογής deck σε ομάδες",
@@ -275,7 +260,6 @@ OC.L10N.register(
"Clone board" : "Κλώνος πίνακα",
"Unarchive board" : "Κατάργηση αρχειοθέτησης πίνακα",
"Archive board" : "Αρχειοθέτηση πίνακα",
"Export board" : "Εξαγωγή πίνακα",
"Turn on due date reminders" : "Ενεργοποιήστε τις υπενθυμίσεις ημερομηνίας προθεσμίας",
"Turn off due date reminders" : "Απενεργοποιήστε τις υπενθυμίσεις ημερομηνίας προθεσμίας",
"Due date reminders" : "Υπενθυμίσεις ημερομηνίας προθεσμίας",
@@ -287,21 +271,14 @@ OC.L10N.register(
"Only assigned cards" : "Μόνο καρτέλες που έχουν ανατεθεί",
"No reminder" : "Δεν υπάρχει υπενθύμιση",
"An error occurred" : "Παρουσιάστηκε σφάλμα",
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Είστε βέβαιοι ότι θέλετε να διαγράψετε τον πίνακα {title}; Αυτό θα διαγράψει όλα τα δεδομένα του πίνακα συμπεριλαμβανομένων και των αρχειοθετημένων καρτών.",
"Delete the board?" : "Διαγραφή του πίνακα;",
"Loading filtered view" : "Φόρτωση εμφάνισης με βάση το φίλτρο",
"No due" : "Χωρίς λήξη",
"Search for {searchQuery} in all boards" : "Αναζήτηση για {searchQuery} σε όλους τους πίνακες",
"No results found" : "Δεν βρέθηκαν αποτελέσματα",
"Deck board {name}\n* Last modified on {lastMod}" : "Πίνακας Deck {name}\n* Τελευταία τροποποίηση στις {lastMod}",
"{stack} in {board}" : "{stack} στο {board}",
"Click to expand description" : "Κλικ για επέκταση περιγραφής",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Δημιουργήθηκε στις {created}\n* Τροποποιήθηκε στις {lastMod}\n* {nbAttachments} συνημμένα\n* {nbComments} σχόλια",
"{nbCards} cards" : "{nbCards} κάρτες",
"Click to expand comment" : "Κλικ για επέκταση σχολίου",
"No upcoming cards" : "Δεν υπάρχουν επερχόμενες καρτέλες",
"upcoming cards" : "επερχόμενες καρτέλες",
"Due on {date}" : "Προθεσμία στις {date}",
"Link to a board" : "Σύνδεσμος στον πίνακα",
"Link to a card" : "Σύνδεσμος σε καρτέλα",
"Create a card" : "Δημιουργία καρτέλας",
@@ -314,8 +291,6 @@ OC.L10N.register(
"Share {file} with a Deck card" : "Μοιραστείτε το {file} με μια καρτέλα Deck",
"Share" : "Μοιραστείτε",
"Are you sure you want to transfer the board {title} for {user}?" : "Είστε σίγουροι ότι θέλετε να μεταφέρετε τον πίνακα {title} για {user}? ",
"Transfer the board for {user} successfully" : "Επιτυχής μεταφορά του πίνακα για τον χρήστη {user}",
"Failed to transfer the board for {user}" : "Απέτυχε η μεταφορά του πίνακα για τον χρήστη {user}",
"Add a new list" : "Προσθήκη νέας λίστας",
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Είστε βέβαιοι ότι θέλετε να διαγράψετε τον πίνακα {title}; Θα διαγραφούν όλα τα δεδομένα."
},

View File

@@ -77,11 +77,8 @@
"The board \"%s\" has been shared with you by %s." : "Ο πίνακας \"%s\" είναι σε κοινή χρήση μαζί σας από %s.",
"{user} has shared {deck-board} with you." : "Ο/Η διαμοιράστηκε μαζί σας το {deck-board}",
"Deck board" : "Πίνακας του Deck",
"Owned by %1$s" : "Ανήκει στον/στην %1$s",
"Deck boards, cards and comments" : "Πίνακες, κάρτες και σχόλια Deck",
"Card comments" : "Σχόλια καρτέλας",
"%s on %s" : "%s στο %s",
"Deck boards and cards" : "Πίνακες και κάρτες Deck",
"No data was provided to create an attachment." : "Δεν δόθηκαν στοιχεία για δημιουργία συνημμένου.",
"Finished" : "Ολοκληρώθηκε",
"To review" : "Προς επισκόπηση",
@@ -137,7 +134,6 @@
"Archived cards" : "Αρχειοθετημένες καρτέλες",
"Add list" : "Προσθήκη λίστας",
"List name" : "Όνομα λίστας",
"Active filters" : "Ενεργά φίλτρα",
"Apply filter" : "Εφαρμογή φίλτρου",
"Filter by tag" : "Φίλτρο ανά ετικέτα",
"Filter by assigned user" : "Φίλτρο ανά χρήστη",
@@ -154,7 +150,6 @@
"Toggle compact mode" : "Εναλλαγή λειτουργίας μικρού μεγέθους",
"Open details" : "Άνοιγμα λεπτομερειών",
"Details" : "Λεπτομέρειες",
"Currently present people" : "Παρόντες αυτή τη στιγμή",
"Loading board" : "Φόρτωση πίνακα",
"No lists available" : "Δεν υπάρχουν διαθέσιμες λίστες",
"Create a new list to add cards to this board" : "Δημιουργήστε νέα λίστα για να προσθέσετε καρτέλες σε αυτό τον πίνακα.",
@@ -178,17 +173,10 @@
"Owner" : "Κάτοχος",
"Delete" : "Διαγραφή",
"Failed to create share with {displayName}" : "Αποτυχία δημιουργίας κοινής χρήσης με το {displayName}",
"Are you sure you want to transfer the board {title} to {user}?" : "Είστε σίγουροι ότι θέλετε να μεταφέρετε τον πίνακα {title} στον {user}? ",
"Transfer the board." : "Μεταφορά του πίνακα.",
"Transfer" : "Μεταφορά",
"The board has been transferred to {user}" : "Ο πίνακας έχει μεταφερθεί στον/στην {user}",
"Failed to transfer the board to {user}" : "Απέτυχε η μεταφορά του πίνακα στον χρήστη {user}",
"Edit list title" : "Επεξεργασία τίτλου λίστας",
"Archive all cards" : "Αρχειοθέτηση όλων των καρτελών.",
"Unarchive all cards" : "Κατάργηση αρχειοθέτησης όλων των καρτών",
"Delete list" : "Διαγραφή λίστας",
"Archive all cards in this list" : "Αρχειοθέτηση όλων των καρτελών σε αυτή τη λίστα.",
"Unarchive all cards in this list" : "Κατάργηση αρχειοθέτησης όλων των καρτών σε αυτή τη λίστα",
"Add a new card" : "Προσθήκη νέας καρτέλας",
"Card name" : "Όνομα καρτέλας",
"List deleted" : "Η λίστα διαγράφηκε",
@@ -246,9 +234,7 @@
"Write a description …" : "Γράψτε μια περιγραφή…",
"Choose attachment" : "Επιλογή συνημμένου",
"(group)" : "(ομάδα)",
"Todo items" : "Στοιχεία todo",
"{count} comments, {unread} unread" : "{count} σχόλια, {unread} μη αναγνωσμένα",
"Edit card title" : "Επεξεργασία τίτλου κάρτας",
"Assign to me" : "Ανάθεση σε εμένα",
"Unassign myself" : "Αποδέσμευσή μου",
"Move card" : "Μετακίνηση καρτέλας",
@@ -263,7 +249,6 @@
"All boards" : "Όλοι οι πίνακες",
"Archived boards" : "Αρχειοθέτηση πινάκων ",
"Shared with you" : "Διαμοιρασμένα μαζί σας",
"Deck settings" : "Ρυθμίσεις Deck",
"Use bigger card view" : "Χρησιμοποιήστε μεγαλύτερη προβολή καρτέλας",
"Show boards in calendar/tasks" : "Εμφάνιση πινάκων στο ημερολόγιο / εργασίες",
"Limit deck usage of groups" : "Περιορίστε τη χρήση της εφαρμογής deck σε ομάδες",
@@ -273,7 +258,6 @@
"Clone board" : "Κλώνος πίνακα",
"Unarchive board" : "Κατάργηση αρχειοθέτησης πίνακα",
"Archive board" : "Αρχειοθέτηση πίνακα",
"Export board" : "Εξαγωγή πίνακα",
"Turn on due date reminders" : "Ενεργοποιήστε τις υπενθυμίσεις ημερομηνίας προθεσμίας",
"Turn off due date reminders" : "Απενεργοποιήστε τις υπενθυμίσεις ημερομηνίας προθεσμίας",
"Due date reminders" : "Υπενθυμίσεις ημερομηνίας προθεσμίας",
@@ -285,21 +269,14 @@
"Only assigned cards" : "Μόνο καρτέλες που έχουν ανατεθεί",
"No reminder" : "Δεν υπάρχει υπενθύμιση",
"An error occurred" : "Παρουσιάστηκε σφάλμα",
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Είστε βέβαιοι ότι θέλετε να διαγράψετε τον πίνακα {title}; Αυτό θα διαγράψει όλα τα δεδομένα του πίνακα συμπεριλαμβανομένων και των αρχειοθετημένων καρτών.",
"Delete the board?" : "Διαγραφή του πίνακα;",
"Loading filtered view" : "Φόρτωση εμφάνισης με βάση το φίλτρο",
"No due" : "Χωρίς λήξη",
"Search for {searchQuery} in all boards" : "Αναζήτηση για {searchQuery} σε όλους τους πίνακες",
"No results found" : "Δεν βρέθηκαν αποτελέσματα",
"Deck board {name}\n* Last modified on {lastMod}" : "Πίνακας Deck {name}\n* Τελευταία τροποποίηση στις {lastMod}",
"{stack} in {board}" : "{stack} στο {board}",
"Click to expand description" : "Κλικ για επέκταση περιγραφής",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Δημιουργήθηκε στις {created}\n* Τροποποιήθηκε στις {lastMod}\n* {nbAttachments} συνημμένα\n* {nbComments} σχόλια",
"{nbCards} cards" : "{nbCards} κάρτες",
"Click to expand comment" : "Κλικ για επέκταση σχολίου",
"No upcoming cards" : "Δεν υπάρχουν επερχόμενες καρτέλες",
"upcoming cards" : "επερχόμενες καρτέλες",
"Due on {date}" : "Προθεσμία στις {date}",
"Link to a board" : "Σύνδεσμος στον πίνακα",
"Link to a card" : "Σύνδεσμος σε καρτέλα",
"Create a card" : "Δημιουργία καρτέλας",
@@ -312,8 +289,6 @@
"Share {file} with a Deck card" : "Μοιραστείτε το {file} με μια καρτέλα Deck",
"Share" : "Μοιραστείτε",
"Are you sure you want to transfer the board {title} for {user}?" : "Είστε σίγουροι ότι θέλετε να μεταφέρετε τον πίνακα {title} για {user}? ",
"Transfer the board for {user} successfully" : "Επιτυχής μεταφορά του πίνακα για τον χρήστη {user}",
"Failed to transfer the board for {user}" : "Απέτυχε η μεταφορά του πίνακα για τον χρήστη {user}",
"Add a new list" : "Προσθήκη νέας λίστας",
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Είστε βέβαιοι ότι θέλετε να διαγράψετε τον πίνακα {title}; Θα διαγραφούν όλα τα δεδομένα."
},"pluralForm" :"nplurals=2; plural=(n != 1);"

View File

@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "Click to expand comment",
"No upcoming cards" : "No upcoming cards",
"upcoming cards" : "upcoming cards",
"New card" : "New card",
"Due on {date}" : "Due on {date}",
"Link to a board" : "Link to a board",
"Link to a card" : "Link to a card",

View File

@@ -301,7 +301,6 @@
"Click to expand comment" : "Click to expand comment",
"No upcoming cards" : "No upcoming cards",
"upcoming cards" : "upcoming cards",
"New card" : "New card",
"Due on {date}" : "Due on {date}",
"Link to a board" : "Link to a board",
"Link to a card" : "Link to a card",

View File

@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "Pulse para expandir el comentario",
"No upcoming cards" : "No hay tarjetas próximas",
"upcoming cards" : "próximas tarjetas",
"New card" : "Nueva tarjeta",
"Due on {date}" : "Vence en {date}",
"Link to a board" : "Enlace a un tablero",
"Link to a card" : "Enlace a una tarjeta",

View File

@@ -301,7 +301,6 @@
"Click to expand comment" : "Pulse para expandir el comentario",
"No upcoming cards" : "No hay tarjetas próximas",
"upcoming cards" : "próximas tarjetas",
"New card" : "Nueva tarjeta",
"Due on {date}" : "Vence en {date}",
"Link to a board" : "Enlace a un tablero",
"Link to a card" : "Enlace a una tarjeta",

View File

@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "Egin klik iruzkina handitzeko",
"No upcoming cards" : "Ez dago hurrengo txartelik",
"upcoming cards" : "hurrengo txartelak",
"New card" : "Txartel berria",
"Due on {date}" : "Iraungitze-data {date}",
"Link to a board" : "Estekatu taula batera",
"Link to a card" : "Estekatu txartel batera",

View File

@@ -301,7 +301,6 @@
"Click to expand comment" : "Egin klik iruzkina handitzeko",
"No upcoming cards" : "Ez dago hurrengo txartelik",
"upcoming cards" : "hurrengo txartelak",
"New card" : "Txartel berria",
"Due on {date}" : "Iraungitze-data {date}",
"Link to a board" : "Estekatu taula batera",
"Link to a card" : "Estekatu txartel batera",

View File

@@ -81,7 +81,6 @@ OC.L10N.register(
"Deck board" : "Tableau",
"Owned by %1$s" : "Assignée à %1$s",
"Deck boards, cards and comments" : "Tableaux, cartes et commentaires",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "De %1$s, dans %2$s / %3$s, appartenant à %4$s",
"Card comments" : "Commentaires de la carte",
"%s on %s" : "%s sur %s",
"Deck boards and cards" : "Tableaux et cartes",
@@ -125,7 +124,7 @@ OC.L10N.register(
"Card \"{card}\" was added to \"{board}\"" : "La carte \"{card}\" a été ajoutée au tableau \"{board}\"",
"Open card" : "Ouvrir la carte",
"Close" : "Fermer",
"Create card" : "Créer la carte",
"Create card" : "Créer une carte",
"Select a card" : "Sélectionnez une carte",
"Select the card to link to a project" : "Sélectionner la carte à relier à un projet",
"Link to card" : "Relier à une carte",
@@ -212,7 +211,7 @@ OC.L10N.register(
"File to share" : "Fichier à partager",
"Invalid path selected" : "Chemin sélectionné non valide",
"Open in sidebar view" : "Ouvrir dans le panneau latéral",
"Open in bigger view" : "Ouvrir dans la vue large",
"Open in bigger view" : "Ouvrir dans la vue principale",
"Attachments" : "Pièces jointes",
"Comments" : "Commentaires",
"Modified" : "Modifiée",
@@ -303,7 +302,6 @@ OC.L10N.register(
"Click to expand comment" : "Cliquer pour déplier le commentaire",
"No upcoming cards" : "Pas de cartes à venir",
"upcoming cards" : "cartes à venir",
"New card" : "Nouvelle carte",
"Due on {date}" : "Échéance le {date}",
"Link to a board" : "Relier à un tableau",
"Link to a card" : "Relier à une carte",

View File

@@ -79,7 +79,6 @@
"Deck board" : "Tableau",
"Owned by %1$s" : "Assignée à %1$s",
"Deck boards, cards and comments" : "Tableaux, cartes et commentaires",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "De %1$s, dans %2$s / %3$s, appartenant à %4$s",
"Card comments" : "Commentaires de la carte",
"%s on %s" : "%s sur %s",
"Deck boards and cards" : "Tableaux et cartes",
@@ -123,7 +122,7 @@
"Card \"{card}\" was added to \"{board}\"" : "La carte \"{card}\" a été ajoutée au tableau \"{board}\"",
"Open card" : "Ouvrir la carte",
"Close" : "Fermer",
"Create card" : "Créer la carte",
"Create card" : "Créer une carte",
"Select a card" : "Sélectionnez une carte",
"Select the card to link to a project" : "Sélectionner la carte à relier à un projet",
"Link to card" : "Relier à une carte",
@@ -210,7 +209,7 @@
"File to share" : "Fichier à partager",
"Invalid path selected" : "Chemin sélectionné non valide",
"Open in sidebar view" : "Ouvrir dans le panneau latéral",
"Open in bigger view" : "Ouvrir dans la vue large",
"Open in bigger view" : "Ouvrir dans la vue principale",
"Attachments" : "Pièces jointes",
"Comments" : "Commentaires",
"Modified" : "Modifiée",
@@ -301,7 +300,6 @@
"Click to expand comment" : "Cliquer pour déplier le commentaire",
"No upcoming cards" : "Pas de cartes à venir",
"upcoming cards" : "cartes à venir",
"New card" : "Nouvelle carte",
"Due on {date}" : "Échéance le {date}",
"Link to a board" : "Relier à un tableau",
"Link to a card" : "Relier à une carte",

View File

@@ -220,7 +220,7 @@ OC.L10N.register(
"Formatting help" : "Axuda de formatado",
"Edit description" : "Editar a descrición",
"View description" : "Ver a descrición",
"Add Attachment" : "Engadir un anexo",
"Add Attachment" : "Engadir o anexo",
"Write a description …" : "Escriba unha descrición…",
"Choose attachment" : "Escoller o anexo",
"(group)" : "(grupo)",

View File

@@ -218,7 +218,7 @@
"Formatting help" : "Axuda de formatado",
"Edit description" : "Editar a descrición",
"View description" : "Ver a descrición",
"Add Attachment" : "Engadir un anexo",
"Add Attachment" : "Engadir o anexo",
"Write a description …" : "Escriba unha descrición…",
"Choose attachment" : "Escoller o anexo",
"(group)" : "(grupo)",

View File

@@ -79,12 +79,8 @@ OC.L10N.register(
"The board \"%s\" has been shared with you by %s." : "A(z) „%s” táblát %s osztotta meg Önnel.",
"{user} has shared {deck-board} with you." : "{user} megosztotta Önnel a(z) {deck-board} táblát.",
"Deck board" : "Kártyatábla",
"Owned by %1$s" : "Tulajdonos: %1$s",
"Deck boards, cards and comments" : "Kártyatáblák, kártyák és megjegyzések",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "A következőtől: %1$s, ebben: %2$s/%3$s, tulajdonos: %4$s",
"Card comments" : "Kártya hozzászólásai",
"%s on %s" : "%s ezen: %s",
"Deck boards and cards" : "Kártyatáblák és kártyák",
"No data was provided to create an attachment." : "Nincsenek megadva adatok a melléklet létrehozásához.",
"Finished" : "Kész",
"To review" : "Áttekintendő",
@@ -295,7 +291,6 @@ OC.L10N.register(
"No due" : "Nincs határidő",
"Search for {searchQuery} in all boards" : "Keresés a(z) {searchQuery} kifejezésre az összes táblában",
"No results found" : "Nincs találat",
"Deck board {name}\n* Last modified on {lastMod}" : "{name} kártyatábla\n* Legutóbb módosítva: {lastMod}",
"{stack} in {board}" : "{stack} itt: {board}",
"Click to expand description" : "Kattintson a leírás kibontásához",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Létrehozva: {created}\n* Utoljára módosítva: {lastMod}\n* {nbAttachments} melléklet\n* {nbComments} megjegyzés",
@@ -303,7 +298,6 @@ OC.L10N.register(
"Click to expand comment" : "Kattintson a megjegyzés kibontásához",
"No upcoming cards" : "Nincsenek közelgő kártyák",
"upcoming cards" : "közelgő kártyák",
"New card" : "Új kártya",
"Due on {date}" : "Határidő: {date}",
"Link to a board" : "Hivatkozás egy táblához",
"Link to a card" : "Hivatkozás egy kártyához",

View File

@@ -77,12 +77,8 @@
"The board \"%s\" has been shared with you by %s." : "A(z) „%s” táblát %s osztotta meg Önnel.",
"{user} has shared {deck-board} with you." : "{user} megosztotta Önnel a(z) {deck-board} táblát.",
"Deck board" : "Kártyatábla",
"Owned by %1$s" : "Tulajdonos: %1$s",
"Deck boards, cards and comments" : "Kártyatáblák, kártyák és megjegyzések",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "A következőtől: %1$s, ebben: %2$s/%3$s, tulajdonos: %4$s",
"Card comments" : "Kártya hozzászólásai",
"%s on %s" : "%s ezen: %s",
"Deck boards and cards" : "Kártyatáblák és kártyák",
"No data was provided to create an attachment." : "Nincsenek megadva adatok a melléklet létrehozásához.",
"Finished" : "Kész",
"To review" : "Áttekintendő",
@@ -293,7 +289,6 @@
"No due" : "Nincs határidő",
"Search for {searchQuery} in all boards" : "Keresés a(z) {searchQuery} kifejezésre az összes táblában",
"No results found" : "Nincs találat",
"Deck board {name}\n* Last modified on {lastMod}" : "{name} kártyatábla\n* Legutóbb módosítva: {lastMod}",
"{stack} in {board}" : "{stack} itt: {board}",
"Click to expand description" : "Kattintson a leírás kibontásához",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Létrehozva: {created}\n* Utoljára módosítva: {lastMod}\n* {nbAttachments} melléklet\n* {nbComments} megjegyzés",
@@ -301,7 +296,6 @@
"Click to expand comment" : "Kattintson a megjegyzés kibontásához",
"No upcoming cards" : "Nincsenek közelgő kártyák",
"upcoming cards" : "közelgő kártyák",
"New card" : "Új kártya",
"Due on {date}" : "Határidő: {date}",
"Link to a board" : "Hivatkozás egy táblához",
"Link to a card" : "Hivatkozás egy kártyához",

View File

@@ -3,14 +3,6 @@ OC.L10N.register(
{
"Personal" : "Անձնական",
"Done" : "Done",
"The file was uploaded" : "Նիշքը վերբերռնված է",
"The uploaded file exceeds the upload_max_filesize directive in php.ini" : "Վերբեռնած նիշքը գերազանցում է upload_max_filesize սահմանված php.ini֊ում",
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" : "Վերբեռնած նիշքը գերազանցում է MAX_FILE_SIZE, որը սահմանված է HTML ձևաթղթում",
"The file was only partially uploaded" : "Նիշքի մի մասն է վերբեռնված",
"No file was uploaded" : "Ոչ մի նիշք չի վերնբեռնվել",
"Missing a temporary folder" : "Բացակայում է ժամանակավոր պանակը",
"Could not write file to disk" : "Չհաջողվեց գրառել նիշքը սկավառակի վրա",
"A PHP extension stopped the file upload" : "PHP֊ի ընդլայնումն կանգնեցրեց նիշքի վերբեռնումը",
"Cancel" : "ընդհատել",
"Close" : "Փակել",
"Details" : "Մանրամասներ",

View File

@@ -1,14 +1,6 @@
{ "translations": {
"Personal" : "Անձնական",
"Done" : "Done",
"The file was uploaded" : "Նիշքը վերբերռնված է",
"The uploaded file exceeds the upload_max_filesize directive in php.ini" : "Վերբեռնած նիշքը գերազանցում է upload_max_filesize սահմանված php.ini֊ում",
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" : "Վերբեռնած նիշքը գերազանցում է MAX_FILE_SIZE, որը սահմանված է HTML ձևաթղթում",
"The file was only partially uploaded" : "Նիշքի մի մասն է վերբեռնված",
"No file was uploaded" : "Ոչ մի նիշք չի վերնբեռնվել",
"Missing a temporary folder" : "Բացակայում է ժամանակավոր պանակը",
"Could not write file to disk" : "Չհաջողվեց գրառել նիշքը սկավառակի վրա",
"A PHP extension stopped the file upload" : "PHP֊ի ընդլայնումն կանգնեցրեց նիշքի վերբեռնումը",
"Cancel" : "ընդհատել",
"Close" : "Փակել",
"Details" : "Մանրամասներ",

View File

@@ -67,7 +67,6 @@ OC.L10N.register(
"Deck" : "Longgok",
"Changes in the <strong>Deck app</strong>" : "Perubahan pada <strong>aplikasi Longgok</strong>",
"A <strong>comment</strong> was created on a card" : "<strong>Komentar</strong> telah dibuat pada suatu kartu",
"Upcoming cards" : "Kartu berikut",
"Personal" : "Personal",
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Kartu \"%s\" pada \"%s\" telah ditugaskan kepada Anda oleh %s.",
"The card \"%s\" on \"%s\" has reached its due date." : "Kartu \"%s\" pada \"%s\" telah melampaui tenggat.",
@@ -94,7 +93,6 @@ OC.L10N.register(
"Could not write file to disk" : "Tidak dapat menulis berkas ke diska",
"A PHP extension stopped the file upload" : "Ekstensi PHP menghentikan proses unggah berkas",
"No file uploaded or file size exceeds maximum of %s" : "Gagal unggah berkas atau ukuran melampaui batas maksimum %s",
"Card not found" : "Kartu tidak ditemukan",
"Invalid date, date format must be YYYY-MM-DD" : "Tanggal salah, format tanggal harus TTTT-BB-HH",
"Personal planning and team project organization" : "Perencanaan pribadi dan pengelolaan proyek tim",
"Add board" : "Tambah papan",
@@ -117,12 +115,10 @@ OC.L10N.register(
"Drop your files to upload" : "Lepas berkas Anda untuk mengunggah",
"Add card" : "Tambah kartu",
"Archived cards" : "Arsip kartu",
"Add list" : "Tambahkan daftar",
"List name" : "Nama daftar",
"Apply filter" : "Terapkan filter",
"Filter by tag" : "Filter dengan tag",
"Filter by assigned user" : "Filter dengan pengguna",
"Unassigned" : "Belum ditugaskan",
"Filter by due date" : "Filter dengan tenggat",
"Overdue" : "Lewat tenggat",
"Next 24 hours" : "Jangka 24 jam",
@@ -212,14 +208,11 @@ OC.L10N.register(
"Clone board" : "Pengklonaan papan",
"Unarchive board" : "Memulihkan papan",
"Archive board" : "Mengarsipkan papan",
"No notifications" : "Tidak ada notifikasi",
"No notifications" : "Tidak ada notifikasi.",
"Delete board" : "Hapus papan",
"Board {0} deleted" : "{0} papan terhapus",
"An error occurred" : "Terjadi kesalahan",
"Delete the board?" : "Hapus papan?",
"Click to expand comment" : "Klik untuk membuka komentar",
"No upcoming cards" : "Tidak ada kartu berikut",
"upcoming cards" : "kartu berikut",
"Link to a board" : "Tautan ke papan",
"Link to a card" : "Tautan ke kartu",
"Something went wrong" : "Ada yang salah",

View File

@@ -65,7 +65,6 @@
"Deck" : "Longgok",
"Changes in the <strong>Deck app</strong>" : "Perubahan pada <strong>aplikasi Longgok</strong>",
"A <strong>comment</strong> was created on a card" : "<strong>Komentar</strong> telah dibuat pada suatu kartu",
"Upcoming cards" : "Kartu berikut",
"Personal" : "Personal",
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Kartu \"%s\" pada \"%s\" telah ditugaskan kepada Anda oleh %s.",
"The card \"%s\" on \"%s\" has reached its due date." : "Kartu \"%s\" pada \"%s\" telah melampaui tenggat.",
@@ -92,7 +91,6 @@
"Could not write file to disk" : "Tidak dapat menulis berkas ke diska",
"A PHP extension stopped the file upload" : "Ekstensi PHP menghentikan proses unggah berkas",
"No file uploaded or file size exceeds maximum of %s" : "Gagal unggah berkas atau ukuran melampaui batas maksimum %s",
"Card not found" : "Kartu tidak ditemukan",
"Invalid date, date format must be YYYY-MM-DD" : "Tanggal salah, format tanggal harus TTTT-BB-HH",
"Personal planning and team project organization" : "Perencanaan pribadi dan pengelolaan proyek tim",
"Add board" : "Tambah papan",
@@ -115,12 +113,10 @@
"Drop your files to upload" : "Lepas berkas Anda untuk mengunggah",
"Add card" : "Tambah kartu",
"Archived cards" : "Arsip kartu",
"Add list" : "Tambahkan daftar",
"List name" : "Nama daftar",
"Apply filter" : "Terapkan filter",
"Filter by tag" : "Filter dengan tag",
"Filter by assigned user" : "Filter dengan pengguna",
"Unassigned" : "Belum ditugaskan",
"Filter by due date" : "Filter dengan tenggat",
"Overdue" : "Lewat tenggat",
"Next 24 hours" : "Jangka 24 jam",
@@ -210,14 +206,11 @@
"Clone board" : "Pengklonaan papan",
"Unarchive board" : "Memulihkan papan",
"Archive board" : "Mengarsipkan papan",
"No notifications" : "Tidak ada notifikasi",
"No notifications" : "Tidak ada notifikasi.",
"Delete board" : "Hapus papan",
"Board {0} deleted" : "{0} papan terhapus",
"An error occurred" : "Terjadi kesalahan",
"Delete the board?" : "Hapus papan?",
"Click to expand comment" : "Klik untuk membuka komentar",
"No upcoming cards" : "Tidak ada kartu berikut",
"upcoming cards" : "kartu berikut",
"Link to a board" : "Tautan ke papan",
"Link to a card" : "Tautan ke kartu",
"Something went wrong" : "Ada yang salah",

View File

@@ -175,7 +175,6 @@ OC.L10N.register(
"Owner" : "Proprietario",
"Delete" : "Elimina",
"Failed to create share with {displayName}" : "Creazione della condivisione con {displayName} non riuscita",
"Transfer the board." : "Trasferisci la bacheca.",
"Transfer" : "Trasferisci",
"Archive all cards" : "Archivia tutte le schede",
"Delete list" : "Elimina elenco",
@@ -291,8 +290,6 @@ OC.L10N.register(
"Share with a Deck card" : "Condividi con una scheda di Deck",
"Share {file} with a Deck card" : "Condividi {file} con una scheda di Deck",
"Share" : "Condividi",
"Transfer the board for {user} successfully" : "Trasferimento della bacheca per {user} avvenuta con successo.",
"Failed to transfer the board for {user}" : "Trasferimento della bacheca per {user} fallito",
"Add a new list" : "Aggiungi un nuovo elenco",
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Sei sicuro di voler eliminare la lavagna {title}? Questo eliminerà tutti i dati di questa lavagna?"
},

View File

@@ -173,7 +173,6 @@
"Owner" : "Proprietario",
"Delete" : "Elimina",
"Failed to create share with {displayName}" : "Creazione della condivisione con {displayName} non riuscita",
"Transfer the board." : "Trasferisci la bacheca.",
"Transfer" : "Trasferisci",
"Archive all cards" : "Archivia tutte le schede",
"Delete list" : "Elimina elenco",
@@ -289,8 +288,6 @@
"Share with a Deck card" : "Condividi con una scheda di Deck",
"Share {file} with a Deck card" : "Condividi {file} con una scheda di Deck",
"Share" : "Condividi",
"Transfer the board for {user} successfully" : "Trasferimento della bacheca per {user} avvenuta con successo.",
"Failed to transfer the board for {user}" : "Trasferimento della bacheca per {user} fallito",
"Add a new list" : "Aggiungi un nuovo elenco",
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Sei sicuro di voler eliminare la lavagna {title}? Questo eliminerà tutti i dati di questa lavagna?"
},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"

View File

@@ -30,8 +30,6 @@ OC.L10N.register(
"Created" : "Үүсгэсэн",
"Today" : "өнөөдөр",
"Tomorrow" : "маргааш",
"Next week" : "Дараа 7 хоног",
"Next month" : "Дараа сар",
"Save" : "Хадгалах",
"Reply" : "хариулт",
"Update" : "Шинэчлэх",

View File

@@ -28,8 +28,6 @@
"Created" : "Үүсгэсэн",
"Today" : "өнөөдөр",
"Tomorrow" : "маргааш",
"Next week" : "Дараа 7 хоног",
"Next month" : "Дараа сар",
"Save" : "Хадгалах",
"Reply" : "хариулт",
"Update" : "Шинэчлэх",

View File

@@ -78,13 +78,9 @@ OC.L10N.register(
"{user} has mentioned you in a comment on {deck-card}." : "{user} har nevnt deg i en kommentar på {deck-card}.",
"The board \"%s\" has been shared with you by %s." : "Brettet \"%s\" har blitt delt med deg av %s.",
"{user} has shared {deck-board} with you." : "{user} har delt brettet {deck-board} med deg.",
"Deck board" : "Stokktavle",
"Owned by %1$s" : "Eid av %1$s",
"Deck boards, cards and comments" : "Stokktavler, kort og kommentarer",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "Fra %1$s, under %2$s/%3$s, eid av %4$s",
"Deck board" : "Deck tavle",
"Card comments" : "Kommentarer på kortet",
"%s on %s" : "%s på %s",
"Deck boards and cards" : "Stokktavler og kort",
"No data was provided to create an attachment." : "Ingen data for å opprette vedlegg.",
"Finished" : "Fullført",
"To review" : "Til gjennomlesning",
@@ -157,7 +153,6 @@ OC.L10N.register(
"Toggle compact mode" : "Endre kompakt modus",
"Open details" : "Åpne detaljer",
"Details" : "Detaljer",
"Currently present people" : "Tilstedeværende personer for øyeblikket",
"Loading board" : "Laster tavle",
"No lists available" : "Ingen stabler tilgjengelig",
"Create a new list to add cards to this board" : "Lag en ny stabel for å legge til kort til denne tavlen",
@@ -186,12 +181,9 @@ OC.L10N.register(
"Transfer" : "Overfør",
"The board has been transferred to {user}" : "Tavlen har blitt overført til {user}",
"Failed to transfer the board to {user}" : "Klarte ikke overføre tavlen til {user}",
"Edit list title" : "Rediger listetittel",
"Archive all cards" : "Arkiver alle kort",
"Unarchive all cards" : "Fjern alle kort fra arkiv",
"Delete list" : "Slett listen",
"Archive all cards in this list" : "Arkiver alle kort i en stabel",
"Unarchive all cards in this list" : "Fjern alle kortene i denne listen fra arkiv",
"Add a new card" : "Legg til nytt kort",
"Card name" : "Navn på kort",
"List deleted" : "Stabel slettet",
@@ -268,7 +260,6 @@ OC.L10N.register(
"Shared with you" : "Delt med deg",
"Deck settings" : "Innstillinger for Stokk",
"Use bigger card view" : "Bruk større visning på kort",
"Show card ID badge" : "Vis ID-merke til kort",
"Show boards in calendar/tasks" : "Vis tavler i kalender/oppgaver",
"Limit deck usage of groups" : "Begrens stokk-bruk til grupper",
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Begrensning av tavler vil hindre tilgang til de brukere som ikke er medlem av en gruppe fra å lage egne tavler. Bruker kan arbeide på de tavler som er delt med dem.",
@@ -277,7 +268,6 @@ OC.L10N.register(
"Clone board" : "Klon tavle",
"Unarchive board" : "Aktiver tavle",
"Archive board" : "Arkiver tavle",
"Export board" : "Eksporter tavle",
"Turn on due date reminders" : "Skru på påminnelser for forfallsdato",
"Turn off due date reminders" : "Skru av påminnelser for forfallsdato",
"Due date reminders" : "Påminnelser for forfallsdato",
@@ -288,19 +278,17 @@ OC.L10N.register(
"Board {0} deleted" : "Tavle {0} slettet",
"Only assigned cards" : "Kun tildelte kort",
"No reminder" : "Ingen varsel",
"An error occurred" : "En feil oppsto",
"An error occurred" : "En feil oppstod",
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Are du sikker på sletting av tavlen {title}? Handlingen vil slette all data i denne tavlen, inkludert arkiverte kort.",
"Delete the board?" : "Slett tavlen?",
"Loading filtered view" : "Laster filtrert visning",
"No due" : "Ingen forfall",
"Search for {searchQuery} in all boards" : "Søk etter {searchQuery} i alle tavler",
"No results found" : "Ingen resultater funnet",
"Deck board {name}\n* Last modified on {lastMod}" : "Stokktavle {name}\n* Sist endret {lastMod}",
"{stack} in {board}" : "{stack} i {board}",
"Click to expand description" : "Klikk for å utvide beskrivelsen",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Opprettet {created}\n* Sist endret {lastMod}\n* {nbAttachments} vedlegg\n* {nbComments} kommentarer",
"{nbCards} cards" : "{nbCards} kort",
"Click to expand comment" : "Klikk for å utvide kommentaren",
"No upcoming cards" : "Ingen kommende kort",
"upcoming cards" : "kommende kort",
"Due on {date}" : "Utløper {date}",

View File

@@ -76,13 +76,9 @@
"{user} has mentioned you in a comment on {deck-card}." : "{user} har nevnt deg i en kommentar på {deck-card}.",
"The board \"%s\" has been shared with you by %s." : "Brettet \"%s\" har blitt delt med deg av %s.",
"{user} has shared {deck-board} with you." : "{user} har delt brettet {deck-board} med deg.",
"Deck board" : "Stokktavle",
"Owned by %1$s" : "Eid av %1$s",
"Deck boards, cards and comments" : "Stokktavler, kort og kommentarer",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "Fra %1$s, under %2$s/%3$s, eid av %4$s",
"Deck board" : "Deck tavle",
"Card comments" : "Kommentarer på kortet",
"%s on %s" : "%s på %s",
"Deck boards and cards" : "Stokktavler og kort",
"No data was provided to create an attachment." : "Ingen data for å opprette vedlegg.",
"Finished" : "Fullført",
"To review" : "Til gjennomlesning",
@@ -155,7 +151,6 @@
"Toggle compact mode" : "Endre kompakt modus",
"Open details" : "Åpne detaljer",
"Details" : "Detaljer",
"Currently present people" : "Tilstedeværende personer for øyeblikket",
"Loading board" : "Laster tavle",
"No lists available" : "Ingen stabler tilgjengelig",
"Create a new list to add cards to this board" : "Lag en ny stabel for å legge til kort til denne tavlen",
@@ -184,12 +179,9 @@
"Transfer" : "Overfør",
"The board has been transferred to {user}" : "Tavlen har blitt overført til {user}",
"Failed to transfer the board to {user}" : "Klarte ikke overføre tavlen til {user}",
"Edit list title" : "Rediger listetittel",
"Archive all cards" : "Arkiver alle kort",
"Unarchive all cards" : "Fjern alle kort fra arkiv",
"Delete list" : "Slett listen",
"Archive all cards in this list" : "Arkiver alle kort i en stabel",
"Unarchive all cards in this list" : "Fjern alle kortene i denne listen fra arkiv",
"Add a new card" : "Legg til nytt kort",
"Card name" : "Navn på kort",
"List deleted" : "Stabel slettet",
@@ -266,7 +258,6 @@
"Shared with you" : "Delt med deg",
"Deck settings" : "Innstillinger for Stokk",
"Use bigger card view" : "Bruk større visning på kort",
"Show card ID badge" : "Vis ID-merke til kort",
"Show boards in calendar/tasks" : "Vis tavler i kalender/oppgaver",
"Limit deck usage of groups" : "Begrens stokk-bruk til grupper",
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Begrensning av tavler vil hindre tilgang til de brukere som ikke er medlem av en gruppe fra å lage egne tavler. Bruker kan arbeide på de tavler som er delt med dem.",
@@ -275,7 +266,6 @@
"Clone board" : "Klon tavle",
"Unarchive board" : "Aktiver tavle",
"Archive board" : "Arkiver tavle",
"Export board" : "Eksporter tavle",
"Turn on due date reminders" : "Skru på påminnelser for forfallsdato",
"Turn off due date reminders" : "Skru av påminnelser for forfallsdato",
"Due date reminders" : "Påminnelser for forfallsdato",
@@ -286,19 +276,17 @@
"Board {0} deleted" : "Tavle {0} slettet",
"Only assigned cards" : "Kun tildelte kort",
"No reminder" : "Ingen varsel",
"An error occurred" : "En feil oppsto",
"An error occurred" : "En feil oppstod",
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Are du sikker på sletting av tavlen {title}? Handlingen vil slette all data i denne tavlen, inkludert arkiverte kort.",
"Delete the board?" : "Slett tavlen?",
"Loading filtered view" : "Laster filtrert visning",
"No due" : "Ingen forfall",
"Search for {searchQuery} in all boards" : "Søk etter {searchQuery} i alle tavler",
"No results found" : "Ingen resultater funnet",
"Deck board {name}\n* Last modified on {lastMod}" : "Stokktavle {name}\n* Sist endret {lastMod}",
"{stack} in {board}" : "{stack} i {board}",
"Click to expand description" : "Klikk for å utvide beskrivelsen",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Opprettet {created}\n* Sist endret {lastMod}\n* {nbAttachments} vedlegg\n* {nbComments} kommentarer",
"{nbCards} cards" : "{nbCards} kort",
"Click to expand comment" : "Klikk for å utvide kommentaren",
"No upcoming cards" : "Ingen kommende kort",
"upcoming cards" : "kommende kort",
"Due on {date}" : "Utløper {date}",

View File

@@ -79,12 +79,8 @@ OC.L10N.register(
"The board \"%s\" has been shared with you by %s." : "Tablica \"%s\" została Tobie udostępniona przez %s.",
"{user} has shared {deck-board} with you." : "{user} udostępnił Tobie {deck-board}.",
"Deck board" : "Tablica Deck",
"Owned by %1$s" : "Właścicielem jest %1$s",
"Deck boards, cards and comments" : "Tablice, karty i komentarze",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "Od %1$s, w %2$s/%3$s, posiadane przez %4$s",
"Card comments" : "Komentarze karty",
"%s on %s" : "%s na %s",
"Deck boards and cards" : "Tablice i karty",
"No data was provided to create an attachment." : "Nie podano żadnych danych do utworzenia załącznika.",
"Finished" : "Ukończone",
"To review" : "Do sprawdzenia",
@@ -295,7 +291,6 @@ OC.L10N.register(
"No due" : "Bez ważności",
"Search for {searchQuery} in all boards" : "Wyszukaj dla {searchQuery} na wszystkich tablicach",
"No results found" : "Nie znaleziono wyników",
"Deck board {name}\n* Last modified on {lastMod}" : "Tablica {name}\n* Ostatnia modyfikacja w dniu {lastMod}",
"{stack} in {board}" : "{stack} na {board}",
"Click to expand description" : "Kliknij, aby rozwinąć opis",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Utworzono {created}\n* Ostatnia modyfikacja {lastMod}\n* Załączniki {nbAttachments}\n* Komentarze {nbComments}",
@@ -303,7 +298,6 @@ OC.L10N.register(
"Click to expand comment" : "Kliknij, aby rozwinąć komentarz",
"No upcoming cards" : "Brak nadchodzących kart",
"upcoming cards" : "nadchodzące karty",
"New card" : "Nowa karta",
"Due on {date}" : "Termin {date}",
"Link to a board" : "Link do tablicy",
"Link to a card" : "Link do karty",

View File

@@ -77,12 +77,8 @@
"The board \"%s\" has been shared with you by %s." : "Tablica \"%s\" została Tobie udostępniona przez %s.",
"{user} has shared {deck-board} with you." : "{user} udostępnił Tobie {deck-board}.",
"Deck board" : "Tablica Deck",
"Owned by %1$s" : "Właścicielem jest %1$s",
"Deck boards, cards and comments" : "Tablice, karty i komentarze",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "Od %1$s, w %2$s/%3$s, posiadane przez %4$s",
"Card comments" : "Komentarze karty",
"%s on %s" : "%s na %s",
"Deck boards and cards" : "Tablice i karty",
"No data was provided to create an attachment." : "Nie podano żadnych danych do utworzenia załącznika.",
"Finished" : "Ukończone",
"To review" : "Do sprawdzenia",
@@ -293,7 +289,6 @@
"No due" : "Bez ważności",
"Search for {searchQuery} in all boards" : "Wyszukaj dla {searchQuery} na wszystkich tablicach",
"No results found" : "Nie znaleziono wyników",
"Deck board {name}\n* Last modified on {lastMod}" : "Tablica {name}\n* Ostatnia modyfikacja w dniu {lastMod}",
"{stack} in {board}" : "{stack} na {board}",
"Click to expand description" : "Kliknij, aby rozwinąć opis",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Utworzono {created}\n* Ostatnia modyfikacja {lastMod}\n* Załączniki {nbAttachments}\n* Komentarze {nbComments}",
@@ -301,7 +296,6 @@
"Click to expand comment" : "Kliknij, aby rozwinąć komentarz",
"No upcoming cards" : "Brak nadchodzących kart",
"upcoming cards" : "nadchodzące karty",
"New card" : "Nowa karta",
"Due on {date}" : "Termin {date}",
"Link to a board" : "Link do tablicy",
"Link to a card" : "Link do karty",

View File

@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "Clique para expandir o comentário",
"No upcoming cards" : "Não há mais cartões",
"upcoming cards" : "próximos cartões",
"New card" : "New card",
"Due on {date}" : "Vencimento em {date}",
"Link to a board" : "Vincular a um painel",
"Link to a card" : "Vincular a um cartão",

View File

@@ -301,7 +301,6 @@
"Click to expand comment" : "Clique para expandir o comentário",
"No upcoming cards" : "Não há mais cartões",
"upcoming cards" : "próximos cartões",
"New card" : "New card",
"Due on {date}" : "Vencimento em {date}",
"Link to a board" : "Vincular a um painel",
"Link to a card" : "Vincular a um cartão",

View File

@@ -79,11 +79,8 @@ OC.L10N.register(
"The board \"%s\" has been shared with you by %s." : "Вам предоставлен доступ к рабочей доске «%s» пользователем %s.",
"{user} has shared {deck-board} with you." : "{user} предоставил(а) вам доступ к {deck-board}.",
"Deck board" : "Доска",
"Owned by %1$s" : "Владелец: %1$s",
"Deck boards, cards and comments" : "Доски, карточки и комментарии",
"Card comments" : "Комментарии карточки",
"%s on %s" : "%s на %s",
"Deck boards and cards" : "Доски и карточки",
"No data was provided to create an attachment." : "Отсутствуют данные для создания вложения.",
"Finished" : "Завершено",
"To review" : "Проверить",
@@ -184,7 +181,6 @@ OC.L10N.register(
"Transfer" : "Передача",
"The board has been transferred to {user}" : "Доска была передана пользователю {user}",
"Failed to transfer the board to {user}" : "Не удалось передать доску пользователю {user}",
"Edit list title" : "Изменить название списка",
"Archive all cards" : "Переместить все карточки в архив",
"Unarchive all cards" : "Восстановить все карточки из архива",
"Delete list" : "Удалить список",
@@ -275,7 +271,6 @@ OC.L10N.register(
"Clone board" : "Скопировать доску",
"Unarchive board" : "Восстановить доску из архива",
"Archive board" : "Переместить доску в архив",
"Export board" : "Экспортировать доску",
"Turn on due date reminders" : "Включить напоминания о сроке выполнения",
"Turn off due date reminders" : "Отключить напоминания о сроке выполнения",
"Due date reminders" : "Напоминания о сроке выполнения",
@@ -293,14 +288,11 @@ OC.L10N.register(
"No due" : "Без назначенной даты",
"Search for {searchQuery} in all boards" : "Искать {searchQuery} на всех досках",
"No results found" : "Результаты отсутствуют",
"Deck board {name}\n* Last modified on {lastMod}" : "Доска «{name}»\n* Последнее изменение: {lastMod}",
"{stack} in {board}" : "«{stack}» с доски «{board}»",
"Click to expand description" : "Нажмите, чтобы развернуть поле описания",
"{nbCards} cards" : "карточек: {nbCards}",
"Click to expand comment" : "Нажмите, чтобы развернуть комментарии",
"No upcoming cards" : "Отсутствуют карточки, ожидающие выполнения",
"upcoming cards" : "карточки, ожидающие выполнения",
"Due on {date}" : "Дата исполнения: {date}",
"Link to a board" : "Ссылка на доску",
"Link to a card" : "Ссылка на карточку",
"Create a card" : "Создать карточку",

View File

@@ -77,11 +77,8 @@
"The board \"%s\" has been shared with you by %s." : "Вам предоставлен доступ к рабочей доске «%s» пользователем %s.",
"{user} has shared {deck-board} with you." : "{user} предоставил(а) вам доступ к {deck-board}.",
"Deck board" : "Доска",
"Owned by %1$s" : "Владелец: %1$s",
"Deck boards, cards and comments" : "Доски, карточки и комментарии",
"Card comments" : "Комментарии карточки",
"%s on %s" : "%s на %s",
"Deck boards and cards" : "Доски и карточки",
"No data was provided to create an attachment." : "Отсутствуют данные для создания вложения.",
"Finished" : "Завершено",
"To review" : "Проверить",
@@ -182,7 +179,6 @@
"Transfer" : "Передача",
"The board has been transferred to {user}" : "Доска была передана пользователю {user}",
"Failed to transfer the board to {user}" : "Не удалось передать доску пользователю {user}",
"Edit list title" : "Изменить название списка",
"Archive all cards" : "Переместить все карточки в архив",
"Unarchive all cards" : "Восстановить все карточки из архива",
"Delete list" : "Удалить список",
@@ -273,7 +269,6 @@
"Clone board" : "Скопировать доску",
"Unarchive board" : "Восстановить доску из архива",
"Archive board" : "Переместить доску в архив",
"Export board" : "Экспортировать доску",
"Turn on due date reminders" : "Включить напоминания о сроке выполнения",
"Turn off due date reminders" : "Отключить напоминания о сроке выполнения",
"Due date reminders" : "Напоминания о сроке выполнения",
@@ -291,14 +286,11 @@
"No due" : "Без назначенной даты",
"Search for {searchQuery} in all boards" : "Искать {searchQuery} на всех досках",
"No results found" : "Результаты отсутствуют",
"Deck board {name}\n* Last modified on {lastMod}" : "Доска «{name}»\n* Последнее изменение: {lastMod}",
"{stack} in {board}" : "«{stack}» с доски «{board}»",
"Click to expand description" : "Нажмите, чтобы развернуть поле описания",
"{nbCards} cards" : "карточек: {nbCards}",
"Click to expand comment" : "Нажмите, чтобы развернуть комментарии",
"No upcoming cards" : "Отсутствуют карточки, ожидающие выполнения",
"upcoming cards" : "карточки, ожидающие выполнения",
"Due on {date}" : "Дата исполнения: {date}",
"Link to a board" : "Ссылка на доску",
"Link to a card" : "Ссылка на карточку",
"Create a card" : "Создать карточку",

View File

@@ -71,20 +71,11 @@ OC.L10N.register(
"Load more" : "Учитај још",
"Personal" : "Лично",
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Корисник %s Вам је доделио картицу „%s“ са табле „%s“.",
"{user} has assigned the card {deck-card} on {deck-board} to you." : "{user} вам је доделио картицу {deck-card} на {deck-board}.",
"The card \"%s\" on \"%s\" has reached its due date." : "Картици „%s“ на табли „%s“ је истекао рок.",
"The card {deck-card} on {deck-board} has reached its due date." : "Картица {deck-card} на {deck-board} је дошла достигла датум када треба да се реши.",
"%s has mentioned you in a comment on \"%s\"." : "%s Вас је поменуо у коментару на „%s“.",
"{user} has mentioned you in a comment on {deck-card}." : "{user} вас је поменуо у коментару на {deck-card}.",
"The board \"%s\" has been shared with you by %s." : "Корисник „%s“ је поделио са Вама таблу „%s“.",
"{user} has shared {deck-board} with you." : "{user} је са вама поделио {deck-board}.",
"Deck board" : "Табла Шпила",
"Owned by %1$s" : "Власник је %1$s",
"Deck boards, cards and comments" : "Табле шпилова, картице и коментари",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "Од %1$s, у %2$s/%3$s, власник је %4$s",
"Card comments" : "Коментари картица",
"%s on %s" : "%s на %s",
"Deck boards and cards" : "Табле шпилова и картице",
"No data was provided to create an attachment." : "Нису дати подаци за креирање прилога.",
"Finished" : "Завршено",
"To review" : "Треба прегледати",
@@ -106,24 +97,16 @@ OC.L10N.register(
"Could not write file to disk" : "Не могу да пишем на диск",
"A PHP extension stopped the file upload" : "PHP екстензија је зауставила отпремање фајла",
"No file uploaded or file size exceeds maximum of %s" : "Ниједан фајл није отпремљен или величина фајла премашује максимум од %s",
"This comment has more than %s characters.\nAdded as an attachment to the card with name %s.\nAccessible on URL: %s." : "Овај коментар има више од %s карактера.\nДодат је као прилог картици под именом %s.\nДоступно је на URL адреси: %s.",
"Card not found" : "Картица није нађена",
"Path is already shared with this card" : "Путања се већ дели са овом картицом",
"Invalid date, date format must be YYYY-MM-DD" : "Неисправан датим, формат датума мора бити ГГГГ-ММ-ДД",
"Personal planning and team project organization" : "Лични планер и организатор тимског пројекта",
"Deck is a kanban style organization tool aimed at personal planning and project organization for teams integrated with Nextcloud.\n\n\n- 📥 Add your tasks to cards and put them in order\n- 📄 Write down additional notes in Markdown\n- 🔖 Assign labels for even better organization\n- 👥 Share with your team, friends or family\n- 📎 Attach files and embed them in your Markdown description\n- 💬 Discuss with your team using comments\n- ⚡ Keep track of changes in the activity stream\n- 🚀 Get your project organized" : "Шпил је организациони алат у канбан стилу који је намењен личном планирању и организацији пројекта у тимовима интегрисаним са Nextcloud.\n\n\n- 📥 Додајте своје задатке у картице и поређајте их по редоследу\n- 📄 Напишите додатне белешке употребом Markdown синтаксе\n- 🔖 Доделите ознаке у циљу још боље организације\n- 👥 Делите са својим тимом, пријатељима или породицом\n- 📎 Прикачите фајлове и уградите их у свој Markdown опис\n- 💬 Дискутујте са својим тимом користећи коментаре\n- ⚡ Пратите измене у току активности\n- 🚀 Организујте свој пројекат",
"Add board" : "Додај таблу",
"Select the board to link to a project" : "Одаберите таблу да је повежете са пројектом",
"Search by board title" : "Претражи по наслову табле",
"Select board" : "Одаберите таблу",
"Create a new card" : "Креирај нову картицу",
"Select a board" : "Изаберите таблу",
"Select a list" : "Одабери списак",
"Card title" : "Наслов картицњ",
"Cancel" : "Одустани",
"Creating the new card …" : "Креира се нова картица ...",
"Card \"{card}\" was added to \"{board}\"" : "Картица „{card}” је додта на „{board}",
"Open card" : "Отвори картицу",
"Close" : "Затвори",
"Create card" : "Направите картицу",
"Select a card" : "Изаберите картицу",
@@ -140,7 +123,6 @@ OC.L10N.register(
"Archived cards" : "Архивиране картице",
"Add list" : "Додај списак",
"List name" : "Назив листе",
"Active filters" : "Активни филтери",
"Apply filter" : "Примени филтер",
"Filter by tag" : "Филтрирај по ознаци",
"Filter by assigned user" : "Филтрирај по додељеном кориснику",
@@ -157,7 +139,6 @@ OC.L10N.register(
"Toggle compact mode" : "Укључи/искључи компактни режим",
"Open details" : "Отвори детаље",
"Details" : "Детаљи",
"Currently present people" : "Тренутно присутне особе",
"Loading board" : "Учитавам таблу",
"No lists available" : "Нема доступних спискова",
"Create a new list to add cards to this board" : "Направите нови списак да додате картице на ову таблу",
@@ -170,7 +151,6 @@ OC.L10N.register(
"Undo" : "Опозови",
"Deleted cards" : "Обрисане картице",
"Share board with a user, group or circle …" : "Подели таблу са корисником, групом или кругом…",
"Searching for users, groups and circles …" : "Претрага корисника, група и кругова ...",
"No participants found" : "Нема нађених учесника",
"Board owner" : "Власник табле",
"(Group)" : "(група)",
@@ -181,17 +161,10 @@ OC.L10N.register(
"Owner" : "Власник",
"Delete" : "Избриши",
"Failed to create share with {displayName}" : "Грешка у прављењу дељења са {displayName}",
"Are you sure you want to transfer the board {title} to {user}?" : "Да ли сте сигурни да кориснику {user} пренесете таблу {title}?",
"Transfer the board." : "Пренос табле.",
"Transfer" : "Пренеси",
"The board has been transferred to {user}" : "Табла је пренета кориснику {user}",
"Failed to transfer the board to {user}" : "Није успео пренос табле кориснику {user}",
"Edit list title" : "Уреди наслов листе",
"Archive all cards" : "Архивирај све картице",
"Unarchive all cards" : "Врати све картице из архиве",
"Delete list" : "Обриши списак",
"Archive all cards in this list" : "Архивирај све картице са овог списка",
"Unarchive all cards in this list" : "Враћа из архиве све картице у овој листи",
"Add a new card" : "Додај нову картицу",
"Card name" : "Име картице",
"List deleted" : "Листа обрисана",
@@ -200,13 +173,8 @@ OC.L10N.register(
"title and color value must be provided" : "морају се дати вредности за наслов и боју",
"Board name" : "Име табле",
"Members" : "Чланови",
"Upload new files" : "Отпреми нове фајлове",
"Share from Files" : "Подели из Фајлова",
"Pending share" : "Дељење на чекању",
"Add this attachment" : "Додај овај прилог",
"Show in Files" : "Прикажи у Фајловима",
"Download" : "Преузми",
"Remove attachment" : "Уклони прилог",
"Delete Attachment" : "Обриши прилог",
"Restore Attachment" : "Поврати прилог",
"File to share" : "Фајл за дељење",
@@ -219,7 +187,6 @@ OC.L10N.register(
"Created" : "Направљен",
"The title cannot be empty." : "Наслов не може бити празан.",
"No comments yet. Begin the discussion!" : "Нема још коментара. Започните дискусију!",
"Failed to load comments" : "Није успело учитавање коментара",
"Assign a tag to this card…" : "Додели ознаку овој картици…",
"Assign to users" : "Додели корисницима",
"Assign to users/groups/circles" : "Додели корисницима/групама/круговима",
@@ -230,13 +197,10 @@ OC.L10N.register(
"Select Date" : "Одаберите датум",
"Today" : "Данас",
"Tomorrow" : "сутра",
"Next week" : "Наредне недеље",
"Next month" : "Наредног месеца",
"Save" : "Сачувај",
"The comment cannot be empty." : "Коментар не може да буде празан.",
"The comment cannot be longer than 1000 characters." : "Коментар не може да има преко 1000 карактера.",
"In reply to" : "Као одговор на",
"Cancel reply" : "Откажи одговор",
"Reply" : "Одговори",
"Update" : "Ажурирај",
"Description" : "Опис",
@@ -246,12 +210,8 @@ OC.L10N.register(
"Edit description" : "Измени опис",
"View description" : "Погледај опис",
"Add Attachment" : "Додај прилог",
"Write a description …" : "Напишите опис ...",
"Choose attachment" : "Одабери прилог",
"(group)" : "(група)",
"Todo items" : "Ставке обавеза",
"{count} comments, {unread} unread" : "{count} коментара, {unread} није прочитано",
"Edit card title" : "Уреди наслов картице",
"Assign to me" : "Додели мени",
"Unassign myself" : "Склони са мене",
"Move card" : "Премести картицу",
@@ -266,9 +226,6 @@ OC.L10N.register(
"All boards" : "Све табле",
"Archived boards" : "Архивиране табле",
"Shared with you" : "Дељено са Вама",
"Deck settings" : "Поставке Шпила",
"Use bigger card view" : "Користи већи приказ картице",
"Show card ID badge" : "Прикажи беџ ID картице",
"Show boards in calendar/tasks" : "Прикажи табле у календару/задацима",
"Limit deck usage of groups" : "Ограничи употребу шпила на групе",
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ограничавање Deck апликације ће блокирати кориснике који нису део одабраних група да креирају своје табле. Корисници ће и даље моћи да раде на таблама које су подељене са њима.",
@@ -277,48 +234,22 @@ OC.L10N.register(
"Clone board" : "Клонирај таблу",
"Unarchive board" : "Врати таблу из архиве",
"Archive board" : "Архивирај таблу",
"Export board" : "Извези таблу",
"Turn on due date reminders" : "Укључи подсетнике о року",
"Turn off due date reminders" : "Искључи подсетнике о року",
"Due date reminders" : "Подсетници о року",
"All cards" : "Све картице",
"Assigned cards" : "Додељене картице",
"No notifications" : "Нема обавештења",
"Delete board" : "Избриши таблу",
"Board {0} deleted" : "Табла {0} обрисана",
"Only assigned cards" : "Само додељене картице",
"No reminder" : "Нема подсетника",
"An error occurred" : "Догодила се грешка",
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Да ли сте сигурни да желите да обришете таблу {title}? Ово ће да обрише све податке на овој табли, укључијући и архивиране картице.",
"Delete the board?" : "Обрисати таблу?",
"Loading filtered view" : "Учитам филтрирани преглед",
"No due" : "Нема рокова",
"Search for {searchQuery} in all boards" : "Тражи се {searchQuery} у свим таблама",
"No results found" : "Нема пронађених резултата",
"Deck board {name}\n* Last modified on {lastMod}" : "Шпил табла {name}\n* Последњи пут измењена дана {lastMod}",
"{stack} in {board}" : "{stack} у {board}",
"Click to expand description" : "Кликните да проширите опис",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Креирано дана {created}\n* Последњи пут измењено дана {lastMod}\n* {nbAttachments} прилога\n* {nbComments} коментара",
"{nbCards} cards" : "{nbCards} картица",
"Click to expand comment" : "Кликните да проширите коментар",
"No upcoming cards" : "Нема предстојећих картица",
"upcoming cards" : "предстојеће картице",
"New card" : "Нова картица",
"Due on {date}" : "Рок је {date}",
"Link to a board" : "Веза ка табли",
"Link to a card" : "Веза ка картици",
"Create a card" : "Креирај картицу",
"Message from {author} in {conversationName}" : "Порука од {author} у {conversationName}",
"Something went wrong" : "Нешто је пошло наопако",
"Failed to upload {name}" : "Није успело отпремање {name}",
"Maximum file size of {size} exceeded" : "Премашена максимална величина фајла од {size}",
"Error creating the share" : "Грешка при прављењу дељења",
"Share with a Deck card" : "Дели са Шпил картицом",
"Share {file} with a Deck card" : "Дели {file} са Шпил картицом",
"Share" : "Подели",
"Are you sure you want to transfer the board {title} for {user}?" : "Да ли сте сигурни да желите пренети таблу {title} за {user}?",
"Transfer the board for {user} successfully" : "Пренос табле за {user} је успео",
"Failed to transfer the board for {user}" : "Пренос табле за {user} није успео",
"Add a new list" : "Додај нови списак",
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Да ли стварно желите да обришете таблу {title}? Овим ћете обрисати све податке са табле."
},

View File

@@ -69,20 +69,11 @@
"Load more" : "Учитај још",
"Personal" : "Лично",
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Корисник %s Вам је доделио картицу „%s“ са табле „%s“.",
"{user} has assigned the card {deck-card} on {deck-board} to you." : "{user} вам је доделио картицу {deck-card} на {deck-board}.",
"The card \"%s\" on \"%s\" has reached its due date." : "Картици „%s“ на табли „%s“ је истекао рок.",
"The card {deck-card} on {deck-board} has reached its due date." : "Картица {deck-card} на {deck-board} је дошла достигла датум када треба да се реши.",
"%s has mentioned you in a comment on \"%s\"." : "%s Вас је поменуо у коментару на „%s“.",
"{user} has mentioned you in a comment on {deck-card}." : "{user} вас је поменуо у коментару на {deck-card}.",
"The board \"%s\" has been shared with you by %s." : "Корисник „%s“ је поделио са Вама таблу „%s“.",
"{user} has shared {deck-board} with you." : "{user} је са вама поделио {deck-board}.",
"Deck board" : "Табла Шпила",
"Owned by %1$s" : "Власник је %1$s",
"Deck boards, cards and comments" : "Табле шпилова, картице и коментари",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "Од %1$s, у %2$s/%3$s, власник је %4$s",
"Card comments" : "Коментари картица",
"%s on %s" : "%s на %s",
"Deck boards and cards" : "Табле шпилова и картице",
"No data was provided to create an attachment." : "Нису дати подаци за креирање прилога.",
"Finished" : "Завршено",
"To review" : "Треба прегледати",
@@ -104,24 +95,16 @@
"Could not write file to disk" : "Не могу да пишем на диск",
"A PHP extension stopped the file upload" : "PHP екстензија је зауставила отпремање фајла",
"No file uploaded or file size exceeds maximum of %s" : "Ниједан фајл није отпремљен или величина фајла премашује максимум од %s",
"This comment has more than %s characters.\nAdded as an attachment to the card with name %s.\nAccessible on URL: %s." : "Овај коментар има више од %s карактера.\nДодат је као прилог картици под именом %s.\nДоступно је на URL адреси: %s.",
"Card not found" : "Картица није нађена",
"Path is already shared with this card" : "Путања се већ дели са овом картицом",
"Invalid date, date format must be YYYY-MM-DD" : "Неисправан датим, формат датума мора бити ГГГГ-ММ-ДД",
"Personal planning and team project organization" : "Лични планер и организатор тимског пројекта",
"Deck is a kanban style organization tool aimed at personal planning and project organization for teams integrated with Nextcloud.\n\n\n- 📥 Add your tasks to cards and put them in order\n- 📄 Write down additional notes in Markdown\n- 🔖 Assign labels for even better organization\n- 👥 Share with your team, friends or family\n- 📎 Attach files and embed them in your Markdown description\n- 💬 Discuss with your team using comments\n- ⚡ Keep track of changes in the activity stream\n- 🚀 Get your project organized" : "Шпил је организациони алат у канбан стилу који је намењен личном планирању и организацији пројекта у тимовима интегрисаним са Nextcloud.\n\n\n- 📥 Додајте своје задатке у картице и поређајте их по редоследу\n- 📄 Напишите додатне белешке употребом Markdown синтаксе\n- 🔖 Доделите ознаке у циљу још боље организације\n- 👥 Делите са својим тимом, пријатељима или породицом\n- 📎 Прикачите фајлове и уградите их у свој Markdown опис\n- 💬 Дискутујте са својим тимом користећи коментаре\n- ⚡ Пратите измене у току активности\n- 🚀 Организујте свој пројекат",
"Add board" : "Додај таблу",
"Select the board to link to a project" : "Одаберите таблу да је повежете са пројектом",
"Search by board title" : "Претражи по наслову табле",
"Select board" : "Одаберите таблу",
"Create a new card" : "Креирај нову картицу",
"Select a board" : "Изаберите таблу",
"Select a list" : "Одабери списак",
"Card title" : "Наслов картицњ",
"Cancel" : "Одустани",
"Creating the new card …" : "Креира се нова картица ...",
"Card \"{card}\" was added to \"{board}\"" : "Картица „{card}” је додта на „{board}",
"Open card" : "Отвори картицу",
"Close" : "Затвори",
"Create card" : "Направите картицу",
"Select a card" : "Изаберите картицу",
@@ -138,7 +121,6 @@
"Archived cards" : "Архивиране картице",
"Add list" : "Додај списак",
"List name" : "Назив листе",
"Active filters" : "Активни филтери",
"Apply filter" : "Примени филтер",
"Filter by tag" : "Филтрирај по ознаци",
"Filter by assigned user" : "Филтрирај по додељеном кориснику",
@@ -155,7 +137,6 @@
"Toggle compact mode" : "Укључи/искључи компактни режим",
"Open details" : "Отвори детаље",
"Details" : "Детаљи",
"Currently present people" : "Тренутно присутне особе",
"Loading board" : "Учитавам таблу",
"No lists available" : "Нема доступних спискова",
"Create a new list to add cards to this board" : "Направите нови списак да додате картице на ову таблу",
@@ -168,7 +149,6 @@
"Undo" : "Опозови",
"Deleted cards" : "Обрисане картице",
"Share board with a user, group or circle …" : "Подели таблу са корисником, групом или кругом…",
"Searching for users, groups and circles …" : "Претрага корисника, група и кругова ...",
"No participants found" : "Нема нађених учесника",
"Board owner" : "Власник табле",
"(Group)" : "(група)",
@@ -179,17 +159,10 @@
"Owner" : "Власник",
"Delete" : "Избриши",
"Failed to create share with {displayName}" : "Грешка у прављењу дељења са {displayName}",
"Are you sure you want to transfer the board {title} to {user}?" : "Да ли сте сигурни да кориснику {user} пренесете таблу {title}?",
"Transfer the board." : "Пренос табле.",
"Transfer" : "Пренеси",
"The board has been transferred to {user}" : "Табла је пренета кориснику {user}",
"Failed to transfer the board to {user}" : "Није успео пренос табле кориснику {user}",
"Edit list title" : "Уреди наслов листе",
"Archive all cards" : "Архивирај све картице",
"Unarchive all cards" : "Врати све картице из архиве",
"Delete list" : "Обриши списак",
"Archive all cards in this list" : "Архивирај све картице са овог списка",
"Unarchive all cards in this list" : "Враћа из архиве све картице у овој листи",
"Add a new card" : "Додај нову картицу",
"Card name" : "Име картице",
"List deleted" : "Листа обрисана",
@@ -198,13 +171,8 @@
"title and color value must be provided" : "морају се дати вредности за наслов и боју",
"Board name" : "Име табле",
"Members" : "Чланови",
"Upload new files" : "Отпреми нове фајлове",
"Share from Files" : "Подели из Фајлова",
"Pending share" : "Дељење на чекању",
"Add this attachment" : "Додај овај прилог",
"Show in Files" : "Прикажи у Фајловима",
"Download" : "Преузми",
"Remove attachment" : "Уклони прилог",
"Delete Attachment" : "Обриши прилог",
"Restore Attachment" : "Поврати прилог",
"File to share" : "Фајл за дељење",
@@ -217,7 +185,6 @@
"Created" : "Направљен",
"The title cannot be empty." : "Наслов не може бити празан.",
"No comments yet. Begin the discussion!" : "Нема још коментара. Започните дискусију!",
"Failed to load comments" : "Није успело учитавање коментара",
"Assign a tag to this card…" : "Додели ознаку овој картици…",
"Assign to users" : "Додели корисницима",
"Assign to users/groups/circles" : "Додели корисницима/групама/круговима",
@@ -228,13 +195,10 @@
"Select Date" : "Одаберите датум",
"Today" : "Данас",
"Tomorrow" : "сутра",
"Next week" : "Наредне недеље",
"Next month" : "Наредног месеца",
"Save" : "Сачувај",
"The comment cannot be empty." : "Коментар не може да буде празан.",
"The comment cannot be longer than 1000 characters." : "Коментар не може да има преко 1000 карактера.",
"In reply to" : "Као одговор на",
"Cancel reply" : "Откажи одговор",
"Reply" : "Одговори",
"Update" : "Ажурирај",
"Description" : "Опис",
@@ -244,12 +208,8 @@
"Edit description" : "Измени опис",
"View description" : "Погледај опис",
"Add Attachment" : "Додај прилог",
"Write a description …" : "Напишите опис ...",
"Choose attachment" : "Одабери прилог",
"(group)" : "(група)",
"Todo items" : "Ставке обавеза",
"{count} comments, {unread} unread" : "{count} коментара, {unread} није прочитано",
"Edit card title" : "Уреди наслов картице",
"Assign to me" : "Додели мени",
"Unassign myself" : "Склони са мене",
"Move card" : "Премести картицу",
@@ -264,9 +224,6 @@
"All boards" : "Све табле",
"Archived boards" : "Архивиране табле",
"Shared with you" : "Дељено са Вама",
"Deck settings" : "Поставке Шпила",
"Use bigger card view" : "Користи већи приказ картице",
"Show card ID badge" : "Прикажи беџ ID картице",
"Show boards in calendar/tasks" : "Прикажи табле у календару/задацима",
"Limit deck usage of groups" : "Ограничи употребу шпила на групе",
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ограничавање Deck апликације ће блокирати кориснике који нису део одабраних група да креирају своје табле. Корисници ће и даље моћи да раде на таблама које су подељене са њима.",
@@ -275,48 +232,22 @@
"Clone board" : "Клонирај таблу",
"Unarchive board" : "Врати таблу из архиве",
"Archive board" : "Архивирај таблу",
"Export board" : "Извези таблу",
"Turn on due date reminders" : "Укључи подсетнике о року",
"Turn off due date reminders" : "Искључи подсетнике о року",
"Due date reminders" : "Подсетници о року",
"All cards" : "Све картице",
"Assigned cards" : "Додељене картице",
"No notifications" : "Нема обавештења",
"Delete board" : "Избриши таблу",
"Board {0} deleted" : "Табла {0} обрисана",
"Only assigned cards" : "Само додељене картице",
"No reminder" : "Нема подсетника",
"An error occurred" : "Догодила се грешка",
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Да ли сте сигурни да желите да обришете таблу {title}? Ово ће да обрише све податке на овој табли, укључијући и архивиране картице.",
"Delete the board?" : "Обрисати таблу?",
"Loading filtered view" : "Учитам филтрирани преглед",
"No due" : "Нема рокова",
"Search for {searchQuery} in all boards" : "Тражи се {searchQuery} у свим таблама",
"No results found" : "Нема пронађених резултата",
"Deck board {name}\n* Last modified on {lastMod}" : "Шпил табла {name}\n* Последњи пут измењена дана {lastMod}",
"{stack} in {board}" : "{stack} у {board}",
"Click to expand description" : "Кликните да проширите опис",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Креирано дана {created}\n* Последњи пут измењено дана {lastMod}\n* {nbAttachments} прилога\n* {nbComments} коментара",
"{nbCards} cards" : "{nbCards} картица",
"Click to expand comment" : "Кликните да проширите коментар",
"No upcoming cards" : "Нема предстојећих картица",
"upcoming cards" : "предстојеће картице",
"New card" : "Нова картица",
"Due on {date}" : "Рок је {date}",
"Link to a board" : "Веза ка табли",
"Link to a card" : "Веза ка картици",
"Create a card" : "Креирај картицу",
"Message from {author} in {conversationName}" : "Порука од {author} у {conversationName}",
"Something went wrong" : "Нешто је пошло наопако",
"Failed to upload {name}" : "Није успело отпремање {name}",
"Maximum file size of {size} exceeded" : "Премашена максимална величина фајла од {size}",
"Error creating the share" : "Грешка при прављењу дељења",
"Share with a Deck card" : "Дели са Шпил картицом",
"Share {file} with a Deck card" : "Дели {file} са Шпил картицом",
"Share" : "Подели",
"Are you sure you want to transfer the board {title} for {user}?" : "Да ли сте сигурни да желите пренети таблу {title} за {user}?",
"Transfer the board for {user} successfully" : "Пренос табле за {user} је успео",
"Failed to transfer the board for {user}" : "Пренос табле за {user} није успео",
"Add a new list" : "Додај нови списак",
"Are you sure you want to delete the board {title}? This will delete all the data of this board." : "Да ли стварно желите да обришете таблу {title}? Овим ћете обрисати све податке са табле."
},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"

View File

@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "Klicka för att utöka kommentaren",
"No upcoming cards" : "Inga kommande kort",
"upcoming cards" : "kommande kort",
"New card" : "Nytt kort",
"Due on {date}" : "Går ut {date}",
"Link to a board" : "Länka till en tavla",
"Link to a card" : "Länka till ett kort",

View File

@@ -301,7 +301,6 @@
"Click to expand comment" : "Klicka för att utöka kommentaren",
"No upcoming cards" : "Inga kommande kort",
"upcoming cards" : "kommande kort",
"New card" : "Nytt kort",
"Due on {date}" : "Går ut {date}",
"Link to a board" : "Länka till en tavla",
"Link to a card" : "Länka till ett kort",

View File

@@ -63,10 +63,10 @@ OC.L10N.register(
"{user} has restored the attachment {attachment} to card {card}" : "{user}, {card} kartındaki {attachment} dosyasını geri yükledi",
"You have commented on card {card}" : "{card} kartı hakkında yorum yaptınız",
"{user} has commented on card {card}" : "{user}, {card} kartı hakkında yorum yaptı",
"A <strong>card description</strong> inside the Deck app has been changed" : "Tahta uygulamasında bir <strong>kart açıklaması</strong> değiştirildiğinde",
"A <strong>card description</strong> inside the Deck app has been changed" : "Tahta uygulamasında bir <strong>kart açıklaması</strong> değiştirildi",
"Deck" : "Tahta",
"Changes in the <strong>Deck app</strong>" : "<strong>Tahta uygulamasında</strong> değişiklik yapıldığında",
"A <strong>comment</strong> was created on a card" : "Bir kart için bir <strong>yorum</strong> yapıldığında",
"Changes in the <strong>Deck app</strong>" : "<strong>Tahta uygulamasındaki</strong> değişiklikler",
"A <strong>comment</strong> was created on a card" : "Bir kart için bir <strong>yorum</strong> yapıldı",
"Upcoming cards" : "Yaklaşan kartlar",
"Load more" : "Diğerlerini yükle",
"Personal" : "Kişisel",
@@ -128,7 +128,7 @@ OC.L10N.register(
"Create card" : "Kart ekle",
"Select a card" : "Bir kart seçin",
"Select the card to link to a project" : "Bir proje ile ilişkilendirilecek kart bağlantısını seçin",
"Link to card" : "Kart bağlantısı",
"Link to card" : "Kart ile ilişkilendir",
"File already exists" : "Dosya zaten var",
"A file with the name {filename} already exists." : "{filename} adlı bir dosya zaten var.",
"Do you want to overwrite it?" : "Üzerine yazmak ister misiniz?",
@@ -293,7 +293,7 @@ OC.L10N.register(
"Delete the board?" : "Pano silinsin mi?",
"Loading filtered view" : "Süzülmüş görünüm yükleniyor",
"No due" : "Bitiş yok",
"Search for {searchQuery} in all boards" : "Tüm panolarda {searchQuery} araması için sonuçlar",
"Search for {searchQuery} in all boards" : "Tüm panolarda {searchQuery} için sonuçlar",
"No results found" : "Herhangi bir sonuç bulunamadı",
"Deck board {name}\n* Last modified on {lastMod}" : "{name} tahta panosu\n* Son değişiklik: {lastMod}",
"{stack} in {board}" : "{stack} {board} panosunda",
@@ -303,10 +303,9 @@ OC.L10N.register(
"Click to expand comment" : "Yorumu genişletmek için tıklayın",
"No upcoming cards" : "Yaklaşan bir kart yok",
"upcoming cards" : "yaklaşan kartlar",
"New card" : "Kart ekle",
"Due on {date}" : "{date} tarihinde bitecek",
"Link to a board" : "Bir pano bağlantısı",
"Link to a card" : "Bir kart bağlantısı",
"Link to a board" : "Bir pano ile ilişkilendir",
"Link to a card" : "Bir kart ile ilişkilendir",
"Create a card" : "Bir kart ekle",
"Message from {author} in {conversationName}" : "{conversationName} görüşmesinde {author} iletisi",
"Something went wrong" : "Bir şeyler ters gitti",

View File

@@ -61,10 +61,10 @@
"{user} has restored the attachment {attachment} to card {card}" : "{user}, {card} kartındaki {attachment} dosyasını geri yükledi",
"You have commented on card {card}" : "{card} kartı hakkında yorum yaptınız",
"{user} has commented on card {card}" : "{user}, {card} kartı hakkında yorum yaptı",
"A <strong>card description</strong> inside the Deck app has been changed" : "Tahta uygulamasında bir <strong>kart açıklaması</strong> değiştirildiğinde",
"A <strong>card description</strong> inside the Deck app has been changed" : "Tahta uygulamasında bir <strong>kart açıklaması</strong> değiştirildi",
"Deck" : "Tahta",
"Changes in the <strong>Deck app</strong>" : "<strong>Tahta uygulamasında</strong> değişiklik yapıldığında",
"A <strong>comment</strong> was created on a card" : "Bir kart için bir <strong>yorum</strong> yapıldığında",
"Changes in the <strong>Deck app</strong>" : "<strong>Tahta uygulamasındaki</strong> değişiklikler",
"A <strong>comment</strong> was created on a card" : "Bir kart için bir <strong>yorum</strong> yapıldı",
"Upcoming cards" : "Yaklaşan kartlar",
"Load more" : "Diğerlerini yükle",
"Personal" : "Kişisel",
@@ -126,7 +126,7 @@
"Create card" : "Kart ekle",
"Select a card" : "Bir kart seçin",
"Select the card to link to a project" : "Bir proje ile ilişkilendirilecek kart bağlantısını seçin",
"Link to card" : "Kart bağlantısı",
"Link to card" : "Kart ile ilişkilendir",
"File already exists" : "Dosya zaten var",
"A file with the name {filename} already exists." : "{filename} adlı bir dosya zaten var.",
"Do you want to overwrite it?" : "Üzerine yazmak ister misiniz?",
@@ -291,7 +291,7 @@
"Delete the board?" : "Pano silinsin mi?",
"Loading filtered view" : "Süzülmüş görünüm yükleniyor",
"No due" : "Bitiş yok",
"Search for {searchQuery} in all boards" : "Tüm panolarda {searchQuery} araması için sonuçlar",
"Search for {searchQuery} in all boards" : "Tüm panolarda {searchQuery} için sonuçlar",
"No results found" : "Herhangi bir sonuç bulunamadı",
"Deck board {name}\n* Last modified on {lastMod}" : "{name} tahta panosu\n* Son değişiklik: {lastMod}",
"{stack} in {board}" : "{stack} {board} panosunda",
@@ -301,10 +301,9 @@
"Click to expand comment" : "Yorumu genişletmek için tıklayın",
"No upcoming cards" : "Yaklaşan bir kart yok",
"upcoming cards" : "yaklaşan kartlar",
"New card" : "Kart ekle",
"Due on {date}" : "{date} tarihinde bitecek",
"Link to a board" : "Bir pano bağlantısı",
"Link to a card" : "Bir kart bağlantısı",
"Link to a board" : "Bir pano ile ilişkilendir",
"Link to a card" : "Bir kart ile ilişkilendir",
"Create a card" : "Bir kart ekle",
"Message from {author} in {conversationName}" : "{conversationName} görüşmesinde {author} iletisi",
"Something went wrong" : "Bir şeyler ters gitti",

View File

@@ -34,7 +34,6 @@ OC.L10N.register(
"You have updated the description of card {card} in list {stack} on board {board}" : "Ви оновили опис картки {card} у списку {stack} на дошці {board}",
"Deck" : "Колода",
"Changes in the <strong>Deck app</strong>" : "Зміни у застосунку <strong>Колода</strong>",
"Upcoming cards" : "Очікують на виконання",
"Load more" : "Більше",
"Personal" : "Особисте",
"Deck board" : "Дошка Deck",
@@ -65,10 +64,8 @@ OC.L10N.register(
"Select the board to link to a project" : "Виберіть дошку для прив'зки до проєкту",
"Search by board title" : "Шукати за назвою дошки",
"Select board" : "Вибрати дошку",
"Create a new card" : "Створити нову картку",
"Select a board" : "Вибрати дошку",
"Select a list" : "Виберіть список",
"Card title" : "Заголовок картки",
"Cancel" : "Скасувати",
"Close" : "закрити",
"Select a card" : "Вибрати картку",
@@ -100,7 +97,6 @@ OC.L10N.register(
"Toggle compact mode" : "Перемкнути компактний вигляд",
"Details" : "Деталі",
"Loading board" : "Завантаження дошки",
"Create a new list to add cards to this board" : "Створіть список щоб додати картки на цю дошку",
"Board not found" : "Дошку не знайдено",
"Sharing" : "Поділитися",
"Tags" : "Теги",
@@ -124,7 +120,6 @@ OC.L10N.register(
"Edit" : "Редагувати",
"Add a new tag" : "Додати нову позначку",
"title and color value must be provided" : "потрібно зазначити назву та колір",
"Board name" : "Назва дошки",
"Members" : "Учасники",
"Upload new files" : "Додати файл",
"Share from Files" : "Відкрити Файли",
@@ -138,7 +133,6 @@ OC.L10N.register(
"Comments" : "Коментарі",
"Modified" : "Змінено",
"Created" : "Створено",
"No comments yet. Begin the discussion!" : "Коментарів немає, почніть обговорення!",
"Assign a tag to this card…" : "Додати позначку до цієї картки",
"Assign to users" : "Призначити користувачам",
"Assign to users/groups/circles" : "Призначити користувачам/групам/колам",
@@ -159,15 +153,13 @@ OC.L10N.register(
"Description" : "Опис",
"(Unsaved)" : "(Не збережено)",
"(Saving…)" : "(Зберігання...)",
"Formatting help" : "Допомога",
"Formatting help" : "Форматування довідки",
"Edit description" : "Редагувати опис",
"View description" : "Переглянути опис",
"Add Attachment" : "Долучити вкладення",
"Write a description …" : "Додайте опис ...",
"Choose attachment" : "Вибрати вкладення",
"(group)" : "(група)",
"Todo items" : "Пункти завдань",
"Edit card title" : "Редагувати заголовок картки",
"Assign to me" : "Призначити мені",
"Move card" : "Пересунути картку",
"Card details" : "Деталі картки",
@@ -179,19 +171,13 @@ OC.L10N.register(
"All boards" : "Усі дошки",
"Archived boards" : "Архівні дошки",
"Shared with you" : "Вам надано доступ",
"Deck settings" : "Налаштування колоди",
"Use bigger card view" : "Режим перегляду зі збільшеними картками",
"Show boards in calendar/tasks" : "Показувати дошки в календарі та завданнях",
"Limit deck usage of groups" : "Обмежити доступ до колоди для груп",
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Створення власних робочих дощок користувачам, які не входять у задані групи, буде заблоковано. Проте, такі користувачі зможуть продовжити працювати зі спільними дошками, до яких у них є доступ.",
"Board details" : "Деталі дошки",
"Edit board" : "Редагувати дошку",
"Clone board" : "Копіювати дошку",
"Unarchive board" : "Розархівувати дошку",
"Archive board" : "Архівувати дошку",
"Turn on due date reminders" : "Нагадування про термін виконання",
"Turn off due date reminders" : "Вимкнути нагадування про терміни виконання",
"Due date reminders" : "Нагадування про терміни виконання",
"No notifications" : "Немає сповіщень",
"Delete board" : "Вилучити дошку",
"Board {0} deleted" : "Дошку {0} вилучено",
@@ -199,10 +185,6 @@ OC.L10N.register(
"An error occurred" : "Виникла помилка",
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Ви впевнені, що хочете вилучити дошку {title}? Це призведе до видалення всіх даних цієї дошки, включаючи архівні картки.",
"Delete the board?" : "Вилучити дошку?",
"No due" : "Без призначеної дати",
"No upcoming cards" : "Немає майбутніх завдань",
"upcoming cards" : "очікують на виконання",
"Due on {date}" : "До {date}",
"Link to a board" : "Прив'язати до дошки",
"Link to a card" : "Прив'язати до картки",
"Message from {author} in {conversationName}" : "Повідомлення від {author} у {conversationName}",

View File

@@ -32,7 +32,6 @@
"You have updated the description of card {card} in list {stack} on board {board}" : "Ви оновили опис картки {card} у списку {stack} на дошці {board}",
"Deck" : "Колода",
"Changes in the <strong>Deck app</strong>" : "Зміни у застосунку <strong>Колода</strong>",
"Upcoming cards" : "Очікують на виконання",
"Load more" : "Більше",
"Personal" : "Особисте",
"Deck board" : "Дошка Deck",
@@ -63,10 +62,8 @@
"Select the board to link to a project" : "Виберіть дошку для прив'зки до проєкту",
"Search by board title" : "Шукати за назвою дошки",
"Select board" : "Вибрати дошку",
"Create a new card" : "Створити нову картку",
"Select a board" : "Вибрати дошку",
"Select a list" : "Виберіть список",
"Card title" : "Заголовок картки",
"Cancel" : "Скасувати",
"Close" : "закрити",
"Select a card" : "Вибрати картку",
@@ -98,7 +95,6 @@
"Toggle compact mode" : "Перемкнути компактний вигляд",
"Details" : "Деталі",
"Loading board" : "Завантаження дошки",
"Create a new list to add cards to this board" : "Створіть список щоб додати картки на цю дошку",
"Board not found" : "Дошку не знайдено",
"Sharing" : "Поділитися",
"Tags" : "Теги",
@@ -122,7 +118,6 @@
"Edit" : "Редагувати",
"Add a new tag" : "Додати нову позначку",
"title and color value must be provided" : "потрібно зазначити назву та колір",
"Board name" : "Назва дошки",
"Members" : "Учасники",
"Upload new files" : "Додати файл",
"Share from Files" : "Відкрити Файли",
@@ -136,7 +131,6 @@
"Comments" : "Коментарі",
"Modified" : "Змінено",
"Created" : "Створено",
"No comments yet. Begin the discussion!" : "Коментарів немає, почніть обговорення!",
"Assign a tag to this card…" : "Додати позначку до цієї картки",
"Assign to users" : "Призначити користувачам",
"Assign to users/groups/circles" : "Призначити користувачам/групам/колам",
@@ -157,15 +151,13 @@
"Description" : "Опис",
"(Unsaved)" : "(Не збережено)",
"(Saving…)" : "(Зберігання...)",
"Formatting help" : "Допомога",
"Formatting help" : "Форматування довідки",
"Edit description" : "Редагувати опис",
"View description" : "Переглянути опис",
"Add Attachment" : "Долучити вкладення",
"Write a description …" : "Додайте опис ...",
"Choose attachment" : "Вибрати вкладення",
"(group)" : "(група)",
"Todo items" : "Пункти завдань",
"Edit card title" : "Редагувати заголовок картки",
"Assign to me" : "Призначити мені",
"Move card" : "Пересунути картку",
"Card details" : "Деталі картки",
@@ -177,19 +169,13 @@
"All boards" : "Усі дошки",
"Archived boards" : "Архівні дошки",
"Shared with you" : "Вам надано доступ",
"Deck settings" : "Налаштування колоди",
"Use bigger card view" : "Режим перегляду зі збільшеними картками",
"Show boards in calendar/tasks" : "Показувати дошки в календарі та завданнях",
"Limit deck usage of groups" : "Обмежити доступ до колоди для груп",
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Створення власних робочих дощок користувачам, які не входять у задані групи, буде заблоковано. Проте, такі користувачі зможуть продовжити працювати зі спільними дошками, до яких у них є доступ.",
"Board details" : "Деталі дошки",
"Edit board" : "Редагувати дошку",
"Clone board" : "Копіювати дошку",
"Unarchive board" : "Розархівувати дошку",
"Archive board" : "Архівувати дошку",
"Turn on due date reminders" : "Нагадування про термін виконання",
"Turn off due date reminders" : "Вимкнути нагадування про терміни виконання",
"Due date reminders" : "Нагадування про терміни виконання",
"No notifications" : "Немає сповіщень",
"Delete board" : "Вилучити дошку",
"Board {0} deleted" : "Дошку {0} вилучено",
@@ -197,10 +183,6 @@
"An error occurred" : "Виникла помилка",
"Are you sure you want to delete the board {title}? This will delete all the data of this board including archived cards." : "Ви впевнені, що хочете вилучити дошку {title}? Це призведе до видалення всіх даних цієї дошки, включаючи архівні картки.",
"Delete the board?" : "Вилучити дошку?",
"No due" : "Без призначеної дати",
"No upcoming cards" : "Немає майбутніх завдань",
"upcoming cards" : "очікують на виконання",
"Due on {date}" : "До {date}",
"Link to a board" : "Прив'язати до дошки",
"Link to a card" : "Прив'язати до картки",
"Message from {author} in {conversationName}" : "Повідомлення від {author} у {conversationName}",

View File

@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "點擊展開評論",
"No upcoming cards" : "沒有快將到期的卡片",
"upcoming cards" : "快將到期的卡片",
"New card" : "新卡片",
"Due on {date}" : "於 {date} 到期",
"Link to a board" : "連結到面板",
"Link to a card" : "連結到卡片",

View File

@@ -301,7 +301,6 @@
"Click to expand comment" : "點擊展開評論",
"No upcoming cards" : "沒有快將到期的卡片",
"upcoming cards" : "快將到期的卡片",
"New card" : "新卡片",
"Due on {date}" : "於 {date} 到期",
"Link to a board" : "連結到面板",
"Link to a card" : "連結到卡片",

View File

@@ -78,7 +78,7 @@ OC.L10N.register(
"{user} has mentioned you in a comment on {deck-card}." : "{user} 在 {deck-card} 的留言中提及您。",
"The board \"%s\" has been shared with you by %s." : "佈告欄「%s」已由 %s 分享給您。",
"{user} has shared {deck-board} with you." : "{user} 已與您分享 {deck-board}。",
"Deck board" : "Deck 佈告欄",
"Deck board" : "看板佈告欄",
"Owned by %1$s" : "由 %1$s 擁有",
"Deck boards, cards and comments" : "Deck 看板、卡片與評論",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "來自 %1$s在 %2$s/%3$s由 %4$s 擁有",
@@ -303,7 +303,6 @@ OC.L10N.register(
"Click to expand comment" : "點擊展開留言",
"No upcoming cards" : "無接下來的卡片",
"upcoming cards" : "接下來的卡片",
"New card" : "新卡片",
"Due on {date}" : "於 {date} 到期",
"Link to a board" : "連結到佈告欄",
"Link to a card" : "連結到卡片",

View File

@@ -76,7 +76,7 @@
"{user} has mentioned you in a comment on {deck-card}." : "{user} 在 {deck-card} 的留言中提及您。",
"The board \"%s\" has been shared with you by %s." : "佈告欄「%s」已由 %s 分享給您。",
"{user} has shared {deck-board} with you." : "{user} 已與您分享 {deck-board}。",
"Deck board" : "Deck 佈告欄",
"Deck board" : "看板佈告欄",
"Owned by %1$s" : "由 %1$s 擁有",
"Deck boards, cards and comments" : "Deck 看板、卡片與評論",
"From %1$s, in %2$s/%3$s, owned by %4$s" : "來自 %1$s在 %2$s/%3$s由 %4$s 擁有",
@@ -301,7 +301,6 @@
"Click to expand comment" : "點擊展開留言",
"No upcoming cards" : "無接下來的卡片",
"upcoming cards" : "接下來的卡片",
"New card" : "新卡片",
"Due on {date}" : "於 {date} 到期",
"Link to a board" : "連結到佈告欄",
"Link to a card" : "連結到卡片",

View File

@@ -36,7 +36,6 @@ use OCA\Deck\Db\CardMapper;
use OCA\Deck\Event\AclCreatedEvent;
use OCA\Deck\Event\AclDeletedEvent;
use OCA\Deck\Event\AclUpdatedEvent;
use OCA\Deck\Event\BoardUpdatedEvent;
use OCA\Deck\Event\CardCreatedEvent;
use OCA\Deck\Event\CardDeletedEvent;
use OCA\Deck\Event\CardUpdatedEvent;
@@ -155,13 +154,6 @@ class Application extends App implements IBootstrap {
// Event listening for realtime updates via notify_push
$context->registerEventListener(SessionCreatedEvent::class, LiveUpdateListener::class);
$context->registerEventListener(SessionClosedEvent::class, LiveUpdateListener::class);
$context->registerEventListener(BoardUpdatedEvent::class, LiveUpdateListener::class);
$context->registerEventListener(CardCreatedEvent::class, LiveUpdateListener::class);
$context->registerEventListener(CardUpdatedEvent::class, LiveUpdateListener::class);
$context->registerEventListener(CardDeletedEvent::class, LiveUpdateListener::class);
$context->registerEventListener(AclCreatedEvent::class, LiveUpdateListener::class);
$context->registerEventListener(AclUpdatedEvent::class, LiveUpdateListener::class);
$context->registerEventListener(AclDeletedEvent::class, LiveUpdateListener::class);
$context->registerNotifierService(Notifier::class);
$context->registerEventListener(LoadAdditionalScriptsEvent::class, ResourceAdditionalScriptsListener::class);

View File

@@ -60,14 +60,12 @@ class BoardApiController extends ApiController {
* @NoCSRFRequired
*
* Return all of the boards that the current user has access to.
*
* @param bool $details
* @throws StatusException
*/
public function index(bool $details = false) {
public function index($details = null) {
$modified = $this->request->getHeader('If-Modified-Since');
if ($modified === null || $modified === '') {
$boards = $this->boardService->findAll(0, $details === true);
$boards = $this->boardService->findAll(0, $details);
} else {
$date = Util::parseHTTPDate($modified);
if (!$date) {

View File

@@ -59,21 +59,20 @@ class Calendar extends ExternalCalendar {
}
public function getACL() {
// the calendar should always have the read and the write-properties permissions
// write-properties is needed to allow the user to toggle the visibility of shared deck calendars
$acl = [
[
'privilege' => '{DAV:}read',
'principal' => $this->getOwner(),
'protected' => true,
],
[
]
];
if ($this->backend->checkBoardPermission($this->board->getId(), Acl::PERMISSION_MANAGE)) {
$acl[] = [
'privilege' => '{DAV:}write-properties',
'principal' => $this->getOwner(),
'protected' => true,
]
];
];
}
return $acl;
}
@@ -188,18 +187,12 @@ class Calendar extends ExternalCalendar {
foreach ($properties as $key => $value) {
switch ($key) {
case '{DAV:}displayname':
if (!$this->backend->checkBoardPermission($this->board->getId(), Acl::PERMISSION_MANAGE)) {
throw new Forbidden('no permission to change the displayname');
}
if (mb_strpos($value, 'Deck: ') === 0) {
$value = mb_substr($value, strlen('Deck: '));
}
$this->board->setTitle($value);
break;
case '{http://apple.com/ns/ical/}calendar-color':
if (!$this->backend->checkBoardPermission($this->board->getId(), Acl::PERMISSION_MANAGE)) {
throw new Forbidden('no permission to change the calendar color');
}
$color = substr($value, 1, 6);
if (!preg_match('/[a-f0-9]{6}/i', $color)) {
throw new InvalidDataException('No valid color provided');

View File

@@ -59,7 +59,7 @@ class DeckCalendarBackend {
}
public function getBoards(): array {
return $this->boardService->findAll(-1, false, false);
return $this->boardService->findAll(-1, null, false);
}
public function getBoard(int $id): Board {

View File

@@ -117,7 +117,7 @@ class DeckWidget implements IAPIWidget, IButtonWidget, IIconWidget {
$nowTimestamp = (new Datetime())->getTimestamp();
$sinceTimestamp = $since !== null ? (new Datetime($since))->getTimestamp() : null;
$upcomingCards = array_filter($upcomingCards, static function (array $card) use ($nowTimestamp, $sinceTimestamp) {
if (isset($card['duedate'])) {
if ($card['duedate']) {
$ts = (new Datetime($card['duedate']))->getTimestamp();
return $ts > $nowTimestamp && ($sinceTimestamp === null || $ts > $sinceTimestamp);
}

View File

@@ -52,20 +52,6 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
return $this->findEntities($qb);
}
public function findIn(array $boardIds, ?int $limit = null, ?int $offset = null): array {
$qb = $this->db->getQueryBuilder();
$qb->select('id', 'board_id', 'type', 'participant', 'permission_edit', 'permission_share', 'permission_manage')
->from('deck_board_acl')
->where($qb->expr()->in('board_id', $qb->createParameter('boardIds')))
->setMaxResults($limit)
->setFirstResult($offset);
return iterator_to_array($this->chunkQuery($boardIds, function (array $ids) use ($qb) {
$qb->setParameter('boardIds', $ids, IQueryBuilder::PARAM_INT_ARRAY);
return $this->findEntities($qb);
}));
}
/**
* @param numeric $userId
* @param numeric $id

View File

@@ -28,13 +28,15 @@ namespace OCA\Deck\Db;
use OCA\Deck\NotFoundException;
use OCA\Deck\Service\CirclesService;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IUserManager;
use PDO;
/** @template-extends DeckMapper<Assignment> */
class AssignmentMapper extends DeckMapper implements IPermissionMapper {
/** @template-extends QBMapper<Assignment> */
class AssignmentMapper extends QBMapper implements IPermissionMapper {
/** @var CardMapper */
private $cardMapper;
@@ -58,7 +60,7 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from('deck_assigned_users')
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)));
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, PDO::PARAM_INT)));
$users = $this->findEntities($qb);
foreach ($users as $user) {
$this->mapParticipant($user);
@@ -66,29 +68,12 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
return $users;
}
public function findIn(array $cardIds): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from('deck_assigned_users')
->where($qb->expr()->in('card_id', $qb->createParameter('cardIds')));
$users = iterator_to_array($this->chunkQuery($cardIds, function (array $ids) use ($qb) {
$qb->setParameter('cardIds', $ids, IQueryBuilder::PARAM_INT_ARRAY);
return $this->findEntities($qb);
}));
foreach ($users as $user) {
$this->mapParticipant($user);
}
return $users;
}
public function findByParticipant(string $participant, $type = Assignment::TYPE_USER): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from('deck_assigned_users')
->where($qb->expr()->eq('participant', $qb->createNamedParameter($participant, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq('type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT)));
->where($qb->expr()->eq('participant', $qb->createNamedParameter($participant, PDO::PARAM_STR)))
->andWhere($qb->expr()->eq('type', $qb->createNamedParameter($type, PDO::PARAM_INT)));
return $this->findEntities($qb);
}
@@ -147,8 +132,8 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
private function getOrigin(Assignment $assignment) {
if ($assignment->getType() === Assignment::TYPE_USER) {
$origin = $this->userManager->userExists($assignment->getParticipant());
return $origin ? new User($assignment->getParticipant(), $this->userManager) : null;
$origin = $this->userManager->get($assignment->getParticipant());
return $origin ? new User($origin) : null;
}
if ($assignment->getType() === Assignment::TYPE_GROUP) {
$origin = $this->groupManager->get($assignment->getParticipant());

View File

@@ -90,6 +90,9 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
$this->boardCache[$id] = $this->findEntity($qb);
}
// FIXME is this necessary? it was NOT done with the old mapper
// $this->mapOwner($board);
// Add labels
if ($withLabels && $this->boardCache[$id]->getLabels() === null) {
$labels = $this->labelMapper->findAll($id);
@@ -156,21 +159,7 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
$userBoards = $this->findAllByUser($userId, null, null, $since, $includeArchived, $before, $term);
$groupBoards = $this->findAllByGroups($userId, $groups, null, null, $since, $includeArchived, $before, $term);
$circleBoards = $this->findAllByCircles($userId, null, null, $since, $includeArchived, $before, $term);
$allBoards = array_values(array_unique(array_merge($userBoards, $groupBoards, $circleBoards)));
// Could be moved outside
$acls = $this->aclMapper->findIn(array_map(function ($board) {
return $board->getId();
}, $allBoards));
/* @var Board $entry */
foreach ($allBoards as $entry) {
$boardAcls = array_values(array_filter($acls, function ($acl) use ($entry) {
return $acl->getBoardId() === $entry->getId();
}));
$entry->setAcl($boardAcls);
}
$allBoards = array_unique(array_merge($userBoards, $groupBoards, $circleBoards));
foreach ($allBoards as $board) {
$this->boardCache[$board->getId()] = $board;
}
@@ -270,7 +259,11 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
$entry->setShared(1);
}
$entries = array_merge($entries, $sharedEntries);
/* @var Board $entry */
foreach ($entries as $entry) {
$acl = $this->aclMapper->findAll($entry->id);
$entry->setAcl($acl);
}
return $entries;
}
@@ -343,6 +336,11 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
foreach ($entries as $entry) {
$entry->setShared(2);
}
/* @var Board $entry */
foreach ($entries as $entry) {
$acl = $this->aclMapper->findAll($entry->id);
$entry->setAcl($acl);
}
return $entries;
}
@@ -399,6 +397,11 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
foreach ($entries as $entry) {
$entry->setShared(2);
}
/* @var Board $entry */
foreach ($entries as $entry) {
$acl = $this->aclMapper->findAll($entry->id);
$entry->setAcl($acl);
}
return $entries;
}
@@ -452,11 +455,13 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
}
public function mapAcl(Acl &$acl) {
$userManager = $this->userManager;
$groupManager = $this->groupManager;
$acl->resolveRelation('participant', function ($participant) use (&$acl, &$userManager, &$groupManager) {
if ($acl->getType() === Acl::PERMISSION_TYPE_USER) {
if ($this->userManager->userExists($acl->getParticipant())) {
return new User($acl->getParticipant(), $this->userManager);
$user = $userManager->get($participant);
if ($user !== null) {
return new User($user);
}
$this->logger->debug('User ' . $acl->getId() . ' not found when mapping acl ' . $acl->getParticipant());
return null;
@@ -494,8 +499,9 @@ class BoardMapper extends QBMapper implements IPermissionMapper {
public function mapOwner(Board &$board) {
$userManager = $this->userManager;
$board->resolveRelation('owner', function ($owner) use (&$userManager) {
if ($this->userManager->userExists($owner)) {
return new User($owner, $userManager);
$user = $userManager->get($owner);
if ($user !== null) {
return new User($user);
}
return null;
});

View File

@@ -159,17 +159,16 @@ class Card extends RelationalEntity {
}
public function getDaysUntilDue(): ?int {
if ($this->getDuedate() === null) {
$today = new DateTime();
$match_date = $this->getDuedate();
if ($match_date === null) {
return null;
}
$today = new DateTime();
$today->setTime(0, 0);
$match_date->setTime(0, 0);
$matchDate = DateTime::createFromInterface($this->getDuedate());
$matchDate->setTime(0, 0);
$diff = $today->diff($matchDate);
$diff = $today->diff($match_date);
return (int) $diff->format('%R%a'); // Extract days count in interval
}

View File

@@ -254,13 +254,13 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb);
}
public function findAllWithDue(array $boardIds) {
public function findAllWithDue($boardId) {
$qb = $this->db->getQueryBuilder();
$qb->select('c.*')
->from('deck_cards', 'c')
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
->innerJoin('s', 'deck_boards', 'b', 'b.id = s.board_id')
->where($qb->expr()->in('s.board_id', $qb->createNamedParameter($boardIds, IQueryBuilder::PARAM_INT_ARRAY)))
->where($qb->expr()->eq('s.board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->isNotNull('c.duedate'))
->andWhere($qb->expr()->eq('c.archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($qb->expr()->eq('c.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
@@ -270,14 +270,14 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb);
}
public function findToMeOrNotAssignedCards(array $boardIds, string $username) {
public function findToMeOrNotAssignedCards($boardId, $username) {
$qb = $this->db->getQueryBuilder();
$qb->select('c.*')
->from('deck_cards', 'c')
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
->innerJoin('s', 'deck_boards', 'b', 'b.id = s.board_id')
->leftJoin('c', 'deck_assigned_users', 'u', 'c.id = u.card_id')
->where($qb->expr()->in('s.board_id', $qb->createNamedParameter($boardIds, IQueryBuilder::PARAM_INT_ARRAY)))
->where($qb->expr()->eq('s.board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->orX(
$qb->expr()->eq('u.participant', $qb->createNamedParameter($username, IQueryBuilder::PARAM_STR)),
$qb->expr()->isNull('u.participant'))
@@ -607,8 +607,9 @@ class CardMapper extends QBMapper implements IPermissionMapper {
public function mapOwner(Card &$card) {
$userManager = $this->userManager;
$card->resolveRelation('owner', function ($owner) use (&$userManager) {
if ($userManager->userExists($owner)) {
return new User($owner, $this->userManager);
$user = $userManager->get($owner);
if ($user !== null) {
return new User($user);
}
return null;
});

View File

@@ -23,7 +23,6 @@
namespace OCA\Deck\Db;
use Generator;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
@@ -36,7 +35,7 @@ abstract class DeckMapper extends QBMapper {
/**
* @param $id
* @return T
* @return \OCP\AppFramework\Db\Entity if not found
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws \OCP\AppFramework\Db\DoesNotExistException
*/
@@ -48,21 +47,4 @@ abstract class DeckMapper extends QBMapper {
return $this->findEntity($qb);
}
/**
* Helper function to split passed array into chunks of 1000 elements and
* call a given callback for fetching query results
*
* Can be useful to limit to 1000 results per query for oracle compatiblity
* but still iterate over all results
*/
public function chunkQuery(array $ids, callable $callback): Generator {
$limit = 1000;
while (!empty($ids)) {
$slice = array_splice($ids, 0, $limit);
foreach ($callback($slice) as $item) {
yield $item;
}
}
}
}

View File

@@ -79,19 +79,6 @@ class LabelMapper extends DeckMapper implements IPermissionMapper {
return $this->findEntities($qb);
}
public function findAssignedLabelsForCards($cardIds, $limit = null, $offset = null): array {
$qb = $this->db->getQueryBuilder();
$qb->select('l.*', 'card_id')
->from($this->getTableName(), 'l')
->innerJoin('l', 'deck_assigned_labels', 'al', 'l.id = al.label_id')
->where($qb->expr()->in('card_id', $qb->createNamedParameter($cardIds, IQueryBuilder::PARAM_INT_ARRAY)))
->orderBy('l.id')
->setMaxResults($limit)
->setFirstResult($offset);
return $this->findEntities($qb);
}
/**
* @param numeric $boardId
* @param int|null $limit

View File

@@ -33,7 +33,7 @@ class RelationalObject implements JsonSerializable {
* RelationalObject constructor.
*
* @param $primaryKey string
* @param callable|mixed $object
* @param $object
*/
public function __construct($primaryKey, $object) {
$this->primaryKey = $primaryKey;
@@ -47,24 +47,16 @@ class RelationalObject implements JsonSerializable {
);
}
public function getObject() {
if (is_callable($this->object)) {
$this->object = call_user_func($this->object, $this);
}
return $this->object;
}
/**
* This method should be overwritten if object doesn't implement \JsonSerializable
*
* @throws \Exception
*/
public function getObjectSerialization() {
if ($this->getObject() instanceof JsonSerializable) {
return $this->getObject()->jsonSerialize();
if ($this->object instanceof JsonSerializable) {
return $this->object->jsonSerialize();
} else {
throw new \Exception('jsonSerialize is not implemented on ' . get_class($this->getObject()));
throw new \Exception('jsonSerialize is not implemented on ' . get_class($this));
}
}

View File

@@ -26,27 +26,16 @@ namespace OCA\Deck\Db;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\Cache\CappedMemoryCache;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\ICache;
use OCP\ICacheFactory;
/** @template-extends DeckMapper<Stack> */
class StackMapper extends DeckMapper implements IPermissionMapper {
private CappedMemoryCache $stackCache;
private CardMapper $cardMapper;
private ICache $cache;
private $cardMapper;
public function __construct(
IDBConnection $db,
CardMapper $cardMapper,
ICacheFactory $cacheFactory
) {
public function __construct(IDBConnection $db, CardMapper $cardMapper) {
parent::__construct($db, 'deck_stacks', Stack::class);
$this->cardMapper = $cardMapper;
$this->stackCache = new CappedMemoryCache();
$this->cache = $cacheFactory->createDistributed('deck-stackMapper');
}
@@ -58,17 +47,12 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
* @throws \OCP\DB\Exception
*/
public function find($id): Stack {
if (isset($this->stackCache[(string)$id])) {
return $this->stackCache[(string)$id];
}
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
$this->stackCache[(string)$id] = $this->findEntity($qb);
return $this->stackCache[(string)$id];
return $this->findEntity($qb);
}
/**
@@ -129,16 +113,9 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
return $this->findEntities($qb);
}
public function update(Entity $entity): Entity {
$result = parent::update($entity);
$this->stackCache[(string)$entity->getId()] = $result;
return $result;
}
public function delete(Entity $entity): Entity {
// delete cards on stack
$this->cardMapper->deleteByStack($entity->getId());
unset($this->stackCache[(string)$entity->getId()]);
return parent::delete($entity);
}
@@ -165,19 +142,12 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
* @throws \OCP\DB\Exception
*/
public function findBoardId($id): ?int {
$result = $this->cache->get('findBoardId:' . $id);
if ($result !== null) {
return $result !== false ? $result : null;
}
try {
$entity = $this->find($id);
$result = $entity->getBoardId();
return $entity->getBoardId();
} catch (DoesNotExistException $e) {
$result = false;
} catch (MultipleObjectsReturnedException $e) {
}
$this->cache->set('findBoardId:' . $id, $result);
return $result !== false ? $result : null;
return null;
}
}

View File

@@ -23,30 +23,27 @@
namespace OCA\Deck\Db;
use OCP\IUserManager;
use OCP\IUser;
class User extends RelationalObject {
private IUserManager $userManager;
public function __construct($uid, IUserManager $userManager) {
$this->userManager = $userManager;
parent::__construct($uid, function ($object) {
return $this->userManager->get($object->getPrimaryKey());
});
public function __construct(IUser $user) {
$primaryKey = $user->getUID();
parent::__construct($primaryKey, $user);
}
public function getObjectSerialization() {
return [
'uid' => $this->getObject()->getUID(),
'displayname' => $this->getObject()->getDisplayName(),
'type' => Acl::PERMISSION_TYPE_USER
'uid' => $this->object->getUID(),
'displayname' => $this->object->getDisplayName(),
'type' => 0
];
}
public function getUID() {
return $this->getPrimaryKey();
return $this->object->getUID();
}
public function getDisplayName() {
return $this->userManager->getDisplayName($this->getPrimaryKey());
return $this->object->getDisplayName();
}
}

View File

@@ -31,7 +31,7 @@ use OCP\EventDispatcher\Event;
abstract class AAclEvent extends Event {
private $acl;
public function __construct(Acl $acl) {
parent::__construct();
@@ -41,8 +41,4 @@ abstract class AAclEvent extends Event {
public function getAcl(): Acl {
return $this->acl;
}
public function getBoardId(): int {
return $this->acl->getBoardId();
}
}

View File

@@ -1,43 +0,0 @@
<?php
/*
* @copyright Copyright (c) 2022 chandi Langecker <git@chandi.it>
*
* @author chandi Langecker <git@chandi.it>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
declare(strict_types=1);
namespace OCA\Deck\Event;
use OCP\EventDispatcher\Event;
class BoardUpdatedEvent extends Event {
private $boardId;
public function __construct(int $boardId) {
parent::__construct();
$this->boardId = $boardId;
}
public function getBoardId(): int {
return $this->boardId;
}
}

View File

@@ -26,17 +26,5 @@ declare(strict_types=1);
namespace OCA\Deck\Event;
use OCA\Deck\Db\Card;
class CardUpdatedEvent extends ACardEvent {
private $cardBefore;
public function __construct(Card $card, Card $before = null) {
parent::__construct($card);
$this->cardBefore = $before;
}
public function getCardBefore() {
return $this->cardBefore;
}
}

View File

@@ -26,12 +26,7 @@ declare(strict_types=1);
namespace OCA\Deck\Listeners;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\NotifyPushEvents;
use OCA\Deck\Event\AAclEvent;
use OCA\Deck\Event\ACardEvent;
use OCA\Deck\Event\BoardUpdatedEvent;
use OCA\Deck\Event\CardUpdatedEvent;
use OCA\Deck\Event\SessionClosedEvent;
use OCA\Deck\Event\SessionCreatedEvent;
use OCA\Deck\Service\SessionService;
@@ -42,20 +37,18 @@ use OCP\IRequest;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
/** @template-implements IEventListener<Event|SessionCreatedEvent|SessionClosedEvent|AAclEvent|ACardEvent|CardUpdatedEvent|BoardUpdatedEvent> */
/** @template-implements IEventListener<Event|SessionCreatedEvent|SessionClosedEvent> */
class LiveUpdateListener implements IEventListener {
private LoggerInterface $logger;
private SessionService $sessionService;
private IRequest $request;
private StackMapper $stackMapper;
private $queue;
public function __construct(
ContainerInterface $container,
IRequest $request,
LoggerInterface $logger,
SessionService $sessionService,
StackMapper $stackMapper
SessionService $sessionService
) {
try {
$this->queue = $container->get(IQueue::class);
@@ -66,7 +59,6 @@ class LiveUpdateListener implements IEventListener {
$this->logger = $logger;
$this->sessionService = $sessionService;
$this->request = $request;
$this->stackMapper = $stackMapper;
}
public function handle(Event $event): void {
@@ -76,37 +68,17 @@ class LiveUpdateListener implements IEventListener {
}
try {
// the web frontend is adding the Session-ID as a header
// the web frontend is adding the Session-ID as a header on every request
// TODO: verify the token! this currently allows to spoof a token from someone
// else, preventing this person from getting updates
// else, preventing this person from getting any live updates
$causingSessionToken = $this->request->getHeader('x-nc-deck-session');
if (
$event instanceof SessionCreatedEvent ||
$event instanceof SessionClosedEvent ||
$event instanceof BoardUpdatedEvent ||
$event instanceof AAclEvent
$event instanceof SessionClosedEvent
) {
$this->sessionService->notifyAllSessions($this->queue, $event->getBoardId(), NotifyPushEvents::DeckBoardUpdate, [
'id' => $event->getBoardId()
], $causingSessionToken);
} elseif ($event instanceof ACardEvent) {
$boardId = $this->stackMapper->findBoardId($event->getCard()->getStackId());
$this->sessionService->notifyAllSessions($this->queue, $boardId, NotifyPushEvents::DeckCardUpdate, [
'boardId' => $boardId,
'cardId' => $event->getCard()->getId()
], $causingSessionToken);
// if card got moved to a diferent board, we should notify
// also sessions active on the previous board
if ($event instanceof CardUpdatedEvent && $event->getCardBefore()) {
$previousBoardId = $this->stackMapper->findBoardId($event->getCardBefore()->getStackId());
if ($boardId !== $previousBoardId) {
$this->sessionService->notifyAllSessions($this->queue, $previousBoardId, NotifyPushEvents::DeckCardUpdate, [
'boardId' => $boardId,
'cardId' => $event->getCard()->getId()
], $causingSessionToken);
}
}
}
} catch (\Exception $e) {
$this->logger->error('Error when handling live update event', ['exception' => $e]);

View File

@@ -26,5 +26,4 @@ namespace OCA\Deck;
class NotifyPushEvents {
public const DeckBoardUpdate = 'deck_board_update';
public const DeckCardUpdate = 'deck_card_update';
}

View File

@@ -23,7 +23,6 @@
namespace OCA\Deck\Reference;
use OCA\Deck\AppInfo\Application;
use OCA\Deck\NoPermissionException;
use OCA\Deck\Service\BoardService;
use OCP\Collaboration\Reference\IReference;
use OCP\Collaboration\Reference\IReferenceProvider;
@@ -68,12 +67,7 @@ class BoardReferenceProvider implements IReferenceProvider {
if ($this->matchReference($referenceText)) {
$boardId = $this->getBoardId($referenceText);
if ($boardId !== null) {
try {
$board = $this->boardService->find($boardId)->jsonSerialize();
} catch (NoPermissionException $e) {
// Skip throwing if user has no permissions
return null;
}
$board = $this->boardService->find($boardId)->jsonSerialize();
$board = $this->sanitizeSerializedBoard($board);
/** @var IReference $reference */
$reference = new Reference($referenceText);

View File

@@ -27,7 +27,6 @@ use OCA\Deck\Db\Assignment;
use OCA\Deck\Db\Attachment;
use OCA\Deck\Db\Label;
use OCA\Deck\Model\CardDetails;
use OCA\Deck\NoPermissionException;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\CardService;
use OCA\Deck\Service\StackService;
@@ -122,15 +121,9 @@ class CardReferenceProvider extends ADiscoverableReferenceProvider implements IS
$ids = $this->getBoardCardId($referenceText);
if ($ids !== null) {
[$boardId, $cardId] = $ids;
try {
$card = $this->cardService->find((int) $cardId)->jsonSerialize();
$board = $this->boardService->find((int) $boardId)->jsonSerialize();
$stack = $this->stackService->find((int) $card['stackId'])->jsonSerialize();
} catch (NoPermissionException $e) {
// Skip throwing if user has no permissions
return null;
}
$card = $this->cardService->find((int) $cardId)->jsonSerialize();
$board = $this->boardService->find((int) $boardId)->jsonSerialize();
$stack = $this->stackService->find((int) $card['stackId'])->jsonSerialize();
$card = $this->sanitizeSerializedCard($card);
$board = $this->sanitizeSerializedBoard($board);

View File

@@ -27,7 +27,6 @@ use OCA\Deck\Db\Assignment;
use OCA\Deck\Db\Attachment;
use OCA\Deck\Db\Label;
use OCA\Deck\Model\CardDetails;
use OCA\Deck\NoPermissionException;
use OCA\Deck\Service\BoardService;
use OCA\Deck\Service\CardService;
use OCA\Deck\Service\CommentService;
@@ -86,14 +85,9 @@ class CommentReferenceProvider implements IReferenceProvider {
if ($ids !== null) {
[$boardId, $cardId, $commentId] = $ids;
try {
$card = $this->cardService->find($cardId)->jsonSerialize();
$board = $this->boardService->find($boardId)->jsonSerialize();
$stack = $this->stackService->find((int) $card['stackId'])->jsonSerialize();
} catch (NoPermissionException $e) {
// Skip throwing if user has no permissions
return null;
}
$card = $this->cardService->find($cardId)->jsonSerialize();
$board = $this->boardService->find($boardId)->jsonSerialize();
$stack = $this->stackService->find((int) $card['stackId'])->jsonSerialize();
$card = $this->sanitizeSerializedCard($card);
$board = $this->sanitizeSerializedBoard($board);
$stack = $this->sanitizeSerializedStack($stack);

View File

@@ -56,7 +56,6 @@ use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\LabelMapper;
use OCP\IUserManager;
use OCA\Deck\BadRequestException;
use OCA\Deck\Event\BoardUpdatedEvent;
use OCA\Deck\Validators\BoardServiceValidator;
use OCP\IURLGenerator;
use OCP\Server;
@@ -80,8 +79,7 @@ class BoardService {
private IEventDispatcher $eventDispatcher;
private ChangeHelper $changeHelper;
private CardMapper $cardMapper;
private ?array $boardsCacheFull = null;
private ?array $boardsCachePartial = null;
private ?array $boardsCache = null;
private IURLGenerator $urlGenerator;
private IDBConnection $connection;
private BoardServiceValidator $boardServiceValidator;
@@ -149,45 +147,96 @@ class BoardService {
}
/**
* @return Board[]
* @return array
*/
public function findAll(int $since = -1, bool $fullDetails = false, bool $includeArchived = true): array {
if ($this->boardsCacheFull && $fullDetails) {
return $this->boardsCacheFull;
public function findAll($since = -1, $details = null, $includeArchived = true) {
if ($this->boardsCache) {
return $this->boardsCache;
}
if ($this->boardsCachePartial && !$fullDetails) {
return $this->boardsCachePartial;
}
$complete = $this->getUserBoards($since, $includeArchived);
return $this->enrichBoards($complete, $fullDetails);
$result = [];
/** @var Board $item */
foreach ($complete as &$item) {
$this->boardMapper->mapOwner($item);
if ($item->getAcl() !== null) {
foreach ($item->getAcl() as &$acl) {
$this->boardMapper->mapAcl($acl);
}
}
if ($details !== null) {
$this->enrichWithStacks($item);
$this->enrichWithLabels($item);
$this->enrichWithUsers($item);
}
$permissions = $this->permissionService->matchPermissions($item);
$item->setPermissions([
'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ] ?? false,
'PERMISSION_EDIT' => $permissions[Acl::PERMISSION_EDIT] ?? false,
'PERMISSION_MANAGE' => $permissions[Acl::PERMISSION_MANAGE] ?? false,
'PERMISSION_SHARE' => $permissions[Acl::PERMISSION_SHARE] ?? false
]);
$this->enrichWithBoardSettings($item);
$result[$item->getId()] = $item;
}
$this->boardsCache = $result;
return array_values($result);
}
/**
* @param $boardId
* @return Board
* @throws DoesNotExistException
* @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/
public function find(int $boardId, bool $fullDetails = true): Board {
public function find($boardId) {
$this->boardServiceValidator->check(compact('boardId'));
if (isset($this->boardsCacheFull[$boardId]) && $fullDetails) {
return $this->boardsCacheFull[$boardId];
if ($this->boardsCache && isset($this->boardsCache[$boardId])) {
return $this->boardsCache[$boardId];
}
if (isset($this->boardsCachePartial[$boardId]) && !$fullDetails) {
return $this->boardsCachePartial[$boardId];
if (is_numeric($boardId) === false) {
throw new BadRequestException('board id must be a number');
}
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
/** @var Board $board */
$board = $this->boardMapper->find($boardId, true, true);
[$board] = $this->enrichBoards([$board], $fullDetails);
$this->boardMapper->mapOwner($board);
if ($board->getAcl() !== null) {
foreach ($board->getAcl() as $acl) {
if ($acl !== null) {
$this->boardMapper->mapAcl($acl);
}
}
}
$permissions = $this->permissionService->matchPermissions($board);
$board->setPermissions([
'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ] ?? false,
'PERMISSION_EDIT' => $permissions[Acl::PERMISSION_EDIT] ?? false,
'PERMISSION_MANAGE' => $permissions[Acl::PERMISSION_MANAGE] ?? false,
'PERMISSION_SHARE' => $permissions[Acl::PERMISSION_SHARE] ?? false
]);
$this->enrichWithUsers($board);
$this->enrichWithBoardSettings($board);
$this->enrichWithActiveSessions($board);
$this->boardsCache[$board->getId()] = $board;
return $board;
}
/**
* @return array
*/
private function getBoardPrerequisites() {
$groups = $this->groupManager->getUserGroupIds(
$this->userManager->get($this->userId)
);
return [
'user' => $this->userId,
'groups' => $groups
];
}
/**
* @param $mapper
* @param $id
@@ -380,7 +429,6 @@ class BoardService {
$this->boardMapper->mapOwner($board);
$this->activityManager->triggerUpdateEvents(ActivityManager::DECK_OBJECT_BOARD, $changes, ActivityManager::SUBJECT_BOARD_UPDATE);
$this->changeHelper->boardChanged($board->getId());
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($board->getId()));
return $board;
}
@@ -408,7 +456,7 @@ class BoardService {
public function enrichWithActiveSessions(Board $board) {
$sessions = $this->sessionMapper->findAllActive($board->getId());
$board->setActiveSessions(array_values(
array_unique(
array_map(function (Session $session) {
@@ -643,45 +691,6 @@ class BoardService {
return $board;
}
/** @param Board[] $boards */
private function enrichBoards(array $boards, bool $fullDetails = true): array {
$result = [];
foreach ($boards as $board) {
// FIXME The enrichment in here could make use of combined queries
$this->boardMapper->mapOwner($board);
if ($board->getAcl() !== null) {
foreach ($board->getAcl() as &$acl) {
$this->boardMapper->mapAcl($acl);
}
}
$permissions = $this->permissionService->matchPermissions($board);
$board->setPermissions([
'PERMISSION_READ' => $permissions[Acl::PERMISSION_READ] ?? false,
'PERMISSION_EDIT' => $permissions[Acl::PERMISSION_EDIT] ?? false,
'PERMISSION_MANAGE' => $permissions[Acl::PERMISSION_MANAGE] ?? false,
'PERMISSION_SHARE' => $permissions[Acl::PERMISSION_SHARE] ?? false
]);
if ($fullDetails) {
$this->enrichWithStacks($board);
$this->enrichWithLabels($board);
$this->enrichWithUsers($board);
$this->enrichWithBoardSettings($board);
$this->enrichWithActiveSessions($board);
}
// Cache for further usage
if ($fullDetails) {
$this->boardsCacheFull[$board->getId()] = $board;
} else {
$this->boardsCachePartial[$board->getId()] = $board;
}
}
return $boards;
}
private function enrichWithStacks($board, $since = -1) {
$stacks = $this->stackMapper->findAll($board->getId(), null, null, $since);
@@ -704,7 +713,7 @@ class BoardService {
private function enrichWithUsers($board, $since = -1) {
$boardUsers = $this->permissionService->findUsers($board->getId());
if ($boardUsers === null || \count($boardUsers) === 0) {
if (\count($boardUsers) === 0) {
return;
}
$board->setUsers(array_values($boardUsers));
@@ -714,6 +723,10 @@ class BoardService {
return $this->urlGenerator->linkToRouteAbsolute('deck.page.index') . '#' . $endpoint;
}
private function clearBoardsCache() {
$this->boardsCache = null;
}
/**
* Clean a given board data from the Cache
*/
@@ -722,8 +735,7 @@ class BoardService {
$boardOwnerId = $board->getOwner();
$this->boardMapper->flushCache($boardId, $boardOwnerId);
unset($this->boardsCacheFull[$boardId]);
unset($this->boardsCachePartial[$boardId]);
unset($this->boardsCache[$boardId]);
}
private function enrichWithCards($board) {

View File

@@ -28,13 +28,11 @@ namespace OCA\Deck\Service;
use OCA\Deck\Activity\ActivityManager;
use OCA\Deck\Activity\ChangeSet;
use OCA\Deck\Db\Assignment;
use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\Card;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\ChangeHelper;
use OCA\Deck\Db\Label;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\Event\CardCreatedEvent;
use OCA\Deck\Event\CardDeletedEvent;
@@ -116,52 +114,32 @@ class CardService {
$this->cardServiceValidator = $cardServiceValidator;
}
public function enrichCards($cards) {
public function enrich($card) {
$cardId = $card->getId();
$this->cardMapper->mapOwner($card);
$card->setAssignedUsers($this->assignedUsersMapper->findAll($cardId));
$card->setLabels($this->labelMapper->findAssignedLabelsForCard($cardId));
$card->setAttachmentCount($this->attachmentService->count($cardId));
$user = $this->userManager->get($this->currentUser);
$lastRead = $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user);
$countUnreadComments = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead);
$countComments = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId());
$card->setCommentsUnread($countUnreadComments);
$card->setCommentsCount($countComments);
$cardIds = array_map(function (Card $card) use ($user) {
// Everything done in here might be heavy as it is executed for every card
$cardId = $card->getId();
$this->cardMapper->mapOwner($card);
$card->setAttachmentCount($this->attachmentService->count($cardId));
// TODO We should find a better way just to get the comment count so we can save 1-3 queries per card here
$countComments = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId());
$lastRead = $countComments > 0 ? $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user) : null;
$countUnreadComments = $lastRead ? $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead) : 0;
$card->setCommentsUnread($countUnreadComments);
$card->setCommentsCount($countComments);
$stack = $this->stackMapper->find($card->getStackId());
$board = $this->boardService->find($stack->getBoardId(), false);
$card->setRelatedStack($stack);
$card->setRelatedBoard($board);
return $card->getId();
}, $cards);
$assignedLabels = $this->labelMapper->findAssignedLabelsForCards($cardIds);
$assignedUsers = $this->assignedUsersMapper->findIn($cardIds);
foreach ($cards as $card) {
$cardLabels = array_values(array_filter($assignedLabels, function (Label $label) use ($card) {
return $label->getCardId() === $card->getId();
}));
$cardAssignedUsers = array_values(array_filter($assignedUsers, function (Assignment $assignment) use ($card) {
return $assignment->getCardId() === $card->getId();
}));
$card->setLabels($cardLabels);
$card->setAssignedUsers($cardAssignedUsers);
}
return $cards;
$stack = $this->stackMapper->find($card->getStackId());
$board = $this->boardService->find($stack->getBoardId());
$card->setRelatedStack($stack);
$card->setRelatedBoard($board);
}
public function fetchDeleted($boardId) {
$this->cardServiceValidator->check(compact('boardId'));
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
$cards = $this->cardMapper->findDeleted($boardId);
$this->enrichCards($cards);
foreach ($cards as $card) {
$this->enrich($card);
}
return $cards;
}
@@ -175,17 +153,16 @@ class CardService {
public function find(int $cardId) {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
$card = $this->cardMapper->find($cardId);
[$card] = $this->enrichCards([$card]);
// Attachments are only enriched on individual card fetching
$assignedUsers = $this->assignedUsersMapper->findAll($card->getId());
$attachments = $this->attachmentService->findAll($cardId, true);
if ($this->request->getParam('apiVersion') === '1.0') {
$attachments = array_filter($attachments, function ($attachment) {
return $attachment->getType() === 'deck_file';
});
}
$card->setAssignedUsers($assignedUsers);
$card->setAttachments($attachments);
$this->enrich($card);
return $card;
}
@@ -197,7 +174,9 @@ class CardService {
return [];
}
$cards = $this->cardMapper->findCalendarEntries($boardId);
$this->enrichCards($cards);
foreach ($cards as $card) {
$this->enrich($card);
}
return $cards;
}
@@ -353,7 +332,7 @@ class CardService {
}
$this->changeHelper->cardChanged($card->getId(), true);
$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card, $changes->getBefore()));
$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card));
return $card;
}
@@ -443,8 +422,6 @@ class CardService {
$result[$card->getOrder()] = $card;
}
$this->changeHelper->cardChanged($id, false);
$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card));
return array_values($result);
}

View File

@@ -224,7 +224,7 @@ class ConfigService {
}
public function getAttachmentFolder(string $userId = null): string {
if ($userId === null && $this->getUserId() === null) {
if ($this->getUserId() === null) {
throw new NoPermissionException('Must be logged in get the attachment folder');
}

View File

@@ -62,8 +62,9 @@ class DefaultBoardService {
*/
public function checkFirstRun($userId): bool {
$firstRun = $this->config->getUserValue($userId, Application::APP_ID, 'firstRun', 'yes');
$userBoards = $this->boardMapper->findAllByUser($userId);
if ($firstRun === 'yes') {
if ($firstRun === 'yes' && count($userBoards) === 0) {
try {
$this->config->setUserValue($userId, Application::APP_ID, 'firstRun', 'no');
} catch (PreConditionNotMetException $e) {

View File

@@ -28,7 +28,7 @@ declare(strict_types=1);
namespace OCA\Deck\Service;
use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\Card;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Model\CardDetails;
use OCP\Comments\ICommentsManager;
@@ -37,7 +37,6 @@ use OCA\Deck\Db\LabelMapper;
use OCP\IUserManager;
class OverviewService {
private CardService $cardService;
private BoardMapper $boardMapper;
private LabelMapper $labelMapper;
private CardMapper $cardMapper;
@@ -47,7 +46,6 @@ class OverviewService {
private AttachmentService $attachmentService;
public function __construct(
CardService $cardService,
BoardMapper $boardMapper,
LabelMapper $labelMapper,
CardMapper $cardMapper,
@@ -56,7 +54,6 @@ class OverviewService {
ICommentsManager $commentsManager,
AttachmentService $attachmentService
) {
$this->cardService = $cardService;
$this->boardMapper = $boardMapper;
$this->labelMapper = $labelMapper;
$this->cardMapper = $cardMapper;
@@ -66,43 +63,66 @@ class OverviewService {
$this->attachmentService = $attachmentService;
}
public function enrich(Card $card, string $userId): void {
$cardId = $card->getId();
$this->cardMapper->mapOwner($card);
$card->setAssignedUsers($this->assignedUsersMapper->findAll($cardId));
$card->setLabels($this->labelMapper->findAssignedLabelsForCard($cardId));
$card->setAttachmentCount($this->attachmentService->count($cardId));
$user = $this->userManager->get($userId);
if ($user !== null) {
$lastRead = $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user);
$count = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead);
$card->setCommentsUnread($count);
}
}
public function findAllWithDue(string $userId): array {
$userBoards = $this->boardMapper->findAllForUser($userId);
$allDueCards = [];
foreach ($userBoards as $userBoard) {
$allDueCards[] = array_map(function ($card) use ($userBoard, $userId) {
$this->enrich($card, $userId);
return (new CardDetails($card, $userBoard))->jsonSerialize();
}, $this->cardMapper->findAllWithDue($userBoard->getId()));
}
return array_merge(...$allDueCards);
}
public function findUpcomingCards(string $userId): array {
$userBoards = $this->boardMapper->findAllForUser($userId);
$boardOwnerIds = array_filter(array_map(function (Board $board) {
return count($board->getAcl()) === 0 ? $board->getId() : null;
}, $userBoards));
$boardSharedIds = array_filter(array_map(function (Board $board) {
return count($board->getAcl()) > 0 ? $board->getId() : null;
}, $userBoards));
$foundCards = array_merge(
// private board: get cards with due date
$this->cardMapper->findAllWithDue($boardOwnerIds),
// shared board: get all my assigned or unassigned cards
$this->cardMapper->findToMeOrNotAssignedCards($boardSharedIds, $userId)
);
$this->cardService->enrichCards($foundCards);
$overview = [];
foreach ($foundCards as $card) {
$diffDays = $card->getDaysUntilDue();
$key = 'later';
if ($diffDays === null) {
$key = 'nodue';
} elseif ($diffDays < 0) {
$key = 'overdue';
} elseif ($diffDays === 0) {
$key = 'today';
} elseif ($diffDays === 1) {
$key = 'tomorrow';
} elseif ($diffDays <= 7) {
$key = 'nextSevenDays';
foreach ($userBoards as $userBoard) {
if (count($userBoard->getAcl()) === 0) {
// private board: get cards with due date
$cards = $this->cardMapper->findAllWithDue($userBoard->getId());
} else {
// shared board: get all my assigned or unassigned cards
$cards = $this->cardMapper->findToMeOrNotAssignedCards($userBoard->getId(), $userId);
}
$card = (new CardDetails($card, $card->getRelatedBoard()));
$overview[$key][] = $card->jsonSerialize();
foreach ($cards as $card) {
$this->enrich($card, $userId);
$diffDays = $card->getDaysUntilDue();
$key = 'later';
if ($diffDays === null) {
$key = 'nodue';
} elseif ($diffDays < 0) {
$key = 'overdue';
} elseif ($diffDays === 0) {
$key = 'today';
} elseif ($diffDays === 1) {
$key = 'tomorrow';
} elseif ($diffDays <= 7) {
$key = 'nextSevenDays';
}
$card = (new CardDetails($card, $userBoard));
$overview[$key][] = $card->jsonSerialize();
}
}
return $overview;
}

View File

@@ -97,26 +97,21 @@ class PermissionService {
* @param $boardId
* @return bool|array
*/
public function getPermissions($boardId, ?string $userId = null) {
if ($userId === null) {
$userId = $this->userId;
}
$cacheKey = $boardId . '-' . $userId;
if ($cached = $this->permissionCache->get($cacheKey)) {
public function getPermissions($boardId) {
if ($cached = $this->permissionCache->get($boardId)) {
return $cached;
}
$owner = $this->userIsBoardOwner($boardId, $userId);
$owner = $this->userIsBoardOwner($boardId);
$acls = $this->aclMapper->findAll($boardId);
$permissions = [
Acl::PERMISSION_READ => $owner || $this->userCan($acls, Acl::PERMISSION_READ, $userId),
Acl::PERMISSION_EDIT => $owner || $this->userCan($acls, Acl::PERMISSION_EDIT, $userId),
Acl::PERMISSION_MANAGE => $owner || $this->userCan($acls, Acl::PERMISSION_MANAGE, $userId),
Acl::PERMISSION_SHARE => ($owner || $this->userCan($acls, Acl::PERMISSION_SHARE, $userId))
&& (!$this->shareManager->sharingDisabledForUser($userId))
Acl::PERMISSION_READ => $owner || $this->userCan($acls, Acl::PERMISSION_READ),
Acl::PERMISSION_EDIT => $owner || $this->userCan($acls, Acl::PERMISSION_EDIT),
Acl::PERMISSION_MANAGE => $owner || $this->userCan($acls, Acl::PERMISSION_MANAGE),
Acl::PERMISSION_SHARE => ($owner || $this->userCan($acls, Acl::PERMISSION_SHARE))
&& (!$this->shareManager->sharingDisabledForUser($this->userId))
];
$this->permissionCache->set($cacheKey, $permissions);
$this->permissionCache->set($boardId, $permissions);
return $permissions;
}
@@ -148,7 +143,7 @@ class PermissionService {
* @return bool
* @throws NoPermissionException
*/
public function checkPermission($mapper, $id, $permission, $userId = null): bool {
public function checkPermission($mapper, $id, $permission, $userId = null) {
$boardId = $id;
if ($mapper instanceof IPermissionMapper && !($mapper instanceof BoardMapper)) {
$boardId = $mapper->findBoardId($id);
@@ -158,11 +153,23 @@ class PermissionService {
throw new NoPermissionException('Permission denied');
}
$permissions = $this->getPermissions($boardId, $userId);
if ($permissions[$permission] === true) {
if ($permission === Acl::PERMISSION_SHARE && $this->shareManager->sharingDisabledForUser($this->userId)) {
throw new NoPermissionException('Permission denied');
}
if ($this->userIsBoardOwner($boardId, $userId)) {
return true;
}
try {
$acls = $this->getBoard($boardId)->getAcl() ?? [];
$result = $this->userCan($acls, $permission, $userId);
if ($result) {
return true;
}
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
}
// Throw NoPermission to not leak information about existing entries
throw new NoPermissionException('Permission denied');
}
@@ -253,20 +260,22 @@ class PermissionService {
}
$users = [];
if (!$this->userManager->userExists($board->getOwner())) {
$owner = $this->userManager->get($board->getOwner());
if ($owner === null) {
$this->logger->info('No owner found for board ' . $board->getId());
} else {
$users[$board->getOwner()] = new User($board->getOwner(), $this->userManager);
$users[$owner->getUID()] = new User($owner);
}
$acls = $this->aclMapper->findAll($boardId);
/** @var Acl $acl */
foreach ($acls as $acl) {
if ($acl->getType() === Acl::PERMISSION_TYPE_USER) {
if (!$this->userManager->userExists($acl->getParticipant())) {
$user = $this->userManager->get($acl->getParticipant());
if ($user === null) {
$this->logger->info('No user found for acl rule ' . $acl->getId());
continue;
}
$users[$acl->getParticipant()] = new User($acl->getParticipant(), $this->userManager);
$users[$user->getUID()] = new User($user);
}
if ($acl->getType() === Acl::PERMISSION_TYPE_GROUP) {
$group = $this->groupManager->get($acl->getParticipant());
@@ -275,7 +284,7 @@ class PermissionService {
continue;
}
foreach ($group->getUsers() as $user) {
$users[$user->getUID()] = new User($user->getUID(), $this->userManager);
$users[$user->getUID()] = new User($user);
}
}
@@ -296,7 +305,7 @@ class PermissionService {
if ($user === null) {
$this->logger->info('No user found for circle member ' . $member->getUserId());
} else {
$users[$member->getUserId()] = new User($member->getUserId(), $this->userManager);
$users[$member->getUserId()] = new User($user);
}
}
} catch (\Exception $e) {

View File

@@ -82,7 +82,11 @@ class SearchService {
}, $boards);
$matchedCards = $this->cardMapper->search($boardIds, $this->filterStringParser->parse($term), $limit, $cursor);
return $this->cardService->enrichCards($matchedCards);
$self = $this;
return array_map(function (Card $card) use ($self) {
$self->cardService->enrich($card);
return $card;
}, $matchedCards);
}
public function searchBoards(string $term, ?int $limit, ?int $cursor): array {
@@ -113,8 +117,7 @@ class SearchService {
$comment = $this->commentsManager->get($cardRow['comment_id']);
unset($cardRow['comment_id']);
$card = Card::fromRow($cardRow);
// TODO: Only perform one enrich call here
$self->cardService->enrichCards([$card]);
$self->cardService->enrich($card);
$user = $this->userManager->get($comment->getActorId());
$displayName = $user ? $user->getDisplayName() : '';
return new CommentSearchResultEntry($comment->getId(), $comment->getMessage(), $displayName, $card, $this->urlGenerator, $this->l10n);

View File

@@ -36,12 +36,10 @@ use OCA\Deck\Db\ChangeHelper;
use OCA\Deck\Db\LabelMapper;
use OCA\Deck\Db\Stack;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\Event\BoardUpdatedEvent;
use OCA\Deck\Model\CardDetails;
use OCA\Deck\NoPermissionException;
use OCA\Deck\StatusException;
use OCA\Deck\Validators\StackServiceValidator;
use OCP\EventDispatcher\IEventDispatcher;
use Psr\Log\LoggerInterface;
class StackService {
@@ -57,7 +55,6 @@ class StackService {
private ActivityManager $activityManager;
private ChangeHelper $changeHelper;
private LoggerInterface $logger;
private IEventDispatcher $eventDispatcher;
private StackServiceValidator $stackServiceValidator;
public function __construct(
@@ -73,7 +70,6 @@ class StackService {
ActivityManager $activityManager,
ChangeHelper $changeHelper,
LoggerInterface $logger,
IEventDispatcher $eventDispatcher,
StackServiceValidator $stackServiceValidator
) {
$this->stackMapper = $stackMapper;
@@ -88,7 +84,6 @@ class StackService {
$this->activityManager = $activityManager;
$this->changeHelper = $changeHelper;
$this->logger = $logger;
$this->eventDispatcher = $eventDispatcher;
$this->stackServiceValidator = $stackServiceValidator;
}
@@ -99,9 +94,9 @@ class StackService {
return;
}
$this->cardService->enrichCards($cards);
$cards = array_map(
function (Card $card): CardDetails {
$this->cardService->enrich($card);
return new CardDetails($card);
},
$cards
@@ -242,7 +237,6 @@ class StackService {
ActivityManager::DECK_OBJECT_BOARD, $stack, ActivityManager::SUBJECT_STACK_CREATE
);
$this->changeHelper->boardChanged($boardId);
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($boardId));
return $stack;
}
@@ -271,7 +265,6 @@ class StackService {
ActivityManager::DECK_OBJECT_BOARD, $stack, ActivityManager::SUBJECT_STACK_DELETE
);
$this->changeHelper->boardChanged($stack->getBoardId());
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($stack->getBoardId()));
$this->enrichStackWithCards($stack);
return $stack;
@@ -313,7 +306,6 @@ class StackService {
ActivityManager::DECK_OBJECT_BOARD, $changes, ActivityManager::SUBJECT_STACK_UPDATE
);
$this->changeHelper->boardChanged($stack->getBoardId());
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($stack->getBoardId()));
return $stack;
}
@@ -353,7 +345,6 @@ class StackService {
$result[$stack->getOrder()] = $stack;
}
$this->changeHelper->boardChanged($stackToSort->getBoardId());
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($stackToSort->getBoardId()));
return $result;
}

View File

@@ -30,10 +30,8 @@ use OCA\Deck\Db\Acl;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\NoPermissionException;
use OCA\Deck\Service\PermissionService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Files\NotFoundException;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Share\IShare;
@@ -55,11 +53,7 @@ class ShareAPIHelper {
public function formatShare(IShare $share): array {
$result = [];
try {
$card = $this->cardMapper->find($share->getSharedWith());
} catch (DoesNotExistException $e) {
throw new NotFoundException($e->getMessage());
}
$card = $this->cardMapper->find($share->getSharedWith());
$boardId = $this->cardMapper->findBoardId($card->getId());
$result['share_with'] = $share->getSharedWith();
$result['share_with_displayname'] = $card->getTitle();

64881
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,108 +1,109 @@
{
"name": "deck",
"description": "",
"version": "1.9.2",
"authors": [
{
"name": "Julius Härtl",
"email": "jus@bitgrid.net",
"role": "Developer"
},
{
"name": "Michael Weimann",
"email": "mail@michael-weimann.eu",
"role": "Developer"
}
],
"license": "agpl",
"private": true,
"scripts": {
"build": "NODE_ENV=production webpack --progress --config webpack.js",
"dev": "NODE_ENV=development webpack --progress --config webpack.js",
"watch": "NODE_ENV=development webpack --progress --watch --config webpack.js",
"lint": "eslint --ext .js,.vue src",
"lint:fix": "eslint --ext .js,.vue src --fix",
"lint:cypress": "eslint --ext .js cypress",
"stylelint": "stylelint src",
"stylelint:fix": "stylelint src --fix",
"test": "jest",
"test:coverage": "jest --coverage"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.21.0",
"@nextcloud/auth": "^2.0.0",
"@nextcloud/axios": "^2.3.0",
"@nextcloud/dialogs": "^4.0.1",
"@nextcloud/event-bus": "^3.0.2",
"@nextcloud/files": "^2.1.0",
"@nextcloud/initial-state": "^2.0.0",
"@nextcloud/l10n": "^2.1.0",
"@nextcloud/moment": "^1.2.1",
"@nextcloud/notify_push": "^1.1.3",
"@nextcloud/router": "^2.0.1",
"@nextcloud/vue": "^7.8.4",
"@nextcloud/vue-richtext": "^2.0.4",
"blueimp-md5": "^2.19.0",
"dompurify": "^3.0.0",
"lodash": "^4.17.21",
"markdown-it": "^13.0.1",
"markdown-it-link-attributes": "^4.0.1",
"markdown-it-task-checkbox": "^1.0.6",
"moment": "^2.29.4",
"nextcloud-vue-collections": "^0.11.0",
"p-queue": "^7.3.4",
"url-search-params-polyfill": "^8.1.1",
"vue": "^2.7.14",
"vue-at": "^2.5.1",
"vue-click-outside": "^1.1.0",
"vue-easymde": "^2.0.0",
"vue-infinite-loading": "^2.4.5",
"vue-material-design-icons": "^5.2.0",
"vue-router": "^3.6.5",
"vue-smooth-dnd": "^0.8.1",
"vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0"
},
"browserslist": [
"extends @nextcloud/browserslist-config"
],
"engines": {
"node": "^16.0.0",
"npm": "^7.0.0 || ^8.0.0"
},
"devDependencies": {
"@nextcloud/babel-config": "^1.0.0",
"@nextcloud/browserslist-config": "^2.3.0",
"@nextcloud/cypress": "^1.0.0-beta.2",
"@nextcloud/eslint-config": "^8.2.1",
"@nextcloud/stylelint-config": "^2.3.0",
"@nextcloud/webpack-vue-config": "^5.4.0",
"@relative-ci/agent": "^4.1.3",
"@vue/test-utils": "^1.3.4",
"@vue/vue2-jest": "^29.2.2",
"cypress": "^12.7.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-webpack-plugin": "^4.0.0",
"jest": "^29.4.3",
"jest-serializer-vue": "^3.1.0",
"stylelint-webpack-plugin": "^4.1.0",
"vue-template-compiler": "^2.7.14"
},
"jest": {
"moduleFileExtensions": [
"js",
"vue"
],
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
},
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
},
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
]
}
}
"name": "deck",
"description": "",
"version": "1.9.0-beta.1",
"authors": [
{
"name": "Julius Härtl",
"email": "jus@bitgrid.net",
"role": "Developer"
},
{
"name": "Michael Weimann",
"email": "mail@michael-weimann.eu",
"role": "Developer"
}
],
"license": "agpl",
"private": true,
"scripts": {
"build": "NODE_ENV=production webpack --progress --config webpack.js",
"dev": "NODE_ENV=development webpack --progress --config webpack.js",
"watch": "NODE_ENV=development webpack --progress --watch --config webpack.js",
"lint": "eslint --ext .js,.vue src",
"lint:fix": "eslint --ext .js,.vue src --fix",
"lint:cypress": "eslint --ext .js cypress",
"stylelint": "stylelint src",
"stylelint:fix": "stylelint src --fix",
"test": "jest",
"test:coverage": "jest --coverage"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.20.13",
"@nextcloud/auth": "^2.0.0",
"@nextcloud/axios": "^2.3.0",
"@nextcloud/dialogs": "^3.2.0",
"@nextcloud/event-bus": "^3.0.2",
"@nextcloud/files": "^2.1.0",
"@nextcloud/initial-state": "^2.0.0",
"@nextcloud/l10n": "^2.0.1",
"@nextcloud/moment": "^1.2.1",
"@nextcloud/notify_push": "^1.1.3",
"@nextcloud/router": "^2.0.1",
"@nextcloud/vue": "^7.5.0",
"@nextcloud/vue-dashboard": "^2.0.1",
"@nextcloud/vue-richtext": "^2.0.4",
"blueimp-md5": "^2.19.0",
"dompurify": "^2.4.3",
"lodash": "^4.17.21",
"markdown-it": "^13.0.1",
"markdown-it-link-attributes": "^4.0.1",
"markdown-it-task-checkbox": "^1.0.6",
"moment": "^2.29.4",
"nextcloud-vue-collections": "^0.10.0",
"p-queue": "^7.3.4",
"url-search-params-polyfill": "^8.1.1",
"vue": "^2.7.14",
"vue-at": "^2.5.1",
"vue-click-outside": "^1.1.0",
"vue-easymde": "^2.0.0",
"vue-infinite-loading": "^2.4.5",
"vue-material-design-icons": "^5.2.0",
"vue-router": "^3.6.5",
"vue-smooth-dnd": "^0.8.1",
"vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0"
},
"browserslist": [
"extends @nextcloud/browserslist-config"
],
"engines": {
"node": "^16.0.0",
"npm": "^7.0.0 || ^8.0.0"
},
"devDependencies": {
"@nextcloud/babel-config": "^1.0.0",
"@nextcloud/browserslist-config": "^2.3.0",
"@nextcloud/cypress": "^1.0.0-beta.2",
"@nextcloud/eslint-config": "^8.2.1",
"@nextcloud/stylelint-config": "^2.3.0",
"@nextcloud/webpack-vue-config": "^5.4.0",
"@relative-ci/agent": "^4.1.3",
"@vue/test-utils": "^1.3.4",
"@vue/vue2-jest": "^29.2.2",
"cypress": "^12.5.1",
"eslint-plugin-cypress": "^2.12.1",
"eslint-webpack-plugin": "^4.0.0",
"jest": "^29.4.3",
"jest-serializer-vue": "^3.1.0",
"stylelint-webpack-plugin": "^4.0.0",
"vue-template-compiler": "^2.7.14"
},
"jest": {
"moduleFileExtensions": [
"js",
"vue"
],
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
},
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
},
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
]
}
}

View File

@@ -71,22 +71,12 @@
</div>
</div>
<div v-else id="modal-inner">
<NcEmptyContent v-if="creating">
<template #icon>
<NcLoadingIcon />
</template>
<template #title>
{{ t('deck', 'Creating the new card …') }}
</template>
<NcEmptyContent v-if="creating" icon="icon-loading">
{{ t('deck', 'Creating the new card ') }}
</NcEmptyContent>
<NcEmptyContent v-else-if="created">
<template #icon>
<CardPlusOutline />
</template>
<template #title>
{{ t('deck', 'Card "{card}" was added to "{board}"', { card: pendingTitle, board: selectedBoard.title }) }}
</template>
<template #action>
<NcEmptyContent v-else-if="created" icon="icon-checkmark">
{{ t('deck', 'Card "{card}" was added to "{board}"', { card: pendingTitle, board: selectedBoard.title }) }}
<template #desc>
<button class="primary" @click="openNewCard">
{{ t('deck', 'Open card') }}
</button>
@@ -102,8 +92,7 @@
<script>
import { generateUrl } from '@nextcloud/router'
import { NcModal, NcMultiselect, NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue'
import CardPlusOutline from 'vue-material-design-icons/CardPlusOutline.vue'
import { NcModal, NcMultiselect, NcEmptyContent } from '@nextcloud/vue'
import axios from '@nextcloud/axios'
import { CardApi } from './services/CardApi.js'
@@ -115,8 +104,6 @@ export default {
NcEmptyContent,
NcModal,
NcMultiselect,
NcLoadingIcon,
CardPlusOutline,
},
props: {
title: {
@@ -216,7 +203,6 @@ export default {
max-width: 400px;
padding: 10px;
min-height: 200px;
margin: auto;
}
.multiselect-board, .multiselect-list, input, textarea {

View File

@@ -95,7 +95,8 @@ export default {
.avatar-wrapper {
background-color: #b9b9b9;
border-radius: 50%;
border: 1px solid var(--color-border-dark);
border-width: 2px;
border-style: solid;
width: var(--size);
height: var(--size);
text-align: center;

View File

@@ -30,14 +30,9 @@
<h2>{{ t('deck', 'Loading board') }}</h2>
<p />
</div>
<NcEmptyContent v-else-if="isEmpty" key="empty">
<template #icon>
<DeckIcon />
</template>
<template #title>
{{ t('deck', 'No lists available') }}
</template>
<template v-if="canManage" #action>
<NcEmptyContent v-else-if="isEmpty" key="empty" icon="icon-deck">
{{ t('deck', 'No lists available') }}
<template v-if="canManage" #desc>
{{ t('deck', 'Create a new list to add cards to this board') }}
<form @submit.prevent="addNewStack()">
<input id="new-stack-input-main"
@@ -62,10 +57,7 @@
@drag-start="draggingStack = true"
@drag-end="draggingStack = false"
@drop="onDropStack">
<Draggable v-for="stack in stacksByBoard"
:key="stack.id"
data-click-closes-sidebar="true"
class="stack-draggable-wrapper">
<Draggable v-for="stack in stacksByBoard" :key="stack.id" data-click-closes-sidebar="true">
<Stack :stack="stack" :dragging="draggingStack" data-click-closes-sidebar="true" />
</Draggable>
</Container>
@@ -85,7 +77,6 @@
import { Container, Draggable } from 'vue-smooth-dnd'
import { mapState, mapGetters } from 'vuex'
import Controls from '../Controls.vue'
import DeckIcon from '../icons/DeckIcon.vue'
import Stack from './Stack.vue'
import { NcEmptyContent } from '@nextcloud/vue'
import GlobalSearchResults from '../search/GlobalSearchResults.vue'
@@ -98,7 +89,6 @@ export default {
GlobalSearchResults,
Controls,
Container,
DeckIcon,
Draggable,
Stack,
NcEmptyContent,
@@ -233,7 +223,7 @@ export default {
align-items: stretch;
height: 100%;
&:deep(.stack-draggable-wrapper.smooth-dnd-draggable-wrapper) {
&:deep(.smooth-dnd-draggable-wrapper) {
display: flex;
height: auto;

View File

@@ -150,13 +150,13 @@
import ClickOutside from 'vue-click-outside'
import { mapGetters, mapState } from 'vuex'
import { Container, Draggable } from 'vue-smooth-dnd'
import ArchiveIcon from 'vue-material-design-icons/Archive.vue'
import { NcActions, NcActionButton, NcModal } from '@nextcloud/vue'
import { showError, showUndo } from '@nextcloud/dialogs'
import CardItem from '../cards/CardItem.vue'
import '@nextcloud/dialogs/dist/index.css'
import '@nextcloud/dialogs/styles/toast.scss'
import ArchiveIcon from 'vue-material-design-icons/Archive.vue'
export default {
name: 'Stack',

View File

@@ -147,7 +147,7 @@ export default {
return this.$store.getters.cardById(this.id)
},
subtitle() {
return t('deck', 'Modified') + ': ' + this.relativeDate(this.currentCard.lastModified * 1000) + ' ' + t('deck', 'Created') + ': ' + this.relativeDate(this.currentCard.createdAt * 1000)
return t('deck', 'Modified') + ': ' + this.relativeDate(this.currentCard.lastModified * 1000) + ' ' + t('deck', 'Created') + ': ' + this.relativeDate(this.currentCard.createdAt * 1000)
},
subtitleTooltip() {
return t('deck', 'Modified') + ': ' + this.formatDate(this.currentCard.lastModified) + '\n' + t('deck', 'Created') + ': ' + this.formatDate(this.currentCard.createdAt)

View File

@@ -103,7 +103,6 @@
:formatter="format"
:disabled="saving || !canEdit"
:shortcuts="shortcuts"
:append-to-body="true"
confirm />
<NcActions v-if="canEdit">
<NcActionButton v-if="copiedCard.duedate" icon="icon-delete" @click="removeDue()">
@@ -449,10 +448,5 @@ export default {
.multiselect.multiselect--active:deep(.multiselect__tags-wrap) {
z-index: 0;
}
</style>
<style>
.mx-datepicker-main.mx-datepicker-popup {
/* above the modal */
z-index: 9999 !important;
}
</style>

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