Compare commits

..

55 Commits

Author SHA1 Message Date
Julius Härtl
40ac9b6c3e fix: Avoid double tap on iOS and close navigation on click
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:29 +02:00
Julius Härtl
06fcf8f2cd fix: Auto-scroll horizontally
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:28 +02:00
Julius Härtl
2f0241df2e fix: Hide navigation initially on mobile
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:28 +02:00
Julius Härtl
34ff6f4aac fix: Proper drag zone height (fix #6264)
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:28 +02:00
Julius Härtl
40f7f0907a fix: Fix modal sizing, focus error and cover image sizing
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:28 +02:00
Julius Härtl
0e5006616e fix: Set proper name on modal
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:28 +02:00
Julius Härtl
792a513bb5 fix: Fix focus and emptycontent titles
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:28 +02:00
Julius Härtl
a9b65de341 fix: Move card create input to the bottom
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:27 +02:00
Julius Härtl
a0fc1bbeb8 fix: Fix empty board view design
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:27 +02:00
Julius Härtl
482bcb3149 fix: Fix styling of navigation input fields
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 08:09:27 +02:00
Julius Härtl
cf0b90369a fix: Adapt spacing to new compact design
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 07:59:42 +02:00
Julius Härtl
a0bcbc5cc6 fix: Proper slots for card selector dialog
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 07:59:42 +02:00
Julius Härtl
e73eec8ba4 fix: Avoid swipe navigation while scrolling
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 07:59:42 +02:00
Julius Härtl
c1ed33848c fix: Properly scroll on mobile devices
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-09-02 07:59:42 +02:00
github-actions[bot]
d9d75fdfe4 Merge pull request #6284 from nextcloud/automated/noid/main-update-nextcloud-ocp
[main] Update nextcloud/ocp dependency
2024-09-01 04:57:53 +00:00
nextcloud-command
c348b824c8 chore(dev-deps): Bump nextcloud/ocp package
Signed-off-by: GitHub <noreply@github.com>
2024-09-01 03:02:56 +00:00
Nextcloud bot
39987a0303 Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-09-01 00:41:40 +00:00
dependabot[bot]
0906b06192 Merge pull request #6270 from nextcloud/dependabot/npm_and_yarn/main/cypress-13.14.1 2024-08-31 03:38:18 +00:00
dependabot[bot]
434f59d06d Chore(deps-dev): Bump cypress from 13.13.3 to 13.14.1
Bumps [cypress](https://github.com/cypress-io/cypress) from 13.13.3 to 13.14.1.
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/cypress-io/cypress/compare/v13.13.3...v13.14.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-31 02:56:18 +00:00
dependabot[bot]
af4c01abd4 Merge pull request #6268 from nextcloud/dependabot/npm_and_yarn/main/babel/runtime-7.25.6 2024-08-31 02:55:55 +00:00
dependabot[bot]
516bc6d5fc Merge pull request #6269 from nextcloud/dependabot/npm_and_yarn/main/nextcloud/vue-8.17.1 2024-08-31 02:55:38 +00:00
dependabot[bot]
d7b3aedab4 Merge pull request #6267 from nextcloud/dependabot/npm_and_yarn/main/relative-ci/agent-4.2.11 2024-08-31 02:55:26 +00:00
dependabot[bot]
fb641946d6 Chore(deps): Bump @nextcloud/vue from 8.17.0 to 8.17.1
Bumps [@nextcloud/vue](https://github.com/nextcloud-libraries/nextcloud-vue) from 8.17.0 to 8.17.1.
- [Release notes](https://github.com/nextcloud-libraries/nextcloud-vue/releases)
- [Changelog](https://github.com/nextcloud-libraries/nextcloud-vue/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud-libraries/nextcloud-vue/compare/v8.17.0...v8.17.1)

---
updated-dependencies:
- dependency-name: "@nextcloud/vue"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-31 01:39:08 +00:00
dependabot[bot]
b3bc532e81 Chore(deps): Bump @babel/runtime from 7.25.4 to 7.25.6
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.25.4 to 7.25.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.6/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-31 01:38:48 +00:00
dependabot[bot]
fe1006d643 Chore(deps-dev): Bump @relative-ci/agent from 4.2.10 to 4.2.11
Bumps [@relative-ci/agent](https://github.com/relative-ci/agent) from 4.2.10 to 4.2.11.
- [Release notes](https://github.com/relative-ci/agent/releases)
- [Commits](https://github.com/relative-ci/agent/compare/v4.2.10...v4.2.11)

---
updated-dependencies:
- dependency-name: "@relative-ci/agent"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-31 01:38:32 +00:00
Julius Härtl
9a37d6dbfc Merge pull request #6266 from nextcloud/dependabot/npm_and_yarn/webpack-5.94.0 2024-08-30 20:15:19 +02:00
dependabot[bot]
bf704309ad Chore(deps-dev): Bump webpack from 5.88.2 to 5.94.0
Bumps [webpack](https://github.com/webpack/webpack) from 5.88.2 to 5.94.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.88.2...v5.94.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-30 17:49:09 +00:00
Nextcloud bot
635cf3962f Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-08-30 00:56:02 +00:00
Julius Härtl
43a0fec9a6 Merge pull request #6257 from nextcloud/fix/no-cross-referencing-in-labels
copy labels when moving cards between boards
2024-08-29 12:30:17 +02:00
Julius Härtl
c6c41c59d2 Merge pull request #6232 from nextcloud/fix/nextcloud-30-design-issues
fix: 30 design issues
2024-08-29 12:28:53 +02:00
Julius Härtl
fb54b8126a fix: Avoid duplicate scrollbars
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-08-29 11:36:23 +02:00
Luka Trovic
a4f2a99776 fix: 30 design issues
Signed-off-by: Luka Trovic <luka@nextcloud.com>
2024-08-29 11:19:30 +02:00
grnd-alt
dbca6bc0d7 copy labels when moving cards between boards
Signed-off-by: grnd-alt <salimbelakkaf@outlook.de>
2024-08-28 11:59:34 +02:00
Nextcloud bot
e647faf31c Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-08-28 00:41:42 +00:00
Julius Härtl
fdd05853af Merge pull request #6260 from nextcloud/Jerome-Herbinet-translation-call-fix
Translation call fix
2024-08-26 13:19:55 +02:00
Jérôme Herbinet
afd8372baa Translation call fix
Signed-off-by: Jérôme Herbinet <33763786+Jerome-Herbinet@users.noreply.github.com>
2024-08-26 13:12:35 +02:00
Julius Härtl
f99d1f516c Merge pull request #6259 from Dinock/patch-1
Fixed a typo in Markdown.md
2024-08-26 13:01:54 +02:00
Dinock
1aa23407f1 Update Markdown.md
Fixed a typo in the sentence "Markdown comes in may flavors.". (old="may", new="many")

Signed-off-by: Dinock <54438803+Dinock@users.noreply.github.com>
2024-08-26 12:44:19 +02:00
Julius Härtl
83d59dd3a9 Merge pull request #6235 from nextcloud/fix/ui
Fix UI with the new compact design
2024-08-26 12:43:24 +02:00
dependabot[bot]
2233786605 Merge pull request #6236 from nextcloud/dependabot/composer/nextcloud/coding-standard-1.2.3 2024-08-26 06:21:33 +00:00
Julius Härtl
2d2f7c6772 Merge pull request #6240 from nextcloud/dependabot/github_actions/mdecoleman/pr-branch-name-3.0.0
Chore(deps): Bump mdecoleman/pr-branch-name from 2.0.0 to 3.0.0
2024-08-26 08:15:21 +02:00
dependabot[bot]
ba3e97b73d Chore(deps-dev): Bump nextcloud/coding-standard from 1.2.1 to 1.2.3
Bumps [nextcloud/coding-standard](https://github.com/nextcloud/coding-standard) from 1.2.1 to 1.2.3.
- [Release notes](https://github.com/nextcloud/coding-standard/releases)
- [Changelog](https://github.com/nextcloud/coding-standard/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud/coding-standard/compare/v1.2.1...v1.2.3)

---
updated-dependencies:
- dependency-name: nextcloud/coding-standard
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-26 08:14:42 +02:00
Julius Härtl
4107481b07 Merge pull request #6237 from nextcloud/dependabot/npm_and_yarn/main/chroma-js-3.0.0
Chore(deps): Bump chroma-js from 2.6.0 to 3.0.0
2024-08-26 08:11:37 +02:00
Julius Härtl
6e158992dc Merge pull request #6253 from nextcloud/automated/noid/main-fix-npm-audit
[main] Fix npm audit
2024-08-26 08:11:18 +02:00
nextcloud-command
0e4c60c23f fix(deps): Fix npm audit
Signed-off-by: GitHub <noreply@github.com>
2024-08-25 03:08:35 +00:00
dependabot[bot]
702672de28 Chore(deps): Bump chroma-js from 2.6.0 to 3.0.0
Bumps [chroma-js](https://github.com/gka/chroma.js) from 2.6.0 to 3.0.0.
- [Release notes](https://github.com/gka/chroma.js/releases)
- [Changelog](https://github.com/gka/chroma.js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gka/chroma.js/compare/v2.6.0...v3.0.0)

---
updated-dependencies:
- dependency-name: chroma-js
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-24 08:12:19 +00:00
Julius Härtl
48bdf83887 Merge pull request #6238 from nextcloud/dependabot/npm_and_yarn/main/nextcloud/vue-8.17.0 2024-08-24 10:11:32 +02:00
dependabot[bot]
520a0f8c26 Merge pull request #6239 from nextcloud/dependabot/npm_and_yarn/main/babel/runtime-7.25.4 2024-08-24 02:16:38 +00:00
dependabot[bot]
b84564b0f7 Chore(deps): Bump mdecoleman/pr-branch-name from 2.0.0 to 3.0.0
Bumps [mdecoleman/pr-branch-name](https://github.com/mdecoleman/pr-branch-name) from 2.0.0 to 3.0.0.
- [Release notes](https://github.com/mdecoleman/pr-branch-name/releases)
- [Commits](bab4c71506...55795d86b4)

---
updated-dependencies:
- dependency-name: mdecoleman/pr-branch-name
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-24 01:19:34 +00:00
dependabot[bot]
ba33a83e9f Chore(deps): Bump @babel/runtime from 7.25.0 to 7.25.4
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.25.0 to 7.25.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.4/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-24 01:11:07 +00:00
dependabot[bot]
b645c1e974 Chore(deps): Bump @nextcloud/vue from 8.16.0 to 8.17.0
Bumps [@nextcloud/vue](https://github.com/nextcloud-libraries/nextcloud-vue) from 8.16.0 to 8.17.0.
- [Release notes](https://github.com/nextcloud-libraries/nextcloud-vue/releases)
- [Changelog](https://github.com/nextcloud-libraries/nextcloud-vue/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nextcloud-libraries/nextcloud-vue/compare/v8.16.0...v8.17.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-24 01:10:48 +00:00
Nextcloud bot
3daad1b9bc Fix(l10n): Update translations from Transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2024-08-24 00:38:58 +00:00
Julius Härtl
5416a2b3a1 fix: Adjust UI to be more consistent with new Nextcloud compact UI
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-08-23 20:13:09 +02:00
Julius Härtl
5c3098afa1 fix: Hide inline search box as the global one is working now
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-08-23 20:11:48 +02:00
Julius Härtl
e25470ece3 Merge pull request #6234 from nextcloud/automated/update-workflows/default 2024-08-23 09:26:53 +02:00
77 changed files with 739 additions and 457 deletions

View File

@@ -39,7 +39,7 @@ jobs:
echo 'Can not approve PRs from forks'
exit 1
- uses: mdecoleman/pr-branch-name@bab4c71506bcd299fb350af63bb8e53f2940a599 # v2.0.0
- uses: mdecoleman/pr-branch-name@55795d86b4566d300d237883103f052125cc7508 # v3.0.0
id: branchname
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

32
composer.lock generated
View File

@@ -399,16 +399,16 @@
},
{
"name": "nextcloud/coding-standard",
"version": "v1.2.1",
"version": "v1.2.3",
"source": {
"type": "git",
"url": "https://github.com/nextcloud/coding-standard.git",
"reference": "cf5f18d989ec62fb4cdc7fc92a36baf34b3d829e"
"reference": "bc9c53a5306114b60c4363057aff9c2ed10a54da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/cf5f18d989ec62fb4cdc7fc92a36baf34b3d829e",
"reference": "cf5f18d989ec62fb4cdc7fc92a36baf34b3d829e",
"url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/bc9c53a5306114b60c4363057aff9c2ed10a54da",
"reference": "bc9c53a5306114b60c4363057aff9c2ed10a54da",
"shasum": ""
},
"require": {
@@ -434,9 +434,9 @@
"description": "Nextcloud coding standards for the php cs fixer",
"support": {
"issues": "https://github.com/nextcloud/coding-standard/issues",
"source": "https://github.com/nextcloud/coding-standard/tree/v1.2.1"
"source": "https://github.com/nextcloud/coding-standard/tree/v1.2.3"
},
"time": "2024-02-01T14:54:37+00:00"
"time": "2024-08-23T14:32:32+00:00"
},
{
"name": "nextcloud/ocp",
@@ -444,12 +444,12 @@
"source": {
"type": "git",
"url": "https://github.com/nextcloud-deps/ocp.git",
"reference": "b0127d6fd2932bf1fdffe334ae59fdd6c8272029"
"reference": "b6538d7f14472c2ef6182c51df6be34cae033099"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/b0127d6fd2932bf1fdffe334ae59fdd6c8272029",
"reference": "b0127d6fd2932bf1fdffe334ae59fdd6c8272029",
"url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/b6538d7f14472c2ef6182c51df6be34cae033099",
"reference": "b6538d7f14472c2ef6182c51df6be34cae033099",
"shasum": ""
},
"require": {
@@ -481,7 +481,7 @@
"issues": "https://github.com/nextcloud-deps/ocp/issues",
"source": "https://github.com/nextcloud-deps/ocp/tree/master"
},
"time": "2024-08-14T08:51:54+00:00"
"time": "2024-08-31T00:39:40+00:00"
},
{
"name": "nikic/php-parser",
@@ -661,16 +661,16 @@
},
{
"name": "php-cs-fixer/shim",
"version": "v3.49.0",
"version": "v3.62.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/shim.git",
"reference": "f7d3219cac46632f12362c9aa7c2ac0d2fe92c52"
"reference": "7a91d5ce45c486f5b445d95901228507a02f60ae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/f7d3219cac46632f12362c9aa7c2ac0d2fe92c52",
"reference": "f7d3219cac46632f12362c9aa7c2ac0d2fe92c52",
"url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/7a91d5ce45c486f5b445d95901228507a02f60ae",
"reference": "7a91d5ce45c486f5b445d95901228507a02f60ae",
"shasum": ""
},
"require": {
@@ -707,9 +707,9 @@
"description": "A tool to automatically fix PHP code style",
"support": {
"issues": "https://github.com/PHP-CS-Fixer/shim/issues",
"source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.49.0"
"source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.62.0"
},
"time": "2024-02-02T00:42:09+00:00"
"time": "2024-08-07T17:03:46+00:00"
},
{
"name": "phpunit/php-code-coverage",

View File

@@ -35,7 +35,7 @@ describe('Board', function() {
.type(board, { force: true })
// Submit
cy.get('.board-create form input[type=submit]')
cy.get('.board-create form button[type=submit]')
.first().click({ force: true })
cy.wait('@createBoardRequest').its('response.statusCode').should('equal', 200)

View File

@@ -13,7 +13,7 @@ The Deck application plugin uses the [markdown-it](https://github.com/markdown-i
## Supported Markdown
Markdown comes in may flavors. The best way to learn markdown and understand how to use it, is simply to [try it](https://markdown-it.github.io) on the original script official playground.
Markdown comes in many flavors. The best way to learn markdown and understand how to use it, is simply to [try it](https://markdown-it.github.io) on the original script official playground.
That same link offers also a comprehensive list of what is supported, and what is not - rendering it unnecessary to duplicate that content in here.
[CommonMark Markdown Reference](http://commonmark.org/help/)

View File

@@ -34,9 +34,14 @@ OC.L10N.register(
"Later" : "Después",
"copy" : "copiar",
"Done" : "Hecho",
"The file was uploaded" : "El archivo ha sido subido",
"The uploaded file exceeds the upload_max_filesize directive in php.ini" : "El archivo cargado excede el valor establecido en la directiva upload_max_filesize en el archivo php.ini",
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" : "El archivo subido sobrepasa el valor MAX_FILE_SIZE especificada en el formulario HTML",
"The file was only partially uploaded" : "El archivo sólo fue cargado parcialmente",
"No file was uploaded" : "No se subió ningún archivo ",
"Missing a temporary folder" : "Falta un directorio temporal",
"Could not write file to disk" : "No se pudo escribir el archivo en el disco",
"A PHP extension stopped the file upload" : "Una extensión de PHP detuvo la carga del archivo",
"Card not found" : "Tarjeta no encontrada",
"Invalid date, date format must be YYYY-MM-DD" : "La fecha es inválida, favor de seguir el formato AAAA-MM-DD",
"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" : "Deck es una herramienta de organización de estilo kanban dirigida a la planificación personal y la organización de proyectos para equipos integrados con Nextcloud.\n\n\n- 📥 Agrega tus tareas a las tarjetas y ordénalas.\n- 📄 Escriba notas adicionales\n- 🔖 Asignar etiquetas para una organización mejor\n- 👥 Comparte con tu equipo, amigos o familia.\n- 📎 Adjuntar archivos e incrustarlos en su descripción\n- 💬 Discuta con su equipo usando comentarios.\n- ⚡ Mantenga un registro de los cambios en el flujo de actividad\n- 🚀 Organiza tu proyecto",

View File

@@ -32,9 +32,14 @@
"Later" : "Después",
"copy" : "copiar",
"Done" : "Hecho",
"The file was uploaded" : "El archivo ha sido subido",
"The uploaded file exceeds the upload_max_filesize directive in php.ini" : "El archivo cargado excede el valor establecido en la directiva upload_max_filesize en el archivo php.ini",
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" : "El archivo subido sobrepasa el valor MAX_FILE_SIZE especificada en el formulario HTML",
"The file was only partially uploaded" : "El archivo sólo fue cargado parcialmente",
"No file was uploaded" : "No se subió ningún archivo ",
"Missing a temporary folder" : "Falta un directorio temporal",
"Could not write file to disk" : "No se pudo escribir el archivo en el disco",
"A PHP extension stopped the file upload" : "Una extensión de PHP detuvo la carga del archivo",
"Card not found" : "Tarjeta no encontrada",
"Invalid date, date format must be YYYY-MM-DD" : "La fecha es inválida, favor de seguir el formato AAAA-MM-DD",
"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" : "Deck es una herramienta de organización de estilo kanban dirigida a la planificación personal y la organización de proyectos para equipos integrados con Nextcloud.\n\n\n- 📥 Agrega tus tareas a las tarjetas y ordénalas.\n- 📄 Escriba notas adicionales\n- 🔖 Asignar etiquetas para una organización mejor\n- 👥 Comparte con tu equipo, amigos o familia.\n- 📎 Adjuntar archivos e incrustarlos en su descripción\n- 💬 Discuta con su equipo usando comentarios.\n- ⚡ Mantenga un registro de los cambios en el flujo de actividad\n- 🚀 Organiza tu proyecto",

View File

@@ -257,6 +257,7 @@ OC.L10N.register(
"Shift" : "تغییر مکان",
"Ctrl" : "Ctrl",
"Search" : "جستجو",
"Show help dialog" : "نمایش پنجرهٔ راهنما",
"Enter" : "Enter",
"Space" : "Space",
"All boards" : "همه تخته‌ها",

View File

@@ -255,6 +255,7 @@
"Shift" : "تغییر مکان",
"Ctrl" : "Ctrl",
"Search" : "جستجو",
"Show help dialog" : "نمایش پنجرهٔ راهنما",
"Enter" : "Enter",
"Space" : "Space",
"All boards" : "همه تخته‌ها",

View File

@@ -149,8 +149,9 @@ OC.L10N.register(
"Filter by tag" : "Filtrer par étiquette",
"Filter by assigned user" : "Filtrer par utilisateur",
"Unassigned" : "Non attribué",
"Filter by status" : "Filtrer par statut",
"Open and completed" : "Ouvert et terminé",
"Open" : "Ouvrir",
"Open" : "Ouvert",
"Completed" : "Terminé",
"Filter by due date" : "Filtrer par échéance",
"Overdue" : "En retard",

View File

@@ -147,8 +147,9 @@
"Filter by tag" : "Filtrer par étiquette",
"Filter by assigned user" : "Filtrer par utilisateur",
"Unassigned" : "Non attribué",
"Filter by status" : "Filtrer par statut",
"Open and completed" : "Ouvert et terminé",
"Open" : "Ouvrir",
"Open" : "Ouvert",
"Completed" : "Terminé",
"Filter by due date" : "Filtrer par échéance",
"Overdue" : "En retard",

View File

@@ -247,6 +247,7 @@ OC.L10N.register(
"Choose a date" : "Válasszon dátumot",
"Remove due date" : "Határidő eltávolítása",
"Mark as done" : "Megjelölés készként",
"Not done" : "Nincs kész",
"Unarchive card" : "Kártya archiválásának visszavonása",
"Archive card" : "Kártya archiválása",
"Select Date" : "Dátum kiválasztása",

View File

@@ -245,6 +245,7 @@
"Choose a date" : "Válasszon dátumot",
"Remove due date" : "Határidő eltávolítása",
"Mark as done" : "Megjelölés készként",
"Not done" : "Nincs kész",
"Unarchive card" : "Kártya archiválásának visszavonása",
"Archive card" : "Kártya archiválása",
"Select Date" : "Dátum kiválasztása",

View File

@@ -39,8 +39,8 @@ class Filter implements \OCP\Activity\IFilter {
/**
* @return int whether the filter should be rather on the top or bottom of
* the admin section. The filters are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
* the admin section. The filters are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
* @since 11.0.0
*/
public function getPriority(): int {

View File

@@ -47,8 +47,8 @@ abstract class SettingBase extends ActivitySettings {
/**
* @return int whether the filter should be rather on the top or bottom of
* the admin section. The filters are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
* the admin section. The filters are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
* @since 11.0.0
*/
public function getPriority(): int {

View File

@@ -25,8 +25,8 @@ class SettingChanges extends SettingBase {
/**
* @return int whether the filter should be rather on the top or bottom of
* the admin section. The filters are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
* the admin section. The filters are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
* @since 11.0.0
*/
public function getPriority(): int {

View File

@@ -176,7 +176,7 @@ class Application extends App implements IBootstrap {
$permissionService = $this->getContainer()->get(PermissionService::class);
try {
return $permissionService->checkPermission($cardMapper, (int) $name, Acl::PERMISSION_READ);
return $permissionService->checkPermission($cardMapper, (int)$name, Acl::PERMISSION_READ);
} catch (\Exception $e) {
return false;
}

View File

@@ -14,7 +14,7 @@ class Capabilities implements ICapability {
/** @var IAppManager */
private $appManager;
/** @var PermissionService */
/** @var PermissionService */
private $permissionService;

View File

@@ -72,17 +72,17 @@ final class TransferOwnership extends Command {
try {
$board = $boardId ? $this->boardMapper->find($boardId) : null;
} catch (\Exception $e) {
$output->writeln("Could not find a board for the provided id.");
$output->writeln('Could not find a board for the provided id.');
return 1;
}
if ($boardId !== null && $board->getOwner() !== $owner) {
$output->writeln("$owner is not the owner of the board $boardId (" . $board->getTitle() . ")");
$output->writeln("$owner is not the owner of the board $boardId (" . $board->getTitle() . ')');
return 1;
}
if ($boardId) {
$output->writeln("Transfer board " . $board->getTitle() . " from ". $board->getOwner() ." to $newOwner");
$output->writeln('Transfer board ' . $board->getTitle() . ' from '. $board->getOwner() ." to $newOwner");
} else {
$output->writeln("Transfer all boards from $owner to $newOwner");
}
@@ -94,12 +94,12 @@ final class TransferOwnership extends Command {
if ($boardId) {
$this->boardService->transferBoardOwnership($boardId, $newOwner, $remapAssignment);
$output->writeln("<info>Board " . $board->getTitle() . " from ". $board->getOwner() ." transferred to $newOwner completed</info>");
$output->writeln('<info>Board ' . $board->getTitle() . ' from '. $board->getOwner() ." transferred to $newOwner completed</info>");
return 0;
}
foreach ($this->boardService->transferOwnership($owner, $newOwner, $remapAssignment) as $board) {
$output->writeln(" - " . $board->getTitle() . " transferred");
$output->writeln(' - ' . $board->getTitle() . ' transferred');
}
$output->writeln("<info>All boards from $owner to $newOwner transferred</info>");

View File

@@ -25,7 +25,7 @@ class Calendar extends ExternalCalendar {
private $children;
/** @var DeckCalendarBackend */
private $backend;
/** @var Board */
/** @var Board */
private $board;
public function __construct(string $principalUri, string $calendarUri, Board $board, DeckCalendarBackend $backend) {

View File

@@ -75,7 +75,7 @@ class AclMapper extends DeckMapper implements IPermissionMapper {
try {
$entity = $this->find($id);
return $entity->getBoardId();
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
} catch (DoesNotExistException|MultipleObjectsReturnedException $e) {
}
return null;
}

View File

@@ -61,9 +61,9 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper {
public function findByData($cardId, $data) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('data', $qb->createNamedParameter($data, IQueryBuilder::PARAM_STR)));
->from($this->getTableName())
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('data', $qb->createNamedParameter($data, IQueryBuilder::PARAM_STR)));
return $this->findEntity($qb);
}

View File

@@ -165,7 +165,7 @@ class Card extends RelationalEntity {
$matchDate->setTime(0, 0);
$diff = $today->diff($matchDate);
return (int) $diff->format('%R%a'); // Extract days count in interval
return (int)$diff->format('%R%a'); // Extract days count in interval
}
public function getCalendarPrefix(): string {

View File

@@ -410,7 +410,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
foreach ($query->getDuedate() as $duedate) {
$dueDateColumn = $this->databaseType === 'sqlite3' ? $qb->createFunction('DATETIME(`c`.`duedate`)') : 'c.duedate';
$date = $duedate->getValue();
if ($date === "") {
if ($date === '') {
$qb->andWhere($qb->expr()->isNotNull('c.duedate'));
continue;
}
@@ -461,7 +461,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
foreach ($query->getAssigned() as $index => $assignment) {
$qb->innerJoin('c', 'deck_assigned_users', 'au' . $index, $qb->expr()->eq('c.id', 'au' . $index . '.card_id'));
$assignedQueryValue = $assignment->getValue();
if ($assignedQueryValue === "") {
if ($assignedQueryValue === '') {
$qb->andWhere($qb->expr()->isNotNull('au' . $index . '.participant'));
continue;
}
@@ -589,7 +589,7 @@ class CardMapper extends QBMapper implements IPermissionMapper {
}
$this->cache->set('findBoardId:' . $id, $result);
}
return $result !== false ? (int) $result : null;
return $result !== false ? (int)$result : null;
}
public function mapOwner(Card &$card) {

View File

@@ -89,7 +89,7 @@ class ExceptionMiddleware extends Middleware {
];
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
if ($debugMode === true) {
$response['exception'] = (array) $exception;
$response['exception'] = (array)$exception;
}
return new JSONResponse($response, 500);
}

View File

@@ -142,11 +142,11 @@ class NotificationHelper {
->setUser($userId)
->setDateTime(new DateTime())
->setObject('card', (string)$card->getId())
->setSubject('card-assigned', [
$card->getTitle(),
$board->getTitle(),
$this->currentUser
]);
->setSubject('card-assigned', [
$card->getTitle(),
$board->getTitle(),
$this->currentUser
]);
$this->notificationManager->notify($notification);
}
@@ -206,9 +206,9 @@ class NotificationHelper {
$notification = $this->notificationManager->createNotification();
$notification
->setApp('deck')
->setUser((string) $mention['id'])
->setUser((string)$mention['id'])
->setDateTime(new DateTime())
->setObject('card', (string) $card->getId())
->setObject('card', (string)$card->getId())
->setSubject('card-comment-mentioned', [$card->getTitle(), $boardId, $this->currentUser])
->setMessage('{message}', ['message' => $comment->getMessage()]);
$this->notificationManager->notify($notification);

View File

@@ -97,7 +97,7 @@ class BoardReferenceProvider implements IReferenceProvider {
preg_match('/^' . preg_quote($startIndex, '/') . '(?:\/#!?)?\/board\/([0-9]+)$/', $url, $matches);
}
if ($matches && count($matches) > 1) {
return (int) $matches[1];
return (int)$matches[1];
}
return null;
@@ -106,7 +106,7 @@ class BoardReferenceProvider implements IReferenceProvider {
public function getCachePrefix(string $referenceId): string {
$boardId = $this->getBoardId($referenceId);
if ($boardId !== null) {
return (string) $boardId;
return (string)$boardId;
}
return $referenceId;

View File

@@ -111,9 +111,9 @@ class CardReferenceProvider extends ADiscoverableReferenceProvider implements IS
if ($ids !== null) {
[, $cardId] = $ids;
try {
$card = $this->cardService->find((int) $cardId)->jsonSerialize();
$stack = $this->stackService->find((int) $card['stackId'])->jsonSerialize();
$board = $this->boardService->find((int) $stack['boardId'])->jsonSerialize();
$card = $this->cardService->find((int)$cardId)->jsonSerialize();
$stack = $this->stackService->find((int)$card['stackId'])->jsonSerialize();
$board = $this->boardService->find((int)$stack['boardId'])->jsonSerialize();
} catch (NoPermissionException $e) {
// Skip throwing if user has no permissions
return null;

View File

@@ -73,7 +73,7 @@ class CommentReferenceProvider implements IReferenceProvider {
try {
$card = $this->cardService->find($cardId)->jsonSerialize();
$board = $this->boardService->find($boardId)->jsonSerialize();
$stack = $this->stackService->find((int) $card['stackId'])->jsonSerialize();
$stack = $this->stackService->find((int)$card['stackId'])->jsonSerialize();
} catch (NoPermissionException $e) {
// Skip throwing if user has no permissions
return null;
@@ -162,9 +162,9 @@ class CommentReferenceProvider implements IReferenceProvider {
}
if ($matches && count($matches) > 3) {
return [
(int) $matches[1],
(int) $matches[2],
(int) $matches[3],
(int)$matches[1],
(int)$matches[2],
(int)$matches[3],
];
}

View File

@@ -40,6 +40,7 @@ class CardService {
private StackMapper $stackMapper;
private BoardMapper $boardMapper;
private LabelMapper $labelMapper;
private LabelService $labelService;
private PermissionService $permissionService;
private BoardService $boardService;
private NotificationHelper $notificationHelper;
@@ -61,6 +62,7 @@ class CardService {
StackMapper $stackMapper,
BoardMapper $boardMapper,
LabelMapper $labelMapper,
LabelService $labelService,
PermissionService $permissionService,
BoardService $boardService,
NotificationHelper $notificationHelper,
@@ -81,6 +83,7 @@ class CardService {
$this->stackMapper = $stackMapper;
$this->boardMapper = $boardMapper;
$this->labelMapper = $labelMapper;
$this->labelService = $labelService;
$this->permissionService = $permissionService;
$this->boardService = $boardService;
$this->notificationHelper = $notificationHelper;
@@ -349,8 +352,34 @@ class CardService {
}
$card->setDescription($description);
// @var Card $card
$card = $this->cardMapper->update($card);
$oldBoardId = $this->stackMapper->findBoardId($changes->getBefore()->getStackId());
$boardId = $this->cardMapper->findBoardId($card->getId());
if($boardId !== $oldBoardId) {
$stack = $this->stackMapper->find($card->getStackId());
$board = $this->boardService->find($this->cardMapper->findBoardId($card->getId()));
$boardLabels = $board->getLabels() ?? [];
foreach($card->getLabels() as $cardLabel) {
$this->removeLabel($card->getId(), $cardLabel->getId());
$label = $this->labelMapper->find($cardLabel->getId());
$filteredLabels = array_values(array_filter($boardLabels, fn ($item) => $item->getTitle() === $label->getTitle()));
// clone labels that are assigned to card but don't exist in new board
if (empty($filteredLabels)) {
if ($this->permissionService->getPermissions($boardId)[Acl::PERMISSION_MANAGE] === true) {
$newLabel = $this->labelService->create($label->getTitle(), $label->getColor(), $board->getId());
$boardLabels[] = $label;
$this->assignLabel($card->getId(), $newLabel->getId());
}
} else {
$this->assignLabel($card->getId(), $filteredLabels[0]->getId());
}
}
$board->setLabels($boardLabels);
$this->boardMapper->update($board);
$this->changeHelper->boardChanged($board->getId());
}
if ($resetDuedateNotification) {
$this->notificationHelper->markDuedateAsRead($card);
}

View File

@@ -65,8 +65,8 @@ class CommentService {
private function get(int $cardId, int $commentId): IComment {
$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ);
try {
$comment = $this->commentsManager->get((string) $commentId);
if ($comment->getObjectType() !== Application::COMMENT_ENTITY_TYPE || (int) $comment->getObjectId() !== $cardId) {
$comment = $this->commentsManager->get((string)$commentId);
if ($comment->getObjectType() !== Application::COMMENT_ENTITY_TYPE || (int)$comment->getObjectId() !== $cardId) {
throw new CommentNotFoundException();
}
} catch (CommentNotFoundException $e) {
@@ -134,7 +134,7 @@ class CommentService {
if (!is_numeric($commentId)) {
throw new BadRequestException('A valid comment id must be provided');
}
$comment = $this->get((int) $cardId, (int) $commentId);
$comment = $this->get((int)$cardId, (int)$commentId);
if ($comment->getActorType() !== 'users' || $comment->getActorId() !== $this->userId) {
throw new NoPermissionException('Only authors are allowed to edit their comment.');
}

View File

@@ -404,7 +404,7 @@ class BoardImportService {
* @return void
*/
public function setConfig(string $configName, $value): void {
if (empty((array) $this->config)) {
if (empty((array)$this->config)) {
$this->setConfigInstance(new \stdClass);
}
$this->config->$configName = $value;

View File

@@ -51,7 +51,7 @@ class DeckJsonService extends ABoardImportService {
if (!is_string($nextcloudUid) && !is_numeric($nextcloudUid)) {
throw new \LogicException('User on setting uidRelation is invalid');
}
$nextcloudUid = (string) $nextcloudUid;
$nextcloudUid = (string)$nextcloudUid;
$this->getImportService()->getConfig('uidRelation')->$exportUid = $this->userManager->get($nextcloudUid);
if (!$this->getImportService()->getConfig('uidRelation')->$exportUid) {
throw new \LogicException('User on setting uidRelation not found: ' . $nextcloudUid);
@@ -106,7 +106,7 @@ class DeckJsonService extends ABoardImportService {
public function getComments(): array {
$comments = [];
foreach ($this->tmpCards as $sourceCard) {
if (!property_exists($sourceCard, "comments")) {
if (!property_exists($sourceCard, 'comments')) {
continue;
}
$commentsOriginal = $sourceCard->comments;
@@ -125,8 +125,10 @@ class DeckJsonService extends ABoardImportService {
foreach ($this->tmpCards as $sourceCard) {
foreach ($sourceCard->labels as $label) {
$cardId = $this->cards[$sourceCard->id]->getId();
$labelId = $this->labels[$label->id]->getId();
$cardsLabels[$cardId][] = $labelId;
if ($this->getImportService()->getData()->id === $label->boardId) {
$labelId = $this->labels[$label->id]->getId();
$cardsLabels[$cardId][] = $labelId;
}
}
}
return $cardsLabels;

View File

@@ -71,7 +71,7 @@ class TrelloJsonService extends ABoardImportService {
if (!is_string($nextcloudUid) && !is_numeric($nextcloudUid)) {
throw new \LogicException('User on setting uidRelation is invalid');
}
$nextcloudUid = (string) $nextcloudUid;
$nextcloudUid = (string)$nextcloudUid;
$this->getImportService()->getConfig('uidRelation')->$trelloUid = $this->userManager->get($nextcloudUid);
if (!$this->getImportService()->getConfig('uidRelation')->$trelloUid) {
throw new \LogicException('User on setting uidRelation not found: ' . $nextcloudUid);
@@ -141,7 +141,7 @@ class TrelloJsonService extends ABoardImportService {
$message = $this->l10n->t(
"This comment has more than %s characters.\n" .
"Added as an attachment to the card with name %s.\n" .
"Accessible on URL: %s.",
'Accessible on URL: %s.',
[
IComment::MAX_MESSAGE_LENGTH,
'comment_' . $commentId . '.md',

View File

@@ -143,7 +143,7 @@ class PermissionService {
try {
$board = $this->getBoard($boardId);
return $userId === $board->getOwner();
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
} catch (DoesNotExistException|MultipleObjectsReturnedException $e) {
}
return false;
}
@@ -205,8 +205,8 @@ class PermissionService {
*/
public function findUsers($boardId, $refresh = false) {
// cache users of a board so we don't query them for every cards
if (array_key_exists((string) $boardId, $this->users) && !$refresh) {
return $this->users[(string) $boardId];
if (array_key_exists((string)$boardId, $this->users) && !$refresh) {
return $this->users[(string)$boardId];
}
try {
@@ -269,8 +269,8 @@ class PermissionService {
}
}
}
$this->users[(string) $boardId] = $users;
return $this->users[(string) $boardId];
$this->users[(string)$boardId] = $users;
return $this->users[(string)$boardId];
}
public function canCreate() {

View File

@@ -110,7 +110,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
try {
$board = $this->boardMapper->find($boardId);
$valid = $valid && !$board->getArchived();
} catch (DoesNotExistException | MultipleObjectsReturnedException $e) {
} catch (DoesNotExistException|MultipleObjectsReturnedException $e) {
$valid = false;
}
@@ -966,8 +966,8 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
protected function filterSharesOfUser(array $shares): array {
// Deck shares when the user has a share exception
foreach ($shares as $id => $share) {
$type = (int) $share['share_type'];
$permissions = (int) $share['permissions'];
$type = (int)$share['share_type'];
$permissions = (int)$share['permissions'];
if ($type === self::SHARE_TYPE_DECK_USER) {
unset($shares[$share['parent']]);

View File

@@ -45,7 +45,7 @@ abstract class BaseValidator {
} else {
if (!$this->{$rule}($value)) {
throw new BadRequestException(
$field . ' must be provided and must be '. str_replace("_", " ", $rule));
$field . ' must be provided and must be '. str_replace('_', ' ', $rule));
}
}
}
@@ -111,7 +111,7 @@ abstract class BaseValidator {
*/
private function max($value, $limit): bool {
if (!$limit || !is_numeric($limit)) {
throw new Exception("Validation rule max requires at least 1 parameter. " . json_encode($limit));
throw new Exception('Validation rule max requires at least 1 parameter. ' . json_encode($limit));
}
return $this->getSize($value) <= $limit;
}
@@ -121,7 +121,7 @@ abstract class BaseValidator {
*/
private function min($value, $limit): bool {
if (!$limit || !is_numeric($limit)) {
throw new Exception("Validation rule max requires at least 1 parameter.");
throw new Exception('Validation rule max requires at least 1 parameter.');
}
return $this->getSize($value) >= $limit;
}
@@ -129,7 +129,7 @@ abstract class BaseValidator {
/**
* Get the size of an attribute.
*
* @param mixed $value
* @param mixed $value
* @return int
*/
protected function getSize($value): int {
@@ -158,6 +158,6 @@ abstract class BaseValidator {
: $field . ' must be at least '. $parameter . ' characters long ';
}
return $field . ' must be provided and must be '. str_replace("_", " ", $rule);
return $field . ' must be provided and must be '. str_replace('_', ' ', $rule);
}
}

332
package-lock.json generated
View File

@@ -10,7 +10,7 @@
"license": "agpl",
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.25.0",
"@babel/runtime": "^7.25.6",
"@nextcloud/auth": "^2.4.0",
"@nextcloud/axios": "^2.5.0",
"@nextcloud/capabilities": "^1.2.0",
@@ -22,9 +22,9 @@
"@nextcloud/moment": "^1.3.1",
"@nextcloud/notify_push": "^1.3.0",
"@nextcloud/router": "^3.0.1",
"@nextcloud/vue": "^8.16.0",
"@nextcloud/vue": "^8.17.1",
"blueimp-md5": "^2.19.0",
"chroma-js": "^2.6.0",
"chroma-js": "^3.0.0",
"dompurify": "^3.1.6",
"lodash": "^4.17.21",
"markdown-it": "^14.1.0",
@@ -52,10 +52,10 @@
"@nextcloud/eslint-config": "^8.4.1",
"@nextcloud/stylelint-config": "^3.0.1",
"@nextcloud/webpack-vue-config": "^6.0.0",
"@relative-ci/agent": "^4.2.10",
"@relative-ci/agent": "^4.2.11",
"@vue/test-utils": "^2.4.6",
"@vue/vue2-jest": "^29.2.6",
"cypress": "^13.13.3",
"cypress": "^13.14.1",
"eslint-plugin-cypress": "^3.5.0",
"eslint-webpack-plugin": "^4.2.0",
"jest": "^29.7.0",
@@ -1917,9 +1917,9 @@
"peer": true
},
"node_modules/@babel/runtime": {
"version": "7.25.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz",
"integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==",
"version": "7.25.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz",
"integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -1994,9 +1994,9 @@
"dev": true
},
"node_modules/@bundle-stats/plugin-webpack-validate": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@bundle-stats/plugin-webpack-validate/-/plugin-webpack-validate-4.14.0.tgz",
"integrity": "sha512-VLXk50dAriPXM4i1HfH3rX6rKXKqnU7EKI/xkUaRfGgSCiMWsLfNpA/T+gv3CYYXM/HqCM2tXOy3dc9V5OIh8w==",
"version": "4.15.0",
"resolved": "https://registry.npmjs.org/@bundle-stats/plugin-webpack-validate/-/plugin-webpack-validate-4.15.0.tgz",
"integrity": "sha512-AKj6okcTFgQMFnJg3rSrLDw4dQ2U9I0WGecKf4qzeW3MsoSgnTW58ZBCebIoODEatw7bhawBlXhkl6tvjkjY4A==",
"dev": true,
"dependencies": {
"lodash": "4.17.21",
@@ -3340,14 +3340,14 @@
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
"integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"dev": true,
"peer": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
@@ -3895,9 +3895,9 @@
}
},
"node_modules/@nextcloud/vue": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-8.16.0.tgz",
"integrity": "sha512-xkoR2VeWk+WTTmXC01Z7hI0yztSf222XMPXhy9OkDNQBXmCl/idEjNnMWmxezJMyqALtFD/csouW+GS7JUVoFw==",
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-8.17.1.tgz",
"integrity": "sha512-DC7nI04pp69vS5VxMDhpwPFhb5TWvyJgtmFciAx6j8RFrTPutdjNfOxOCncGaNXOlodaIpg/6EYV8YHU9DR9ng==",
"dependencies": {
"@floating-ui/dom": "^1.1.0",
"@linusborg/vue-simple-portal": "^0.1.5",
@@ -3913,8 +3913,8 @@
"@nextcloud/sharing": "^0.2.2",
"@nextcloud/timezones": "^0.1.1",
"@nextcloud/vue-select": "^3.25.0",
"@vueuse/components": "^10.9.0",
"@vueuse/core": "^10.9.0",
"@vueuse/components": "^11.0.0",
"@vueuse/core": "^11.0.0",
"clone": "^2.1.2",
"debounce": "2.1.0",
"dompurify": "^3.0.5",
@@ -4180,14 +4180,14 @@
}
},
"node_modules/@relative-ci/agent": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/@relative-ci/agent/-/agent-4.2.10.tgz",
"integrity": "sha512-w3aMOrSEyrL6s8i69o6Jjo58WYMz51cI3MuCuoQDKJANew08lXpaQEBI6cyf/gQrVH/ixy9MQhOcESKUqwexEQ==",
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/@relative-ci/agent/-/agent-4.2.11.tgz",
"integrity": "sha512-EnX0yiSWUkHUnuWzvmysqJJk44EsSmCD7TuXGMgJ9EGxHkAFdEg/+d3+r0UHdThSJ1tDKX6C0h9S4DoOIl8BSQ==",
"dev": true,
"dependencies": {
"@bundle-stats/plugin-webpack-filter": "4.14.0",
"@bundle-stats/plugin-webpack-validate": "4.14.0",
"core-js": "3.38.0",
"@bundle-stats/plugin-webpack-filter": "4.15.0",
"@bundle-stats/plugin-webpack-validate": "4.15.0",
"core-js": "3.38.1",
"cosmiconfig": "9.0.0",
"debug": "4.3.6",
"dotenv": "16.4.5",
@@ -4213,9 +4213,9 @@
}
},
"node_modules/@relative-ci/agent/node_modules/@bundle-stats/plugin-webpack-filter": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@bundle-stats/plugin-webpack-filter/-/plugin-webpack-filter-4.14.0.tgz",
"integrity": "sha512-/p8kMPHyFNcmpgQIOIFkSYObQQUf5F5Gbzsy+dgH+QXSGEppyI1m5Os4BJEBzqS8jUewwzcKVDIQCg2pWoKNAw==",
"version": "4.15.0",
"resolved": "https://registry.npmjs.org/@bundle-stats/plugin-webpack-filter/-/plugin-webpack-filter-4.15.0.tgz",
"integrity": "sha512-DQIFkcAkH4VjrDiaoe02c7n5ShGYHIdSMihwDAvRk/4x4PQ1v0/W1kyPxs71glj+6iSddumqNIE28G0DQ4mTQA==",
"dev": true,
"engines": {
"node": ">= 14.0"
@@ -4225,9 +4225,9 @@
}
},
"node_modules/@relative-ci/agent/node_modules/core-js": {
"version": "3.38.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.0.tgz",
"integrity": "sha512-XPpwqEodRljce9KswjZShh95qJ1URisBeKCjUdq27YdenkslVe7OO0ZJhlYXAChW7OhXaRLl8AAba7IBfoIHug==",
"version": "3.38.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz",
"integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==",
"dev": true,
"hasInstallScript": true,
"funding": {
@@ -4420,21 +4420,10 @@
"@types/json-schema": "*"
}
},
"node_modules/@types/eslint-scope": {
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
"integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
"dev": true,
"peer": true,
"dependencies": {
"@types/eslint": "*",
"@types/estree": "*"
}
},
"node_modules/@types/estree": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA=="
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
},
"node_modules/@types/express": {
"version": "4.17.17",
@@ -5128,19 +5117,19 @@
}
},
"node_modules/@vueuse/components": {
"version": "10.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/components/-/components-10.9.0.tgz",
"integrity": "sha512-BHQpA0yIi3y7zKa1gYD0FUzLLkcRTqVhP8smnvsCK6GFpd94Nziq1XVPD7YpFeho0k5BzbBiNZF7V/DpkJ967A==",
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/@vueuse/components/-/components-11.0.1.tgz",
"integrity": "sha512-iZYHc7XcZ2NqpEaSiDXF6qcVcCzAwnA74s+ZV8aHJhdxO61BFpACGuT32Jb5oR+pVc6dfrUUspcCoYzLcFtOOA==",
"dependencies": {
"@vueuse/core": "10.9.0",
"@vueuse/shared": "10.9.0",
"vue-demi": ">=0.14.7"
"@vueuse/core": "11.0.1",
"@vueuse/shared": "11.0.1",
"vue-demi": ">=0.14.10"
}
},
"node_modules/@vueuse/components/node_modules/vue-demi": {
"version": "0.14.7",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
"integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
@@ -5163,23 +5152,23 @@
}
},
"node_modules/@vueuse/core": {
"version": "10.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz",
"integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==",
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-11.0.1.tgz",
"integrity": "sha512-YTrekI18WwEyP3h168Fir94G/HNC27wvXJI21Alm0sPOwvhihfkrvHIe+5PNJq+MpgWdRcsjvE/38JaoKrgZhQ==",
"dependencies": {
"@types/web-bluetooth": "^0.0.20",
"@vueuse/metadata": "10.9.0",
"@vueuse/shared": "10.9.0",
"vue-demi": ">=0.14.7"
"@vueuse/metadata": "11.0.1",
"@vueuse/shared": "11.0.1",
"vue-demi": ">=0.14.10"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.14.7",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
"integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
@@ -5202,28 +5191,28 @@
}
},
"node_modules/@vueuse/metadata": {
"version": "10.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz",
"integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==",
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-11.0.1.tgz",
"integrity": "sha512-dTFvuHFAjLYOiSd+t9Sk7xUiuL6jbfay/eX+g+jaipXXlwKur2VCqBCZX+jfu+2vROUGcUsdn3fJR9KkpadIOg==",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "10.9.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz",
"integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==",
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-11.0.1.tgz",
"integrity": "sha512-eAPf5CQB3HR0S76HqrhjBqFYstZfiHWZq8xF9EQmobGBkrhPfErJEhr8aMNQMqd6MkENIx2pblIEfJGlHpClug==",
"dependencies": {
"vue-demi": ">=0.14.7"
"vue-demi": ">=0.14.10"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.14.7",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
"integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
@@ -5246,9 +5235,9 @@
}
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
"integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
"integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
"dev": true,
"peer": true,
"dependencies": {
@@ -5271,9 +5260,9 @@
"peer": true
},
"node_modules/@webassemblyjs/helper-buffer": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
"integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==",
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
"integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
"dev": true,
"peer": true
},
@@ -5297,16 +5286,16 @@
"peer": true
},
"node_modules/@webassemblyjs/helper-wasm-section": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
"integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
"integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
"dev": true,
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.11.6",
"@webassemblyjs/helper-buffer": "1.11.6",
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-buffer": "1.12.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
"@webassemblyjs/wasm-gen": "1.11.6"
"@webassemblyjs/wasm-gen": "1.12.1"
}
},
"node_modules/@webassemblyjs/ieee754": {
@@ -5337,30 +5326,30 @@
"peer": true
},
"node_modules/@webassemblyjs/wasm-edit": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
"integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
"integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
"dev": true,
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.11.6",
"@webassemblyjs/helper-buffer": "1.11.6",
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-buffer": "1.12.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
"@webassemblyjs/helper-wasm-section": "1.11.6",
"@webassemblyjs/wasm-gen": "1.11.6",
"@webassemblyjs/wasm-opt": "1.11.6",
"@webassemblyjs/wasm-parser": "1.11.6",
"@webassemblyjs/wast-printer": "1.11.6"
"@webassemblyjs/helper-wasm-section": "1.12.1",
"@webassemblyjs/wasm-gen": "1.12.1",
"@webassemblyjs/wasm-opt": "1.12.1",
"@webassemblyjs/wasm-parser": "1.12.1",
"@webassemblyjs/wast-printer": "1.12.1"
}
},
"node_modules/@webassemblyjs/wasm-gen": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
"integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
"integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
"dev": true,
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.11.6",
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
"@webassemblyjs/ieee754": "1.11.6",
"@webassemblyjs/leb128": "1.11.6",
@@ -5368,26 +5357,26 @@
}
},
"node_modules/@webassemblyjs/wasm-opt": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
"integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
"integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
"dev": true,
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.11.6",
"@webassemblyjs/helper-buffer": "1.11.6",
"@webassemblyjs/wasm-gen": "1.11.6",
"@webassemblyjs/wasm-parser": "1.11.6"
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-buffer": "1.12.1",
"@webassemblyjs/wasm-gen": "1.12.1",
"@webassemblyjs/wasm-parser": "1.12.1"
}
},
"node_modules/@webassemblyjs/wasm-parser": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
"integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
"integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
"dev": true,
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.11.6",
"@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-api-error": "1.11.6",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
"@webassemblyjs/ieee754": "1.11.6",
@@ -5396,13 +5385,13 @@
}
},
"node_modules/@webassemblyjs/wast-printer": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
"integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
"integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
"dev": true,
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.11.6",
"@webassemblyjs/ast": "1.12.1",
"@xtuc/long": "4.2.2"
}
},
@@ -5516,10 +5505,10 @@
"node": ">=0.4.0"
}
},
"node_modules/acorn-import-assertions": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
"integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
"node_modules/acorn-import-attributes": {
"version": "1.9.5",
"resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
"integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
"dev": true,
"peer": true,
"peerDependencies": {
@@ -6899,9 +6888,9 @@
"dev": true
},
"node_modules/chroma-js": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.6.0.tgz",
"integrity": "sha512-BLHvCB9s8Z1EV4ethr6xnkl/P2YRFOGqfgvuMG/MyCbZPrTA+NeiByY6XvgF0zP4/2deU2CXnWyMa3zu1LqQ3A=="
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-3.0.0.tgz",
"integrity": "sha512-ZFn4qxtZTvRJ7XatOLgaHGJYN10LoS6T0EMsu7IVayFG5+b6Yw8wCGQL5qLgo4B+wrRZ9niCrozOQ4a584bvaA=="
},
"node_modules/chrome-trace-event": {
"version": "1.0.3",
@@ -7730,9 +7719,9 @@
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA=="
},
"node_modules/cypress": {
"version": "13.13.3",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.13.3.tgz",
"integrity": "sha512-hUxPrdbJXhUOTzuML+y9Av7CKoYznbD83pt8g3klgpioEha0emfx4WNIuVRx0C76r0xV2MIwAW9WYiXfVJYFQw==",
"version": "13.14.1",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.1.tgz",
"integrity": "sha512-Wo+byPmjps66hACEH5udhXINEiN3qS3jWNGRzJOjrRJF3D0+YrcP2LVB1T7oYaVQM/S+eanqEvBWYc8cf7Vcbg==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -8582,9 +8571,9 @@
}
},
"node_modules/enhanced-resolve": {
"version": "5.15.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
"integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==",
"version": "5.17.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
"dev": true,
"peer": true,
"dependencies": {
@@ -10513,6 +10502,21 @@
"dev": true,
"license": "ISC"
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"dev": true,
@@ -10810,9 +10814,9 @@
}
},
"node_modules/graceful-fs": {
"version": "4.2.9",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true
},
"node_modules/graphemer": {
@@ -15432,12 +15436,13 @@
]
},
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.2",
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -17937,9 +17942,9 @@
"peer": true
},
"node_modules/serialize-javascript": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
"integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"peer": true,
"dependencies": {
@@ -19187,9 +19192,9 @@
}
},
"node_modules/terser": {
"version": "5.19.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz",
"integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==",
"version": "5.31.6",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz",
"integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==",
"dev": true,
"peer": true,
"dependencies": {
@@ -19206,17 +19211,17 @@
}
},
"node_modules/terser-webpack-plugin": {
"version": "5.3.9",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz",
"integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==",
"version": "5.3.10",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
"integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
"dev": true,
"peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.17",
"@jridgewell/trace-mapping": "^0.3.20",
"jest-worker": "^27.4.5",
"schema-utils": "^3.1.1",
"serialize-javascript": "^6.0.1",
"terser": "^5.16.8"
"terser": "^5.26.0"
},
"engines": {
"node": ">= 10.13.0"
@@ -20508,9 +20513,9 @@
}
},
"node_modules/watchpack": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
"dev": true,
"peer": true,
"dependencies": {
@@ -20623,35 +20628,34 @@
}
},
"node_modules/webpack": {
"version": "5.88.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz",
"integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==",
"version": "5.94.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
"integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==",
"dev": true,
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^1.0.0",
"@webassemblyjs/ast": "^1.11.5",
"@webassemblyjs/wasm-edit": "^1.11.5",
"@webassemblyjs/wasm-parser": "^1.11.5",
"@types/estree": "^1.0.5",
"@webassemblyjs/ast": "^1.12.1",
"@webassemblyjs/wasm-edit": "^1.12.1",
"@webassemblyjs/wasm-parser": "^1.12.1",
"acorn": "^8.7.1",
"acorn-import-assertions": "^1.9.0",
"browserslist": "^4.14.5",
"acorn-import-attributes": "^1.9.5",
"browserslist": "^4.21.10",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.15.0",
"enhanced-resolve": "^5.17.1",
"es-module-lexer": "^1.2.1",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.2.9",
"graceful-fs": "^4.2.11",
"json-parse-even-better-errors": "^2.3.1",
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^3.2.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.3.7",
"watchpack": "^2.4.0",
"terser-webpack-plugin": "^5.3.10",
"watchpack": "^2.4.1",
"webpack-sources": "^3.2.3"
},
"bin": {

View File

@@ -31,7 +31,7 @@
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.25.0",
"@babel/runtime": "^7.25.6",
"@nextcloud/auth": "^2.4.0",
"@nextcloud/axios": "^2.5.0",
"@nextcloud/capabilities": "^1.2.0",
@@ -43,9 +43,9 @@
"@nextcloud/moment": "^1.3.1",
"@nextcloud/notify_push": "^1.3.0",
"@nextcloud/router": "^3.0.1",
"@nextcloud/vue": "^8.16.0",
"@nextcloud/vue": "^8.17.1",
"blueimp-md5": "^2.19.0",
"chroma-js": "^2.6.0",
"chroma-js": "^3.0.0",
"dompurify": "^3.1.6",
"lodash": "^4.17.21",
"markdown-it": "^14.1.0",
@@ -80,10 +80,10 @@
"@nextcloud/eslint-config": "^8.4.1",
"@nextcloud/stylelint-config": "^3.0.1",
"@nextcloud/webpack-vue-config": "^6.0.0",
"@relative-ci/agent": "^4.2.10",
"@relative-ci/agent": "^4.2.11",
"@vue/test-utils": "^2.4.6",
"@vue/vue2-jest": "^29.2.6",
"cypress": "^13.13.3",
"cypress": "^13.14.1",
"eslint-plugin-cypress": "^3.5.0",
"eslint-webpack-plugin": "^4.2.0",
"jest": "^29.7.0",

View File

@@ -6,12 +6,13 @@
<template>
<NcContent app-name="deck" :class="{ 'nav-hidden': !navShown, 'sidebar-hidden': !sidebarRouterView }">
<AppNavigation />
<NcAppContent>
<NcAppContent :allow-swipe-navigation="false">
<router-view />
</NcAppContent>
<div v-if="$route.params.id || $route.params.cardId">
<NcModal v-if="cardDetailsInModal && $route.params.cardId"
:name="t('deck', 'Card details')"
:clear-view-delay="0"
:close-button-contained="true"
size="large"
@@ -32,7 +33,7 @@
import { mapState } from 'vuex'
import AppNavigation from './components/navigation/AppNavigation.vue'
import KeyboardShortcuts from './components/KeyboardShortcuts.vue'
import { NcModal, NcContent, NcAppContent } from '@nextcloud/vue'
import { NcModal, NcContent, NcAppContent, isMobile } from '@nextcloud/vue'
import { BoardApi } from './services/BoardApi.js'
import { emit, subscribe } from '@nextcloud/event-bus'
import { loadState } from '@nextcloud/initial-state'
@@ -50,6 +51,7 @@ export default {
NcAppContent,
KeyboardShortcuts,
},
mixins: [isMobile],
provide() {
return {
boardApi,
@@ -106,7 +108,7 @@ export default {
},
mounted() {
// Set navigation to initial state and update in case it gets toggled
emit('toggle-navigation', { open: this.navShown, _initial: true })
emit('toggle-navigation', { open: !this.isMobile && this.navShown, _initial: true })
this.$nextTick(() => {
subscribe('navigation-toggled', (navState) => {
this.$store.dispatch('toggleNav', navState.open)
@@ -190,9 +192,8 @@ export default {
.modal__card {
width: 100%;
min-width: 100%;
height: 100vh;
max-height: calc(100vh - 120px);
overflow: auto;
height: calc(100% - 20px);
overflow: hidden;
}
</style>

View File

@@ -92,7 +92,6 @@ export default {
<style lang="scss" scoped>
.modal__content {
width: 25vw;
min-width: 250px;
min-height: 120px;
margin: 20px 20px 100px 20px;

View File

@@ -13,16 +13,16 @@
:disabled="loading"
label="title"
@option:selected="fetchCardsFromBoard">
<template slot="singleLabel" slot-scope="props">
<template #selected-option="props">
<span>
<span :style="{ 'backgroundColor': '#' + props.option.color }" class="board-bullet" />
<span>{{ props.option.title }}</span>
<span :style="{ 'backgroundColor': '#' + props.color }" class="board-bullet" />
<span>{{ props.title }}</span>
</span>
</template>
<template slot="option" slot-scope="props">
<template #option="props">
<span>
<span :style="{ 'backgroundColor': '#' + props.option.color }" class="board-bullet" />
<span>{{ props.option.title }}</span>
<span :style="{ 'backgroundColor': '#' + props.color }" class="board-bullet" />
<span>{{ props.title }}</span>
</span>
</template>
</NcSelect>

View File

@@ -31,7 +31,8 @@
<div class="board-actions">
<SessionList v-if="isNotifyPushEnabled && presentUsers.length"
:sessions="presentUsers" />
<div v-if="searchQuery || true" class="deck-search">
<!-- Hide but not remove for now as search might change in the future -->
<div v-if="false" class="deck-search">
<input id="deck-search-input"
ref="search"
:tabindex="0"
@@ -46,8 +47,11 @@
id="stack-add"
v-click-outside="hideAddStack">
<NcActions v-if="!isAddStackVisible">
<NcActionButton icon="icon-add" @click.stop="showAddStack">
<NcActionButton @click.stop="showAddStack">
{{ t('deck', 'Add list') }}
<template #icon>
<TableColumnPlusAfter :size="20" />
</template>
</NcActionButton>
</NcActions>
<form v-else @submit.prevent="addNewStack()">
@@ -263,6 +267,7 @@ import ArchiveIcon from 'vue-material-design-icons/Archive.vue'
import ImageIcon from 'vue-material-design-icons/ImageMultiple.vue'
import FilterIcon from 'vue-material-design-icons/Filter.vue'
import FilterOffIcon from 'vue-material-design-icons/FilterOff.vue'
import TableColumnPlusAfter from 'vue-material-design-icons/TableColumnPlusAfter.vue'
import ArrowCollapseVerticalIcon from 'vue-material-design-icons/ArrowCollapseVertical.vue'
import ArrowExpandVerticalIcon from 'vue-material-design-icons/ArrowExpandVertical.vue'
import SessionList from './SessionList.vue'
@@ -286,6 +291,7 @@ export default {
FilterOffIcon,
ArrowCollapseVerticalIcon,
ArrowExpandVerticalIcon,
TableColumnPlusAfter,
SessionList,
},
mixins: [labelStyle],
@@ -475,7 +481,7 @@ export default {
<style lang="scss" scoped>
.controls {
display: flex;
margin: 5px;
margin: calc(var(--default-grid-baseline) * 2);
height: var(--default-clickable-area);
padding-left: var(--default-clickable-area);
@@ -486,17 +492,17 @@ export default {
h2 {
margin: 0;
margin-right: 10px;
font-size: 18px;
}
.board-bullet {
display: inline-block;
width: 20px;
height: 20px;
width: 16px;
height: 16px;
border: none;
border-radius: 50%;
background-color: transparent;
margin: 12px;
margin-left: -4px;
margin: var(--default-grid-baseline);
}
}
@@ -538,7 +544,7 @@ export default {
.filter--item {
input + label {
display: block;
padding: 6px 0;
padding: var(--default-grid-baseline) 0;
.avatardiv {
vertical-align: middle;
margin-bottom: 2px;

View File

@@ -4,7 +4,7 @@
-->
<template>
<div :title="t('text', 'Currently present people')"
<div :title="t('deck', 'Currently present people')"
class="avatar-list">
<div v-for="session in sessionsVisible"
:key="session.uid"

View File

@@ -4,7 +4,7 @@
-->
<template>
<div class="board-wrapper" :tabindex="-1">
<div class="board-wrapper" :tabindex="-1" @touchend="fixActionRestriction">
<Controls :board="board" />
<transition name="fade" mode="out-in">
@@ -22,23 +22,27 @@
<template #icon>
<DeckIcon />
</template>
<template #title>
<template #name>
{{ t('deck', 'No lists available') }}
</template>
<template v-if="canManage" #action>
{{ t('deck', 'Create a new list to add cards to this board') }}
<form @submit.prevent="addNewStack()">
<input id="new-stack-input-main"
v-model="newStackTitle"
v-focus
type="text"
class="no-close"
<NcTextField ref="newStackInput"
:disable="loading"
:value.sync="newStackTitle"
:placeholder="t('deck', 'List name')"
required>
<input title="t('deck', 'Add list')"
class="icon-confirm"
type="submit"
value="">
type="text" />
<NcButton type="secondary"
native-type="submit"
:disabled="loading"
:title="t('deck', 'Add list')">
<template #icon>
<CheckIcon v-if="!loading" :size="20" />
<NcLoadingIcon v-else :size="20" />
</template>
{{ t('deck', 'Add list') }}
</NcButton>
</form>
</template>
</NcEmptyContent>
@@ -82,8 +86,9 @@ import { Container, Draggable } from 'vue-smooth-dnd'
import { mapState, mapGetters } from 'vuex'
import Controls from '../Controls.vue'
import DeckIcon from '../icons/DeckIcon.vue'
import CheckIcon from 'vue-material-design-icons/Check.vue'
import Stack from './Stack.vue'
import { NcEmptyContent, NcModal } from '@nextcloud/vue'
import { NcEmptyContent, NcModal, NcButton, NcTextField, NcLoadingIcon } from '@nextcloud/vue'
import GlobalSearchResults from '../search/GlobalSearchResults.vue'
import { showError } from '../../helpers/errors.js'
import { createSession } from '../../sessions.js'
@@ -99,6 +104,10 @@ export default {
Stack,
NcEmptyContent,
NcModal,
NcTextField,
NcButton,
NcLoadingIcon,
CheckIcon,
CardSidebar,
},
inject: [
@@ -131,7 +140,7 @@ export default {
'canManage',
]),
stacksByBoard() {
return this.$store.getters.stacksByBoard(this.board.id)
return this.board?.id ? this.$store.getters.stacksByBoard(this.board.id) : []
},
dragHandleSelector() {
return this.canEdit ? '.stack__title' : '.no-drag'
@@ -147,6 +156,11 @@ export default {
showArchived() {
this.fetchData()
},
isEmpty(newValue) {
newValue && this.$nextTick(() => {
this.$refs?.newStackInput?.focus()
})
},
},
created() {
this.session = createSession(this.id)
@@ -217,6 +231,13 @@ export default {
window.removeEventListener('mouseup', this.stopMouseDrag)
window.removeEventListener('mouseleave', this.stopMouseDrag)
},
fixActionRestriction() {
document.body.classList.remove(
'smooth-dnd-no-user-select',
'smooth-dnd-disable-touch-action',
)
},
},
}
</script>
@@ -229,13 +250,16 @@ export default {
text-align: center;
display: flex;
width: 100%;
max-width: 200px;
margin: auto;
margin-top: 20px;
margin-top: calc(var(--default-grid-baseline) * 4);
gap: var(--default-grid-baseline);
input[type=text] {
input[type="text"] {
flex-grow: 1;
}
button[type="submit"] {
flex-shrink: 0;
}
}
.board-wrapper {
@@ -278,7 +302,9 @@ export default {
flex-grow: 1;
display: flex;
flex-direction: column;
padding: $stack-spacing;
// Margin left instead of padidng to avoid jumps on dropping a card
margin-left: $stack-spacing;
padding-right: $stack-spacing;
overflow-x: hidden;
overflow-y: auto;
padding-top: 15px;

View File

@@ -57,8 +57,11 @@
</NcActionButton>
</NcActions>
<NcActions v-if="canEdit && !showArchived && !isArchived">
<NcActionButton icon="icon-add" data-cy="action:add-card" @click.stop="showAddCard=true">
<NcActionButton data-cy="action:add-card" @click.stop="showAddCard=true">
{{ t('deck', 'Add card') }}
<template #icon>
<CardPlusOutline :size="20" />
</template>
</NcActionButton>
</NcActions>
</div>
@@ -85,15 +88,33 @@
</div>
</NcModal>
<transition name="slide-top" appear>
<div v-if="showAddCard" class="stack__card-add">
<Container :get-child-payload="payloadForCard(stack.id)"
group-name="stack"
data-click-closes-sidebar="true"
non-drag-area-selector=".dragDisabled"
:drag-handle-selector="dragHandleSelector"
data-dragscroll-enabled
@should-accept-drop="canEdit"
@drag-start="draggingCard = true"
@drag-end="draggingCard = false"
@drop="($event) => onDropCard(stack.id, $event)">
<Draggable v-for="card in cardsByStack" :key="card.id">
<transition :appear="animate && !card.animated && (card.animated=true)"
:appear-class="'zoom-appear-class'"
:appear-active-class="'zoom-appear-active-class'">
<CardItem :id="card.id" ref="card" :dragging="draggingCard" />
</transition>
</Draggable>
</Container>
<transition name="slide-bottom" appear>
<div v-show="showAddCard" class="stack__card-add">
<form :class="{ 'icon-loading-small': stateCardCreating }"
@submit.prevent.stop="clickAddCard()">
<label for="new-stack-input-main" class="hidden-visually">{{ t('deck', 'Add a new card') }}</label>
<input id="new-stack-input-main"
ref="newCardInput"
v-model="newCardTitle"
v-focus
type="text"
class="no-close"
:disabled="stateCardCreating"
@@ -109,25 +130,6 @@
</form>
</div>
</transition>
<Container :get-child-payload="payloadForCard(stack.id)"
group-name="stack"
data-click-closes-sidebar="true"
non-drag-area-selector=".dragDisabled"
:drag-handle-selector="dragHandleSelector"
data-dragscroll-enabled
@should-accept-drop="canEdit"
@drag-start="draggingCard = true"
@drag-end="draggingCard = false"
@drop="($event) => onDropCard(stack.id, $event)">
<Draggable v-for="card in cardsByStack" :key="card.id">
<transition :appear="animate && !card.animated && (card.animated=true)"
:appear-class="'zoom-appear-class'"
:appear-active-class="'zoom-appear-active-class'">
<CardItem :id="card.id" :dragging="draggingCard" />
</transition>
</Draggable>
</Container>
</div>
</template>
@@ -136,6 +138,7 @@ import ClickOutside from 'vue-click-outside'
import { mapGetters, mapState } from 'vuex'
import { Container, Draggable } from 'vue-smooth-dnd'
import ArchiveIcon from 'vue-material-design-icons/Archive.vue'
import CardPlusOutline from 'vue-material-design-icons/CardPlusOutline.vue'
import { NcActions, NcActionButton, NcModal } from '@nextcloud/vue'
import { showError, showUndo } from '@nextcloud/dialogs'
@@ -153,6 +156,7 @@ export default {
Draggable,
NcModal,
ArchiveIcon,
CardPlusOutline,
},
directives: {
ClickOutside,
@@ -216,10 +220,18 @@ export default {
showAddCard(newValue) {
if (!newValue) {
this.$store.dispatch('toggleShortcutLock', false)
} else {
this.$nextTick(() => {
this.$refs.newCardInput.focus()
})
}
},
},
mounted() {
this.setupAutoscrollOnDrag()
},
methods: {
stopCardCreation(e) {
// For some reason the submit event triggers a MouseEvent that is bubbling to the outside
@@ -298,6 +310,7 @@ export default {
this.$nextTick(() => {
this.$refs.newCardInput.focus()
this.animate = false
this.$refs.card[(this.$refs.card.length - 1)].scrollIntoView()
})
if (!this.cardDetailsInModal) {
this.$router.push({ name: 'card', params: { cardId: newCard.id } })
@@ -311,6 +324,36 @@ export default {
onCreateCardFocus() {
this.$store.dispatch('toggleShortcutLock', true)
},
setupAutoscrollOnDrag() {
let timer
const autoscroll = (event) => {
const viewportX = event.clientX
const boardElement = document.querySelector('.board')
const viewportWidth = boardElement.clientWidth
const offset = viewportWidth - viewportX
const scrollMultiplier = 10
const scrollBoundary = window.innerWidth * 0.15
if (offset < 100) {
const scrollToX = boardElement.scrollLeft + scrollMultiplier * (1 - offset / scrollBoundary)
boardElement.scrollTo(scrollToX, boardElement.scrollTop)
}
if (boardElement.scrollLeft > 0 && viewportX < scrollBoundary) {
const scrollToX = boardElement.scrollLeft - scrollMultiplier * (1 - viewportX / scrollBoundary)
boardElement.scrollTo(scrollToX, boardElement.scrollTop)
}
}
window.addEventListener('mousemove', (e) => {
if (!this.draggingCard) {
timer && clearInterval(timer)
return
}
clearInterval(timer)
timer = window.setInterval(() => autoscroll(e), 25)
})
},
},
}
</script>
@@ -332,8 +375,10 @@ export default {
z-index: 100;
padding-left: $card-spacing;
padding-right: $card-spacing;
margin: 6px;
margin-top: 0;
cursor: grab;
min-height: var(--default-clickable-area);
background-color: var(--color-main-background);
// Smooth fade out of the cards at the top
&:before {
@@ -353,14 +398,6 @@ export default {
}
}
&--add:before {
height: 80px;
background-image: linear-gradient(180deg, var(--color-main-background) 68px, rgba(255, 255, 255, 0) 100%);
body.theme--dark & {
background-image: linear-gradient(180deg, var(--color-main-background) 68px, rgba(0, 0, 0, 0) 100%);
}
}
& > * {
position: relative;
z-index: 100;
@@ -383,9 +420,8 @@ export default {
text-overflow: ellipsis;
max-width: calc($stack-width - 60px);
border-radius: 3px;
margin: 6px;
padding: 4px 4px;
font-size: 120%;
font-size: var(--default-font-size);
&:focus-visible {
outline: 2px solid var(--color-border-dark);
@@ -394,7 +430,15 @@ export default {
}
form {
margin: 2px 0;
margin: -4px;
input {
font-weight: bold;
padding: 0 6px;
}
input[type="submit"] {
border-style: solid;
border-left-style: none;
}
}
:deep {
@@ -406,20 +450,19 @@ export default {
}
.stack__card-add {
height: var(--default-clickable-area);
flex-shrink: 0;
z-index: 100;
display: flex;
margin-top: 5px;
margin-bottom: 8px;
margin-bottom: 5px;
padding-top: var(--default-grid-baseline);
background-color: var(--color-main-background);
form {
display: flex;
margin-left: 12px;
margin-right: 12px;
margin-left: $stack-spacing;
margin-right: $stack-spacing;
width: 100%;
border: 2px solid var(--color-border);
border: 2px solid var(--color-border-maxcontrast);
border-radius: var(--border-radius-large);
overflow: hidden;
padding: 2px;
@@ -436,6 +479,8 @@ export default {
input {
border: none;
margin: 0;
padding: 4px;
}
}
@@ -451,7 +496,16 @@ export default {
.slide-top-enter, .slide-top-leave-to {
transform: translateY(-10px);
opacity: 0;
height: 0px;
}
.slide-bottom-enter-active,
.slide-bottom-leave-active {
transition: all 100ms ease;
}
.slide-bottom-enter, .slide-bottom-leave-to {
transform: translateY(20px);
opacity: 0;
}
.modal__content {

View File

@@ -248,6 +248,10 @@ export default {
<style lang="scss" scoped>
.drop-upload--sidebar {
min-height: 100%;
}
.button-group {
display: flex;
gap: calc(var(--default-grid-baseline) * 3);

View File

@@ -162,7 +162,9 @@ export default {
},
methods: {
focusHeader() {
this.$refs.cardSidebar.$el.querySelector('.app-sidebar-header__mainname').focus()
this.$nextTick(() => {
this.$refs?.cardSidebar.$el.querySelector('.app-sidebar-header__mainname')?.focus()
})
},
handleUpdateTitleEditable(value) {
this.titleEditable = value
@@ -209,6 +211,10 @@ section.app-sidebar__tab--active {
height: 100%;
}
.modal-container {
overflow: hidden;
}
// FIXME: Obivously we should at some point not randomly reuse the sidebar component
// since this is not oficially supported
.modal__card .app-sidebar {
@@ -220,12 +226,26 @@ section.app-sidebar__tab--active {
left: 0;
right: 0;
max-width: calc(100% - #{$modal-padding * 2});
min-height: calc(100vh - var(--header-height) * 4);
padding: 0 14px;
height: 97%;
overflow: initial;
overflow: hidden !important;
user-select: text;
-webkit-user-select: text;
.app-sidebar-header__mainname-container {
padding-top: calc(var(--default-grid-baseline, 4px) * 2);
}
.app-sidebar-tabs {
max-height: 90%;
}
.app-sidebar__tab {
min-height: calc(100% - 20px);
max-height: calc(100% - 20px);
}
// FIXME: test
&:deep {
.app-sidebar-header {

View File

@@ -247,7 +247,6 @@ export default defineComponent({
.done-info--duedate,
.done-info--done {
display: flex;
padding-top: 10px;
&.dimmed {
color: var(--color-text-maxcontrast);
}

View File

@@ -168,13 +168,13 @@ export default {
}
.badge-left {
align-self: end;
margin-bottom: 8px;
flex-basis: auto;
flex-grow: 1;
flex-shrink: 1;
flex-wrap: wrap;
align-content: flex-end;
align-items: center;
align-self: center;
gap: 3px;
}
@@ -196,6 +196,10 @@ export default {
opacity: 0;
}
.avatars:deep(button) {
margin: 0;
}
@media print {
.badges {
align-items: flex-start;

View File

@@ -66,11 +66,11 @@ export default {
@import '../../css/variables';
.card-cover {
height: 100px;
height: 90px;
display: flex;
margin-top: -8px;
margin-left: -8px;
margin-right: -8px;
margin-top: -4px;
margin-left: -4px;
margin-right: -4px;
.image-wrapper {
flex: 1;
@@ -79,10 +79,10 @@ export default {
background-repeat: no-repeat;
background-position: center center;
&.rounded-left {
border-top-left-radius: 10px;
border-top-left-radius: calc(var(--border-radius-large) - 1px);
}
&.rounded-right {
border-top-right-radius: 10px;
border-top-right-radius: calc(var(--border-radius-large) - 1px);
}
}
}

View File

@@ -6,7 +6,7 @@
<template>
<AttachmentDragAndDrop v-if="card" :card-id="card.id" class="drop-upload--card">
<div :ref="`card${card.id}`"
:class="{'compact': compactMode, 'current-card': currentCard, 'has-labels': card.labels && card.labels.length > 0, 'card__editable': canEdit, 'card__archived': card.archived }"
:class="{'compact': compactMode, 'current-card': currentCard, 'has-labels': card.labels && card.labels.length > 0, 'card__editable': canEdit, 'card__archived': card.archived, 'card__highlight': highlight}"
tag="div"
:tabindex="0"
class="card"
@@ -19,10 +19,10 @@
</div>
<CardCover v-if="showCardCover" :card-id="card.id" />
<div class="card-upper">
<h3 v-if="inlineEditingBlocked" dir="auto">
<h4 v-if="inlineEditingBlocked" dir="auto">
{{ card.title }}
</h3>
<h3 v-else
</h4>
<h4 v-else
dir="auto"
class="editable"
:aria-label="t('deck', 'Edit card title')">
@@ -35,7 +35,7 @@
@click.stop
@keyup.esc="cancelEdit"
@keyup.stop>{{ card.title }}</span>
</h3>
</h4>
<DueDate v-if="compactMode" :card="card" />
<CardMenu v-if="showMenuAtTitle" :card="card" class="right card-menu" />
@@ -103,6 +103,11 @@ export default {
default: false,
},
},
data() {
return {
highlight: false,
}
},
computed: {
...mapState({
compactMode: state => state.compactMode,
@@ -270,6 +275,14 @@ export default {
},
})
},
scrollIntoView() {
this.$el.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' })
this.focus()
this.highlight = true
setTimeout(() => {
this.highlight = false
}, 2000)
},
},
}
</script>
@@ -290,11 +303,10 @@ export default {
background-color: var(--color-main-background);
margin-bottom: $card-spacing;
padding: var(--default-grid-baseline) $card-padding;
border: 2px solid var(--color-border);
border: 2px solid var(--color-border-dark);
width: 100%;
display: flex;
flex-direction: column;
gap: 6px;
&:deep(*) {
cursor: pointer;
@@ -314,9 +326,10 @@ export default {
.card-upper {
display: flex;
h3 {
h4 {
font-weight: normal;
margin: 0;
padding: 6px;
padding: var(--default-grid-baseline);
flex-grow: 1;
font-size: 100%;
overflow: hidden;
@@ -359,10 +372,28 @@ export default {
&.card__archived {
background-color: var(--color-background-dark);
}
@keyframes highlight {
0% {
border-color: var(--color-border-dark);
}
20% {
border-color: var(--color-primary-element);
}
70% {
border-color: var(--color-primary-element);
}
100% {
border-color: var(--color-border-dark);
}
}
&.card__highlight {
animation: highlight 2s;
}
.card-labels {
display: flex;
align-items: end;
margin-bottom: var(--default-grid-baseline);
padding-left: var(--default-grid-baseline);
padding-top: var(--default-grid-baseline);
.labels {
flex-wrap: wrap;
@@ -402,7 +433,6 @@ export default {
display: flex;
height: 32px;
width: 32px;
margin-top: 6px;
}
&.has-labels {
padding-bottom: $card-padding;

View File

@@ -8,19 +8,41 @@
icon="icon-add"
@click.prevent.stop="startCreateBoard" />
<div v-else class="board-create">
<NcColorPicker v-model="color" class="app-navigation-entry-bullet-wrapper">
<NcColorPicker v-model="color" class="app-navigation-entry-bullet-wrapper" :disabled="loading">
<div :style="{ backgroundColor: color }" class="color0 icon-colorpicker app-navigation-entry-bullet" />
</NcColorPicker>
<form @submit.prevent.stop="createBoard">
<input :placeholder="t('deck', 'Board name')" type="text" required>
<input type="submit" value="" class="icon-confirm">
<NcActions><NcActionButton icon="icon-close" @click.stop.prevent="cancelEdit" /></NcActions>
<NcTextField ref="inputField"
:disable="loading"
:value.sync="value"
:placeholder="t('deck', 'Board name')"
type="text"
required />
<NcButton type="tertiary"
:disabled="loading"
:title="t('deck', 'Cancel edit')"
@click.stop.prevent="cancelEdit">
<template #icon>
<CloseIcon :size="20" />
</template>
</NcButton>
<NcButton type="tertiary"
native-type="submit"
:disabled="loading"
:title="t('deck', 'Save board')">
<template #icon>
<CheckIcon v-if="!loading" :size="20" />
<NcLoadingIcon v-else :size="20" />
</template>
</NcButton>
</form>
</div>
</template>
<script>
import { NcColorPicker, NcActionButton, NcActions, NcAppNavigationItem } from '@nextcloud/vue'
import { NcButton, NcColorPicker, NcAppNavigationItem, NcLoadingIcon, NcTextField } from '@nextcloud/vue'
import CheckIcon from 'vue-material-design-icons/Check.vue'
import CloseIcon from 'vue-material-design-icons/Close.vue'
/**
*
@@ -35,30 +57,33 @@ function randomColor() {
export default {
name: 'AppNavigationAddBoard',
components: { NcColorPicker, NcAppNavigationItem, NcActionButton, NcActions },
components: { NcButton, NcColorPicker, NcAppNavigationItem, NcLoadingIcon, NcTextField, CheckIcon, CloseIcon },
directives: {},
props: {},
data() {
return {
value: '',
classes: [],
editing: false,
loading: false,
color: randomColor(),
}
},
computed: {},
watch: {},
mounted() {},
methods: {
startCreateBoard(e) {
this.editing = true
this.$nextTick(() => {
this.$refs?.inputField.focus()
})
},
async createBoard(e) {
const title = e.currentTarget.childNodes[0].value
this.loading = true
const title = this.value.trim()
await this.$store.dispatch('createBoard', {
title,
color: this.color.substring(1),
})
this.loading = false
this.editing = false
this.color = randomColor()
},
@@ -89,10 +114,9 @@ export default {
width: var(--default-clickable-area);
height: var(--default-clickable-area);
.color0 {
width: 30px !important;
margin: 5px;
margin-left: 7px;
height: 30px;
width: 24px !important;
margin: var(--default-grid-baseline);
height: 24px;
border-radius: 50%;
background-size: 14px;
}

View File

@@ -9,6 +9,8 @@
:to="routeTo"
:undo="deleted"
:menu-placement="'auto'"
:force-display-actions="isTouchDevice"
@click="onNavigate"
@undo="unDelete">
<NcAppNavigationIconBullet slot="icon" :color="board.color" />
@@ -114,24 +116,47 @@
<div :style="{ backgroundColor: getColor }" class="color0 icon-colorpicker app-navigation-entry-bullet" />
</NcColorPicker>
<form @submit.prevent.stop="applyEdit">
<input v-model="editTitle"
v-focus
dir="auto"
<NcTextField ref="inputField"
:disable="loading"
:value.sync="editTitle"
:placeholder="t('deck', 'Board name')"
type="text"
required>
<input type="submit" value="" class="icon-confirm">
<NcActions><NcActionButton icon="icon-close" @click.stop.prevent="cancelEdit" /></NcActions>
required />
<NcButton type="tertiary"
:disabled="loading"
native-type="submit"
:title="t('deck', 'Cancel edit')"
@click.stop.prevent="cancelEdit">
<template #icon>
<CloseIcon :size="20" />
</template>
</NcButton>
<NcButton type="tertiary"
native-type="submit"
:disabled="loading"
:title="t('deck', 'Save board')">
<template #icon>
<CheckIcon v-if="!loading" :size="20" />
<NcLoadingIcon v-else :size="20" />
</template>
</NcButton>
</form>
</div>
</template>
<script>
import { NcAppNavigationIconBullet, NcAppNavigationItem, NcColorPicker, NcActions, NcActionButton } from '@nextcloud/vue'
import { NcAppNavigationIconBullet, NcAppNavigationItem, NcColorPicker, NcButton, NcTextField, NcActionButton } from '@nextcloud/vue'
import ClickOutside from 'vue-click-outside'
import ArchiveIcon from 'vue-material-design-icons/Archive.vue'
import CloneIcon from 'vue-material-design-icons/ContentDuplicate.vue'
import AccountIcon from 'vue-material-design-icons/Account.vue'
import CloseIcon from 'vue-material-design-icons/Close.vue'
import CheckIcon from 'vue-material-design-icons/Check.vue'
import { loadState } from '@nextcloud/initial-state'
import { emit } from '@nextcloud/event-bus'
import isTouchDevice from '../../mixins/isTouchDevice.js'
const canCreateState = loadState('deck', 'canCreate')
@@ -141,15 +166,19 @@ export default {
NcAppNavigationIconBullet,
NcAppNavigationItem,
NcColorPicker,
NcActions,
NcButton,
NcTextField,
NcActionButton,
AccountIcon,
ArchiveIcon,
CloneIcon,
CloseIcon,
CheckIcon,
},
directives: {
ClickOutside,
},
mixins: [isTouchDevice],
inject: [
'boardApi',
],
@@ -313,13 +342,20 @@ export default {
actionExport() {
this.boardApi.exportBoard(this.board)
},
onNavigate() {
if (this.isTouchDevice) {
emit('toggle-navigation', {
open: false,
})
}
},
},
}
</script>
<style lang="scss" scoped>
.board-edit {
margin-left: var(--default-clickable-area);
margin-left: calc(var(--default-clickable-area) / 2);
order: 1;
display: flex;
height: var(--default-clickable-area);
@@ -338,10 +374,9 @@ export default {
width: var(--default-clickable-area);
height: var(--default-clickable-area);
.color0 {
width: 30px !important;
margin: 5px;
margin-left: 7px;
height: 30px;
width: 24px !important;
margin: var(--default-grid-baseline);
height: 24px;
border-radius: 50%;
background-size: 14px;
}
@@ -350,4 +385,10 @@ export default {
.forced-active {
box-shadow: inset 4px 0 var(--color-primary-element);
}
:deep(.active) {
.material-design-icon svg {
fill: var(--color-primary-element-text);
}
}
</style>

View File

@@ -168,11 +168,13 @@ export default {
.dashboard-column {
display: flex;
flex-direction: column;
min-width: $stack-width;
width: $stack-width;
margin-left: $stack-spacing;
margin-right: $stack-spacing;
h3 {
font-size: var(--default-font-size);
margin: -6px;
margin-bottom: 12px;
padding: 6px 13px;

View File

@@ -9,9 +9,13 @@
margin-top: 10px;
&--icon {
width: 38px;
padding-top: 12px;
width: var(--default-clickable-area);
height: var(--default-clickable-area);
flex-shrink: 0;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
}
&--selector {
@@ -21,5 +25,6 @@
&--content {
display: flex;
flex-grow: 1;
align-items: center;
}
}

View File

@@ -2,8 +2,8 @@
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
$card-spacing: 16px;
$card-padding: 8px;
$stack-spacing: 12px;
$stack-width: 280px;
$board-spacing: 16px;
$card-spacing: 8px;
$card-padding: 4px;
$stack-spacing: 12px;
$stack-width: 280px;
$board-spacing: 16px;

View File

@@ -0,0 +1,12 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
export default {
computed: {
isTouchDevice() {
return ('ontouchstart' in window) || (navigator.maxTouchPoints > 0)
},
},
}

View File

@@ -93,7 +93,7 @@
<template #icon>
<NcLoadingIcon />
</template>
<template #title>
<template #name>
{{ t('deck', 'Creating the new card …') }}
</template>
</NcEmptyContent>
@@ -101,7 +101,7 @@
<template #icon>
<CardPlusOutline />
</template>
<template #title>
<template #name>
{{ t('deck', 'Card "{card}" was added to "{board}"', { card: card.title, board: selectedBoard.title }) }}
</template>
<template #action>

View File

@@ -31,11 +31,11 @@ use OCP\Server;
* @group DB
*/
class BoardDatabaseTest extends \Test\TestCase {
public const TEST_USER1 = "test-share-user1";
public const TEST_USER2 = "test-share-user2";
public const TEST_USER3 = "test-share-user3";
public const TEST_USER4 = "test-share-user4";
public const TEST_GROUP1 = "test-share-group1";
public const TEST_USER1 = 'test-share-user1';
public const TEST_USER2 = 'test-share-user2';
public const TEST_USER3 = 'test-share-user3';
public const TEST_USER4 = 'test-share-user4';
public const TEST_GROUP1 = 'test-share-group1';
/** @var BoardService */
private $boardService;

View File

@@ -71,7 +71,7 @@ class BoardContext implements Context {
break;
}
}
Assert::assertNotNull($id, "Could not find board named ".$boardName);
Assert::assertNotNull($id, 'Could not find board named '.$boardName);
} else {
$id = $this->board['id'];
}

View File

@@ -36,7 +36,7 @@ class SearchContext implements Context {
/**
* @When /^searching for "([^"]*)" in comments in unified search$/
* @param string $term
* https://cloud.nextcloud.com/ocs/v2.php/search/providers/talk-conversations/search?term=an&from=%2Fapps%2Fdashboard%2F
* https://cloud.nextcloud.com/ocs/v2.php/search/providers/talk-conversations/search?term=an&from=%2Fapps%2Fdashboard%2F
*/
public function searchingForComments(string $term) {
$this->requestContext->sendOCSRequest('GET', '/search/providers/search-deck-comment/search?term=' . urlencode($term), []);

View File

@@ -32,7 +32,7 @@ class SessionContext implements Context {
'boardId' => $board['id'],
]);
$res = json_decode((string)$this->getResponse()->getBody(), true);
Assert::assertArrayHasKey('token', $res['ocs']['data'], "session creation did not respond with a token");
Assert::assertArrayHasKey('token', $res['ocs']['data'], 'session creation did not respond with a token');
// store token
$user = $this->serverContext->getCurrentUser();
@@ -44,7 +44,7 @@ class SessionContext implements Context {
*/
public function theResponseShouldHaveActiveSessions($length) {
$board = $this->boardContext->getLastUsedBoard();
Assert::assertEquals($length, count($board['activeSessions']), "unexpected count of active sessions");
Assert::assertEquals($length, count($board['activeSessions']), 'unexpected count of active sessions');
}
/**
@@ -52,7 +52,7 @@ class SessionContext implements Context {
*/
public function theUserShouldBeInTheListOfActiveSessions($user) {
$board = $this->boardContext->getLastUsedBoard();
Assert::assertContains($user, $board['activeSessions'], "user is not found in the list of active sessions");
Assert::assertContains($user, $board['activeSessions'], 'user is not found in the list of active sessions');
}
/**
@@ -67,7 +67,7 @@ class SessionContext implements Context {
$user = $this->serverContext->getCurrentUser();
$token = $this->tokens[$user];
Assert::assertNotEmpty($token, "no token for the user found");
Assert::assertNotEmpty($token, 'no token for the user found');
$this->requestContext->sendOCSRequest('POST', '/apps/deck/api/v1.0/session/close', [
'boardId' => $board['id'],
'token' => $token

View File

@@ -88,8 +88,8 @@ class UserExportTest extends \Test\TestCase {
public function getComment($id) {
$comment = new Comment();
$comment->setActor("users", "admin");
$comment->setMessage("fake comment" . $id);
$comment->setActor('users', 'admin');
$comment->setMessage('fake comment' . $id);
return $comment;
}
public function testExecute() {

View File

@@ -27,7 +27,7 @@ class AclTest extends \Test\TestCase {
private function createAclUser() {
$acl = new Acl();
$acl->setId(1);
$acl->setParticipant("admin");
$acl->setParticipant('admin');
$acl->setType(Acl::PERMISSION_TYPE_USER);
$acl->setBoardId(1);
$acl->setPermissionEdit(true);
@@ -39,7 +39,7 @@ class AclTest extends \Test\TestCase {
private function createAclGroup() {
$acl = new Acl();
$acl->setId(1);
$acl->setParticipant("administrators");
$acl->setParticipant('administrators');
$acl->setType(Acl::PERMISSION_TYPE_GROUP);
$acl->setBoardId(1);
$acl->setPermissionEdit(true);

View File

@@ -28,7 +28,7 @@ class AttachmentTest extends \Test\TestCase {
$attachment = new Attachment();
$attachment->setId(1);
$attachment->setCardId(123);
$attachment->setData("blob");
$attachment->setData('blob');
$attachment->setCreatedBy('admin');
$attachment->setType('deck_file');
return $attachment;

View File

@@ -8,9 +8,9 @@ class BoardTest extends TestCase {
private function createBoard() {
$board = new Board();
$board->setId(1);
$board->setTitle("My Board");
$board->setOwner("admin");
$board->setColor("000000");
$board->setTitle('My Board');
$board->setOwner('admin');
$board->setColor('000000');
$board->setArchived(false);
// TODO: relation shared labels acl
return $board;
@@ -20,9 +20,9 @@ class BoardTest extends TestCase {
$board->setUsers(['user1', 'user2']);
$this->assertEquals([
'id' => 1,
'title' => "My Board",
'owner' => "admin",
'color' => "000000",
'title' => 'My Board',
'owner' => 'admin',
'color' => '000000',
'labels' => [],
'permissions' => [],
'stacks' => [],
@@ -44,9 +44,9 @@ class BoardTest extends TestCase {
self::assertNull($board->getLabels());
$this->assertEquals([
'id' => 1,
'title' => "My Board",
'owner' => "admin",
'color' => "000000",
'title' => 'My Board',
'owner' => 'admin',
'color' => '000000',
'labels' => [],
'permissions' => [],
'stacks' => [],
@@ -63,13 +63,13 @@ class BoardTest extends TestCase {
public function testSetLabels() {
$board = $this->createBoard();
$board->setLabels(["foo", "bar"]);
$board->setLabels(['foo', 'bar']);
$this->assertEquals([
'id' => 1,
'title' => "My Board",
'owner' => "admin",
'color' => "000000",
'labels' => ["foo", "bar"],
'title' => 'My Board',
'owner' => 'admin',
'color' => '000000',
'labels' => ['foo', 'bar'],
'permissions' => [],
'stacks' => [],
'deletedAt' => 0,
@@ -95,9 +95,9 @@ class BoardTest extends TestCase {
$board->setShared(1);
$this->assertEquals([
'id' => 1,
'title' => "My Board",
'owner' => "admin",
'color' => "000000",
'title' => 'My Board',
'owner' => 'admin',
'color' => '000000',
'labels' => [],
'permissions' => [],
'stacks' => [],

View File

@@ -32,13 +32,13 @@ class CardTest extends TestCase {
private function createCard() {
$card = new Card();
$card->setId(1);
$card->setTitle("My Card");
$card->setDescription("a long description");
$card->setTitle('My Card');
$card->setDescription('a long description');
$card->setStackId(1);
$card->setType('text');
$card->setLastModified(234);
$card->setCreatedAt(123);
$card->setOwner("admin");
$card->setOwner('admin');
$card->setOrder(12);
$card->setArchived(false);
$card->setDone(null);
@@ -68,8 +68,8 @@ class CardTest extends TestCase {
$card = $this->createCard();
$this->assertEquals([
'id' => 1,
'title' => "My Card",
'description' => "a long description",
'title' => 'My Card',
'description' => 'a long description',
'type' => 'text',
'lastModified' => 234,
'createdAt' => 123,
@@ -96,8 +96,8 @@ class CardTest extends TestCase {
$card->setLabels([]);
$this->assertEquals([
'id' => 1,
'title' => "My Card",
'description' => "a long description",
'title' => 'My Card',
'description' => 'a long description',
'type' => 'text',
'lastModified' => 234,
'createdAt' => 123,
@@ -126,8 +126,8 @@ class CardTest extends TestCase {
$card->setLabels([]);
$this->assertEquals([
'id' => 1,
'title' => "My Card",
'description' => "a long description",
'title' => 'My Card',
'description' => 'a long description',
'type' => 'text',
'lastModified' => 234,
'createdAt' => 123,

View File

@@ -29,8 +29,8 @@ class LabelTest extends TestCase {
private function createLabel() {
$label = new Label();
$label->setId(1);
$label->setTitle("My Label");
$label->setColor("000000");
$label->setTitle('My Label');
$label->setColor('000000');
return $label;
}
public function testJsonSerializeBoard() {

View File

@@ -27,7 +27,7 @@ class StackTest extends \Test\TestCase {
private function createStack() {
$board = new Stack();
$board->setId(1);
$board->setTitle("My Stack");
$board->setTitle('My Stack');
$board->setBoardId(1);
$board->setOrder(1);
return $board;
@@ -36,7 +36,7 @@ class StackTest extends \Test\TestCase {
$stack = $this->createStack();
$this->assertEquals([
'id' => 1,
'title' => "My Stack",
'title' => 'My Stack',
'order' => 1,
'boardId' => 1,
'deletedAt' => 0,
@@ -45,15 +45,15 @@ class StackTest extends \Test\TestCase {
], $stack->jsonSerialize());
}
public function testJsonSerializeWithCards() {
$cards = ["foo", "bar"];
$cards = ['foo', 'bar'];
$stack = $this->createStack();
$stack->setCards($cards);
$this->assertEquals([
'id' => 1,
'title' => "My Stack",
'title' => 'My Stack',
'order' => 1,
'boardId' => 1,
'cards' => ["foo", "bar"],
'cards' => ['foo', 'bar'],
'deletedAt' => 0,
'lastModified' => 0,
'ETag' => $stack->getETag(),

View File

@@ -69,8 +69,8 @@ class ExceptionMiddlewareTest extends \Test\TestCase {
public function testAfterException($exception, $status, $message) {
$result = $this->exceptionMiddleware->afterException($this->controller, 'bar', $exception);
$expected = new JSONResponse([
"status" => $status,
"message" => $message
'status' => $status,
'message' => $message
], $status);
$this->assertEquals($expected, $result);
}

View File

@@ -60,7 +60,7 @@ class NotificationHelperTest extends \Test\TestCase {
protected $cardMapper;
/** @var BoardMapper|MockObject */
protected $boardMapper;
/** @var AssignmentMapper|MockObject */
/** @var AssignmentMapper|MockObject */
protected $assignedUsersMapper;
/** @var PermissionService|MockObject */
protected $permissionService;

View File

@@ -78,7 +78,7 @@ class AssignmentServiceTest extends TestCase {
*/
private $assignmentService;
/**
* @var AssignmentServiceValidator
* @var AssignmentServiceValidator
*/
private $assignmentServiceValidator;

View File

@@ -70,7 +70,7 @@ class AttachmentServiceTest extends TestCase {
private $cardMapper;
/** @var PermissionService|MockObject */
private $permissionService;
/** @var string */
/** @var string */
private $userId = 'admin';
/** @var Application|MockObject */
private $application;
@@ -79,7 +79,7 @@ class AttachmentServiceTest extends TestCase {
private $attachmentService;
/** @var MockObject */
private $attachmentServiceImpl;
/** @var ActivityManager */
/** @var ActivityManager */
private $activityManager;
private $appContainer;
/** @var IL10N */
@@ -91,7 +91,7 @@ class AttachmentServiceTest extends TestCase {
*/
private $filesAppServiceImpl;
/**
* @var AttachmentServiceValidator
* @var AttachmentServiceValidator
*/
private $attachmentServiceValidator;

View File

@@ -68,6 +68,8 @@ class CardServiceTest extends TestCase {
private $boardService;
/** @var LabelMapper|MockObject */
private $labelMapper;
/** @var LabelService|MockObject */
private $labelService;
private $boardMapper;
/** @var AttachmentService|MockObject */
private $attachmentService;
@@ -96,6 +98,7 @@ class CardServiceTest extends TestCase {
$this->stackMapper = $this->createMock(StackMapper::class);
$this->boardMapper = $this->createMock(BoardMapper::class);
$this->labelMapper = $this->createMock(LabelMapper::class);
$this->labelService = $this->createMock(LabelService::class);
$this->permissionService = $this->createMock(PermissionService::class);
$this->boardService = $this->createMock(BoardService::class);
$this->notificationHelper = $this->createMock(NotificationHelper::class);
@@ -118,6 +121,7 @@ class CardServiceTest extends TestCase {
$this->stackMapper,
$this->boardMapper,
$this->labelMapper,
$this->labelService,
$this->permissionService,
$this->boardService,
$this->notificationHelper,

View File

@@ -31,17 +31,17 @@ use Test\TestCase;
class LabelServiceTest extends TestCase {
/** @var LabelMapper|\PHPUnit\Framework\MockObject\MockObject */
/** @var LabelMapper|\PHPUnit\Framework\MockObject\MockObject */
private $labelMapper;
/** @var PermissionService|\PHPUnit\Framework\MockObject\MockObject */
/** @var PermissionService|\PHPUnit\Framework\MockObject\MockObject */
private $permissionService;
/** @var LabelService */
/** @var LabelService */
private $labelService;
/** @var BoardService|\PHPUnit\Framework\MockObject\MockObject */
private $boardService;
/** @var ChangeHelper|\PHPUnit\Framework\MockObject\MockObject */
private $changeHelper;
/** @var LabelServiceValidator\MockObject */
/** @var LabelServiceValidator\MockObject */
private $labelServiceValidator;
public function setUp(): void {

View File

@@ -212,8 +212,8 @@ class StackServiceTest extends TestCase {
$this->stackMapper->expects($this->once())->method('update')->willReturn($stackToBeDeleted);
$this->cardMapper->expects($this->once())->method('findAll')->willReturn([]);
$this->stackService->delete(123);
$this->assertTrue($stackToBeDeleted->getDeletedAt() <= time(), "deletedAt is in the past");
$this->assertTrue($stackToBeDeleted->getDeletedAt() > 0, "deletedAt is set");
$this->assertTrue($stackToBeDeleted->getDeletedAt() <= time(), 'deletedAt is in the past');
$this->assertTrue($stackToBeDeleted->getDeletedAt() > 0, 'deletedAt is set');
}
public function testUpdate() {

View File

@@ -111,8 +111,8 @@ class CardApiControllerTest extends \Test\TestCase {
$this->stackExample['id']);
$this->cardService->expects($this->once())
->method('update')
->willReturn($card);
->method('update')
->willReturn($card);
$expected = new DataResponse($card, HTTP::STATUS_OK);
$actual = $this->controller->update('title', 'plain', 0, 'description', $this->userId, null);