Compare commits
16 Commits
bug/clone-
...
feature/up
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
386131774d | ||
|
|
97b7c1a2f2 | ||
|
|
10a1c68917 | ||
|
|
83b739d117 | ||
|
|
eef33ac220 | ||
|
|
69896d5cca | ||
|
|
021d55226b | ||
|
|
6c59f52c31 | ||
|
|
7d414891f9 | ||
|
|
3cd94f330f | ||
|
|
00a3c8e20f | ||
|
|
309fbc735c | ||
|
|
bcaa74b33f | ||
|
|
427f960c80 | ||
|
|
3ad4fbd96c | ||
|
|
49dccb6199 |
2
.github/workflows/appbuild.yml
vendored
2
.github/workflows/appbuild.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
- name: Set up npm7
|
||||
run: npm i -g npm@7
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.18.0
|
||||
uses: shivammathur/setup-php@2.17.1
|
||||
with:
|
||||
php-version: '7.4'
|
||||
tools: composer
|
||||
|
||||
2
.github/workflows/appstore-build-publish.yml
vendored
2
.github/workflows/appstore-build-publish.yml
vendored
@@ -66,7 +66,7 @@ jobs:
|
||||
run: npm i -g npm@"${{ steps.versions.outputs.npmVersion }}"
|
||||
|
||||
- name: Set up php ${{ env.PHP_VERSION }}
|
||||
uses: shivammathur/setup-php@2.18.0
|
||||
uses: shivammathur/setup-php@2.17.1
|
||||
with:
|
||||
php-version: ${{ env.PHP_VERSION }}
|
||||
coverage: none
|
||||
|
||||
4
.github/workflows/command-rebase.yml
vendored
4
.github/workflows/command-rebase.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Add reaction on start
|
||||
uses: peter-evans/create-or-update-comment@v2
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
with:
|
||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
repository: ${{ github.event.repository.full_name }}
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
|
||||
- name: Add reaction on failure
|
||||
uses: peter-evans/create-or-update-comment@v2
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
if: failure()
|
||||
with:
|
||||
token: ${{ secrets.COMMAND_BOT_PAT }}
|
||||
|
||||
2
.github/workflows/integration.yml
vendored
2
.github/workflows/integration.yml
vendored
@@ -61,7 +61,7 @@ jobs:
|
||||
path: apps/${{ env.APP_NAME }}
|
||||
|
||||
- name: Set up php ${{ matrix.php-versions }}
|
||||
uses: shivammathur/setup-php@2.18.0
|
||||
uses: shivammathur/setup-php@2.17.1
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: phpunit
|
||||
|
||||
6
.github/workflows/lint.yml
vendored
6
.github/workflows/lint.yml
vendored
@@ -13,13 +13,13 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', "8.1"]
|
||||
php-versions: ['7.4', '8.0']
|
||||
|
||||
name: php${{ matrix.php-versions }} lint
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up php${{ matrix.php-versions }}
|
||||
uses: shivammathur/setup-php@2.18.0
|
||||
uses: shivammathur/setup-php@2.17.1
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
coverage: none
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up php
|
||||
uses: shivammathur/setup-php@2.18.0
|
||||
uses: shivammathur/setup-php@2.17.1
|
||||
with:
|
||||
php-version: 7.4
|
||||
coverage: none
|
||||
|
||||
2
.github/workflows/nightly.yml
vendored
2
.github/workflows/nightly.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
- name: Set up npm7
|
||||
run: npm i -g npm@7
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.18.0
|
||||
uses: shivammathur/setup-php@2.17.1
|
||||
with:
|
||||
php-version: '7.4'
|
||||
tools: composer
|
||||
|
||||
4
.github/workflows/phpunit.yml
vendored
4
.github/workflows/phpunit.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', "8.1"]
|
||||
php-versions: ['7.4', '8.0']
|
||||
databases: ['sqlite', 'mysql', 'pgsql']
|
||||
server-versions: ['master']
|
||||
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
path: apps/${{ env.APP_NAME }}
|
||||
|
||||
- name: Set up php ${{ matrix.php-versions }}
|
||||
uses: shivammathur/setup-php@2.18.0
|
||||
uses: shivammathur/setup-php@2.17.1
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: phpunit
|
||||
|
||||
2
.github/workflows/static-analysis.yml
vendored
2
.github/workflows/static-analysis.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up php
|
||||
uses: shivammathur/setup-php@2.18.0
|
||||
uses: shivammathur/setup-php@2.17.1
|
||||
with:
|
||||
php-version: 7.4
|
||||
tools: composer:v1
|
||||
|
||||
24
composer.lock
generated
24
composer.lock
generated
@@ -1675,16 +1675,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
"version": "1.6.1",
|
||||
"version": "1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||
"reference": "77a32518733312af16a44300404e945338981de3"
|
||||
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3",
|
||||
"reference": "77a32518733312af16a44300404e945338981de3",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706",
|
||||
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1719,9 +1719,9 @@
|
||||
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1"
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0"
|
||||
},
|
||||
"time": "2022-03-15T21:29:03+00:00"
|
||||
"time": "2022-01-04T19:58:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
@@ -2110,16 +2110,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.5.20",
|
||||
"version": "9.5.19",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba"
|
||||
"reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba",
|
||||
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/35ea4b7f3acabb26f4bb640f8c30866c401da807",
|
||||
"reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2197,7 +2197,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.19"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2209,7 +2209,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-01T12:37:26+00:00"
|
||||
"time": "2022-03-15T09:57:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
|
||||
3
img/flash-black.svg
Normal file
3
img/flash-black.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve"><g><g><polygon points="426.667,213.333 288.36,213.333 333.706,0 148.817,0 85.333,298.667 227.556,298.667 227.556,512 " /></g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>
|
||||
|
After Width: | Height: | Size: 594 B |
1
img/plus.svg
Normal file
1
img/plus.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="#26e07f" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24px" height="24px"><path fill-rule="evenodd" d="M 11 2 L 11 11 L 2 11 L 2 13 L 11 13 L 11 22 L 13 22 L 13 13 L 22 13 L 22 11 L 13 11 L 13 2 Z"/></svg>
|
||||
|
After Width: | Height: | Size: 235 B |
@@ -170,14 +170,8 @@ OC.L10N.register(
|
||||
"Can edit" : "Může upravovat",
|
||||
"Can share" : "Může sdílet",
|
||||
"Can manage" : "Může spravovat",
|
||||
"Owner" : "Vlastník",
|
||||
"Delete" : "Smazat",
|
||||
"Failed to create share with {displayName}" : "Nepodařilo se vytvořit sdílení s {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Opravdu chcete předat vlastnictví tabule {title} uživateli {user}?",
|
||||
"Transfer the board." : "Předat vlastnictví tabule.",
|
||||
"Transfer" : "Předat vlastnictví",
|
||||
"Transfer the board for {user} successfully" : "Předání vlastnictví tabule uživateli {user} úspěšné",
|
||||
"Failed to transfer the board for {user}" : "Nepodařilo se předat vlastnictví tabule uživateli {user}",
|
||||
"Add a new list" : "Přidat nový sloupec",
|
||||
"Archive all cards" : "Archivovat všechny karty",
|
||||
"Delete list" : "Smazat seznam",
|
||||
|
||||
@@ -168,14 +168,8 @@
|
||||
"Can edit" : "Může upravovat",
|
||||
"Can share" : "Může sdílet",
|
||||
"Can manage" : "Může spravovat",
|
||||
"Owner" : "Vlastník",
|
||||
"Delete" : "Smazat",
|
||||
"Failed to create share with {displayName}" : "Nepodařilo se vytvořit sdílení s {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Opravdu chcete předat vlastnictví tabule {title} uživateli {user}?",
|
||||
"Transfer the board." : "Předat vlastnictví tabule.",
|
||||
"Transfer" : "Předat vlastnictví",
|
||||
"Transfer the board for {user} successfully" : "Předání vlastnictví tabule uživateli {user} úspěšné",
|
||||
"Failed to transfer the board for {user}" : "Nepodařilo se předat vlastnictví tabule uživateli {user}",
|
||||
"Add a new list" : "Přidat nový sloupec",
|
||||
"Archive all cards" : "Archivovat všechny karty",
|
||||
"Delete list" : "Smazat seznam",
|
||||
|
||||
@@ -170,14 +170,8 @@ OC.L10N.register(
|
||||
"Can edit" : "kann bearbeiten",
|
||||
"Can share" : "kann teilen",
|
||||
"Can manage" : "kann verwalten",
|
||||
"Owner" : "Besitzer",
|
||||
"Delete" : "Löschen",
|
||||
"Failed to create share with {displayName}" : "Fehler beim Erstellen der Freigabe mit dem Namen {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Möchtest Du wirklich das Board {title} an {user} übertragen?",
|
||||
"Transfer the board." : "Board übertragen",
|
||||
"Transfer" : "Übertragen",
|
||||
"Transfer the board for {user} successfully" : "Das Board wurde erfolgreich an {user} übertragen",
|
||||
"Failed to transfer the board for {user}" : "Board konnte nicht an {user} übertragen werden",
|
||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||
"Archive all cards" : "Alle Karten archivieren",
|
||||
"Delete list" : "Liste löschen",
|
||||
|
||||
@@ -168,14 +168,8 @@
|
||||
"Can edit" : "kann bearbeiten",
|
||||
"Can share" : "kann teilen",
|
||||
"Can manage" : "kann verwalten",
|
||||
"Owner" : "Besitzer",
|
||||
"Delete" : "Löschen",
|
||||
"Failed to create share with {displayName}" : "Fehler beim Erstellen der Freigabe mit dem Namen {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Möchtest Du wirklich das Board {title} an {user} übertragen?",
|
||||
"Transfer the board." : "Board übertragen",
|
||||
"Transfer" : "Übertragen",
|
||||
"Transfer the board for {user} successfully" : "Das Board wurde erfolgreich an {user} übertragen",
|
||||
"Failed to transfer the board for {user}" : "Board konnte nicht an {user} übertragen werden",
|
||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||
"Archive all cards" : "Alle Karten archivieren",
|
||||
"Delete list" : "Liste löschen",
|
||||
|
||||
@@ -170,14 +170,8 @@ OC.L10N.register(
|
||||
"Can edit" : "kann bearbeiten",
|
||||
"Can share" : "kann teilen",
|
||||
"Can manage" : "kann verwalten",
|
||||
"Owner" : "Besitzer",
|
||||
"Delete" : "Löschen",
|
||||
"Failed to create share with {displayName}" : "Fehler beim Erstellen der Freigabe mit dem Namen {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Möchten Sie wirklich Das Board {title} an {user} übertragen?",
|
||||
"Transfer the board." : "Board übertragen.",
|
||||
"Transfer" : "Übertragen",
|
||||
"Transfer the board for {user} successfully" : "Das Board wurde erfolgreich an {user} übertragen",
|
||||
"Failed to transfer the board for {user}" : "Board konnte nicht an {user} übertragen werden",
|
||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||
"Archive all cards" : "Alle Karten archivieren",
|
||||
"Delete list" : "Liste löschen",
|
||||
|
||||
@@ -168,14 +168,8 @@
|
||||
"Can edit" : "kann bearbeiten",
|
||||
"Can share" : "kann teilen",
|
||||
"Can manage" : "kann verwalten",
|
||||
"Owner" : "Besitzer",
|
||||
"Delete" : "Löschen",
|
||||
"Failed to create share with {displayName}" : "Fehler beim Erstellen der Freigabe mit dem Namen {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Möchten Sie wirklich Das Board {title} an {user} übertragen?",
|
||||
"Transfer the board." : "Board übertragen.",
|
||||
"Transfer" : "Übertragen",
|
||||
"Transfer the board for {user} successfully" : "Das Board wurde erfolgreich an {user} übertragen",
|
||||
"Failed to transfer the board for {user}" : "Board konnte nicht an {user} übertragen werden",
|
||||
"Add a new list" : "Eine neue Liste hinzufügen",
|
||||
"Archive all cards" : "Alle Karten archivieren",
|
||||
"Delete list" : "Liste löschen",
|
||||
|
||||
@@ -170,11 +170,8 @@ OC.L10N.register(
|
||||
"Can edit" : "Μπορεί να επεξεργαστεί",
|
||||
"Can share" : "Μπορεί να διαμοιράσει",
|
||||
"Can manage" : "Μπορεί να διαχειριστεί",
|
||||
"Owner" : "Κάτοχος",
|
||||
"Delete" : "Διαγραφή",
|
||||
"Failed to create share with {displayName}" : "Αποτυχία δημιουργίας κοινής χρήσης με το {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Είστε σίγουροι ότι θέλετε να μεταφέρετε τον πίνακα {title} για {user}? ",
|
||||
"Transfer" : "Μεταφορά",
|
||||
"Add a new list" : "Προσθήκη νέας λίστας",
|
||||
"Archive all cards" : "Αρχειοθέτηση όλων των καρτελών.",
|
||||
"Delete list" : "Διαγραφή λίστας",
|
||||
|
||||
@@ -168,11 +168,8 @@
|
||||
"Can edit" : "Μπορεί να επεξεργαστεί",
|
||||
"Can share" : "Μπορεί να διαμοιράσει",
|
||||
"Can manage" : "Μπορεί να διαχειριστεί",
|
||||
"Owner" : "Κάτοχος",
|
||||
"Delete" : "Διαγραφή",
|
||||
"Failed to create share with {displayName}" : "Αποτυχία δημιουργίας κοινής χρήσης με το {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Είστε σίγουροι ότι θέλετε να μεταφέρετε τον πίνακα {title} για {user}? ",
|
||||
"Transfer" : "Μεταφορά",
|
||||
"Add a new list" : "Προσθήκη νέας λίστας",
|
||||
"Archive all cards" : "Αρχειοθέτηση όλων των καρτελών.",
|
||||
"Delete list" : "Διαγραφή λίστας",
|
||||
|
||||
@@ -168,10 +168,8 @@ OC.L10N.register(
|
||||
"Can edit" : "Editatu dezake",
|
||||
"Can share" : "Partekatu dezake",
|
||||
"Can manage" : "Kudeatu dezake",
|
||||
"Owner" : "Jabea",
|
||||
"Delete" : "Ezabatu",
|
||||
"Failed to create share with {displayName}" : "Ezin izan da {displayName}-(r)ekin partekatzea sortu",
|
||||
"Transfer" : "Transferitu",
|
||||
"Add a new list" : "Gehitu zerrenda berria",
|
||||
"Archive all cards" : "Artxibatu txartel guztiak",
|
||||
"Delete list" : "Zerrenda ezabatu",
|
||||
|
||||
@@ -166,10 +166,8 @@
|
||||
"Can edit" : "Editatu dezake",
|
||||
"Can share" : "Partekatu dezake",
|
||||
"Can manage" : "Kudeatu dezake",
|
||||
"Owner" : "Jabea",
|
||||
"Delete" : "Ezabatu",
|
||||
"Failed to create share with {displayName}" : "Ezin izan da {displayName}-(r)ekin partekatzea sortu",
|
||||
"Transfer" : "Transferitu",
|
||||
"Add a new list" : "Gehitu zerrenda berria",
|
||||
"Archive all cards" : "Artxibatu txartel guztiak",
|
||||
"Delete list" : "Zerrenda ezabatu",
|
||||
|
||||
@@ -148,9 +148,7 @@ OC.L10N.register(
|
||||
"Can edit" : "Voi muokata",
|
||||
"Can share" : "Voi jakaa",
|
||||
"Can manage" : "Voi hallita",
|
||||
"Owner" : "Omistaja",
|
||||
"Delete" : "Poista",
|
||||
"Transfer" : "Siirrä",
|
||||
"Add a new list" : "Lisää uusi lista",
|
||||
"Archive all cards" : "Arkistoi kaikki kortit",
|
||||
"Delete list" : "Poista lista",
|
||||
@@ -165,7 +163,6 @@ OC.L10N.register(
|
||||
"Members" : "Jäsenet",
|
||||
"Upload new files" : "Lähetä uusia tiedostoja",
|
||||
"Add this attachment" : "Lisää tämä liite",
|
||||
"Download" : "Lataa",
|
||||
"Remove attachment" : "Poista liite",
|
||||
"Delete Attachment" : "Poista liite",
|
||||
"Restore Attachment" : "Palauta liite",
|
||||
@@ -191,8 +188,6 @@ OC.L10N.register(
|
||||
"Save" : "Tallenna",
|
||||
"The comment cannot be empty." : "Kommentti ei voi olla tyhjä.",
|
||||
"The comment cannot be longer than 1000 characters." : "Kommentin on oltava alle 1000 merkkiä pitkä.",
|
||||
"In reply to" : "Vastauksena",
|
||||
"Cancel reply" : "Peru vastaus",
|
||||
"Reply" : "Vastaa",
|
||||
"Update" : "Päivitä",
|
||||
"Description" : "Kuvaus",
|
||||
@@ -213,7 +208,6 @@ OC.L10N.register(
|
||||
"Archive card" : "Arkistoi kortti",
|
||||
"Delete card" : "Poista kortti",
|
||||
"Move card to another board" : "Siirrä kortti toiselle taululle",
|
||||
"List is empty" : "Lista on tyhjä",
|
||||
"Card deleted" : "Kortti poistettu",
|
||||
"seconds ago" : "sekuntia sitten",
|
||||
"All boards" : "Kaikki taulut",
|
||||
@@ -244,7 +238,6 @@ OC.L10N.register(
|
||||
"Maximum file size of {size} exceeded" : "Tiedoston enimmäiskoko {size} ylitetty",
|
||||
"Error creating the share" : "Virhe jakoa luotaessa",
|
||||
"Share" : "Jaa",
|
||||
"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" : "Pakka on Nextcloudissa työtään hallinnoivien tiimien käyttöön tarkoitettu kanban-tyyppinen organisointityökalu.\n\n\n- 📥 Lisää tehtävät korteille ja järjestele ne mielesi mukaan\n- 📄 Kirjoita lisätietoja markdown-kielellä\n- 🔖 Määritä tunnisteita helpottaaksesi hallintaa\n- 👥 Jaa tiimin, perheen tai kavereiden kanssa\n- 📎 Lisää tiedostoja ja upota ne lisätietoihin\n- 💬 Keskustele tiimisi kanssa kommenteilla\n- ⚡ Pidä kirjaa muutoksista tapahtumavirran avulla\n- 🚀 Pidä projektisi hallinnassa",
|
||||
"(circle)" : "(piiri)"
|
||||
"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" : "Pakka on Nextcloudissa työtään hallinnoivien tiimien käyttöön tarkoitettu kanban-tyyppinen organisointityökalu.\n\n\n- 📥 Lisää tehtävät korteille ja järjestele ne mielesi mukaan\n- 📄 Kirjoita lisätietoja markdown-kielellä\n- 🔖 Määritä tunnisteita helpottaaksesi hallintaa\n- 👥 Jaa tiimin, perheen tai kavereiden kanssa\n- 📎 Lisää tiedostoja ja upota ne lisätietoihin\n- 💬 Keskustele tiimisi kanssa kommenteilla\n- ⚡ Pidä kirjaa muutoksista tapahtumavirran avulla\n- 🚀 Pidä projektisi hallinnassa"
|
||||
},
|
||||
"nplurals=2; plural=(n != 1);");
|
||||
|
||||
@@ -146,9 +146,7 @@
|
||||
"Can edit" : "Voi muokata",
|
||||
"Can share" : "Voi jakaa",
|
||||
"Can manage" : "Voi hallita",
|
||||
"Owner" : "Omistaja",
|
||||
"Delete" : "Poista",
|
||||
"Transfer" : "Siirrä",
|
||||
"Add a new list" : "Lisää uusi lista",
|
||||
"Archive all cards" : "Arkistoi kaikki kortit",
|
||||
"Delete list" : "Poista lista",
|
||||
@@ -163,7 +161,6 @@
|
||||
"Members" : "Jäsenet",
|
||||
"Upload new files" : "Lähetä uusia tiedostoja",
|
||||
"Add this attachment" : "Lisää tämä liite",
|
||||
"Download" : "Lataa",
|
||||
"Remove attachment" : "Poista liite",
|
||||
"Delete Attachment" : "Poista liite",
|
||||
"Restore Attachment" : "Palauta liite",
|
||||
@@ -189,8 +186,6 @@
|
||||
"Save" : "Tallenna",
|
||||
"The comment cannot be empty." : "Kommentti ei voi olla tyhjä.",
|
||||
"The comment cannot be longer than 1000 characters." : "Kommentin on oltava alle 1000 merkkiä pitkä.",
|
||||
"In reply to" : "Vastauksena",
|
||||
"Cancel reply" : "Peru vastaus",
|
||||
"Reply" : "Vastaa",
|
||||
"Update" : "Päivitä",
|
||||
"Description" : "Kuvaus",
|
||||
@@ -211,7 +206,6 @@
|
||||
"Archive card" : "Arkistoi kortti",
|
||||
"Delete card" : "Poista kortti",
|
||||
"Move card to another board" : "Siirrä kortti toiselle taululle",
|
||||
"List is empty" : "Lista on tyhjä",
|
||||
"Card deleted" : "Kortti poistettu",
|
||||
"seconds ago" : "sekuntia sitten",
|
||||
"All boards" : "Kaikki taulut",
|
||||
@@ -242,7 +236,6 @@
|
||||
"Maximum file size of {size} exceeded" : "Tiedoston enimmäiskoko {size} ylitetty",
|
||||
"Error creating the share" : "Virhe jakoa luotaessa",
|
||||
"Share" : "Jaa",
|
||||
"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" : "Pakka on Nextcloudissa työtään hallinnoivien tiimien käyttöön tarkoitettu kanban-tyyppinen organisointityökalu.\n\n\n- 📥 Lisää tehtävät korteille ja järjestele ne mielesi mukaan\n- 📄 Kirjoita lisätietoja markdown-kielellä\n- 🔖 Määritä tunnisteita helpottaaksesi hallintaa\n- 👥 Jaa tiimin, perheen tai kavereiden kanssa\n- 📎 Lisää tiedostoja ja upota ne lisätietoihin\n- 💬 Keskustele tiimisi kanssa kommenteilla\n- ⚡ Pidä kirjaa muutoksista tapahtumavirran avulla\n- 🚀 Pidä projektisi hallinnassa",
|
||||
"(circle)" : "(piiri)"
|
||||
"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" : "Pakka on Nextcloudissa työtään hallinnoivien tiimien käyttöön tarkoitettu kanban-tyyppinen organisointityökalu.\n\n\n- 📥 Lisää tehtävät korteille ja järjestele ne mielesi mukaan\n- 📄 Kirjoita lisätietoja markdown-kielellä\n- 🔖 Määritä tunnisteita helpottaaksesi hallintaa\n- 👥 Jaa tiimin, perheen tai kavereiden kanssa\n- 📎 Lisää tiedostoja ja upota ne lisätietoihin\n- 💬 Keskustele tiimisi kanssa kommenteilla\n- ⚡ Pidä kirjaa muutoksista tapahtumavirran avulla\n- 🚀 Pidä projektisi hallinnassa"
|
||||
},"pluralForm" :"nplurals=2; plural=(n != 1);"
|
||||
}
|
||||
@@ -292,4 +292,4 @@ OC.L10N.register(
|
||||
"\"{card}\" was added to \"{board}\"" : "La carte \"{card}\" a été ajoutée au tableau \"{board}\"",
|
||||
"(circle)" : "(cercle)"
|
||||
},
|
||||
"nplurals=3; plural=(n==0 || n==1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
|
||||
"nplurals=2; plural=(n > 1);");
|
||||
|
||||
@@ -289,5 +289,5 @@
|
||||
"Creating the new card…" : "Création de la nouvelle carte…",
|
||||
"\"{card}\" was added to \"{board}\"" : "La carte \"{card}\" a été ajoutée au tableau \"{board}\"",
|
||||
"(circle)" : "(cercle)"
|
||||
},"pluralForm" :"nplurals=3; plural=(n==0 || n==1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
|
||||
},"pluralForm" :"nplurals=2; plural=(n > 1);"
|
||||
}
|
||||
@@ -170,14 +170,8 @@ OC.L10N.register(
|
||||
"Can edit" : "Szerkesztheti",
|
||||
"Can share" : "Megoszthatja",
|
||||
"Can manage" : "Kezelheti",
|
||||
"Owner" : "Tulajdonos",
|
||||
"Delete" : "Törlés",
|
||||
"Failed to create share with {displayName}" : "Nem lehet létrehozni a következő megosztást: {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Biztos, hogy átadja a(z) {board} tábla tulajdonjogát {user} számára?",
|
||||
"Transfer the board." : "A tábla átadása.",
|
||||
"Transfer" : "Átadás",
|
||||
"Transfer the board for {user} successfully" : "A tábla átadása {user} számára sikeres",
|
||||
"Failed to transfer the board for {user}" : "A tábla átadása {user} számára sikertelen",
|
||||
"Add a new list" : "Új lista hozzáadása",
|
||||
"Archive all cards" : "Az összes kártya archiválása",
|
||||
"Delete list" : "Lista törlése",
|
||||
|
||||
@@ -168,14 +168,8 @@
|
||||
"Can edit" : "Szerkesztheti",
|
||||
"Can share" : "Megoszthatja",
|
||||
"Can manage" : "Kezelheti",
|
||||
"Owner" : "Tulajdonos",
|
||||
"Delete" : "Törlés",
|
||||
"Failed to create share with {displayName}" : "Nem lehet létrehozni a következő megosztást: {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Biztos, hogy átadja a(z) {board} tábla tulajdonjogát {user} számára?",
|
||||
"Transfer the board." : "A tábla átadása.",
|
||||
"Transfer" : "Átadás",
|
||||
"Transfer the board for {user} successfully" : "A tábla átadása {user} számára sikeres",
|
||||
"Failed to transfer the board for {user}" : "A tábla átadása {user} számára sikertelen",
|
||||
"Add a new list" : "Új lista hozzáadása",
|
||||
"Archive all cards" : "Az összes kártya archiválása",
|
||||
"Delete list" : "Lista törlése",
|
||||
|
||||
@@ -170,14 +170,8 @@ OC.L10N.register(
|
||||
"Can edit" : "Może edytować",
|
||||
"Can share" : "Może udostępnić",
|
||||
"Can manage" : "Może zarządzać",
|
||||
"Owner" : "Właściciel",
|
||||
"Delete" : "Usuń",
|
||||
"Failed to create share with {displayName}" : "Nie udało się utworzyć udostępnienia dla {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Czy na pewno chcesz przenieść tablicę {title} dla {user}?",
|
||||
"Transfer the board." : "Przeniesienie tablicy.",
|
||||
"Transfer" : "Przenieś",
|
||||
"Transfer the board for {user} successfully" : "Przeniesienie tablicy dla {user} pomyślne",
|
||||
"Failed to transfer the board for {user}" : "Nie udało się przenieść tablicy dla {user}",
|
||||
"Add a new list" : "Dodaj nową listę",
|
||||
"Archive all cards" : "Zarchiwizuj wszystkie karty",
|
||||
"Delete list" : "Usuń listę",
|
||||
|
||||
@@ -168,14 +168,8 @@
|
||||
"Can edit" : "Może edytować",
|
||||
"Can share" : "Może udostępnić",
|
||||
"Can manage" : "Może zarządzać",
|
||||
"Owner" : "Właściciel",
|
||||
"Delete" : "Usuń",
|
||||
"Failed to create share with {displayName}" : "Nie udało się utworzyć udostępnienia dla {displayName}",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "Czy na pewno chcesz przenieść tablicę {title} dla {user}?",
|
||||
"Transfer the board." : "Przeniesienie tablicy.",
|
||||
"Transfer" : "Przenieś",
|
||||
"Transfer the board for {user} successfully" : "Przeniesienie tablicy dla {user} pomyślne",
|
||||
"Failed to transfer the board for {user}" : "Nie udało się przenieść tablicy dla {user}",
|
||||
"Add a new list" : "Dodaj nową listę",
|
||||
"Archive all cards" : "Zarchiwizuj wszystkie karty",
|
||||
"Delete list" : "Usuń listę",
|
||||
|
||||
@@ -170,14 +170,8 @@ OC.L10N.register(
|
||||
"Can edit" : "Düzenleyebilir",
|
||||
"Can share" : "Paylaşabilir",
|
||||
"Can manage" : "Yönetebilir",
|
||||
"Owner" : "Sahibi",
|
||||
"Delete" : "Sil",
|
||||
"Failed to create share with {displayName}" : "{displayName} ile paylaşılamadı",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "{title} panosunu {user} kullanıcısına aktarmak istediğinize emin misiniz?",
|
||||
"Transfer the board." : "Panoyu aktar.",
|
||||
"Transfer" : "Aktar",
|
||||
"Transfer the board for {user} successfully" : "Pano {user} kullanıcısına aktarıldı",
|
||||
"Failed to transfer the board for {user}" : "Pano {user} kullanıcısına aktarılamadı",
|
||||
"Add a new list" : "Yeni liste ekle",
|
||||
"Archive all cards" : "Tüm kartları arşivle",
|
||||
"Delete list" : "Listeyi sil",
|
||||
|
||||
@@ -168,14 +168,8 @@
|
||||
"Can edit" : "Düzenleyebilir",
|
||||
"Can share" : "Paylaşabilir",
|
||||
"Can manage" : "Yönetebilir",
|
||||
"Owner" : "Sahibi",
|
||||
"Delete" : "Sil",
|
||||
"Failed to create share with {displayName}" : "{displayName} ile paylaşılamadı",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "{title} panosunu {user} kullanıcısına aktarmak istediğinize emin misiniz?",
|
||||
"Transfer the board." : "Panoyu aktar.",
|
||||
"Transfer" : "Aktar",
|
||||
"Transfer the board for {user} successfully" : "Pano {user} kullanıcısına aktarıldı",
|
||||
"Failed to transfer the board for {user}" : "Pano {user} kullanıcısına aktarılamadı",
|
||||
"Add a new list" : "Yeni liste ekle",
|
||||
"Archive all cards" : "Tüm kartları arşivle",
|
||||
"Delete list" : "Listeyi sil",
|
||||
|
||||
@@ -170,14 +170,8 @@ OC.L10N.register(
|
||||
"Can edit" : "可以編輯",
|
||||
"Can share" : "可以分享",
|
||||
"Can manage" : "可以管理",
|
||||
"Owner" : "所有者",
|
||||
"Delete" : "刪除",
|
||||
"Failed to create share with {displayName}" : "無法為 {displayName} 創建分享",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "您想要轉移 {user} 的面板 {title} 嗎?",
|
||||
"Transfer the board." : "轉移面板。",
|
||||
"Transfer" : "轉移",
|
||||
"Transfer the board for {user} successfully" : "轉移 {user} 的面板成功",
|
||||
"Failed to transfer the board for {user}" : "轉移 {user} 的面板失敗",
|
||||
"Add a new list" : "添加一張新清單",
|
||||
"Archive all cards" : "封存所有卡片",
|
||||
"Delete list" : "刪除清單",
|
||||
|
||||
@@ -168,14 +168,8 @@
|
||||
"Can edit" : "可以編輯",
|
||||
"Can share" : "可以分享",
|
||||
"Can manage" : "可以管理",
|
||||
"Owner" : "所有者",
|
||||
"Delete" : "刪除",
|
||||
"Failed to create share with {displayName}" : "無法為 {displayName} 創建分享",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "您想要轉移 {user} 的面板 {title} 嗎?",
|
||||
"Transfer the board." : "轉移面板。",
|
||||
"Transfer" : "轉移",
|
||||
"Transfer the board for {user} successfully" : "轉移 {user} 的面板成功",
|
||||
"Failed to transfer the board for {user}" : "轉移 {user} 的面板失敗",
|
||||
"Add a new list" : "添加一張新清單",
|
||||
"Archive all cards" : "封存所有卡片",
|
||||
"Delete list" : "刪除清單",
|
||||
|
||||
@@ -170,14 +170,8 @@ OC.L10N.register(
|
||||
"Can edit" : "可以編輯",
|
||||
"Can share" : "可以分享",
|
||||
"Can manage" : "可以管理",
|
||||
"Owner" : "擁有者",
|
||||
"Delete" : "刪除",
|
||||
"Failed to create share with {displayName}" : "無法建立與 {displayName} 的分享",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "您想要轉移 {user} 的看板 {title} 嗎?",
|
||||
"Transfer the board." : "轉移看板。",
|
||||
"Transfer" : "轉移",
|
||||
"Transfer the board for {user} successfully" : "轉移 {user} 的看板成功",
|
||||
"Failed to transfer the board for {user}" : "轉移 {user} 的看板失敗",
|
||||
"Add a new list" : "新增列表",
|
||||
"Archive all cards" : "封存所有卡片",
|
||||
"Delete list" : "刪除列表",
|
||||
|
||||
@@ -168,14 +168,8 @@
|
||||
"Can edit" : "可以編輯",
|
||||
"Can share" : "可以分享",
|
||||
"Can manage" : "可以管理",
|
||||
"Owner" : "擁有者",
|
||||
"Delete" : "刪除",
|
||||
"Failed to create share with {displayName}" : "無法建立與 {displayName} 的分享",
|
||||
"Are you sure you want to transfer the board {title} for {user}?" : "您想要轉移 {user} 的看板 {title} 嗎?",
|
||||
"Transfer the board." : "轉移看板。",
|
||||
"Transfer" : "轉移",
|
||||
"Transfer the board for {user} successfully" : "轉移 {user} 的看板成功",
|
||||
"Failed to transfer the board for {user}" : "轉移 {user} 的看板失敗",
|
||||
"Add a new list" : "新增列表",
|
||||
"Archive all cards" : "封存所有卡片",
|
||||
"Delete list" : "刪除列表",
|
||||
|
||||
@@ -47,11 +47,9 @@ use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\IConfig;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IL10N;
|
||||
use OCA\Deck\Db\Card;
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
use OCA\Deck\Event\CardCreatedEvent;
|
||||
use OCP\IUserManager;
|
||||
use OCA\Deck\BadRequestException;
|
||||
use OCP\IURLGenerator;
|
||||
@@ -675,39 +673,15 @@ class BoardService {
|
||||
|
||||
$stacks = $this->stackMapper->findAll($id);
|
||||
foreach ($stacks as $stack) {
|
||||
$this->cloneStack($stack, $newBoard->getId());
|
||||
$newStack = new Stack();
|
||||
$newStack->setTitle($stack->getTitle());
|
||||
$newStack->setBoardId($newBoard->getId());
|
||||
$this->stackMapper->insert($newStack);
|
||||
}
|
||||
|
||||
return $newBoard;
|
||||
}
|
||||
|
||||
private function cloneStack($stack, $newBoardId)
|
||||
{
|
||||
$newStack = new Stack();
|
||||
$newStack->setTitle($stack->getTitle());
|
||||
$newStack->setBoardId($newBoardId);
|
||||
$insertedStack = $this->stackMapper->insert($newStack);
|
||||
$cards = $this->cardMapper->findAll($stack->getId());
|
||||
|
||||
foreach ($cards as $card) {
|
||||
$newCard = new Card();
|
||||
$newCard->setTitle($card->getTitle());
|
||||
$newCard->setStackId($insertedStack->getId());
|
||||
$newCard->setType($card->getType());
|
||||
$newCard->setOrder($card->getOrder());
|
||||
$newCard->setOwner($card->getOwner());
|
||||
$newCard->setDescription($card->getDescription());
|
||||
$newCard->setDuedate($card->getDuedate());
|
||||
$newCard = $this->cardMapper->insert($newCard);
|
||||
|
||||
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $newCard, ActivityManager::SUBJECT_CARD_CREATE);
|
||||
$this->changeHelper->cardChanged($newCard->getId(), false);
|
||||
$this->eventDispatcher->dispatchTyped(new CardCreatedEvent($newCard));
|
||||
}
|
||||
|
||||
return $stack;
|
||||
}
|
||||
|
||||
public function transferBoardOwnership(int $boardId, string $newOwner, bool $changeContent = false): Board {
|
||||
\OC::$server->getDatabaseConnection()->beginTransaction();
|
||||
try {
|
||||
|
||||
23
package-lock.json
generated
23
package-lock.json
generated
@@ -20,7 +20,7 @@
|
||||
"@nextcloud/l10n": "^1.4.1",
|
||||
"@nextcloud/moment": "^1.2.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/vue": "^5.3.0",
|
||||
"@nextcloud/vue": "^5.1.1",
|
||||
"@nextcloud/vue-dashboard": "^2.0.1",
|
||||
"blueimp-md5": "^2.19.0",
|
||||
"dompurify": "^2.3.6",
|
||||
@@ -2968,9 +2968,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-5.3.0.tgz",
|
||||
"integrity": "sha512-yRxEeQIgNHafvD2MC//BQXCkyyXiNQQZUGErlwOuuKpZbTX2BYTdvrN15On7rTqJNzwmwuzXAIPIFc0D8c2h+g==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-5.1.1.tgz",
|
||||
"integrity": "sha512-BKJTCqlxRxFvUlc1H95vIoUFXUb6Bcub/VGlIccDg0upm/IKFkyDbuhj7gBUDz4j/uqmKAKffzPO2Q9JFFQ8wg==",
|
||||
"dependencies": {
|
||||
"@nextcloud/auth": "^1.2.3",
|
||||
"@nextcloud/axios": "^1.3.2",
|
||||
@@ -13415,9 +13415,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
|
||||
"version": "1.2.5",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/minimist-options": {
|
||||
"version": "4.1.0",
|
||||
@@ -21191,9 +21190,9 @@
|
||||
}
|
||||
},
|
||||
"@nextcloud/vue": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-5.3.0.tgz",
|
||||
"integrity": "sha512-yRxEeQIgNHafvD2MC//BQXCkyyXiNQQZUGErlwOuuKpZbTX2BYTdvrN15On7rTqJNzwmwuzXAIPIFc0D8c2h+g==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-5.1.1.tgz",
|
||||
"integrity": "sha512-BKJTCqlxRxFvUlc1H95vIoUFXUb6Bcub/VGlIccDg0upm/IKFkyDbuhj7gBUDz4j/uqmKAKffzPO2Q9JFFQ8wg==",
|
||||
"requires": {
|
||||
"@nextcloud/auth": "^1.2.3",
|
||||
"@nextcloud/axios": "^1.3.2",
|
||||
@@ -28913,9 +28912,7 @@
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
|
||||
"version": "1.2.5"
|
||||
},
|
||||
"minimist-options": {
|
||||
"version": "4.1.0",
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"@nextcloud/l10n": "^1.4.1",
|
||||
"@nextcloud/moment": "^1.2.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/vue": "^5.3.0",
|
||||
"@nextcloud/vue": "^5.1.1",
|
||||
"@nextcloud/vue-dashboard": "^2.0.1",
|
||||
"blueimp-md5": "^2.19.0",
|
||||
"dompurify": "^2.3.6",
|
||||
|
||||
11
src/App.vue
11
src/App.vue
@@ -157,10 +157,9 @@ export default {
|
||||
|
||||
.modal__card {
|
||||
min-width: 320px;
|
||||
width: 50vw;
|
||||
max-width: 800px;
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
height: 80vh;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -170,4 +169,10 @@ export default {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modal-wrapper--normal .modal-container{
|
||||
width: 900px !important;
|
||||
height: 800px !important;
|
||||
overflow-y: hidden !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -269,7 +269,7 @@ export default {
|
||||
padding-left: 44px;
|
||||
background-position: 16px center;
|
||||
flex-grow: 1;
|
||||
height: 44px;
|
||||
height: auto;
|
||||
margin-bottom: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
39
src/components/card/AttachmentsTab.vue
Normal file
39
src/components/card/AttachmentsTab.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div v-if="activeTabs.includes('attachment')" class="section-details">
|
||||
<AttachmentList
|
||||
:card-id="card.id"
|
||||
:removable="true"
|
||||
@delete-attachment="deleteAttachment"
|
||||
@restore-attachment="restoreAttachment" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import AttachmentList from './AttachmentList'
|
||||
|
||||
export default {
|
||||
components: { AttachmentList },
|
||||
props: {
|
||||
card: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
activeTabs: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteAttachment(attachment) {
|
||||
this.$store.dispatch('deleteAttachment', attachment)
|
||||
},
|
||||
restoreAttachment(attachment) {
|
||||
this.$store.dispatch('restoreAttachment', attachment)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
460
src/components/card/CardModal.vue
Normal file
460
src/components/card/CardModal.vue
Normal file
@@ -0,0 +1,460 @@
|
||||
<!--
|
||||
- @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
|
||||
-
|
||||
- @author Julius Härtl <jus@bitgrid.net>
|
||||
-
|
||||
- @license GNU AGPL version 3 or any later version
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as
|
||||
- published by the Free Software Foundation, either version 3 of the
|
||||
- License, or (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div v-if="currentCard" ref="modalContainer" class="container">
|
||||
<div :class="{defaultTop: scrollPosition < 100, fixedTop: scrollPosition > 100}">
|
||||
<div class="top">
|
||||
<h1 class="top-title">
|
||||
{{ currentCard.title }}
|
||||
</h1>
|
||||
<p class="top-modified">
|
||||
{{ t('deck', 'Modified') }}: {{ currentCard.lastModified | fromNow }}. {{ t('deck', 'Created') }} {{ currentCard.createdAt | fromNow }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="tabs">
|
||||
<div class="tab members" :class="{active: activeTabs.includes('members')}" @click="changeActiveTab('members')">
|
||||
<i class="icon-user icon" />
|
||||
{{ t('deck', 'Members') }}
|
||||
</div>
|
||||
<div class="tab tags" :class="{active: activeTabs.includes('tags')}" @click="changeActiveTab('tags')">
|
||||
<i class="icon icon-tag" />
|
||||
{{ t('deck', 'Tags') }}
|
||||
</div>
|
||||
<div class="tab due-date" :class="{active: activeTabs.includes('duedate')}" @click="changeActiveTab('duedate')">
|
||||
<i class="icon icon-calendar-dark" />
|
||||
{{ t('deck', 'Due date') }}
|
||||
</div>
|
||||
<div class="tab project" :class="{active: activeTabs.includes('project')}" @click="changeActiveTab('project')">
|
||||
<i class="icon icon-deck" />
|
||||
{{ t('deck', 'Project') }}
|
||||
</div>
|
||||
<div class="tab attachments" :class="{active: activeTabs.includes('attachment')}" @click="changeActiveTab('attachment')">
|
||||
<i class="icon-attach icon icon-attach-dark" />
|
||||
{{ t('deck', 'Attachments') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div :class="[currentCard.labels.length > 3 ? 'content-two-tabs' : 'content-three-tabs']">
|
||||
<MembersTab
|
||||
:card="currentCard"
|
||||
:active-tabs="activeTabs"
|
||||
:current-tab="currentTab"
|
||||
@click="activeTabs.push('members')"
|
||||
@active-tab="changeActiveTab"
|
||||
@remove-active-tab="removeActiveTab" />
|
||||
<TagsTab
|
||||
:active-tabs="activeTabs"
|
||||
:card="currentCard"
|
||||
:current-tab="currentTab"
|
||||
@click="activeTabs.push('tags')"
|
||||
@active-tab="changeActiveTab"
|
||||
@remove-active-tab="removeActiveTab" />
|
||||
<DueDateTab
|
||||
:active-tabs="activeTabs"
|
||||
:card="currentCard"
|
||||
:current-tab="currentTab"
|
||||
@click="activeTabs.push('duedate')"
|
||||
@active-tab="changeActiveTab"
|
||||
@remove-active-tab="removeActiveTab" />
|
||||
<ProjectTab
|
||||
:active-tabs="activeTabs"
|
||||
:card="currentCard"
|
||||
:current-tab="currentTab"
|
||||
@click="activeTabs.push('project')"
|
||||
@active-tab="changeActiveTab" />
|
||||
<AttachmentsTab
|
||||
:active-tabs="activeTabs"
|
||||
:card="currentCard"
|
||||
:current-tab="currentTab"
|
||||
@click="activeTabs.push('attachment')"
|
||||
@active-tab="changeActiveTab" />
|
||||
</div>
|
||||
<Description :key="currentCard.id" :card="currentCard" @change="descriptionChanged" />
|
||||
</div>
|
||||
<div class="activities">
|
||||
<div class="activities-header">
|
||||
<div class="activities-title">
|
||||
<i class="icon-activity" /> {{ t('deck', 'Activity') }}
|
||||
</div>
|
||||
<div class="show-details-btn" @click="showDetails = !showDetails">
|
||||
{{ showDetails ? t('deck', 'Hide details') : t('deck', 'Show details') }}
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="showDetails">
|
||||
<CardSidebarTabComments :card="currentCard" :tab-query="tabQuery" />
|
||||
<ActivityList v-if="hasActivity"
|
||||
filter="deck"
|
||||
:object-id="currentBoard.id"
|
||||
object-type="deck"
|
||||
type="deck" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import relativeDate from '../../mixins/relativeDate'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import MembersTab from './MembersTab.vue'
|
||||
import TagsTab from './TagsTab.vue'
|
||||
import DueDateTab from './DueDateTab.vue'
|
||||
import Description from './Description.vue'
|
||||
import ProjectTab from './ProjectTab.vue'
|
||||
import AttachmentsTab from './AttachmentsTab.vue'
|
||||
import CardSidebarTabComments from './CardSidebarTabComments'
|
||||
import moment from '@nextcloud/moment'
|
||||
import ActivityList from '../ActivityList'
|
||||
|
||||
const capabilities = window.OC.getCapabilities()
|
||||
|
||||
export default {
|
||||
name: 'CardModal',
|
||||
components: {
|
||||
MembersTab,
|
||||
Description,
|
||||
TagsTab,
|
||||
DueDateTab,
|
||||
ProjectTab,
|
||||
AttachmentsTab,
|
||||
CardSidebarTabComments,
|
||||
ActivityList,
|
||||
},
|
||||
filters: {
|
||||
fromNow(value) {
|
||||
return moment.unix(value).fromNow()
|
||||
},
|
||||
},
|
||||
mixins: [relativeDate],
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
tabId: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
tabQuery: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newComment: '',
|
||||
titleEditable: false,
|
||||
titleEditing: '',
|
||||
hasActivity: capabilities && capabilities.activity,
|
||||
currentUser: getCurrentUser(),
|
||||
comment: '',
|
||||
currentTab: null,
|
||||
activeTabs: [],
|
||||
showDetails: false,
|
||||
scrollPosition: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'getCommentsForCard',
|
||||
'hasMoreComments',
|
||||
]),
|
||||
...mapState({
|
||||
currentBoard: state => state.currentBoard,
|
||||
replyTo: state => state.comment.replyTo,
|
||||
}),
|
||||
...mapGetters(['canEdit', 'assignables', 'cardActions', 'stackById']),
|
||||
title() {
|
||||
return this.titleEditable ? this.titleEditing : this.currentCard.title
|
||||
},
|
||||
currentCard() {
|
||||
return this.$store.getters.cardById(this.id)
|
||||
},
|
||||
subtitle() {
|
||||
return t('deck', 'Modified') + ': ' + this.relativeDate(this.currentCard.lastModified * 1000) + ' ' + t('deck', 'Created') + ': ' + this.relativeDate(this.currentCard.createdAt * 1000)
|
||||
},
|
||||
cardRichObject() {
|
||||
return {
|
||||
id: '' + this.currentCard.id,
|
||||
name: this.currentCard.title,
|
||||
boardname: this.currentBoard.title,
|
||||
stackname: this.stackById(this.currentCard.stackId)?.title,
|
||||
link: window.location.protocol + '//' + window.location.host + generateUrl('/apps/deck/') + `#/board/${this.currentBoard.id}/card/${this.currentCard.id}`,
|
||||
}
|
||||
},
|
||||
cardDetailsInModal: {
|
||||
get() {
|
||||
return this.$store.getters.config('cardDetailsInModal')
|
||||
},
|
||||
set(newValue) {
|
||||
this.$store.dispatch('setConfig', { cardDetailsInModal: newValue })
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.modalContainer.addEventListener('scroll', this.onScroll)
|
||||
})
|
||||
this.loadComments()
|
||||
},
|
||||
|
||||
methods: {
|
||||
cancelReply() {
|
||||
this.$store.dispatch('setReplyTo', null)
|
||||
},
|
||||
async createComment(content) {
|
||||
const commentObj = {
|
||||
cardId: this.currentCard.id,
|
||||
comment: content,
|
||||
}
|
||||
await this.$store.dispatch('createComment', commentObj)
|
||||
this.$store.dispatch('setReplyTo', null)
|
||||
this.newComment = ''
|
||||
await this.loadComments()
|
||||
},
|
||||
async loadComments() {
|
||||
this.$store.dispatch('setReplyTo', null)
|
||||
this.error = null
|
||||
this.isLoading = true
|
||||
try {
|
||||
await this.$store.dispatch('fetchComments', { cardId: this.currentCard.id })
|
||||
this.isLoading = false
|
||||
if (this.currentCard.commentsUnread > 0) {
|
||||
await this.$store.dispatch('markCommentsAsRead', this.currentCard.id)
|
||||
}
|
||||
} catch (e) {
|
||||
this.isLoading = false
|
||||
console.error('Failed to fetch more comments during infinite loading', e)
|
||||
this.error = t('deck', 'Failed to load comments')
|
||||
}
|
||||
},
|
||||
descriptionChanged(newDesc) {
|
||||
this.copiedCard.description = newDesc
|
||||
},
|
||||
handleUpdateTitleEditable(value) {
|
||||
this.titleEditable = value
|
||||
if (value) {
|
||||
this.titleEditing = this.currentCard.title
|
||||
}
|
||||
},
|
||||
handleUpdateTitle(value) {
|
||||
this.titleEditing = value
|
||||
},
|
||||
handleSubmitTitle(value) {
|
||||
if (value.trim === '') {
|
||||
showError(t('deck', 'The title cannot be empty.'))
|
||||
return
|
||||
}
|
||||
this.titleEditable = false
|
||||
this.$store.dispatch('updateCardTitle', { ...this.currentCard, title: this.titleEditing })
|
||||
},
|
||||
closeSidebar() {
|
||||
this.$router.push({ name: 'board' })
|
||||
},
|
||||
showModal() {
|
||||
this.$store.dispatch('setConfig', { cardDetailsInModal: true })
|
||||
},
|
||||
closeModal() {
|
||||
this.$store.dispatch('setConfig', { cardDetailsInModal: false })
|
||||
},
|
||||
changeActiveTab(tab) {
|
||||
this.currentTab = tab
|
||||
this.activeTabs = this.activeTabs.filter((item) => !['project', 'attachment'].includes(item))
|
||||
|
||||
if (!this.activeTabs.includes(tab)) {
|
||||
this.activeTabs.push(tab)
|
||||
}
|
||||
|
||||
},
|
||||
removeActiveTab(tab) {
|
||||
const index = this.activeTabs.indexOf(tab)
|
||||
if (index > -1) {
|
||||
this.activeTabs = this.activeTabs.splice(index, 1)
|
||||
}
|
||||
},
|
||||
onScroll() {
|
||||
this.scrollPosition = this.$refs.modalContainer.scrollTop
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.show-details-btn {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
color: var(--color-text-maxcontrast);
|
||||
}
|
||||
|
||||
.activities-header{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.content-two-tabs, .content-three-tabs {
|
||||
display: grid;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.content-two-tabs {
|
||||
grid-template-columns: 1fr 2fr;
|
||||
}
|
||||
|
||||
.content-three-tabs {
|
||||
grid-template-columns: 1fr 2fr 1fr;
|
||||
}
|
||||
|
||||
.icon-activity {
|
||||
background-image: url(../../../img/flash-black.svg);
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.icon-plus {
|
||||
background-image: url(../../../img/plus.svg);
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.log-item {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
line-height: 45px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.activities {
|
||||
&-title{
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
margin-top: 100px;
|
||||
padding-left: 20px !important;
|
||||
padding-right: 20px !important;
|
||||
}
|
||||
|
||||
.content{
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.comments {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
&-input{
|
||||
width: 100%;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.comment-form{
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
overflow-y: scroll;
|
||||
height: 800px;
|
||||
}
|
||||
|
||||
.top {
|
||||
padding: 20px 20px 0px 20px;
|
||||
&-title {
|
||||
color: black;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
&-modified {
|
||||
color: #767676;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 5px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tab {
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
background-color: #ededed;
|
||||
color: rgb(0, 0, 0);
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
padding: 10px 20px;
|
||||
border-radius: 10px;
|
||||
font-size: 85%;
|
||||
margin-bottom: 3px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.edit-btns {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.description {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #409eff;
|
||||
background-color: #ecf5ff;
|
||||
}
|
||||
|
||||
.fixedTop {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: #ffffff;
|
||||
z-index: 1000;
|
||||
margin-top: 0px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,19 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="comment--header">
|
||||
<Avatar :user="currentUser.uid" />
|
||||
<span class="has-tooltip username">
|
||||
{{ currentUser.displayName }}
|
||||
</span>
|
||||
<div class="comment-wrapper">
|
||||
<div class="comment--header">
|
||||
<Avatar :user="currentUser.uid" />
|
||||
</div>
|
||||
<CommentItem v-if="replyTo"
|
||||
:comment="replyTo"
|
||||
:reply="true"
|
||||
:preview="true"
|
||||
@cancel="cancelReply" />
|
||||
<CommentForm v-model="newComment" @submit="createComment" />
|
||||
</div>
|
||||
|
||||
<CommentItem v-if="replyTo"
|
||||
:comment="replyTo"
|
||||
:reply="true"
|
||||
:preview="true"
|
||||
@cancel="cancelReply" />
|
||||
<CommentForm v-model="newComment" @submit="createComment" />
|
||||
|
||||
<ul v-if="getCommentsForCard(card.id).length > 0" id="commentsFeed">
|
||||
<CommentItem v-for="comment in getCommentsForCard(card.id)"
|
||||
:key="comment.id"
|
||||
@@ -26,8 +23,7 @@
|
||||
</InfiniteLoading>
|
||||
</ul>
|
||||
<div v-else-if="isLoading" class="icon icon-loading" />
|
||||
<div v-else class="emptycontent">
|
||||
<div :class="{ 'icon-comment': !error, 'icon-error': error }" />
|
||||
<div v-else>
|
||||
<p>{{ error || t('deck', 'No comments yet. Begin the discussion!') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -280,7 +280,9 @@ h5 {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
margin-top: 20px;
|
||||
margin-bottom: 5px;
|
||||
color: var(--color-text-maxcontrast);
|
||||
color: var(--color-main-text);
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
|
||||
.icon-info {
|
||||
display: inline-block;
|
||||
|
||||
187
src/components/card/DueDateTab.vue
Normal file
187
src/components/card/DueDateTab.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<div v-if="activeTabs.includes('duedate') || (copiedCard && copiedCard.duedate)"
|
||||
v-show="!['project', 'attachment'].includes(currentTab)"
|
||||
class="section-details">
|
||||
<div @click="$emit('active-tab', 'duedate')">
|
||||
<DatetimePicker v-model="duedate"
|
||||
:placeholder="t('deck', 'Set a due date')"
|
||||
type="datetime"
|
||||
:minute-step="5"
|
||||
:show-second="false"
|
||||
:lang="lang"
|
||||
:disabled="saving || !canEdit"
|
||||
:shortcuts="shortcuts"
|
||||
confirm />
|
||||
</div>
|
||||
<Actions v-if="canEdit">
|
||||
<ActionButton v-if="copiedCard.duedate" icon="icon-delete" @click="removeDue()">
|
||||
{{ t('deck', 'Remove due date') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { DatetimePicker, Actions, ActionButton } from '@nextcloud/vue'
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import Color from '../../mixins/color'
|
||||
import labelStyle from '../../mixins/labelStyle'
|
||||
import {
|
||||
getDayNamesMin,
|
||||
getFirstDay,
|
||||
getMonthNamesShort,
|
||||
} from '@nextcloud/l10n'
|
||||
import moment from '@nextcloud/moment'
|
||||
|
||||
export default {
|
||||
components: { DatetimePicker, Actions, ActionButton },
|
||||
mixins: [Color, labelStyle],
|
||||
props: {
|
||||
card: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
activeTabs: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
currentTab: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
saving: false,
|
||||
copiedCard: null,
|
||||
lang: {
|
||||
days: getDayNamesMin(),
|
||||
months: getMonthNamesShort(),
|
||||
formatLocale: {
|
||||
firstDayOfWeek: getFirstDay() === 0 ? 7 : getFirstDay(),
|
||||
},
|
||||
placeholder: {
|
||||
date: t('deck', 'Select Date'),
|
||||
},
|
||||
},
|
||||
format: {
|
||||
stringify: this.stringify,
|
||||
parse: this.parse,
|
||||
},
|
||||
shortcuts: [
|
||||
{
|
||||
text: t('deck', 'Today'),
|
||||
onClick() {
|
||||
const date = new Date()
|
||||
date.setDate(date.getDate())
|
||||
date.setHours(23)
|
||||
date.setMinutes(59)
|
||||
return date
|
||||
},
|
||||
},
|
||||
{
|
||||
text: t('deck', 'Tomorrow'),
|
||||
onClick() {
|
||||
const date = new Date()
|
||||
date.setDate(date.getDate() + 1)
|
||||
date.setHours(23)
|
||||
date.setMinutes(59)
|
||||
return date
|
||||
},
|
||||
},
|
||||
{
|
||||
text: t('deck', 'Next week'),
|
||||
onClick() {
|
||||
const date = new Date()
|
||||
date.setDate(date.getDate() + 7)
|
||||
date.setHours(23)
|
||||
date.setMinutes(59)
|
||||
return date
|
||||
},
|
||||
},
|
||||
{
|
||||
text: t('deck', 'Next month'),
|
||||
onClick() {
|
||||
const date = new Date()
|
||||
date.setDate(date.getDate() + 30)
|
||||
date.setHours(23)
|
||||
date.setMinutes(59)
|
||||
return date
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
currentBoard: state => state.currentBoard,
|
||||
}),
|
||||
...mapGetters(['canEdit']),
|
||||
labelsSorted() {
|
||||
return [...this.currentBoard.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
||||
},
|
||||
duedate: {
|
||||
get() {
|
||||
return this.card.duedate ? new Date(this.card.duedate) : null
|
||||
},
|
||||
async set(val) {
|
||||
this.saving = true
|
||||
await this.$store.dispatch('updateCardDue', {
|
||||
...this.copiedCard,
|
||||
duedate: val ? moment(val).format('YYYY-MM-DD H:mm:ss') : null,
|
||||
})
|
||||
this.saving = false
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
card() {
|
||||
this.initialize()
|
||||
if (this.copiedCard.duedate) {
|
||||
this.$emit('active-tab', 'duedate')
|
||||
} else {
|
||||
this.$emit('remove-active-tab', 'duedate')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initialize()
|
||||
if (this.copiedCard.duedate) {
|
||||
this.$emit('active-tab', 'duedate')
|
||||
} else {
|
||||
this.$emit('remove-active-tab', 'duedate')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async initialize() {
|
||||
if (!this.card) {
|
||||
return
|
||||
}
|
||||
|
||||
this.copiedCard = JSON.parse(JSON.stringify(this.card))
|
||||
},
|
||||
removeDue() {
|
||||
this.copiedCard.duedate = null
|
||||
this.$store.dispatch('updateCardDue', this.copiedCard)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.section-details{
|
||||
margin-right: 5px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.section-details .mx-input{
|
||||
height: 36px !important;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.section-details .action-item {
|
||||
height: 30px !important;
|
||||
}
|
||||
</style>
|
||||
208
src/components/card/MembersTab.vue
Normal file
208
src/components/card/MembersTab.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<div v-if="activeTabs.includes('members') || (assignedUsers && assignedUsers.length > 0)"
|
||||
v-show="!['project', 'attachment'].includes(currentTab)"
|
||||
class="section-details">
|
||||
<div v-if="showSelelectMembers" @mouseleave="showSelelectMembers = false">
|
||||
<Multiselect v-if="canEdit"
|
||||
v-model="assignedUsers"
|
||||
:multiple="true"
|
||||
:options="formatedAssignables"
|
||||
:user-select="true"
|
||||
:auto-limit="false"
|
||||
:placeholder="t('deck', 'Assign a user to this card…')"
|
||||
label="displayname"
|
||||
track-by="multiselectKey"
|
||||
@select="assignUserToCard"
|
||||
@remove="removeUserFromCard">
|
||||
<template #tag="scope">
|
||||
<div class="avatarlist--inline">
|
||||
<Avatar :user="scope.option.uid"
|
||||
:display-name="scope.option.displayname"
|
||||
:size="24"
|
||||
:is-no-user="scope.option.isNoUser"
|
||||
:disable-menu="true" />
|
||||
</div>
|
||||
</template>
|
||||
</Multiselect>
|
||||
<div v-else class="avatar-list--readonly">
|
||||
<Avatar v-for="option in assignedUsers"
|
||||
:key="option.primaryKey"
|
||||
:user="option.uid"
|
||||
:display-name="option.displayname"
|
||||
:is-no-user="option.isNoUser"
|
||||
:size="32" />
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="members">
|
||||
<Avatar v-for="option in assignedUsers"
|
||||
:key="option.primaryKey"
|
||||
:user="option.uid"
|
||||
:display-name="option.displayname"
|
||||
:is-no-user="option.isNoUser"
|
||||
:size="32" />
|
||||
<div class="button new select-member-btn" @click="selectMembers">
|
||||
<span class="icon icon-add" />
|
||||
<span class="hidden-visually" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Multiselect, Avatar } from '@nextcloud/vue'
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'MembersTab',
|
||||
components: {
|
||||
Multiselect,
|
||||
Avatar,
|
||||
},
|
||||
props: {
|
||||
card: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
activeTabs: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
currentTab: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
assignedUsers: null,
|
||||
copiedCard: null,
|
||||
showSelelectMembers: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
currentBoard: state => state.currentBoard,
|
||||
}),
|
||||
...mapGetters(['canEdit', 'assignables']),
|
||||
formatedAssignables() {
|
||||
return this.assignables.map(item => {
|
||||
const assignable = {
|
||||
...item,
|
||||
user: item.primaryKey,
|
||||
displayName: item.displayname,
|
||||
icon: 'icon-user',
|
||||
isNoUser: false,
|
||||
multiselectKey: item.type + ':' + item.uid,
|
||||
}
|
||||
|
||||
if (item.type === 1) {
|
||||
assignable.icon = 'icon-group'
|
||||
assignable.isNoUser = true
|
||||
}
|
||||
if (item.type === 7) {
|
||||
assignable.icon = 'icon-circles'
|
||||
assignable.isNoUser = true
|
||||
}
|
||||
|
||||
return assignable
|
||||
})
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
card() {
|
||||
this.initialize()
|
||||
},
|
||||
assignedUsers(value) {
|
||||
if (value.length > 0) {
|
||||
this.$emit('active-tab', 'members')
|
||||
} else {
|
||||
this.$emit('remove-active-tab', 'members')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initialize()
|
||||
},
|
||||
methods: {
|
||||
selectMembers() {
|
||||
this.showSelelectMembers = true
|
||||
this.$emit('active-tab', 'members')
|
||||
},
|
||||
removeUserFromCard(user) {
|
||||
this.$store.dispatch('removeUserFromCard', {
|
||||
card: this.copiedCard,
|
||||
assignee: {
|
||||
userId: user.uid,
|
||||
type: user.type,
|
||||
},
|
||||
})
|
||||
},
|
||||
addLabelToCard(newLabel) {
|
||||
this.copiedCard.labels.push(newLabel)
|
||||
const data = {
|
||||
card: this.copiedCard,
|
||||
labelId: newLabel.id,
|
||||
}
|
||||
this.$store.dispatch('addLabel', data)
|
||||
},
|
||||
assignUserToCard(user) {
|
||||
this.$store.dispatch('assignCardToUser', {
|
||||
card: this.copiedCard,
|
||||
assignee: {
|
||||
userId: user.uid,
|
||||
type: user.type,
|
||||
},
|
||||
})
|
||||
},
|
||||
async initialize() {
|
||||
if (!this.card) {
|
||||
return
|
||||
}
|
||||
|
||||
this.copiedCard = JSON.parse(JSON.stringify(this.card))
|
||||
this.assignedLabels = [...this.card.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
||||
|
||||
if (this.card.assignedUsers && this.card.assignedUsers.length > 0) {
|
||||
this.assignedUsers = this.card.assignedUsers.map((item) => ({
|
||||
...item.participant,
|
||||
isNoUser: item.participant.type !== 0,
|
||||
multiselectKey: item.participant.type + ':' + item.participant.primaryKey,
|
||||
}))
|
||||
} else {
|
||||
this.assignedUsers = []
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.select-member-btn {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
height: 32px;
|
||||
width: 34px;
|
||||
padding: 5px 9px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.section-details {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.members {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.members .multiselect__tags{
|
||||
height: 34px !important;
|
||||
}
|
||||
</style>
|
||||
53
src/components/card/ProjectTab.vue
Normal file
53
src/components/card/ProjectTab.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div v-if="activeTabs.includes('project')" class="section-details">
|
||||
<div class="section-wrapper project-tab">
|
||||
<CollectionList v-if="card.id"
|
||||
:id="`${card.id}`"
|
||||
:name="card.title"
|
||||
type="deck-card" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { CollectionList } from 'nextcloud-vue-collections'
|
||||
export default {
|
||||
components: { CollectionList },
|
||||
props: {
|
||||
card: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
activeTabs: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.section-details{
|
||||
margin-top: 10px;
|
||||
min-width: 500px;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
#collection-select-container p {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#collection-list li {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.project-tab .collection-list-item {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
|
||||
.project-tab .linked-icons {
|
||||
img {
|
||||
height: 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
171
src/components/card/TagsTab.vue
Normal file
171
src/components/card/TagsTab.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div v-if="activeTabs.includes('tags') || card.labels.length > 0"
|
||||
v-show="!['project', 'attachment'].includes(currentTab)"
|
||||
class="section-details">
|
||||
<div v-if="showSelelectTags || card.labels.length <= 0" @mouseleave="showSelelectTags = false">
|
||||
<Multiselect v-model="assignedLabels"
|
||||
:multiple="true"
|
||||
:disabled="!canEdit"
|
||||
:options="labelsSorted"
|
||||
:placeholder="t('deck', 'Assign a tag to this card')"
|
||||
:taggable="true"
|
||||
label="title"
|
||||
track-by="id"
|
||||
@select="addLabelToCard"
|
||||
@remove="removeLabelFromCard">
|
||||
<template #option="scope">
|
||||
<div :style="{ backgroundColor: '#' + scope.option.color, color: textColor(scope.option.color)}" class="tag">
|
||||
{{ scope.option.title }}
|
||||
</div>
|
||||
</template>
|
||||
<template #tag="scope">
|
||||
<div :style="{ backgroundColor: '#' + scope.option.color, color: textColor(scope.option.color)}" class="tag">
|
||||
{{ scope.option.title }}
|
||||
</div>
|
||||
</template>
|
||||
</Multiselect>
|
||||
</div>
|
||||
<div v-else-if="card.labels.length > 0" class="labels">
|
||||
<div v-for="label in card.labels"
|
||||
:key="label.id"
|
||||
:style="labelStyle(label)"
|
||||
class="labels-item">
|
||||
<span @click.stop="applyLabelFilter(label)">{{ label.title }}</span>
|
||||
</div>
|
||||
<div class="button new select-tag" @click="add">
|
||||
<span class="icon icon-add" />
|
||||
<span class="hidden-visually" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { Multiselect } from '@nextcloud/vue'
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import Color from '../../mixins/color'
|
||||
import labelStyle from '../../mixins/labelStyle'
|
||||
|
||||
export default {
|
||||
components: { Multiselect },
|
||||
mixins: [Color, labelStyle],
|
||||
props: {
|
||||
card: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
activeTabs: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
currentTab: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
assignedLabels: null,
|
||||
showSelelectTags: false,
|
||||
copiedCard: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
currentBoard: state => state.currentBoard,
|
||||
}),
|
||||
...mapGetters(['canEdit']),
|
||||
labelsSorted() {
|
||||
return [...this.currentBoard.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
card(value) {
|
||||
if (value.labels.length > 0) {
|
||||
this.$emit('active-tab', 'tags')
|
||||
} else {
|
||||
this.$emit('remove-active-tab', 'tags')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initialize()
|
||||
if (this.card.labels.length > 0) {
|
||||
this.$emit('active-tab', 'tags')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
add() {
|
||||
this.showSelelectTags = true
|
||||
this.$emit('active-tab', 'tags')
|
||||
},
|
||||
async initialize() {
|
||||
if (!this.card) {
|
||||
return
|
||||
}
|
||||
|
||||
this.copiedCard = JSON.parse(JSON.stringify(this.card))
|
||||
this.assignedLabels = [...this.card.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
||||
},
|
||||
openCard() {
|
||||
const boardId = this.card && this.card.boardId ? this.card.boardId : this.$route.params.id
|
||||
this.$router.push({ name: 'card', params: { id: boardId, cardId: this.card.id } }).catch(() => {})
|
||||
},
|
||||
addLabelToCard(newLabel) {
|
||||
this.copiedCard.labels.push(newLabel)
|
||||
const data = {
|
||||
card: this.copiedCard,
|
||||
labelId: newLabel.id,
|
||||
}
|
||||
this.$store.dispatch('addLabel', data)
|
||||
},
|
||||
removeLabelFromCard(removedLabel) {
|
||||
|
||||
const removeIndex = this.copiedCard.labels.findIndex((label) => {
|
||||
return label.id === removedLabel.id
|
||||
})
|
||||
if (removeIndex !== -1) {
|
||||
this.copiedCard.labels.splice(removeIndex, 1)
|
||||
}
|
||||
|
||||
const data = {
|
||||
card: this.copiedCard,
|
||||
labelId: removedLabel.id,
|
||||
}
|
||||
this.$store.dispatch('removeLabel', data)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.labels {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
|
||||
&-item {
|
||||
border-radius: 15px;
|
||||
margin-right: 5px;
|
||||
min-width: 110px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.select-tag {
|
||||
height: 32px;
|
||||
width: 34px;
|
||||
padding: 5px 8px;
|
||||
}
|
||||
|
||||
.tag{
|
||||
padding: 0px 5px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.section-details{
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -135,7 +135,7 @@ export default {
|
||||
},
|
||||
activeBoards() {
|
||||
return this.$store.getters.boards.filter((item) => item.deletedAt === 0 && item.archived === false)
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openCard() {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-text-light);
|
||||
margin-right: 10px;
|
||||
|
||||
.username {
|
||||
padding: 10px;
|
||||
@@ -50,3 +51,16 @@
|
||||
margin-left: 44px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.comment-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.comment-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.comment-form .comment-form__contenteditable {
|
||||
border-radius: 4px;
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import Boards from './components/boards/Boards'
|
||||
import Board from './components/board/Board'
|
||||
import Sidebar from './components/Sidebar'
|
||||
import BoardSidebar from './components/board/BoardSidebar'
|
||||
import CardSidebar from './components/card/CardSidebar'
|
||||
import CardModal from './components/card/CardModal'
|
||||
import Overview from './components/overview/Overview'
|
||||
|
||||
Vue.use(Router)
|
||||
@@ -119,7 +119,7 @@ export default new Router({
|
||||
path: 'card/:cardId/:tabId?/:tabQuery?',
|
||||
name: 'card',
|
||||
components: {
|
||||
sidebar: CardSidebar,
|
||||
sidebar: CardModal,
|
||||
},
|
||||
props: {
|
||||
default: (route) => {
|
||||
|
||||
Reference in New Issue
Block a user