Compare commits

..

1 Commits

Author SHA1 Message Date
Kostiantyn Miakshyn
bbe72b93d9 Feat: Highlight cards with important labels
Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
2025-09-13 23:34:02 +02:00
50 changed files with 568 additions and 534 deletions

View File

@@ -6,7 +6,6 @@
- Adrian Missy <adrian.missy@onewavestudios.com> - Adrian Missy <adrian.missy@onewavestudios.com>
- Alexandru Puiu <alexpuiu20@yahoo.com> - Alexandru Puiu <alexpuiu20@yahoo.com>
- Arne Bartelt <arne.bartelt@gmail.com>
- Chandi Langecker <git@chandi.it> - Chandi Langecker <git@chandi.it>
- Christoph Wurst <christoph@winzerhof-wurst.at> - Christoph Wurst <christoph@winzerhof-wurst.at>
- Gary Kim <gary@garykim.dev> - Gary Kim <gary@garykim.dev>

8
composer.lock generated
View File

@@ -380,12 +380,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nextcloud-deps/ocp.git", "url": "https://github.com/nextcloud-deps/ocp.git",
"reference": "d927392a2a368c372ef80096171139d4287b2339" "reference": "6a5219dda0583a45fb5541719de83c9b673b3efa"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/d927392a2a368c372ef80096171139d4287b2339", "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/6a5219dda0583a45fb5541719de83c9b673b3efa",
"reference": "d927392a2a368c372ef80096171139d4287b2339", "reference": "6a5219dda0583a45fb5541719de83c9b673b3efa",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -421,7 +421,7 @@
"issues": "https://github.com/nextcloud-deps/ocp/issues", "issues": "https://github.com/nextcloud-deps/ocp/issues",
"source": "https://github.com/nextcloud-deps/ocp/tree/master" "source": "https://github.com/nextcloud-deps/ocp/tree/master"
}, },
"time": "2025-09-16T00:45:42+00:00" "time": "2025-09-06T00:45:32+00:00"
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",

View File

@@ -6,7 +6,7 @@ The REST API provides access for authenticated users to their data inside the De
# Prerequisites # Prerequisites
- All requests require a `OCS-APIRequest` HTTP header to be set to `true` and a `Content-Type` of `application/json`. This does not apply to the endpoint for uploading attachments, which consumes `multipart/form-data`. - All requests require a `OCS-APIRequest` HTTP header to be set to `true` and a `Content-Type` of `application/json`.
- The API is located at https://nextcloud.local/index.php/apps/deck/api/v1.0 - The API is located at https://nextcloud.local/index.php/apps/deck/api/v1.0
- All request parameters are required, unless otherwise specified - All request parameters are required, unless otherwise specified
@@ -212,28 +212,32 @@ Returns an array of board items
"color": "31CC7C", "color": "31CC7C",
"boardId": 10, "boardId": 10,
"cardId": null, "cardId": null,
"id": 37 "id": 37,
"customSettings": {}
}, },
{ {
"title": "To review", "title": "To review",
"color": "317CCC", "color": "317CCC",
"boardId": 10, "boardId": 10,
"cardId": null, "cardId": null,
"id": 38 "id": 38,
"customSettings": {}
}, },
{ {
"title": "Action needed", "title": "Action needed",
"color": "FF7A66", "color": "FF7A66",
"boardId": 10, "boardId": 10,
"cardId": null, "cardId": null,
"id": 39 "id": 39,
"customSettings": { "isImportant": true }
}, },
{ {
"title": "Later", "title": "Later",
"color": "F1DB50", "color": "F1DB50",
"boardId": 10, "boardId": 10,
"cardId": null, "cardId": null,
"id": 40 "id": 40,
"customSettings": {}
} }
], ],
"acl": [], "acl": [],
@@ -282,28 +286,32 @@ A 403 response might be returned if the users ability to create new boards has b
"color": "31CC7C", "color": "31CC7C",
"boardId": "10", "boardId": "10",
"cardId": null, "cardId": null,
"id": 37 "id": 37,
"customSettings": {}
}, },
{ {
"title": "To review", "title": "To review",
"color": "317CCC", "color": "317CCC",
"boardId": "10", "boardId": "10",
"cardId": null, "cardId": null,
"id": 38 "id": 38,
"customSettings": {}
}, },
{ {
"title": "Action needed", "title": "Action needed",
"color": "FF7A66", "color": "FF7A66",
"boardId": "10", "boardId": "10",
"cardId": null, "cardId": null,
"id": 39 "id": 39,
"customSettings": {}
}, },
{ {
"title": "Later", "title": "Later",
"color": "F1DB50", "color": "F1DB50",
"boardId": "10", "boardId": "10",
"cardId": null, "cardId": null,
"id": 40 "id": 40,
"customSettings": {}
} }
], ],
"acl": [], "acl": [],
@@ -733,7 +741,6 @@ The board list endpoint supports setting an `If-Modified-Since` header to limit
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ------- | --------------------------------------- | | --------- | ------- | --------------------------------------- |
| labelId | Integer | The label id to assign to the card | | labelId | Integer | The label id to assign to the card |
#### Response #### Response
##### 200 Success ##### 200 Success
@@ -868,7 +875,8 @@ The request can fail with a bad request response for the following reasons:
"color": "31CC7C", "color": "31CC7C",
"boardId": "2", "boardId": "2",
"cardId": null, "cardId": null,
"id": 5 "id": 5,
"customSettings": { "isImportant": false }
} }
``` ```
@@ -876,16 +884,18 @@ The request can fail with a bad request response for the following reasons:
#### Request parameters #### Request parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ------- | ---------------------------------------- | |----------------|---------|------------------------------------------------------------------------------|
| boardId | Integer | The id of the board the label belongs to | | boardId | Integer | The id of the board the label belongs to |
| customSettings | Object | An key-value structure, currently supported only bool property `isImportant` |
#### Request data #### Request data
```json ```json
{ {
"title": "Finished", "title": "Finished",
"color": "31CC7C" "color": "31CC7C",
"customSettings": { "isImportant": false }
} }
``` ```
@@ -897,10 +907,11 @@ The request can fail with a bad request response for the following reasons:
#### Request parameters #### Request parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ------- | ---------------------------------------- | | --------- | ------- |-----------------------------------------------------------------------------------|
| boardId | Integer | The id of the board the label belongs to | | boardId | Integer | The id of the board the label belongs to |
| labelId | Integer | The id of the label | | labelId | Integer | The id of the label |
| customSettings | Object | An key-value structure, currently supported only bool property `isImportant` |
#### Request data #### Request data
@@ -908,7 +919,8 @@ The request can fail with a bad request response for the following reasons:
```json ```json
{ {
"title": "Finished", "title": "Finished",
"color": "31CC7C" "color": "31CC7C",
"customSettings": { }
} }
``` ```
@@ -998,12 +1010,10 @@ The request can fail with a bad request response for the following reasons:
#### Request data #### Request data
The request is performed as `multipart/form-data`. | Parameter | Type | Description |
| --------- | ------- | --------------------------------------------- |
| Parameter | Type | Description | | type | String | The type of the attachement |
| --------- | ------- | ----------------------------------------------------------------------------------------------- | | file | Binary | File data to add as an attachment |
| type | String | The type of the attachement. Use `file` or `deck_file`. |
| file | Binary | File data to add as an attachment together with the `filename` parameter according to RFC 7578. |
- Prior to Deck version v1.3.0 (API v1.0), attachments were stored within deck. For this type of attachments `deck_file` was used as the default type of attachments - Prior to Deck version v1.3.0 (API v1.0), attachments were stored within deck. For this type of attachments `deck_file` was used as the default type of attachments
- Starting with Deck version 1.3.0 (API v1.1) files are stored within the users regular Nextcloud files and the type `file` has been introduced for that - Starting with Deck version 1.3.0 (API v1.1) files are stored within the users regular Nextcloud files and the type `file` has been introduced for that
@@ -1025,13 +1035,12 @@ The request is performed as `multipart/form-data`.
#### Request data #### Request data
The request is performed as `multipart/form-data`. | Parameter | Type | Description |
| --------- | ------- | --------------------------------------------- |
| Parameter | Type | Description | | type | String | The type of the attachement |
| --------- | ------- | ----------------------------------------------------------------------------------------------- | | file | Binary | File data to add as an attachment |
| type | String | The type of the attachement. For now only `deck_file` is supported as an attachment type. |
| file | Binary | File data to add as an attachment together with the `filename` parameter according to RFC 7578. |
For now only `deck_file` is supported as an attachment type.
#### Response #### Response

View File

@@ -13,7 +13,6 @@ OC.L10N.register(
"Done" : "Гатова", "Done" : "Гатова",
"File" : "Файл", "File" : "Файл",
"Cancel" : "Скасаваць", "Cancel" : "Скасаваць",
"Drop your files to upload" : "Перацягніце файлы для запампоўвання",
"File already exists" : "Файл ужо існуе", "File already exists" : "Файл ужо існуе",
"A file with the name {filename} already exists." : "Файл з назвай {filename} ужо існуе.", "A file with the name {filename} already exists." : "Файл з назвай {filename} ужо існуе.",
"Do you want to overwrite it?" : "Хочаце перазапісаць яго?", "Do you want to overwrite it?" : "Хочаце перазапісаць яго?",
@@ -37,7 +36,6 @@ OC.L10N.register(
"Delete" : "Выдаліць", "Delete" : "Выдаліць",
"Edit" : "Рэдагаваць", "Edit" : "Рэдагаваць",
"Members" : "Удзельнікі", "Members" : "Удзельнікі",
"File to share" : "Файл для абагульвання",
"Invalid path selected" : "Выбраны памылковы шлях", "Invalid path selected" : "Выбраны памылковы шлях",
"Share from Files" : "Абагуліць з Файлаў", "Share from Files" : "Абагуліць з Файлаў",
"Show in Files" : "Паказаць у Файлах", "Show in Files" : "Паказаць у Файлах",
@@ -50,13 +48,7 @@ OC.L10N.register(
"Reply" : "Адказаць", "Reply" : "Адказаць",
"Update" : "Абнавіць", "Update" : "Абнавіць",
"Description" : "Апісанне", "Description" : "Апісанне",
"Later today {timeLocale}" : "Пазней сёння {timeLocale}",
"Set due date for later today" : "Задаць дату выканання на пазней сёння",
"Tomorrow {timeLocale}" : "Заўтра {timeLocale}", "Tomorrow {timeLocale}" : "Заўтра {timeLocale}",
"This weekend {timeLocale}" : "У гэты ўік-энд {timeLocale}",
"Set due date for this weekend" : "Задаць дату выканання на гэты ўік-энд",
"Next week {timeLocale}" : "На наступным тыдні {timeLocale}",
"Set due date for next week" : "Задаць дату выканання на наступны тыдзень",
"(group)" : "(група)", "(group)" : "(група)",
"Open link" : "Адкрыць спасылку", "Open link" : "Адкрыць спасылку",
"Edit title" : "Рэдагаваць загаловак", "Edit title" : "Рэдагаваць загаловак",
@@ -64,18 +56,13 @@ OC.L10N.register(
"Keyboard shortcuts" : "Спалучэнні клавіш", "Keyboard shortcuts" : "Спалучэнні клавіш",
"Keyboard shortcut" : "Спалучэнне клавіш", "Keyboard shortcut" : "Спалучэнне клавіш",
"Action" : "Дзеянне", "Action" : "Дзеянне",
"Shift" : "Shift",
"Search" : "Пошук", "Search" : "Пошук",
"Enter" : "Enter",
"Shared with you" : "Абагулена з вамі", "Shared with you" : "Абагулена з вамі",
"Cancel edit" : "Скасаваць рэдагаванне", "Cancel edit" : "Скасаваць рэдагаванне",
"An error occurred" : "Узнікла памылка", "An error occurred" : "Узнікла памылка",
"No notifications" : "Няма апавяшчэнняў", "No notifications" : "Няма апавяшчэнняў",
"Export" : "Экспарт", "Export" : "Экспарт",
"No results found" : "Вынікаў не знойдзена",
"{stack} in {board}" : "{stack} у {board}",
"Close" : "Закрыць", "Close" : "Закрыць",
"Message from {author} in {conversationName}" : "Паведамленне ад {author} у {conversationName}",
"Failed to upload {name}" : "Не ўдалося запампаваць {name}", "Failed to upload {name}" : "Не ўдалося запампаваць {name}",
"Share" : "Абагуліць", "Share" : "Абагуліць",
"Today" : "Сёння", "Today" : "Сёння",

View File

@@ -11,7 +11,6 @@
"Done" : "Гатова", "Done" : "Гатова",
"File" : "Файл", "File" : "Файл",
"Cancel" : "Скасаваць", "Cancel" : "Скасаваць",
"Drop your files to upload" : "Перацягніце файлы для запампоўвання",
"File already exists" : "Файл ужо існуе", "File already exists" : "Файл ужо існуе",
"A file with the name {filename} already exists." : "Файл з назвай {filename} ужо існуе.", "A file with the name {filename} already exists." : "Файл з назвай {filename} ужо існуе.",
"Do you want to overwrite it?" : "Хочаце перазапісаць яго?", "Do you want to overwrite it?" : "Хочаце перазапісаць яго?",
@@ -35,7 +34,6 @@
"Delete" : "Выдаліць", "Delete" : "Выдаліць",
"Edit" : "Рэдагаваць", "Edit" : "Рэдагаваць",
"Members" : "Удзельнікі", "Members" : "Удзельнікі",
"File to share" : "Файл для абагульвання",
"Invalid path selected" : "Выбраны памылковы шлях", "Invalid path selected" : "Выбраны памылковы шлях",
"Share from Files" : "Абагуліць з Файлаў", "Share from Files" : "Абагуліць з Файлаў",
"Show in Files" : "Паказаць у Файлах", "Show in Files" : "Паказаць у Файлах",
@@ -48,13 +46,7 @@
"Reply" : "Адказаць", "Reply" : "Адказаць",
"Update" : "Абнавіць", "Update" : "Абнавіць",
"Description" : "Апісанне", "Description" : "Апісанне",
"Later today {timeLocale}" : "Пазней сёння {timeLocale}",
"Set due date for later today" : "Задаць дату выканання на пазней сёння",
"Tomorrow {timeLocale}" : "Заўтра {timeLocale}", "Tomorrow {timeLocale}" : "Заўтра {timeLocale}",
"This weekend {timeLocale}" : "У гэты ўік-энд {timeLocale}",
"Set due date for this weekend" : "Задаць дату выканання на гэты ўік-энд",
"Next week {timeLocale}" : "На наступным тыдні {timeLocale}",
"Set due date for next week" : "Задаць дату выканання на наступны тыдзень",
"(group)" : "(група)", "(group)" : "(група)",
"Open link" : "Адкрыць спасылку", "Open link" : "Адкрыць спасылку",
"Edit title" : "Рэдагаваць загаловак", "Edit title" : "Рэдагаваць загаловак",
@@ -62,18 +54,13 @@
"Keyboard shortcuts" : "Спалучэнні клавіш", "Keyboard shortcuts" : "Спалучэнні клавіш",
"Keyboard shortcut" : "Спалучэнне клавіш", "Keyboard shortcut" : "Спалучэнне клавіш",
"Action" : "Дзеянне", "Action" : "Дзеянне",
"Shift" : "Shift",
"Search" : "Пошук", "Search" : "Пошук",
"Enter" : "Enter",
"Shared with you" : "Абагулена з вамі", "Shared with you" : "Абагулена з вамі",
"Cancel edit" : "Скасаваць рэдагаванне", "Cancel edit" : "Скасаваць рэдагаванне",
"An error occurred" : "Узнікла памылка", "An error occurred" : "Узнікла памылка",
"No notifications" : "Няма апавяшчэнняў", "No notifications" : "Няма апавяшчэнняў",
"Export" : "Экспарт", "Export" : "Экспарт",
"No results found" : "Вынікаў не знойдзена",
"{stack} in {board}" : "{stack} у {board}",
"Close" : "Закрыць", "Close" : "Закрыць",
"Message from {author} in {conversationName}" : "Паведамленне ад {author} у {conversationName}",
"Failed to upload {name}" : "Не ўдалося запампаваць {name}", "Failed to upload {name}" : "Не ўдалося запампаваць {name}",
"Share" : "Абагуліць", "Share" : "Абагуліць",
"Today" : "Сёння", "Today" : "Сёння",

View File

@@ -373,7 +373,6 @@ OC.L10N.register(
"Note: Only the JSON format is supported for importing back into the Deck app." : "Pozn.: Pro import zpět do aplikace Deck je podporován pouze formát JSON.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Pozn.: Pro import zpět do aplikace Deck je podporován pouze formát JSON.",
"Export" : "Exportovat", "Export" : "Exportovat",
"Loading filtered view" : "Načítání filtrovaného pohledu", "Loading filtered view" : "Načítání filtrovaného pohledu",
"Search for {searchQuery} in other boards" : "Hledat {searchQuery} v ostatních tabulích",
"Search for {searchQuery} in all boards" : "Hledat {searchQuery} na všech tabulích", "Search for {searchQuery} in all boards" : "Hledat {searchQuery} na všech tabulích",
"No results found" : "Nenalezeny žádné výsledky", "No results found" : "Nenalezeny žádné výsledky",
"Deck board {name}\n* Last modified on {lastMod}" : "Deck karta {name}\n* Naposledy změněno {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Deck karta {name}\n* Naposledy změněno {lastMod}",

View File

@@ -371,7 +371,6 @@
"Note: Only the JSON format is supported for importing back into the Deck app." : "Pozn.: Pro import zpět do aplikace Deck je podporován pouze formát JSON.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Pozn.: Pro import zpět do aplikace Deck je podporován pouze formát JSON.",
"Export" : "Exportovat", "Export" : "Exportovat",
"Loading filtered view" : "Načítání filtrovaného pohledu", "Loading filtered view" : "Načítání filtrovaného pohledu",
"Search for {searchQuery} in other boards" : "Hledat {searchQuery} v ostatních tabulích",
"Search for {searchQuery} in all boards" : "Hledat {searchQuery} na všech tabulích", "Search for {searchQuery} in all boards" : "Hledat {searchQuery} na všech tabulích",
"No results found" : "Nenalezeny žádné výsledky", "No results found" : "Nenalezeny žádné výsledky",
"Deck board {name}\n* Last modified on {lastMod}" : "Deck karta {name}\n* Naposledy změněno {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Deck karta {name}\n* Naposledy změněno {lastMod}",

View File

@@ -81,14 +81,10 @@ OC.L10N.register(
"Could not write file to disk" : "Αδυναμία εγγραφής αρχείου στον δίσκο", "Could not write file to disk" : "Αδυναμία εγγραφής αρχείου στον δίσκο",
"A PHP extension stopped the file upload" : "Ένα πρόσθετο PHP διέκοψε την μεταφόρτωση του αρχείου", "A PHP extension stopped the file upload" : "Ένα πρόσθετο PHP διέκοψε την μεταφόρτωση του αρχείου",
"No file uploaded or file size exceeds maximum of %s" : "Δεν μεταφορτώθηκε αρχείο ή το μέγεθος αρχείου υπερβαίνει το μέγιστο %s", "No file uploaded or file size exceeds maximum of %s" : "Δεν μεταφορτώθηκε αρχείο ή το μέγεθος αρχείου υπερβαίνει το μέγιστο %s",
"Invalid file type. Only JSON files are allowed." : "Μη έγκυρος τύπος αρχείου. Επιτρέπονται μόνο αρχεία JSON.",
"Invalid JSON data" : "Μη έγκυρα δεδομένα JSON",
"Failed to import board" : "Αποτυχία εισαγωγής πίνακα",
"Cards due today" : "Κάρτες που λήγουν σήμερα", "Cards due today" : "Κάρτες που λήγουν σήμερα",
"Cards due tomorrow" : "Κάρτες που λήγουν αύριο", "Cards due tomorrow" : "Κάρτες που λήγουν αύριο",
"Upcoming cards" : "Επερχόμενες καρτέλες", "Upcoming cards" : "Επερχόμενες καρτέλες",
"Load more" : "Φόρτωση περισσότερων", "Load more" : "Φόρτωση περισσότερων",
"Welcome to Nextcloud Deck!" : "Καλώς ήρθατε στο Nextcloud Deck!",
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Η καρτέλα \"%s\" του \"%s\" ανατέθηκε σε εσάς από τον %s.", "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} σε εσάς.", "{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 \"%s\" on \"%s\" has reached its due date." : "Η καρτέλα \"%s\" στο \"%s\" έχει λήξει.",
@@ -100,7 +96,6 @@ OC.L10N.register(
"Deck board" : "Πίνακας του Deck", "Deck board" : "Πίνακας του Deck",
"Owned by %1$s" : "Ανήκει στον/στην %1$s", "Owned by %1$s" : "Ανήκει στον/στην %1$s",
"Deck boards, cards and comments" : "Πίνακες, κάρτες και σχόλια Deck", "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",
"Create a new deck card" : "Δημιουργήστε μια νέα κάρτα", "Create a new deck card" : "Δημιουργήστε μια νέα κάρτα",
"Card comments" : "Σχόλια καρτέλας", "Card comments" : "Σχόλια καρτέλας",
"%s on %s" : "%s στο %s", "%s on %s" : "%s στο %s",
@@ -111,20 +106,11 @@ OC.L10N.register(
"Action needed" : "Απαιτείται ενέργεια", "Action needed" : "Απαιτείται ενέργεια",
"Later" : "Αργότερα", "Later" : "Αργότερα",
"copy" : "Αντιγραφή", "copy" : "Αντιγραφή",
"Read more inside" : "Διαβάστε περισσότερα εντός",
"Custom lists - click to rename!" : "Προσαρμοσμένες λίστες - κάντε κλικ για μετονομασία!",
"To Do" : "Προς Ενέργεια", "To Do" : "Προς Ενέργεια",
"In Progress" : "Σε Εξέλιξη",
"Done" : "Ολοκληρώθηκε", "Done" : "Ολοκληρώθηκε",
"1. Open to learn more about boards and cards" : "1. Ανοίξτε για να μάθετε περισσότερα για τους πίνακες και τις κάρτες",
"2. Drag cards left and right, up and down" : "2. Σύρετε κάρτες αριστερά και δεξιά, πάνω και κάτω",
"3. Apply rich formatting and link content" : "3. Εφαρμόστε πλούσια μορφοποίηση και συνδέστε περιεχόμενο",
"4. Share, comment and collaborate!" : "4. Μοιραστείτε, σχολιάστε και συνεργαστείτε!",
"Create your first card!" : "Δημιουργήστε την πρώτη σας κάρτα!",
"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.", "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.",
"Attachments" : "Συνημμένα", "Attachments" : "Συνημμένα",
"File" : "Αρχείο", "File" : "Αρχείο",
"date" : "ημερομηνία",
"Card not found" : "Η καρτέλα δεν βρέθηκε", "Card not found" : "Η καρτέλα δεν βρέθηκε",
"Path is already shared with this card" : "Η διαδρομή κοινοποιείται ήδη σε αυτήν την καρτέλα", "Path is already shared with this card" : "Η διαδρομή κοινοποιείται ήδη σε αυτήν την καρτέλα",
"Invalid date, date format must be YYYY-MM-DD" : "Μη έγκυρη ημερομηνία, η μορφή ημερομηνίας πρέπει να είναι ΕΕΕΕ-ΜΜ-ΗΗ", "Invalid date, date format must be YYYY-MM-DD" : "Μη έγκυρη ημερομηνία, η μορφή ημερομηνίας πρέπει να είναι ΕΕΕΕ-ΜΜ-ΗΗ",
@@ -135,12 +121,10 @@ OC.L10N.register(
"Select the board to link to a project" : "Επιλέξτε πίνακα και συνδέστε τον σε ένα έργο", "Select the board to link to a project" : "Επιλέξτε πίνακα και συνδέστε τον σε ένα έργο",
"Search by board title" : "Αναζήτηση με το όνομα πίνακα", "Search by board title" : "Αναζήτηση με το όνομα πίνακα",
"Select board" : "Επιλογή πίνακα", "Select board" : "Επιλογή πίνακα",
"Move/copy card" : "Μετακίνηση/αντιγραφή κάρτας",
"Select a board" : "Επιλογή ενός πίνακα", "Select a board" : "Επιλογή ενός πίνακα",
"No lists available" : "Δεν υπάρχουν διαθέσιμες λίστες", "No lists available" : "Δεν υπάρχουν διαθέσιμες λίστες",
"Select a list" : "Επιλέξτε μια λίστα", "Select a list" : "Επιλέξτε μια λίστα",
"Move card" : "Μετακίνηση καρτέλας", "Move card" : "Μετακίνηση καρτέλας",
"Copy card" : "Αντίγραφο κάρτας",
"Select the card to link to a project" : "Επιλογή καρτέλας για σύνδεση στο έργο", "Select the card to link to a project" : "Επιλογή καρτέλας για σύνδεση στο έργο",
"Link to card" : "Σύνδεσμος σε καρτέλα", "Link to card" : "Σύνδεσμος σε καρτέλα",
"Select a card" : "Επιλογή μιας καρτέλας", "Select a card" : "Επιλογή μιας καρτέλας",
@@ -228,7 +212,7 @@ OC.L10N.register(
"Select a user to assign to this card…" : "Επιλέξτε έναν χρήστη για να του αναθέσετε αυτή την κάρτα...", "Select a user to assign to this card…" : "Επιλέξτε έναν χρήστη για να του αναθέσετε αυτή την κάρτα...",
"File to share" : "Αρχείο για κοινή χρήση", "File to share" : "Αρχείο για κοινή χρήση",
"Invalid path selected" : "Επιλέχθηκε μη έγκυρη διαδρομή", "Invalid path selected" : "Επιλέχθηκε μη έγκυρη διαδρομή",
"Upload new files" : "Μεταφορτώστε νέα αρχεία", "Upload new files" : "Ανεβάστε νέα αρχεία",
"Share from Files" : "Κοινή χρήση από Αρχεία", "Share from Files" : "Κοινή χρήση από Αρχεία",
"Pending share" : "Κοινή χρήση σε εκκρεμότητα", "Pending share" : "Κοινή χρήση σε εκκρεμότητα",
"Add this attachment" : "Προσθήκη αυτού του συνημμένου", "Add this attachment" : "Προσθήκη αυτού του συνημμένου",
@@ -240,7 +224,6 @@ OC.L10N.register(
"Modified" : "Τροποποιήθηκε", "Modified" : "Τροποποιήθηκε",
"Created" : "Δημιουργήθηκε", "Created" : "Δημιουργήθηκε",
"The title cannot be empty." : "Ο τίτλος δεν μπορεί να είναι κενός.", "The title cannot be empty." : "Ο τίτλος δεν μπορεί να είναι κενός.",
"Cannot close unsaved card!" : "Αδυναμία κλεισίματος της κάρτας που δεν έχει αποθηκευτεί!",
"Open in sidebar view" : "Άνοιγμα σε προβολή πλευρικής στήλης", "Open in sidebar view" : "Άνοιγμα σε προβολή πλευρικής στήλης",
"Open in bigger view" : "Άνοιγμα σε μεγαλύτερη προβολή", "Open in bigger view" : "Άνοιγμα σε μεγαλύτερη προβολή",
"Comments" : "Σχόλια", "Comments" : "Σχόλια",
@@ -255,7 +238,6 @@ OC.L10N.register(
"Reply" : "Απάντηση", "Reply" : "Απάντηση",
"Update" : "Ενημέρωση", "Update" : "Ενημέρωση",
"Write a description …" : "Γράψτε μια περιγραφή…", "Write a description …" : "Γράψτε μια περιγραφή…",
"Could not save description" : "Αδυναμία αποθήκευσης της περιγραφής",
"Description" : "Περιγραφή", "Description" : "Περιγραφή",
"(Unsaved)" : "(Δεν αποθηκεύτηκε)", "(Unsaved)" : "(Δεν αποθηκεύτηκε)",
"(Saving…)" : "(Αποθήκευση...)", "(Saving…)" : "(Αποθήκευση...)",
@@ -290,7 +272,6 @@ OC.L10N.register(
"{count} comments, {unread} unread" : "{count} σχόλια, {unread} μη αναγνωσμένα", "{count} comments, {unread} unread" : "{count} σχόλια, {unread} μη αναγνωσμένα",
"Todo items" : "Στοιχεία todo", "Todo items" : "Στοιχεία todo",
"Edit card title" : "Επεξεργασία τίτλου κάρτας", "Edit card title" : "Επεξεργασία τίτλου κάρτας",
"Open link" : "Άνοιγμα συνδέσμου",
"Card deleted" : "Η καρτέλα διαγράφηκε", "Card deleted" : "Η καρτέλα διαγράφηκε",
"Edit title" : "Επεξεργασία τίτλου", "Edit title" : "Επεξεργασία τίτλου",
"Assign to me" : "Ανάθεση σε εμένα", "Assign to me" : "Ανάθεση σε εμένα",
@@ -334,7 +315,6 @@ OC.L10N.register(
"Limit board creation to some groups" : "Περιορισμός της δημιουργίας πινάκων σε ορισμένες ομάδες", "Limit board creation to some groups" : "Περιορισμός της δημιουργίας πινάκων σε ορισμένες ομάδες",
"Users outside of those groups will not be able to create their own boards, but will still be able to work on boards that have been shared with them." : "Οι χρήστες εκτός αυτών των ομάδων δεν θα μπορούν να δημιουργούν τους δικούς τους πίνακες, αλλά θα μπορούν να εργάζονται σε πίνακες που τους έχουν διαμοιραστεί.", "Users outside of those groups will not be able to create their own boards, but will still be able to work on boards that have been shared with them." : "Οι χρήστες εκτός αυτών των ομάδων δεν θα μπορούν να δημιουργούν τους δικούς τους πίνακες, αλλά θα μπορούν να εργάζονται σε πίνακες που τους έχουν διαμοιραστεί.",
"Cancel edit" : "Ακύρωση επεξεργασίας", "Cancel edit" : "Ακύρωση επεξεργασίας",
"Save board" : "Αποθήκευση πίνακα",
"Board {0} deleted" : "Διαγράφηκε {0} πίνακας ", "Board {0} deleted" : "Διαγράφηκε {0} πίνακας ",
"All cards" : "Όλες οι καρτέλες", "All cards" : "Όλες οι καρτέλες",
"Only assigned cards" : "Μόνο καρτέλες που έχουν ανατεθεί", "Only assigned cards" : "Μόνο καρτέλες που έχουν ανατεθεί",
@@ -342,7 +322,6 @@ OC.L10N.register(
"An error occurred" : "Παρουσιάστηκε σφάλμα", "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}; Αυτό θα διαγράψει όλα τα δεδομένα του πίνακα συμπεριλαμβανομένων και των αρχειοθετημένων καρτών.", "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?" : "Διαγραφή του πίνακα;", "Delete the board?" : "Διαγραφή του πίνακα;",
"Exporting board..." : "Εξαγωγή πίνακα...",
"Board details" : "Λεπτομέριες πίνακα", "Board details" : "Λεπτομέριες πίνακα",
"Edit board" : "Επεξεργασία πίνακα", "Edit board" : "Επεξεργασία πίνακα",
"Clone board" : "Κλώνος πίνακα", "Clone board" : "Κλώνος πίνακα",
@@ -355,25 +334,12 @@ OC.L10N.register(
"Assigned cards" : "Ανατεθειμένες καρτέλες", "Assigned cards" : "Ανατεθειμένες καρτέλες",
"No notifications" : "Δεν υπάρχουν ειδοποιήσεις", "No notifications" : "Δεν υπάρχουν ειδοποιήσεις",
"Delete board" : "Διαγραφή πίνακα", "Delete board" : "Διαγραφή πίνακα",
"Importing board..." : "Εισαγωγή πίνακα...", "Clone cards" : "Κάρτες κλώνου",
"Board imported successfully" : "Ο πίνακας εισήχθη επιτυχώς", "Advanced options" : "Επιλογές για προχωρημένους",
"Import board" : "Εισαγωγή πίνακα", "Clone" : "Κλώνος",
"Clone {boardTitle}" : "Κλωνοποίηση {boardTitle}", "Export as CSV" : "Εξαγωγή σε CSV",
"Clone cards" : "Κλωνοποίηση καρτών",
"Clone assignments" : "Κλωνοποίηση αναθέσεων",
"Clone labels" : "Κλωνοποίηση ετικετών",
"Clone due dates" : "Κλωνοποίηση προθεσμιών",
"Advanced options" : "Προχωρημένες επιλογές",
"Move all cards to the first list" : "Μετακίνηση όλων των καρτών στην πρώτη λίστα",
"Restore archived cards" : "Επαναφορά αρχειοθετημένων καρτών",
"Clone" : "Κλωνοποίηση",
"Export {boardTitle}" : "Εξαγωγή {boardTitle}",
"Export as JSON" : "Εξαγωγή ως JSON",
"Export as CSV" : "Εξαγωγή ως CSV",
"Note: Only the JSON format is supported for importing back into the Deck app." : "Σημείωση: Μόνο η μορφή JSON υποστηρίζεται για εισαγωγή πίσω στην εφαρμογή Deck.",
"Export" : "Εξαγωγή", "Export" : "Εξαγωγή",
"Loading filtered view" : "Φόρτωση εμφάνισης με βάση το φίλτρο", "Loading filtered view" : "Φόρτωση εμφάνισης με βάση το φίλτρο",
"Search for {searchQuery} in other boards" : "Αναζήτηση για {searchQuery} σε άλλους πίνακες",
"Search for {searchQuery} in all boards" : "Αναζήτηση για {searchQuery} σε όλους τους πίνακες", "Search for {searchQuery} in all boards" : "Αναζήτηση για {searchQuery} σε όλους τους πίνακες",
"No results found" : "Δεν βρέθηκαν αποτελέσματα", "No results found" : "Δεν βρέθηκαν αποτελέσματα",
"Deck board {name}\n* Last modified on {lastMod}" : "Πίνακας Deck {name}\n* Τελευταία τροποποίηση στις {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Πίνακας Deck {name}\n* Τελευταία τροποποίηση στις {lastMod}",
@@ -402,7 +368,6 @@ OC.L10N.register(
"Something went wrong" : "Κάτι πήγε στραβά", "Something went wrong" : "Κάτι πήγε στραβά",
"Failed to upload {name}" : "Αποτυχία μεταφόρτωσης {name}", "Failed to upload {name}" : "Αποτυχία μεταφόρτωσης {name}",
"Maximum file size of {size} exceeded" : "Υπέρβαση επιτρεπόμενου μεγέθους αρχείου {size}", "Maximum file size of {size} exceeded" : "Υπέρβαση επιτρεπόμενου μεγέθους αρχείου {size}",
"Assigned users" : "Ανατεθειμένοι χρήστες",
"Due date" : "Προθεσμία", "Due date" : "Προθεσμία",
"Error creating the share" : "Σφάλμα κατά τη δημιουργία της κοινοποίησης", "Error creating the share" : "Σφάλμα κατά τη δημιουργία της κοινοποίησης",
"Share with a Deck card" : "Μοιραστείτε με μια καρτέλα Deck", "Share with a Deck card" : "Μοιραστείτε με μια καρτέλα Deck",

View File

@@ -79,14 +79,10 @@
"Could not write file to disk" : "Αδυναμία εγγραφής αρχείου στον δίσκο", "Could not write file to disk" : "Αδυναμία εγγραφής αρχείου στον δίσκο",
"A PHP extension stopped the file upload" : "Ένα πρόσθετο PHP διέκοψε την μεταφόρτωση του αρχείου", "A PHP extension stopped the file upload" : "Ένα πρόσθετο PHP διέκοψε την μεταφόρτωση του αρχείου",
"No file uploaded or file size exceeds maximum of %s" : "Δεν μεταφορτώθηκε αρχείο ή το μέγεθος αρχείου υπερβαίνει το μέγιστο %s", "No file uploaded or file size exceeds maximum of %s" : "Δεν μεταφορτώθηκε αρχείο ή το μέγεθος αρχείου υπερβαίνει το μέγιστο %s",
"Invalid file type. Only JSON files are allowed." : "Μη έγκυρος τύπος αρχείου. Επιτρέπονται μόνο αρχεία JSON.",
"Invalid JSON data" : "Μη έγκυρα δεδομένα JSON",
"Failed to import board" : "Αποτυχία εισαγωγής πίνακα",
"Cards due today" : "Κάρτες που λήγουν σήμερα", "Cards due today" : "Κάρτες που λήγουν σήμερα",
"Cards due tomorrow" : "Κάρτες που λήγουν αύριο", "Cards due tomorrow" : "Κάρτες που λήγουν αύριο",
"Upcoming cards" : "Επερχόμενες καρτέλες", "Upcoming cards" : "Επερχόμενες καρτέλες",
"Load more" : "Φόρτωση περισσότερων", "Load more" : "Φόρτωση περισσότερων",
"Welcome to Nextcloud Deck!" : "Καλώς ήρθατε στο Nextcloud Deck!",
"The card \"%s\" on \"%s\" has been assigned to you by %s." : "Η καρτέλα \"%s\" του \"%s\" ανατέθηκε σε εσάς από τον %s.", "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} σε εσάς.", "{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 \"%s\" on \"%s\" has reached its due date." : "Η καρτέλα \"%s\" στο \"%s\" έχει λήξει.",
@@ -98,7 +94,6 @@
"Deck board" : "Πίνακας του Deck", "Deck board" : "Πίνακας του Deck",
"Owned by %1$s" : "Ανήκει στον/στην %1$s", "Owned by %1$s" : "Ανήκει στον/στην %1$s",
"Deck boards, cards and comments" : "Πίνακες, κάρτες και σχόλια Deck", "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",
"Create a new deck card" : "Δημιουργήστε μια νέα κάρτα", "Create a new deck card" : "Δημιουργήστε μια νέα κάρτα",
"Card comments" : "Σχόλια καρτέλας", "Card comments" : "Σχόλια καρτέλας",
"%s on %s" : "%s στο %s", "%s on %s" : "%s στο %s",
@@ -109,20 +104,11 @@
"Action needed" : "Απαιτείται ενέργεια", "Action needed" : "Απαιτείται ενέργεια",
"Later" : "Αργότερα", "Later" : "Αργότερα",
"copy" : "Αντιγραφή", "copy" : "Αντιγραφή",
"Read more inside" : "Διαβάστε περισσότερα εντός",
"Custom lists - click to rename!" : "Προσαρμοσμένες λίστες - κάντε κλικ για μετονομασία!",
"To Do" : "Προς Ενέργεια", "To Do" : "Προς Ενέργεια",
"In Progress" : "Σε Εξέλιξη",
"Done" : "Ολοκληρώθηκε", "Done" : "Ολοκληρώθηκε",
"1. Open to learn more about boards and cards" : "1. Ανοίξτε για να μάθετε περισσότερα για τους πίνακες και τις κάρτες",
"2. Drag cards left and right, up and down" : "2. Σύρετε κάρτες αριστερά και δεξιά, πάνω και κάτω",
"3. Apply rich formatting and link content" : "3. Εφαρμόστε πλούσια μορφοποίηση και συνδέστε περιεχόμενο",
"4. Share, comment and collaborate!" : "4. Μοιραστείτε, σχολιάστε και συνεργαστείτε!",
"Create your first card!" : "Δημιουργήστε την πρώτη σας κάρτα!",
"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.", "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.",
"Attachments" : "Συνημμένα", "Attachments" : "Συνημμένα",
"File" : "Αρχείο", "File" : "Αρχείο",
"date" : "ημερομηνία",
"Card not found" : "Η καρτέλα δεν βρέθηκε", "Card not found" : "Η καρτέλα δεν βρέθηκε",
"Path is already shared with this card" : "Η διαδρομή κοινοποιείται ήδη σε αυτήν την καρτέλα", "Path is already shared with this card" : "Η διαδρομή κοινοποιείται ήδη σε αυτήν την καρτέλα",
"Invalid date, date format must be YYYY-MM-DD" : "Μη έγκυρη ημερομηνία, η μορφή ημερομηνίας πρέπει να είναι ΕΕΕΕ-ΜΜ-ΗΗ", "Invalid date, date format must be YYYY-MM-DD" : "Μη έγκυρη ημερομηνία, η μορφή ημερομηνίας πρέπει να είναι ΕΕΕΕ-ΜΜ-ΗΗ",
@@ -133,12 +119,10 @@
"Select the board to link to a project" : "Επιλέξτε πίνακα και συνδέστε τον σε ένα έργο", "Select the board to link to a project" : "Επιλέξτε πίνακα και συνδέστε τον σε ένα έργο",
"Search by board title" : "Αναζήτηση με το όνομα πίνακα", "Search by board title" : "Αναζήτηση με το όνομα πίνακα",
"Select board" : "Επιλογή πίνακα", "Select board" : "Επιλογή πίνακα",
"Move/copy card" : "Μετακίνηση/αντιγραφή κάρτας",
"Select a board" : "Επιλογή ενός πίνακα", "Select a board" : "Επιλογή ενός πίνακα",
"No lists available" : "Δεν υπάρχουν διαθέσιμες λίστες", "No lists available" : "Δεν υπάρχουν διαθέσιμες λίστες",
"Select a list" : "Επιλέξτε μια λίστα", "Select a list" : "Επιλέξτε μια λίστα",
"Move card" : "Μετακίνηση καρτέλας", "Move card" : "Μετακίνηση καρτέλας",
"Copy card" : "Αντίγραφο κάρτας",
"Select the card to link to a project" : "Επιλογή καρτέλας για σύνδεση στο έργο", "Select the card to link to a project" : "Επιλογή καρτέλας για σύνδεση στο έργο",
"Link to card" : "Σύνδεσμος σε καρτέλα", "Link to card" : "Σύνδεσμος σε καρτέλα",
"Select a card" : "Επιλογή μιας καρτέλας", "Select a card" : "Επιλογή μιας καρτέλας",
@@ -226,7 +210,7 @@
"Select a user to assign to this card…" : "Επιλέξτε έναν χρήστη για να του αναθέσετε αυτή την κάρτα...", "Select a user to assign to this card…" : "Επιλέξτε έναν χρήστη για να του αναθέσετε αυτή την κάρτα...",
"File to share" : "Αρχείο για κοινή χρήση", "File to share" : "Αρχείο για κοινή χρήση",
"Invalid path selected" : "Επιλέχθηκε μη έγκυρη διαδρομή", "Invalid path selected" : "Επιλέχθηκε μη έγκυρη διαδρομή",
"Upload new files" : "Μεταφορτώστε νέα αρχεία", "Upload new files" : "Ανεβάστε νέα αρχεία",
"Share from Files" : "Κοινή χρήση από Αρχεία", "Share from Files" : "Κοινή χρήση από Αρχεία",
"Pending share" : "Κοινή χρήση σε εκκρεμότητα", "Pending share" : "Κοινή χρήση σε εκκρεμότητα",
"Add this attachment" : "Προσθήκη αυτού του συνημμένου", "Add this attachment" : "Προσθήκη αυτού του συνημμένου",
@@ -238,7 +222,6 @@
"Modified" : "Τροποποιήθηκε", "Modified" : "Τροποποιήθηκε",
"Created" : "Δημιουργήθηκε", "Created" : "Δημιουργήθηκε",
"The title cannot be empty." : "Ο τίτλος δεν μπορεί να είναι κενός.", "The title cannot be empty." : "Ο τίτλος δεν μπορεί να είναι κενός.",
"Cannot close unsaved card!" : "Αδυναμία κλεισίματος της κάρτας που δεν έχει αποθηκευτεί!",
"Open in sidebar view" : "Άνοιγμα σε προβολή πλευρικής στήλης", "Open in sidebar view" : "Άνοιγμα σε προβολή πλευρικής στήλης",
"Open in bigger view" : "Άνοιγμα σε μεγαλύτερη προβολή", "Open in bigger view" : "Άνοιγμα σε μεγαλύτερη προβολή",
"Comments" : "Σχόλια", "Comments" : "Σχόλια",
@@ -253,7 +236,6 @@
"Reply" : "Απάντηση", "Reply" : "Απάντηση",
"Update" : "Ενημέρωση", "Update" : "Ενημέρωση",
"Write a description …" : "Γράψτε μια περιγραφή…", "Write a description …" : "Γράψτε μια περιγραφή…",
"Could not save description" : "Αδυναμία αποθήκευσης της περιγραφής",
"Description" : "Περιγραφή", "Description" : "Περιγραφή",
"(Unsaved)" : "(Δεν αποθηκεύτηκε)", "(Unsaved)" : "(Δεν αποθηκεύτηκε)",
"(Saving…)" : "(Αποθήκευση...)", "(Saving…)" : "(Αποθήκευση...)",
@@ -288,7 +270,6 @@
"{count} comments, {unread} unread" : "{count} σχόλια, {unread} μη αναγνωσμένα", "{count} comments, {unread} unread" : "{count} σχόλια, {unread} μη αναγνωσμένα",
"Todo items" : "Στοιχεία todo", "Todo items" : "Στοιχεία todo",
"Edit card title" : "Επεξεργασία τίτλου κάρτας", "Edit card title" : "Επεξεργασία τίτλου κάρτας",
"Open link" : "Άνοιγμα συνδέσμου",
"Card deleted" : "Η καρτέλα διαγράφηκε", "Card deleted" : "Η καρτέλα διαγράφηκε",
"Edit title" : "Επεξεργασία τίτλου", "Edit title" : "Επεξεργασία τίτλου",
"Assign to me" : "Ανάθεση σε εμένα", "Assign to me" : "Ανάθεση σε εμένα",
@@ -332,7 +313,6 @@
"Limit board creation to some groups" : "Περιορισμός της δημιουργίας πινάκων σε ορισμένες ομάδες", "Limit board creation to some groups" : "Περιορισμός της δημιουργίας πινάκων σε ορισμένες ομάδες",
"Users outside of those groups will not be able to create their own boards, but will still be able to work on boards that have been shared with them." : "Οι χρήστες εκτός αυτών των ομάδων δεν θα μπορούν να δημιουργούν τους δικούς τους πίνακες, αλλά θα μπορούν να εργάζονται σε πίνακες που τους έχουν διαμοιραστεί.", "Users outside of those groups will not be able to create their own boards, but will still be able to work on boards that have been shared with them." : "Οι χρήστες εκτός αυτών των ομάδων δεν θα μπορούν να δημιουργούν τους δικούς τους πίνακες, αλλά θα μπορούν να εργάζονται σε πίνακες που τους έχουν διαμοιραστεί.",
"Cancel edit" : "Ακύρωση επεξεργασίας", "Cancel edit" : "Ακύρωση επεξεργασίας",
"Save board" : "Αποθήκευση πίνακα",
"Board {0} deleted" : "Διαγράφηκε {0} πίνακας ", "Board {0} deleted" : "Διαγράφηκε {0} πίνακας ",
"All cards" : "Όλες οι καρτέλες", "All cards" : "Όλες οι καρτέλες",
"Only assigned cards" : "Μόνο καρτέλες που έχουν ανατεθεί", "Only assigned cards" : "Μόνο καρτέλες που έχουν ανατεθεί",
@@ -340,7 +320,6 @@
"An error occurred" : "Παρουσιάστηκε σφάλμα", "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}; Αυτό θα διαγράψει όλα τα δεδομένα του πίνακα συμπεριλαμβανομένων και των αρχειοθετημένων καρτών.", "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?" : "Διαγραφή του πίνακα;", "Delete the board?" : "Διαγραφή του πίνακα;",
"Exporting board..." : "Εξαγωγή πίνακα...",
"Board details" : "Λεπτομέριες πίνακα", "Board details" : "Λεπτομέριες πίνακα",
"Edit board" : "Επεξεργασία πίνακα", "Edit board" : "Επεξεργασία πίνακα",
"Clone board" : "Κλώνος πίνακα", "Clone board" : "Κλώνος πίνακα",
@@ -353,25 +332,12 @@
"Assigned cards" : "Ανατεθειμένες καρτέλες", "Assigned cards" : "Ανατεθειμένες καρτέλες",
"No notifications" : "Δεν υπάρχουν ειδοποιήσεις", "No notifications" : "Δεν υπάρχουν ειδοποιήσεις",
"Delete board" : "Διαγραφή πίνακα", "Delete board" : "Διαγραφή πίνακα",
"Importing board..." : "Εισαγωγή πίνακα...", "Clone cards" : "Κάρτες κλώνου",
"Board imported successfully" : "Ο πίνακας εισήχθη επιτυχώς", "Advanced options" : "Επιλογές για προχωρημένους",
"Import board" : "Εισαγωγή πίνακα", "Clone" : "Κλώνος",
"Clone {boardTitle}" : "Κλωνοποίηση {boardTitle}", "Export as CSV" : "Εξαγωγή σε CSV",
"Clone cards" : "Κλωνοποίηση καρτών",
"Clone assignments" : "Κλωνοποίηση αναθέσεων",
"Clone labels" : "Κλωνοποίηση ετικετών",
"Clone due dates" : "Κλωνοποίηση προθεσμιών",
"Advanced options" : "Προχωρημένες επιλογές",
"Move all cards to the first list" : "Μετακίνηση όλων των καρτών στην πρώτη λίστα",
"Restore archived cards" : "Επαναφορά αρχειοθετημένων καρτών",
"Clone" : "Κλωνοποίηση",
"Export {boardTitle}" : "Εξαγωγή {boardTitle}",
"Export as JSON" : "Εξαγωγή ως JSON",
"Export as CSV" : "Εξαγωγή ως CSV",
"Note: Only the JSON format is supported for importing back into the Deck app." : "Σημείωση: Μόνο η μορφή JSON υποστηρίζεται για εισαγωγή πίσω στην εφαρμογή Deck.",
"Export" : "Εξαγωγή", "Export" : "Εξαγωγή",
"Loading filtered view" : "Φόρτωση εμφάνισης με βάση το φίλτρο", "Loading filtered view" : "Φόρτωση εμφάνισης με βάση το φίλτρο",
"Search for {searchQuery} in other boards" : "Αναζήτηση για {searchQuery} σε άλλους πίνακες",
"Search for {searchQuery} in all boards" : "Αναζήτηση για {searchQuery} σε όλους τους πίνακες", "Search for {searchQuery} in all boards" : "Αναζήτηση για {searchQuery} σε όλους τους πίνακες",
"No results found" : "Δεν βρέθηκαν αποτελέσματα", "No results found" : "Δεν βρέθηκαν αποτελέσματα",
"Deck board {name}\n* Last modified on {lastMod}" : "Πίνακας Deck {name}\n* Τελευταία τροποποίηση στις {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Πίνακας Deck {name}\n* Τελευταία τροποποίηση στις {lastMod}",
@@ -400,7 +366,6 @@
"Something went wrong" : "Κάτι πήγε στραβά", "Something went wrong" : "Κάτι πήγε στραβά",
"Failed to upload {name}" : "Αποτυχία μεταφόρτωσης {name}", "Failed to upload {name}" : "Αποτυχία μεταφόρτωσης {name}",
"Maximum file size of {size} exceeded" : "Υπέρβαση επιτρεπόμενου μεγέθους αρχείου {size}", "Maximum file size of {size} exceeded" : "Υπέρβαση επιτρεπόμενου μεγέθους αρχείου {size}",
"Assigned users" : "Ανατεθειμένοι χρήστες",
"Due date" : "Προθεσμία", "Due date" : "Προθεσμία",
"Error creating the share" : "Σφάλμα κατά τη δημιουργία της κοινοποίησης", "Error creating the share" : "Σφάλμα κατά τη δημιουργία της κοινοποίησης",
"Share with a Deck card" : "Μοιραστείτε με μια καρτέλα Deck", "Share with a Deck card" : "Μοιραστείτε με μια καρτέλα Deck",

View File

@@ -357,7 +357,7 @@ OC.L10N.register(
"Delete board" : "Supprimer le tableau", "Delete board" : "Supprimer le tableau",
"Importing board..." : "Importation du tableau...", "Importing board..." : "Importation du tableau...",
"Board imported successfully" : "Carte importée avec succès", "Board imported successfully" : "Carte importée avec succès",
"Import board" : "Importer un tableau", "Import board" : "Tableau d'importation",
"Clone {boardTitle}" : "Cloner {boardTitle}", "Clone {boardTitle}" : "Cloner {boardTitle}",
"Clone cards" : "Dupliquer les cartes", "Clone cards" : "Dupliquer les cartes",
"Clone assignments" : "Cloner les affectations", "Clone assignments" : "Cloner les affectations",
@@ -373,7 +373,6 @@ OC.L10N.register(
"Note: Only the JSON format is supported for importing back into the Deck app." : "Remarque : seul le format JSON est pris en charge pour la réimportation dans l'application Deck.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Remarque : seul le format JSON est pris en charge pour la réimportation dans l'application Deck.",
"Export" : "Exporter", "Export" : "Exporter",
"Loading filtered view" : "Chargement de la vue filtrée", "Loading filtered view" : "Chargement de la vue filtrée",
"Search for {searchQuery} in other boards" : "Rechercher {searchQuery} dans les autres tableaux",
"Search for {searchQuery} in all boards" : "Recherche de {searchQuery} dans tous les tableaux", "Search for {searchQuery} in all boards" : "Recherche de {searchQuery} dans tous les tableaux",
"No results found" : "Aucun résultat", "No results found" : "Aucun résultat",
"Deck board {name}\n* Last modified on {lastMod}" : "Tableau Deck {name}\n* Dernière modification le {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Tableau Deck {name}\n* Dernière modification le {lastMod}",

View File

@@ -355,7 +355,7 @@
"Delete board" : "Supprimer le tableau", "Delete board" : "Supprimer le tableau",
"Importing board..." : "Importation du tableau...", "Importing board..." : "Importation du tableau...",
"Board imported successfully" : "Carte importée avec succès", "Board imported successfully" : "Carte importée avec succès",
"Import board" : "Importer un tableau", "Import board" : "Tableau d'importation",
"Clone {boardTitle}" : "Cloner {boardTitle}", "Clone {boardTitle}" : "Cloner {boardTitle}",
"Clone cards" : "Dupliquer les cartes", "Clone cards" : "Dupliquer les cartes",
"Clone assignments" : "Cloner les affectations", "Clone assignments" : "Cloner les affectations",
@@ -371,7 +371,6 @@
"Note: Only the JSON format is supported for importing back into the Deck app." : "Remarque : seul le format JSON est pris en charge pour la réimportation dans l'application Deck.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Remarque : seul le format JSON est pris en charge pour la réimportation dans l'application Deck.",
"Export" : "Exporter", "Export" : "Exporter",
"Loading filtered view" : "Chargement de la vue filtrée", "Loading filtered view" : "Chargement de la vue filtrée",
"Search for {searchQuery} in other boards" : "Rechercher {searchQuery} dans les autres tableaux",
"Search for {searchQuery} in all boards" : "Recherche de {searchQuery} dans tous les tableaux", "Search for {searchQuery} in all boards" : "Recherche de {searchQuery} dans tous les tableaux",
"No results found" : "Aucun résultat", "No results found" : "Aucun résultat",
"Deck board {name}\n* Last modified on {lastMod}" : "Tableau Deck {name}\n* Dernière modification le {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Tableau Deck {name}\n* Dernière modification le {lastMod}",

View File

@@ -129,7 +129,7 @@ OC.L10N.register(
"Path is already shared with this card" : "A ruta xa está compartida con esta tarxeta", "Path is already shared with this card" : "A ruta xa está compartida con esta tarxeta",
"Invalid date, date format must be YYYY-MM-DD" : "Data incorrecta, o formato da data debe ser AAAA-MM-DD", "Invalid date, date format must be YYYY-MM-DD" : "Data incorrecta, o formato da data debe ser AAAA-MM-DD",
"Personal planning and team project organization" : "Planificación persoal e organización de proxectos de equipo", "Personal planning and team project organization" : "Planificación persoal e organización de proxectos de equipo",
"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" : "Gabeta é unha ferramenta de organización de estilo kanban dirixida a planificación persoal e organización de proxectos para equipos integrados con Nextcloud. \n\n\n-- 📥 Engada as súas tarefas ás tarxetas e fagas ordenadas\n- 📄 Escriba notas adicionais en Markdown\n- 🔖 Asigne etiquetas para unha mellor organización\n- 👥 Comparta co seu equipo, amigos ou a súa familia\n- 📎 Anexe ficheiros e integreos na súa descrición de Markdown\n- 💬 Debata co seu equipo usando os comentarios\n- ⚡ Faga un seguimento dos cambios no fluxo de actividade\n- 🚀 Teña o seu proxecto organizado", "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" : "Gabeta é unha ferramenta de organización de estilo kanban dirixida a planificación persoal e organización de proxectos para equipos integrados con Nextcloud. \n\n\n 📥 Engada as súas tarefas ás tarxetas e fagas ordenadas\n 📄 Escriba notas adicionais en Markdown\n 🔖 Asigne etiquetas para unha mellor organización\n 👥 Comparta co seu equipo, amigos ou a súa familia\n 📎 Anexe ficheiros e integreos na súa descrición de Markdown\n 💬 Debata co seu equipo usando os comentarios\n ⚡ Faga un seguimento dos cambios no fluxo de actividade\n 🚀 Teña o seu proxecto organizado",
"Add board" : "Engadir taboleiro", "Add board" : "Engadir taboleiro",
"Card details" : "Detalles da tarxeta", "Card details" : "Detalles da tarxeta",
"Select the board to link to a project" : "Seleccione o taboleiro para ligar a un proxecto", "Select the board to link to a project" : "Seleccione o taboleiro para ligar a un proxecto",

View File

@@ -127,7 +127,7 @@
"Path is already shared with this card" : "A ruta xa está compartida con esta tarxeta", "Path is already shared with this card" : "A ruta xa está compartida con esta tarxeta",
"Invalid date, date format must be YYYY-MM-DD" : "Data incorrecta, o formato da data debe ser AAAA-MM-DD", "Invalid date, date format must be YYYY-MM-DD" : "Data incorrecta, o formato da data debe ser AAAA-MM-DD",
"Personal planning and team project organization" : "Planificación persoal e organización de proxectos de equipo", "Personal planning and team project organization" : "Planificación persoal e organización de proxectos de equipo",
"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" : "Gabeta é unha ferramenta de organización de estilo kanban dirixida a planificación persoal e organización de proxectos para equipos integrados con Nextcloud. \n\n\n-- 📥 Engada as súas tarefas ás tarxetas e fagas ordenadas\n- 📄 Escriba notas adicionais en Markdown\n- 🔖 Asigne etiquetas para unha mellor organización\n- 👥 Comparta co seu equipo, amigos ou a súa familia\n- 📎 Anexe ficheiros e integreos na súa descrición de Markdown\n- 💬 Debata co seu equipo usando os comentarios\n- ⚡ Faga un seguimento dos cambios no fluxo de actividade\n- 🚀 Teña o seu proxecto organizado", "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" : "Gabeta é unha ferramenta de organización de estilo kanban dirixida a planificación persoal e organización de proxectos para equipos integrados con Nextcloud. \n\n\n 📥 Engada as súas tarefas ás tarxetas e fagas ordenadas\n 📄 Escriba notas adicionais en Markdown\n 🔖 Asigne etiquetas para unha mellor organización\n 👥 Comparta co seu equipo, amigos ou a súa familia\n 📎 Anexe ficheiros e integreos na súa descrición de Markdown\n 💬 Debata co seu equipo usando os comentarios\n ⚡ Faga un seguimento dos cambios no fluxo de actividade\n 🚀 Teña o seu proxecto organizado",
"Add board" : "Engadir taboleiro", "Add board" : "Engadir taboleiro",
"Card details" : "Detalles da tarxeta", "Card details" : "Detalles da tarxeta",
"Select the board to link to a project" : "Seleccione o taboleiro para ligar a un proxecto", "Select the board to link to a project" : "Seleccione o taboleiro para ligar a un proxecto",

View File

@@ -164,13 +164,12 @@ OC.L10N.register(
"Archive all cards in this list" : "Архивирај ги сите картици во листата", "Archive all cards in this list" : "Архивирај ги сите картици во листата",
"Add a new card" : "Додади нова картица", "Add a new card" : "Додади нова картица",
"Card name" : "Име на картицата", "Card name" : "Име на картицата",
"title and color value must be provided" : "Мора да се внесе наслов и боја", "title and color value must be provided" : "наслов и боја мора да се приложи",
"Edit" : "Уреди", "Edit" : "Уреди",
"Add a new tag" : "Додади нова ознака", "Add a new tag" : "Додади нова ознака",
"Board name" : "Име на табла", "Board name" : "Име на табла",
"Members" : "Членови", "Members" : "Членови",
"Assign a user to this card…" : "Додели корисник на оваа картица...", "Assign a user to this card…" : "Додели корисник на оваа картица...",
"Select a user to assign to this card…" : "Избери на кого да се додели оваа картица…",
"File to share" : "Датотека за споделување", "File to share" : "Датотека за споделување",
"Invalid path selected" : "Избрана невалидна патека", "Invalid path selected" : "Избрана невалидна патека",
"Upload new files" : "Прикачи нови датотеки", "Upload new files" : "Прикачи нови датотеки",
@@ -206,16 +205,12 @@ OC.L10N.register(
"Select Date" : "Избери датум", "Select Date" : "Избери датум",
"Later today {timeLocale}" : "Денес покасно {timeLocale}", "Later today {timeLocale}" : "Денес покасно {timeLocale}",
"Tomorrow {timeLocale}" : "Утре {timeLocale}", "Tomorrow {timeLocale}" : "Утре {timeLocale}",
"This weekend {timeLocale}" : "Овој викенд {timeLocale}",
"Set due date for this weekend" : "Постави рок за овој викенд",
"Assign a due date to this card…" : "Додели рок за оваа картица…",
"Set a due date" : "Постави краен рок", "Set a due date" : "Постави краен рок",
"Remove due date" : "Отстрани краен рок", "Remove due date" : "Отстрани краен рок",
"Mark as done" : "Означи како готово", "Mark as done" : "Означи како готово",
"Unarchive card" : "Врати картица од архива", "Unarchive card" : "Врати картица од архива",
"Archive card" : "Архивирај картица", "Archive card" : "Архивирај картица",
"Assign a tag to this card…" : "Додади ознака на оваа картица...", "Assign a tag to this card…" : "Додади ознака на оваа картица...",
"Select or create a tag…" : "Избери или креирај ознака...",
"(group)" : "(group)", "(group)" : "(group)",
"Card deleted" : "Картицата е избришана", "Card deleted" : "Картицата е избришана",
"Edit title" : "Удери наслов", "Edit title" : "Удери наслов",

View File

@@ -162,13 +162,12 @@
"Archive all cards in this list" : "Архивирај ги сите картици во листата", "Archive all cards in this list" : "Архивирај ги сите картици во листата",
"Add a new card" : "Додади нова картица", "Add a new card" : "Додади нова картица",
"Card name" : "Име на картицата", "Card name" : "Име на картицата",
"title and color value must be provided" : "Мора да се внесе наслов и боја", "title and color value must be provided" : "наслов и боја мора да се приложи",
"Edit" : "Уреди", "Edit" : "Уреди",
"Add a new tag" : "Додади нова ознака", "Add a new tag" : "Додади нова ознака",
"Board name" : "Име на табла", "Board name" : "Име на табла",
"Members" : "Членови", "Members" : "Членови",
"Assign a user to this card…" : "Додели корисник на оваа картица...", "Assign a user to this card…" : "Додели корисник на оваа картица...",
"Select a user to assign to this card…" : "Избери на кого да се додели оваа картица…",
"File to share" : "Датотека за споделување", "File to share" : "Датотека за споделување",
"Invalid path selected" : "Избрана невалидна патека", "Invalid path selected" : "Избрана невалидна патека",
"Upload new files" : "Прикачи нови датотеки", "Upload new files" : "Прикачи нови датотеки",
@@ -204,16 +203,12 @@
"Select Date" : "Избери датум", "Select Date" : "Избери датум",
"Later today {timeLocale}" : "Денес покасно {timeLocale}", "Later today {timeLocale}" : "Денес покасно {timeLocale}",
"Tomorrow {timeLocale}" : "Утре {timeLocale}", "Tomorrow {timeLocale}" : "Утре {timeLocale}",
"This weekend {timeLocale}" : "Овој викенд {timeLocale}",
"Set due date for this weekend" : "Постави рок за овој викенд",
"Assign a due date to this card…" : "Додели рок за оваа картица…",
"Set a due date" : "Постави краен рок", "Set a due date" : "Постави краен рок",
"Remove due date" : "Отстрани краен рок", "Remove due date" : "Отстрани краен рок",
"Mark as done" : "Означи како готово", "Mark as done" : "Означи како готово",
"Unarchive card" : "Врати картица од архива", "Unarchive card" : "Врати картица од архива",
"Archive card" : "Архивирај картица", "Archive card" : "Архивирај картица",
"Assign a tag to this card…" : "Додади ознака на оваа картица...", "Assign a tag to this card…" : "Додади ознака на оваа картица...",
"Select or create a tag…" : "Избери или креирај ознака...",
"(group)" : "(group)", "(group)" : "(group)",
"Card deleted" : "Картицата е избришана", "Card deleted" : "Картицата е избришана",
"Edit title" : "Удери наслов", "Edit title" : "Удери наслов",

View File

@@ -373,7 +373,6 @@ OC.L10N.register(
"Note: Only the JSON format is supported for importing back into the Deck app." : "Uwaga: tylko format JSON jest obsługiwany przy imporcie z powrotem do aplikacji Deck.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Uwaga: tylko format JSON jest obsługiwany przy imporcie z powrotem do aplikacji Deck.",
"Export" : "Eksportuj", "Export" : "Eksportuj",
"Loading filtered view" : "Wczytywanie przefiltrowanego widoku", "Loading filtered view" : "Wczytywanie przefiltrowanego widoku",
"Search for {searchQuery} in other boards" : "Szukaj {searchQuery} na innych tablicach",
"Search for {searchQuery} in all boards" : "Wyszukaj dla {searchQuery} na wszystkich tablicach", "Search for {searchQuery} in all boards" : "Wyszukaj dla {searchQuery} na wszystkich tablicach",
"No results found" : "Nie znaleziono wyników", "No results found" : "Nie znaleziono wyników",
"Deck board {name}\n* Last modified on {lastMod}" : "Tablica {name}\n* Ostatnia modyfikacja w dniu {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Tablica {name}\n* Ostatnia modyfikacja w dniu {lastMod}",

View File

@@ -371,7 +371,6 @@
"Note: Only the JSON format is supported for importing back into the Deck app." : "Uwaga: tylko format JSON jest obsługiwany przy imporcie z powrotem do aplikacji Deck.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Uwaga: tylko format JSON jest obsługiwany przy imporcie z powrotem do aplikacji Deck.",
"Export" : "Eksportuj", "Export" : "Eksportuj",
"Loading filtered view" : "Wczytywanie przefiltrowanego widoku", "Loading filtered view" : "Wczytywanie przefiltrowanego widoku",
"Search for {searchQuery} in other boards" : "Szukaj {searchQuery} na innych tablicach",
"Search for {searchQuery} in all boards" : "Wyszukaj dla {searchQuery} na wszystkich tablicach", "Search for {searchQuery} in all boards" : "Wyszukaj dla {searchQuery} na wszystkich tablicach",
"No results found" : "Nie znaleziono wyników", "No results found" : "Nie znaleziono wyników",
"Deck board {name}\n* Last modified on {lastMod}" : "Tablica {name}\n* Ostatnia modyfikacja w dniu {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Tablica {name}\n* Ostatnia modyfikacja w dniu {lastMod}",

View File

@@ -373,7 +373,6 @@ OC.L10N.register(
"Note: Only the JSON format is supported for importing back into the Deck app." : "Observera: Endast JSON-formatet stöds för import tillbaka till Deck-appen.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Observera: Endast JSON-formatet stöds för import tillbaka till Deck-appen.",
"Export" : "Exportera", "Export" : "Exportera",
"Loading filtered view" : "Laddar filtrerad vy", "Loading filtered view" : "Laddar filtrerad vy",
"Search for {searchQuery} in other boards" : "Sök efter {searchQuery} i andra tavlor",
"Search for {searchQuery} in all boards" : "Sök efter {searchQuery} i alla tavlor", "Search for {searchQuery} in all boards" : "Sök efter {searchQuery} i alla tavlor",
"No results found" : "Inga resultat funna", "No results found" : "Inga resultat funna",
"Deck board {name}\n* Last modified on {lastMod}" : "Deck tavla {name}\n* Senast ändrad den {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Deck tavla {name}\n* Senast ändrad den {lastMod}",

View File

@@ -371,7 +371,6 @@
"Note: Only the JSON format is supported for importing back into the Deck app." : "Observera: Endast JSON-formatet stöds för import tillbaka till Deck-appen.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Observera: Endast JSON-formatet stöds för import tillbaka till Deck-appen.",
"Export" : "Exportera", "Export" : "Exportera",
"Loading filtered view" : "Laddar filtrerad vy", "Loading filtered view" : "Laddar filtrerad vy",
"Search for {searchQuery} in other boards" : "Sök efter {searchQuery} i andra tavlor",
"Search for {searchQuery} in all boards" : "Sök efter {searchQuery} i alla tavlor", "Search for {searchQuery} in all boards" : "Sök efter {searchQuery} i alla tavlor",
"No results found" : "Inga resultat funna", "No results found" : "Inga resultat funna",
"Deck board {name}\n* Last modified on {lastMod}" : "Deck tavla {name}\n* Senast ändrad den {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Deck tavla {name}\n* Senast ändrad den {lastMod}",

View File

@@ -373,8 +373,7 @@ OC.L10N.register(
"Note: Only the JSON format is supported for importing back into the Deck app." : "Not: Yeniden Tahta uygulaması içine aktarmak için yalnızca JSON biçimi desteklenir.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Not: Yeniden Tahta uygulaması içine aktarmak için yalnızca JSON biçimi desteklenir.",
"Export" : "Dışa aktar", "Export" : "Dışa aktar",
"Loading filtered view" : "Süzülmüş görünüm yükleniyor", "Loading filtered view" : "Süzülmüş görünüm yükleniyor",
"Search for {searchQuery} in other boards" : "Diğer panolarda {searchQuery} ara", "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} ara",
"No results found" : "Herhangi bir sonuç bulunamadı", "No results found" : "Herhangi bir sonuç bulunamadı",
"Deck board {name}\n* Last modified on {lastMod}" : "{name} tahta panosu\n* Son değişiklik: {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "{name} tahta panosu\n* Son değişiklik: {lastMod}",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Oluşturulma: {created}\n* Son değiştirilme: {lastMod}\n* {nbAttachments} ek dosya\n* {nbComments} yorum", "* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Oluşturulma: {created}\n* Son değiştirilme: {lastMod}\n* {nbAttachments} ek dosya\n* {nbComments} yorum",

View File

@@ -371,8 +371,7 @@
"Note: Only the JSON format is supported for importing back into the Deck app." : "Not: Yeniden Tahta uygulaması içine aktarmak için yalnızca JSON biçimi desteklenir.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Not: Yeniden Tahta uygulaması içine aktarmak için yalnızca JSON biçimi desteklenir.",
"Export" : "Dışa aktar", "Export" : "Dışa aktar",
"Loading filtered view" : "Süzülmüş görünüm yükleniyor", "Loading filtered view" : "Süzülmüş görünüm yükleniyor",
"Search for {searchQuery} in other boards" : "Diğer panolarda {searchQuery} ara", "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} ara",
"No results found" : "Herhangi bir sonuç bulunamadı", "No results found" : "Herhangi bir sonuç bulunamadı",
"Deck board {name}\n* Last modified on {lastMod}" : "{name} tahta panosu\n* Son değişiklik: {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "{name} tahta panosu\n* Son değişiklik: {lastMod}",
"* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Oluşturulma: {created}\n* Son değiştirilme: {lastMod}\n* {nbAttachments} ek dosya\n* {nbComments} yorum", "* Created on {created}\n* Last modified on {lastMod}\n* {nbAttachments} attachments\n* {nbComments} comments" : "* Oluşturulma: {created}\n* Son değiştirilme: {lastMod}\n* {nbAttachments} ek dosya\n* {nbComments} yorum",

View File

@@ -373,7 +373,6 @@ OC.L10N.register(
"Note: Only the JSON format is supported for importing back into the Deck app." : "Примітка: Для імпорту в додаток Deck підтримується лише формат JSON.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Примітка: Для імпорту в додаток Deck підтримується лише формат JSON.",
"Export" : "Експортувати", "Export" : "Експортувати",
"Loading filtered view" : "Завантаження відфільтрованого перегляду", "Loading filtered view" : "Завантаження відфільтрованого перегляду",
"Search for {searchQuery} in other boards" : "Шукати {searchQuery} на інших дошках",
"Search for {searchQuery} in all boards" : "Шукати {searchQuery} на всіх дошках оголошень", "Search for {searchQuery} in all boards" : "Шукати {searchQuery} на всіх дошках оголошень",
"No results found" : "Не знайдено жодного результату", "No results found" : "Не знайдено жодного результату",
"Deck board {name}\n* Last modified on {lastMod}" : "Колода {name}\n* Востаннє змінено на {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Колода {name}\n* Востаннє змінено на {lastMod}",

View File

@@ -371,7 +371,6 @@
"Note: Only the JSON format is supported for importing back into the Deck app." : "Примітка: Для імпорту в додаток Deck підтримується лише формат JSON.", "Note: Only the JSON format is supported for importing back into the Deck app." : "Примітка: Для імпорту в додаток Deck підтримується лише формат JSON.",
"Export" : "Експортувати", "Export" : "Експортувати",
"Loading filtered view" : "Завантаження відфільтрованого перегляду", "Loading filtered view" : "Завантаження відфільтрованого перегляду",
"Search for {searchQuery} in other boards" : "Шукати {searchQuery} на інших дошках",
"Search for {searchQuery} in all boards" : "Шукати {searchQuery} на всіх дошках оголошень", "Search for {searchQuery} in all boards" : "Шукати {searchQuery} на всіх дошках оголошень",
"No results found" : "Не знайдено жодного результату", "No results found" : "Не знайдено жодного результату",
"Deck board {name}\n* Last modified on {lastMod}" : "Колода {name}\n* Востаннє змінено на {lastMod}", "Deck board {name}\n* Last modified on {lastMod}" : "Колода {name}\n* Востаннє змінено на {lastMod}",

View File

@@ -55,7 +55,6 @@ OC.L10N.register(
"Edit title" : "Sarlavhani tahrirlash", "Edit title" : "Sarlavhani tahrirlash",
"Delete card" : "Kartani o'chirish", "Delete card" : "Kartani o'chirish",
"seconds ago" : "seconds ago", "seconds ago" : "seconds ago",
"Keyboard shortcuts" : "Klaviatura yorliqlari",
"Search" : "Qidirish", "Search" : "Qidirish",
"Archived boards" : "Arxivlangan taxtalar", "Archived boards" : "Arxivlangan taxtalar",
"Shared with you" : "Shared with you", "Shared with you" : "Shared with you",

View File

@@ -53,7 +53,6 @@
"Edit title" : "Sarlavhani tahrirlash", "Edit title" : "Sarlavhani tahrirlash",
"Delete card" : "Kartani o'chirish", "Delete card" : "Kartani o'chirish",
"seconds ago" : "seconds ago", "seconds ago" : "seconds ago",
"Keyboard shortcuts" : "Klaviatura yorliqlari",
"Search" : "Qidirish", "Search" : "Qidirish",
"Archived boards" : "Arxivlangan taxtalar", "Archived boards" : "Arxivlangan taxtalar",
"Shared with you" : "Shared with you", "Shared with you" : "Shared with you",

View File

@@ -50,10 +50,12 @@ class LabelApiController extends ApiController {
* *
* @params $title * @params $title
* @params $color * @params $color
* @param array<string, scalar> $customSettings
*
* Create a new label * Create a new label
*/ */
public function create($title, $color) { public function create($title, $color, array $customSettings = []) {
$label = $this->labelService->create($title, $color, $this->request->getParam('boardId')); $label = $this->labelService->create($title, $color, $this->request->getParam('boardId'), $customSettings);
return new DataResponse($label, HTTP::STATUS_OK); return new DataResponse($label, HTTP::STATUS_OK);
} }
@@ -64,10 +66,12 @@ class LabelApiController extends ApiController {
* *
* @params $title * @params $title
* @params $color * @params $color
* @param array<string, scalar> $customSettings
*
* Update a specific label * Update a specific label
*/ */
public function update($title, $color) { public function update($title, $color, array $customSettings = []) {
$label = $this->labelService->update($this->request->getParam('labelId'), $title, $color); $label = $this->labelService->update($this->request->getParam('labelId'), $title, $color, $customSettings);
return new DataResponse($label, HTTP::STATUS_OK); return new DataResponse($label, HTTP::STATUS_OK);
} }

View File

@@ -25,10 +25,11 @@ class LabelController extends Controller {
* @param $title * @param $title
* @param $color * @param $color
* @param $boardId * @param $boardId
* @param array<string, scalar> $customSettings
* @return \OCP\AppFramework\Db\Entity * @return \OCP\AppFramework\Db\Entity
*/ */
public function create($title, $color, $boardId) { public function create($title, $color, $boardId, array $customSettings = []) {
return $this->labelService->create($title, $color, $boardId); return $this->labelService->create($title, $color, $boardId, $customSettings);
} }
/** /**
@@ -36,10 +37,11 @@ class LabelController extends Controller {
* @param $id * @param $id
* @param $title * @param $title
* @param $color * @param $color
* @param array<string, scalar> $customSettings
* @return \OCP\AppFramework\Db\Entity * @return \OCP\AppFramework\Db\Entity
*/ */
public function update($id, $title, $color) { public function update($id, $title, $color, array $customSettings = []) {
return $this->labelService->update($id, $title, $color); return $this->labelService->update($id, $title, $color, $customSettings);
} }
/** /**

View File

@@ -77,33 +77,18 @@ class AssignmentMapper extends DeckMapper implements IPermissionMapper {
} }
public function deleteByParticipantOnBoard(string $participant, int $boardId, $type = Assignment::TYPE_USER) { public function deleteByParticipantOnBoard(string $participant, int $boardId, $type = Assignment::TYPE_USER) {
// Step 1: Get all card IDs for the board that have assignments for this participant $qb = $this->db->getQueryBuilder();
// This avoids MySQL Error 1093 by separating the SELECT from the DELETE operation
$cardIdQuery = $this->db->getQueryBuilder(); $cardIdQuery = $this->db->getQueryBuilder();
$cardIdQuery->select('a.card_id') $cardIdQuery->select('a.card_id')
->from('deck_assigned_users', 'a') ->from('deck_assigned_users', 'a')
->innerJoin('a', 'deck_cards', 'c', 'c.id = a.card_id') ->innerJoin('a', 'deck_cards', 'c', 'c.id = a.card_id')
->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id') ->innerJoin('c', 'deck_stacks', 's', 's.id = c.stack_id')
->where($cardIdQuery->expr()->eq('a.participant', $cardIdQuery->createNamedParameter($participant, IQueryBuilder::PARAM_STR))) ->where($cardIdQuery->expr()->eq('a.participant', $qb->createNamedParameter($participant, IQueryBuilder::PARAM_STR)))
->andWhere($cardIdQuery->expr()->eq('s.board_id', $cardIdQuery->createNamedParameter($boardId, IQueryBuilder::PARAM_INT))) ->andWhere($cardIdQuery->expr()->eq('s.board_id', $qb->createNamedParameter($boardId, IQueryBuilder::PARAM_INT)))
->andWhere($cardIdQuery->expr()->eq('a.type', $cardIdQuery->createNamedParameter($type, IQueryBuilder::PARAM_INT))); ->andWhere($cardIdQuery->expr()->eq('a.type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT)));
$qb->delete('deck_assigned_users')
$result = $cardIdQuery->executeQuery(); ->where($qb->expr()->in('card_id', $qb->createFunction($cardIdQuery->getSQL()), IQueryBuilder::PARAM_INT_ARRAY));
$cardIds = []; $qb->executeStatement();
while ($row = $result->fetch()) {
$cardIds[] = $row['card_id'];
}
$result->closeCursor();
// Step 2: If we have card IDs, delete the assignments
if (!empty($cardIds)) {
$deleteQuery = $this->db->getQueryBuilder();
$deleteQuery->delete('deck_assigned_users')
->where($deleteQuery->expr()->eq('participant', $deleteQuery->createNamedParameter($participant, IQueryBuilder::PARAM_STR)))
->andWhere($deleteQuery->expr()->eq('type', $deleteQuery->createNamedParameter($type, IQueryBuilder::PARAM_INT)))
->andWhere($deleteQuery->expr()->in('card_id', $deleteQuery->createNamedParameter($cardIds, IQueryBuilder::PARAM_INT_ARRAY)));
$deleteQuery->executeStatement();
}
} }

View File

@@ -131,11 +131,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $card; return $card;
} }
/** public function findAll($stackId, $limit = null, $offset = null, $since = -1) {
* @return Card[]
* @throws \OCP\DB\Exception
*/
public function findAll($stackId, ?int $limit = null, ?int $offset = null, int $since = -1) {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from('deck_cards') ->from('deck_cards')
@@ -150,32 +146,6 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $this->findEntities($qb); return $this->findEntities($qb);
} }
/**
* @param int[] $stackIds
* @return array<int, null|Card[]>
* @throws \OCP\DB\Exception
*/
public function findAllForStacks(array $stackIds, ?int $limit = null, ?int $offset = null, int $since = -1): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from('deck_cards')
->where($qb->expr()->in('stack_id', $qb->createNamedParameter($stackIds, IQueryBuilder::PARAM_INT_ARRAY)))
->andWhere($qb->expr()->eq('archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->gt('last_modified', $qb->createNamedParameter($since, IQueryBuilder::PARAM_INT)))
->setMaxResults($limit)
->setFirstResult($offset)
->orderBy('order')
->addOrderBy('id');
$rawCards = $this->findEntities($qb);
$cards = array_fill_keys($stackIds, null);
foreach ($rawCards as $card) {
$cards[$card->getStackId()][] = $card;
}
return $cards;
}
public function queryCardsByBoard(int $boardId): IQueryBuilder { public function queryCardsByBoard(int $boardId): IQueryBuilder {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('c.*') $qb->select('c.*')

View File

@@ -9,6 +9,8 @@ namespace OCA\Deck\Db;
/** /**
* @method getTitle(): string * @method getTitle(): string
* @method getCustomSettings(): string
* @method setCustomSettings(string $customSettings)
*/ */
class Label extends RelationalEntity { class Label extends RelationalEntity {
protected $title; protected $title;
@@ -16,15 +18,32 @@ class Label extends RelationalEntity {
protected $boardId; protected $boardId;
protected $cardId; protected $cardId;
protected $lastModified; protected $lastModified;
protected $customSettings;
public function __construct() { public function __construct() {
$this->addType('id', 'integer'); $this->addType('id', 'integer');
$this->addType('boardId', 'integer'); $this->addType('boardId', 'integer');
$this->addType('cardId', 'integer'); $this->addType('cardId', 'integer');
$this->addType('lastModified', 'integer'); $this->addType('lastModified', 'integer');
$this->addType('customSettings', 'string');
} }
public function getETag() { public function getETag() {
return md5((string)$this->getLastModified()); return md5((string)$this->getLastModified());
} }
public function getCustomSettingsArray(): array {
return $this->customSettings ? json_decode($this->customSettings, true) : [];
}
public function setCustomSettingsArray(array $customSettings): void {
$this->setCustomSettings(json_encode($customSettings ?: new \stdClass()));
}
public function jsonSerialize(): array {
$data = parent::jsonSerialize();
$data['customSettings'] = $this->getCustomSettingsArray() ?: new \stdClass();
return $data;
}
} }

View File

@@ -15,7 +15,6 @@ use Sabre\VObject\Component\VCalendar;
* @method int getDeletedAt() * @method int getDeletedAt()
* @method int getLastModified() * @method int getLastModified()
* @method int getOrder() * @method int getOrder()
* @method Card[] getCards()
*/ */
class Stack extends RelationalEntity { class Stack extends RelationalEntity {
protected $title; protected $title;

View File

@@ -77,10 +77,12 @@ class StackMapper extends DeckMapper implements IPermissionMapper {
/** /**
* @param numeric $boardId * @param numeric $boardId
* @param int|null $limit
* @param int|null $offset
* @return Stack[] * @return Stack[]
* @throws \OCP\DB\Exception * @throws \OCP\DB\Exception
*/ */
public function findAll($boardId, ?int $limit = null, ?int $offset = null): array { public function findAll($boardId, $limit = null, $offset = null): array {
$qb = $this->db->getQueryBuilder(); $qb = $this->db->getQueryBuilder();
$qb->select('*') $qb->select('*')
->from($this->getTableName()) ->from($this->getTableName())

View File

@@ -0,0 +1,32 @@
<?php
/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
declare(strict_types=1);
namespace OCA\Deck\Migration;
use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
class Version20000Date20250907000000 extends SimpleMigrationStep {
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->getTable('deck_labels');
if (!$table->hasColumn('custom_settings')) {
$table->addColumn('custom_settings', Types::JSON, [
'notnull' => false,
]);
}
return $schema;
}
}

View File

@@ -136,7 +136,7 @@ class Notifier implements INotifier {
} }
$notification->setParsedSubject( $notification->setParsedSubject(
$l->t('The card "%1$s" on "%2$s" has reached its due date.', $params) $l->t('The card "%s" on "%s" has reached its due date.', $params)
); );
$notification->setRichSubject( $notification->setRichSubject(
$l->t('The card {deck-card} on {deck-board} has reached its due date.'), $l->t('The card {deck-card} on {deck-board} has reached its due date.'),

View File

@@ -340,7 +340,7 @@ class CardService {
// clone labels that are assigned to card but don't exist in new board // clone labels that are assigned to card but don't exist in new board
if (empty($filteredLabels)) { if (empty($filteredLabels)) {
if ($this->permissionService->getPermissions($boardId)[Acl::PERMISSION_MANAGE] === true) { if ($this->permissionService->getPermissions($boardId)[Acl::PERMISSION_MANAGE] === true) {
$newLabel = $this->labelService->create($label->getTitle(), $label->getColor(), $board->getId()); $newLabel = $this->labelService->create($label->getTitle(), $label->getColor(), $board->getId(), $label->getCustomSettingsArray());
$boardLabels[] = $label; $boardLabels[] = $label;
$this->assignLabel($card->getId(), $newLabel->getId()); $this->assignLabel($card->getId(), $newLabel->getId());
} }

View File

@@ -62,6 +62,7 @@ class LabelService {
* @param $title * @param $title
* @param $color * @param $color
* @param $boardId * @param $boardId
* @param array<string, scalar> $customSettings
* @return \OCP\AppFramework\Db\Entity * @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
@@ -69,7 +70,7 @@ class LabelService {
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function create($title, $color, $boardId) { public function create($title, $color, $boardId, array $customSettings = []) {
$this->labelServiceValidator->check(compact('title', 'color', 'boardId')); $this->labelServiceValidator->check(compact('title', 'color', 'boardId'));
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE);
@@ -89,6 +90,7 @@ class LabelService {
$label->setTitle($title); $label->setTitle($title);
$label->setColor($color); $label->setColor($color);
$label->setBoardId($boardId); $label->setBoardId($boardId);
$label->setCustomSettingsArray($customSettings);
$this->changeHelper->boardChanged($boardId); $this->changeHelper->boardChanged($boardId);
return $this->labelMapper->insert($label); return $this->labelMapper->insert($label);
} }
@@ -99,7 +101,7 @@ class LabelService {
$originLabel = $this->find($labelId); $originLabel = $this->find($labelId);
$filteredValues = array_values(array_filter($boardLabels, fn ($item) => $item->getTitle() === $originLabel->getTitle())); $filteredValues = array_values(array_filter($boardLabels, fn ($item) => $item->getTitle() === $originLabel->getTitle()));
if (empty($filteredValues)) { if (empty($filteredValues)) {
$label = $this->create($originLabel->getTitle(), $originLabel->getColor(), $targetBoardId); $label = $this->create($originLabel->getTitle(), $originLabel->getColor(), $targetBoardId, $originLabel->getCustomSettingsArray());
return $label; return $label;
} }
return $originLabel; return $originLabel;
@@ -130,6 +132,7 @@ class LabelService {
* @param $id * @param $id
* @param $title * @param $title
* @param $color * @param $color
* @param array<string, scalar> $customSettings
* @return \OCP\AppFramework\Db\Entity * @return \OCP\AppFramework\Db\Entity
* @throws StatusException * @throws StatusException
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
@@ -137,7 +140,7 @@ class LabelService {
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException * @throws BadRequestException
*/ */
public function update($id, $title, $color) { public function update($id, $title, $color, array $customSettings = []) {
$this->labelServiceValidator->check(compact('title', 'color', 'id')); $this->labelServiceValidator->check(compact('title', 'color', 'id'));
$this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE); $this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE);
@@ -161,6 +164,7 @@ class LabelService {
$label->setTitle($title); $label->setTitle($title);
$label->setColor($color); $label->setColor($color);
$label->setCustomSettingsArray($customSettings);
$this->changeHelper->boardChanged($label->getBoardId()); $this->changeHelper->boardChanged($label->getBoardId());
return $this->labelMapper->update($label); return $this->labelMapper->update($label);
} }

View File

@@ -75,22 +75,19 @@ class StackService {
$this->stackServiceValidator = $stackServiceValidator; $this->stackServiceValidator = $stackServiceValidator;
} }
/** @param Stack[] $stacks */ private function enrichStackWithCards($stack, $since = -1) {
private function enrichStacksWithCards(array $stacks, $since = -1): void { $cards = $this->cardMapper->findAll($stack->getId(), null, null, $since);
$cardsByStackId = $this->cardMapper->findAllForStacks(array_map(fn (Stack $stack) => $stack->getId(), $stacks), null, null, $since);
foreach ($cardsByStackId as $stackId => $cards) { if (\count($cards) === 0) {
if (!$cards) { return;
continue; }
}
$stack->setCards($this->cardService->enrichCards($cards));
}
foreach ($stacks as $stack) { private function enrichStacksWithCards($stacks, $since = -1) {
if ($stack->getId() === $stackId) { foreach ($stacks as $stack) {
$stack->setCards($this->cardService->enrichCards($cards)); $this->enrichStackWithCards($stack, $since);
break;
}
}
} }
} }
@@ -127,9 +124,9 @@ class StackService {
} }
/** /**
* @param mixed $boardId * @param $boardId
* *
* @return Stack[] * @return array
* @throws \OCA\Deck\NoPermissionException * @throws \OCA\Deck\NoPermissionException
* @throws BadRequestException * @throws BadRequestException
*/ */
@@ -250,7 +247,7 @@ class StackService {
); );
$this->changeHelper->boardChanged($stack->getBoardId()); $this->changeHelper->boardChanged($stack->getBoardId());
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($stack->getBoardId())); $this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($stack->getBoardId()));
$this->enrichStacksWithCards([$stack]); $this->enrichStackWithCards($stack);
return $stack; return $stack;
} }

502
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -39,11 +39,11 @@
"@nextcloud/event-bus": "^3.3.2", "@nextcloud/event-bus": "^3.3.2",
"@nextcloud/files": "^3.10.1", "@nextcloud/files": "^3.10.1",
"@nextcloud/initial-state": "^2.2.0", "@nextcloud/initial-state": "^2.2.0",
"@nextcloud/l10n": "^3.4.0", "@nextcloud/l10n": "^3.1.0",
"@nextcloud/moment": "^1.3.5", "@nextcloud/moment": "^1.3.4",
"@nextcloud/notify_push": "^1.3.0", "@nextcloud/notify_push": "^1.3.0",
"@nextcloud/router": "^3.0.1", "@nextcloud/router": "^3.0.1",
"@nextcloud/vue": "^8.31.0", "@nextcloud/vue": "^8.27.0",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"chroma-js": "^3.1.2", "chroma-js": "^3.1.2",
"dompurify": "^3.2.5", "dompurify": "^3.2.5",
@@ -59,7 +59,6 @@
"vue-click-outside": "^1.1.0", "vue-click-outside": "^1.1.0",
"vue-easymde": "^2.0.0", "vue-easymde": "^2.0.0",
"vue-infinite-loading": "^2.4.5", "vue-infinite-loading": "^2.4.5",
"vue-loader": "^15.11.1",
"vue-material-design-icons": "^5.3.1", "vue-material-design-icons": "^5.3.1",
"vue-router": "^3.6.5", "vue-router": "^3.6.5",
"vue-smooth-dnd": "^0.8.1", "vue-smooth-dnd": "^0.8.1",

View File

@@ -6,7 +6,7 @@
<template> <template>
<div v-if="activity" class="activity"> <div v-if="activity" class="activity">
<div class="activity--header"> <div class="activity--header">
<img :src="activity.icon" class="activity--icon" :class="applyMonochromeIconColor"> <img :src="activity.icon" class="activity--icon">
<NcRichText class="activity--subject" :text="message.subject" :arguments="message.parameters" /> <NcRichText class="activity--subject" :text="message.subject" :arguments="message.parameters" />
<div class="activity--timestamp" :name="formatReadableDate(activity.datetime)"> <div class="activity--timestamp" :name="formatReadableDate(activity.datetime)">
{{ relativeDate(activity.datetime) }} {{ relativeDate(activity.datetime) }}
@@ -94,15 +94,6 @@ export default {
} }
}, },
applyMonochromeIconColor() {
// copied from https://github.com/nextcloud/activity/blob/db919d45c45356082b17104614018e2c7e691996/js/script.js#L225
const monochromeIcon = this.activity.type !== 'file_created' && this.activity.type !== 'file_deleted' && this.activity.type !== 'favorite' && !this.activity.icon.endsWith('-color.svg')
if (monochromeIcon) {
return 'monochrome'
}
return ''
},
sanitizedMessage() { sanitizedMessage() {
return DOMPurify.sanitize(this.activity.message, { ALLOWED_TAGS: ['ins', 'del'], ALLOWED_ATTR: ['class'] }) return DOMPurify.sanitize(this.activity.message, { ALLOWED_TAGS: ['ins', 'del'], ALLOWED_ATTR: ['class'] })
}, },
@@ -124,12 +115,6 @@ export default {
height: 16px; height: 16px;
flex-shrink: 0; flex-shrink: 0;
flex-grow: 0; flex-grow: 0;
/* colored icons, in addition to core ones */
&.monochrome {
opacity: 0.8;
filter: var(--background-invert-if-dark);
}
} }
.activity--subject { .activity--subject {
margin-left: 10px; margin-left: 10px;

View File

@@ -281,6 +281,7 @@ export default {
} }
.board { .board {
padding-left: $board-gap;
position: relative; position: relative;
overflow-x: auto; overflow-x: auto;
flex-grow: 1; flex-grow: 1;

View File

@@ -7,6 +7,7 @@
<NcAppSidebar v-if="board != null" <NcAppSidebar v-if="board != null"
:actions="[]" :actions="[]"
:name="board.title" :name="board.title"
style="width: 400px"
@close="closeSidebar"> @close="closeSidebar">
<NcAppSidebarTab id="sharing" <NcAppSidebarTab id="sharing"
:order="0" :order="0"
@@ -58,7 +59,7 @@ import { NcAppSidebar, NcAppSidebarTab } from '@nextcloud/vue'
import ActivityIcon from 'vue-material-design-icons/LightningBolt.vue' import ActivityIcon from 'vue-material-design-icons/LightningBolt.vue'
import SharingIcon from 'vue-material-design-icons/ShareVariantOutline.vue' import SharingIcon from 'vue-material-design-icons/ShareVariantOutline.vue'
import TagsIcon from 'vue-material-design-icons/TagMultipleOutline.vue' import TagsIcon from 'vue-material-design-icons/TagMultipleOutline.vue'
import TrashIcon from 'vue-material-design-icons/TrashCanOutline.vue' import TrashIcon from 'vue-material-design-icons/DeleteOutline.vue'
const capabilities = window.OC.getCapabilities() const capabilities = window.OC.getCapabilities()
export default { export default {

View File

@@ -15,7 +15,11 @@
@input="updateColor"> @input="updateColor">
<div :style="{ backgroundColor: '#' + editingLabel.color }" class="color0 icon-colorpicker" /> <div :style="{ backgroundColor: '#' + editingLabel.color }" class="color0 icon-colorpicker" />
</NcColorPicker> </NcColorPicker>
<input v-model="editingLabel.title" type="text"> <NcCheckboxRadioSwitch v-model="editingLabelIsImportant"
type="switch">
{{ t('deck', 'Important') }}
</NcCheckboxRadioSwitch>
<input v-model="editingLabel.title" type="text" style="margin-right: 20px;">
<input :disabled="!editLabelObjValidated" <input :disabled="!editLabelObjValidated"
type="submit" type="submit"
value="" value=""
@@ -34,10 +38,18 @@
</template> </template>
<template v-else> <template v-else>
<div v-if="canManage && !isArchived" class="label-title" @click="clickEdit(label)"> <div v-if="canManage && !isArchived" class="label-title" @click="clickEdit(label)">
<span :style="{ backgroundColor: `#${label.color}`, color: textColor(label.color) }">{{ label.title }}</span> <span :style="{
backgroundColor: `#${label.color}`,
color: textColor(label.color),
fontWeight: label.customSettings.isImportant ? 'bold' : 'normal'
}">{{ label.title }}</span>
</div> </div>
<div v-else class="label-title"> <div v-else class="label-title">
<span :style="{ backgroundColor: `#${label.color}`, color: textColor(label.color) }">{{ label.title }}</span> <span :style="{
backgroundColor: `#${label.color}`,
color: textColor(label.color),
fontWeight: label.customSettings.isImportant ? 'bold' : 'normal'
}">{{ label.title }}</span>
</div> </div>
<NcActions v-if="canManage && !isArchived"> <NcActions v-if="canManage && !isArchived">
@@ -62,7 +74,11 @@
@input="updateColor"> @input="updateColor">
<div :style="{ backgroundColor: '#' + addLabelObj.color }" class="color0 icon-colorpicker" /> <div :style="{ backgroundColor: '#' + addLabelObj.color }" class="color0 icon-colorpicker" />
</NcColorPicker> </NcColorPicker>
<input v-model="addLabelObj.title" type="text"> <NcCheckboxRadioSwitch v-model="addLabelIsImportant"
type="switch">
{{ t('deck', 'Important') }}
</NcCheckboxRadioSwitch>
<input v-model="addLabelObj.title" type="text" style="margin-right: 20px;">
<input :disabled="!addLabelObjValidated" <input :disabled="!addLabelObjValidated"
type="submit" type="submit"
value="" value=""
@@ -88,7 +104,7 @@
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import Color from '../../mixins/color.js' import Color from '../../mixins/color.js'
import { NcColorPicker, NcActions, NcActionButton } from '@nextcloud/vue' import { NcColorPicker, NcActions, NcActionButton, NcCheckboxRadioSwitch } from '@nextcloud/vue'
export default { export default {
name: 'TagsTabSidebar', name: 'TagsTabSidebar',
@@ -96,6 +112,7 @@ export default {
NcColorPicker, NcColorPicker,
NcActions, NcActions,
NcActionButton, NcActionButton,
NcCheckboxRadioSwitch,
}, },
mixins: [Color], mixins: [Color],
data() { data() {
@@ -139,7 +156,22 @@ export default {
labelsSorted() { labelsSorted() {
return [...this.labels].sort((a, b) => a.title.localeCompare(b.title)) return [...this.labels].sort((a, b) => a.title.localeCompare(b.title))
}, },
addLabelIsImportant: {
get() {
return this.addLabelObj?.customSettings?.isImportant || false
},
set(isImportant) {
this.addLabelObj.customSettings = { ...this.addLabelObj.customSettings, isImportant }
},
},
editingLabelIsImportant: {
get() {
return this.editingLabel?.customSettings?.isImportant
},
set(isImportant) {
this.editingLabel.customSettings = { ...this.editingLabel.customSettings, isImportant }
},
},
}, },
methods: { methods: {
updateColor(c) { updateColor(c) {
@@ -157,15 +189,23 @@ export default {
this.$store.dispatch('removeLabelFromCurrentBoard', id) this.$store.dispatch('removeLabelFromCurrentBoard', id)
}, },
updateLabel(label) { updateLabel(label) {
this.$store.dispatch('updateLabelFromCurrentBoard', this.editingLabel) const payload = {
...this.editingLabel,
customSettings: { ...this.editingLabel.customSettings },
}
this.$store.dispatch('updateLabelFromCurrentBoard', payload)
this.editingLabelId = null this.editingLabelId = null
}, },
clickShowAddLabel() { clickShowAddLabel() {
this.addLabelObj = { cardId: null, color: this.defaultColors[Math.floor(Math.random() * this.defaultColors.length)], title: '' } this.addLabelObj = { cardId: null, color: this.defaultColors[Math.floor(Math.random() * this.defaultColors.length)], title: '', customSettings: {} }
this.addLabel = true this.addLabel = true
}, },
clickAddLabel() { clickAddLabel() {
this.$store.dispatch('addLabelToCurrentBoard', this.addLabelObj) const payload = {
...this.addLabelObj,
customSettings: { ...this.addLabelObj.customSettings },
}
this.$store.dispatch('addLabelToCurrentBoard', payload)
this.addLabel = false this.addLabel = false
this.addLabelObj = null this.addLabelObj = null
}, },

View File

@@ -131,6 +131,42 @@ export default {
height: var(--default-clickable-area); height: var(--default-clickable-area);
} }
.badges .icon.due {
background-position: 4px center;
border-radius: var(--border-radius);
padding: 4px;
font-size: 13px;
display: flex;
align-items: center;
opacity: .5;
flex-shrink: 1;
.icon {
background-size: contain;
}
&.overdue {
background-color: var(--color-error);
color: var(--color-primary-element-text);
opacity: .7;
}
&.now {
background-color: var(--color-warning);
opacity: .7;
}
&.next {
background-color: var(--color-background-dark);
opacity: .7;
}
span {
margin-left: 20px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
.badge-left, .badge-right { .badge-left, .badge-right {
display: flex; display: flex;
} }

View File

@@ -6,10 +6,19 @@
<template> <template>
<AttachmentDragAndDrop v-if="card" :card-id="card.id" class="drop-upload--card"> <AttachmentDragAndDrop v-if="card" :card-id="card.id" class="drop-upload--card">
<div :ref="`card${card.id}`" <div :ref="`card${card.id}`"
:class="{'compact': compactMode, 'current-card': currentCard, 'no-labels': !hasLabels, 'card__editable': canEdit, 'card__archived': card.archived, 'card__highlight': highlight}" :class="{
'compact': compactMode,
'current-card': currentCard,
'no-labels': !hasLabels,
'card__editable': canEdit,
'card__archived': card.archived,
'card__highlight': highlight,
'card__important': !!importantColor,
}"
tag="div" tag="div"
:tabindex="0" :tabindex="0"
class="card" class="card"
:style="{'box-shadow': importantColor ? `-5px 0px 0px 0px ${importantColor}` : null}"
@click="openCard" @click="openCard"
@keyup.self="handleCardKeyboardShortcut" @keyup.self="handleCardKeyboardShortcut"
@mouseenter="focus(card.id)"> @mouseenter="focus(card.id)">
@@ -133,6 +142,14 @@ export default {
currentBoard: state => state.currentBoard, currentBoard: state => state.currentBoard,
showCardCover: state => state.showCardCover, showCardCover: state => state.showCardCover,
shortcutLock: state => state.shortcutLock, shortcutLock: state => state.shortcutLock,
importantColor() {
for (const label of this.card.labels) {
if (label.customSettings.isImportant) {
return '#' + label.color
}
}
return null
},
}), }),
...mapGetters([ ...mapGetters([
'isArchived', 'isArchived',
@@ -421,6 +438,10 @@ export default {
&.card__highlight { &.card__highlight {
animation: highlight 2s; animation: highlight 2s;
} }
&:not(.card__important) {
box-shadow: -5px 0px 0px 0px var(--color-main-background);
}
.card-labels { .card-labels {
display: flex; display: flex;
align-items: end; align-items: end;

View File

@@ -95,16 +95,16 @@ export default {
z-index: 2; z-index: 2;
[data-due-state='Overdue'] & { [data-due-state='Overdue'] & {
color: var(--color-element-error, var(--color-error-text)); color: var(--color-error-text);
background-color: rgba(var(--color-error-rgb), .5); background-color: rgba(var(--color-error-rgb), .1);
} }
[data-due-state='Now'] & { [data-due-state='Now'] & {
color: var(--color-element-warning, var(--color-warning-text)); color: var(--color-warning-text);
background-color: rgba(var(--color-warning-rgb), .5); background-color: rgba(var(--color-warning-rgb), .1);
} }
[data-due-state='Done'] & { [data-due-state='Done'] & {
color: var(--color-element-success, var(--color-success-text)); color: var(--color-success-text);
background-color: rgba(var(--color-success-rgb), .5); background-color: rgba(var(--color-success-rgb), .1);
} }
.due--label { .due--label {

View File

@@ -272,6 +272,7 @@ export default new Vuex.Store({
labelToUpdate.title = newLabel.title labelToUpdate.title = newLabel.title
labelToUpdate.color = newLabel.color labelToUpdate.color = newLabel.color
labelToUpdate.customSettings = newLabel.customSettings
}, },
addLabelToCurrentBoard(state, newLabel) { addLabelToCurrentBoard(state, newLabel) {
state.currentBoard.labels.push(newLabel) state.currentBoard.labels.push(newLabel)

View File

@@ -45,11 +45,13 @@ class LabelTest extends TestCase {
'lastModified' => null, 'lastModified' => null,
'color' => '000000', 'color' => '000000',
'ETag' => $label->getETag(), 'ETag' => $label->getETag(),
'customSettings' => new \stdClass(),
], $label->jsonSerialize()); ], $label->jsonSerialize());
} }
public function testJsonSerializeCard() { public function testJsonSerializeCard() {
$label = $this->createLabel(); $label = $this->createLabel();
$label->setCardId(123); $label->setCardId(123);
$label->setCustomSettingsArray(['isImportant' => true]);
$this->assertEquals([ $this->assertEquals([
'id' => 1, 'id' => 1,
'title' => 'My Label', 'title' => 'My Label',
@@ -58,6 +60,7 @@ class LabelTest extends TestCase {
'lastModified' => null, 'lastModified' => null,
'color' => '000000', 'color' => '000000',
'ETag' => $label->getETag(), 'ETag' => $label->getETag(),
'customSettings' => ['isImportant' => true]
], $label->jsonSerialize()); ], $label->jsonSerialize());
} }
} }

View File

@@ -75,14 +75,16 @@ class LabelServiceTest extends TestCase {
$label->setTitle('Label title'); $label->setTitle('Label title');
$label->setBoardId(123); $label->setBoardId(123);
$label->setColor('00ff00'); $label->setColor('00ff00');
$label->setCustomSettingsArray(['isImportant' => true]);
$this->labelMapper->expects($this->once()) $this->labelMapper->expects($this->once())
->method('insert') ->method('insert')
->willReturn($label); ->willReturn($label);
$b = $this->labelService->create('Label title', '00ff00', 123); $b = $this->labelService->create('Label title', '00ff00', 123, ['isImportant' => true]);
$this->assertEquals($b->getTitle(), 'Label title'); $this->assertEquals($b->getTitle(), 'Label title');
$this->assertEquals($b->getBoardId(), 123); $this->assertEquals($b->getBoardId(), 123);
$this->assertEquals($b->getColor(), '00ff00'); $this->assertEquals($b->getColor(), '00ff00');
$this->assertEquals($b->getCustomSettingsArray(), ['isImportant' => true]);
} }
@@ -111,6 +113,7 @@ class LabelServiceTest extends TestCase {
$label->setId(1); $label->setId(1);
$label->setTitle('title'); $label->setTitle('title');
$label->setColor('00ff00'); $label->setColor('00ff00');
$label->setCustomSettingsArray(['isImportant' => true]);
$this->labelMapper->expects($this->once()) $this->labelMapper->expects($this->once())
->method('find') ->method('find')
->willReturn($label); ->willReturn($label);
@@ -119,6 +122,7 @@ class LabelServiceTest extends TestCase {
$expectedLabel->setTitle('title'); $expectedLabel->setTitle('title');
$expectedLabel->setColor('00ff00'); $expectedLabel->setColor('00ff00');
$expectedLabel->setBoardId(1); $expectedLabel->setBoardId(1);
$expectedLabel->setCustomSettingsArray(['isImportant' => true]);
$this->labelMapper->expects($this->once()) $this->labelMapper->expects($this->once())
->method('insert') ->method('insert')
->with($expectedLabel) ->with($expectedLabel)

View File

@@ -129,17 +129,12 @@ class StackServiceTest extends TestCase {
} }
) )
); );
$this->cardMapper->expects($this->any())->method('findAllForStacks')->willReturnCallback(function (array $stackIds) { $this->cardMapper->expects($this->any())->method('findAll')->willReturn($this->getCards(222));
$r = [];
foreach ($stackIds as $stackId) {
$r[$stackId] = $this->getCards(222);
}
return $r;
});
$actual = $this->stackService->findAll(123); $actual = $this->stackService->findAll(123);
for ($stackId = 0; $stackId < 3; $stackId++) { for ($stackId = 0; $stackId < 3; $stackId++) {
for ($cardId = 0; $cardId < 10; $cardId++) { for ($cardId = 0;$cardId < 10;$cardId++) {
$this->assertEquals($actual[0]->getCards()[$cardId]->getId(), $cardId); $this->assertEquals($actual[0]->getCards()[$cardId]->getId(), $cardId);
$this->assertEquals($actual[0]->getCards()[$cardId]->getStackId(), 222); $this->assertEquals($actual[0]->getCards()[$cardId]->getStackId(), 222);
$this->assertEquals($actual[0]->getCards()[$cardId]->getLabels(), $this->getLabels()[$cardId]); $this->assertEquals($actual[0]->getCards()[$cardId]->getLabels(), $this->getLabels()[$cardId]);
@@ -216,7 +211,7 @@ class StackServiceTest extends TestCase {
$stackToBeDeleted->setBoardId(1); $stackToBeDeleted->setBoardId(1);
$this->stackMapper->expects($this->once())->method('find')->willReturn($stackToBeDeleted); $this->stackMapper->expects($this->once())->method('find')->willReturn($stackToBeDeleted);
$this->stackMapper->expects($this->once())->method('update')->willReturn($stackToBeDeleted); $this->stackMapper->expects($this->once())->method('update')->willReturn($stackToBeDeleted);
$this->cardMapper->expects($this->once())->method('findAllForStacks')->willReturn([]); $this->cardMapper->expects($this->once())->method('findAll')->willReturn([]);
$this->stackService->delete(123); $this->stackService->delete(123);
$this->assertTrue($stackToBeDeleted->getDeletedAt() <= time(), 'deletedAt is in the past'); $this->assertTrue($stackToBeDeleted->getDeletedAt() <= time(), 'deletedAt is in the past');
$this->assertTrue($stackToBeDeleted->getDeletedAt() > 0, 'deletedAt is set'); $this->assertTrue($stackToBeDeleted->getDeletedAt() > 0, 'deletedAt is set');