Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7350e45
refactor(pinia): move remaining vuex state to pinia setting store
grnd-alt Aug 11, 2026
03b200e
refactor(vue3): use vue3 slot syntax
grnd-alt Aug 13, 2026
e1c4390
refactor(vue3): temporary vue3 compat build
grnd-alt Aug 13, 2026
342b0f3
refactor(vue3): temporarily disable secondary webpack entrypoints
grnd-alt Aug 13, 2026
0d4354c
refactor(vue3): initialize vue3 app correctly
grnd-alt Aug 13, 2026
b2f3d19
refactor(vue3): replace beforeDestroy with beforeUnmount
grnd-alt Aug 13, 2026
ee8527c
refactor(vue3): temporarily enable new vue3 render API in compat
grnd-alt Aug 13, 2026
9c324a8
refactor(vue3): use vue3 modelValue syntax
grnd-alt Aug 14, 2026
10f9777
refactor(vue3): replace value.sync with v-model
grnd-alt Aug 17, 2026
0fe42e8
refactore(vue3): use v-v-on-click-outside directive
grnd-alt Aug 17, 2026
bdf5abb
refactor(vue3): remove Vue.set usage
grnd-alt Aug 17, 2026
38f7547
refactor(vue3): replace deprecated vue-router next calls
grnd-alt Aug 17, 2026
c04fd56
refactor(vue3): convert CardSidebar and DueDate to composition API
grnd-alt Aug 18, 2026
c8662ee
refactor(vue3): disable vue3_compat watch_array flag
grnd-alt Aug 18, 2026
28c9165
refactor(vue3): rename CardMenuEntries.vue to NcActionsCardMenuEntrie…
grnd-alt Aug 19, 2026
150646f
refactor(vue3): align filter popover to nextcloud/vue@9
grnd-alt Aug 19, 2026
b506b5b
refactor(vue3): bring back globalSearchResults vertical scroll
grnd-alt Aug 19, 2026
1bddf4d
refactor(vue3): replace vue instance emitters with nextcloud event bus
grnd-alt Aug 19, 2026
05ac4e5
refactor(vue3): convert alternative entrypoints to vue3
grnd-alt Aug 19, 2026
a2035d6
refactor(vue3): remove @vue/compat
grnd-alt Aug 19, 2026
e379b84
refactor(vue3): update scss @import to @use
grnd-alt Aug 19, 2026
4dde08e
refactor(vue3): cleanup transition remains
grnd-alt Aug 19, 2026
28fc44d
refactor(vue3): lint fixes
grnd-alt Aug 19, 2026
5798b9b
refactor(vue3): remove nextcloud/axios usage from cypress commands
grnd-alt Aug 19, 2026
af75efa
refactor(vue3): replace .sync with v-model
grnd-alt Aug 20, 2026
d909bc8
fix(cypress): open dropdown before searching for option in dropdown
grnd-alt Aug 20, 2026
68adc97
fix(cypress): add data-cy identifier for app navigation categories
grnd-alt Aug 20, 2026
d8371a8
refactor(vue3): replace this. calls from vue2
grnd-alt Aug 20, 2026
5bba6bb
refactor(vue3): switch NcButton type prop to variant
grnd-alt Aug 20, 2026
581c954
refactor(vue3): update cypress to v15
grnd-alt Sep 2, 2026
a29c2cf
refactor(vue3): adapt vue3 refactor to cardFeatures.js cypress
grnd-alt Sep 2, 2026
de06be4
refactor(cypress): move to nextcloud/e2e-test-server
grnd-alt Sep 7, 2026
4c7dee0
fix(ci): install @vue/tsconfig
grnd-alt Sep 7, 2026
d251756
refactor(vue3): fix v-focus directive
grnd-alt Sep 8, 2026
4158ab3
refactor(vue3): adjust cypress deckdashboard selector to new library
grnd-alt Sep 8, 2026
689077b
refactor(vue3): update eslint to vue3 config
grnd-alt Sep 8, 2026
e4ac854
chore(tests): replace Cypress.env
grnd-alt Sep 8, 2026
51ae85e
refactor(vue3): replace :checked with :model-value
grnd-alt Sep 10, 2026
7fd4c3e
refactor(vue3): clear comment form on submit
grnd-alt Sep 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
root: true,
extends: [
'@nextcloud',
'@nextcloud/eslint-config/vue3',
],
rules: {
'jsdoc/require-param-description': ['off'],
Expand All @@ -10,5 +10,6 @@ module.exports = {
'jsdoc/no-undefined-types': ['off'],
'jsdoc/require-property-description': ['off'],
'import/no-named-as-default-member': ['off'],
'@typescript-eslint/no-unused-vars': ['off'],
},
}
1 change: 1 addition & 0 deletions cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { defineConfig } = require('cypress')
const cypressSplit = require('cypress-split')

module.exports = defineConfig({
allowCypressEnv: false,
projectId: '1s7wkc',
viewportWidth: 1280,
viewportHeight: 720,
Expand Down
5 changes: 3 additions & 2 deletions cypress/e2e/cardActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ const user = randUser()
const boardData = sampleBoard()

const auth = {
user: user.userId,
username: user.userId,
password: user.password,
}

const useModal = (useModal) => {
return cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/ocs/v2.php/apps/deck/api/v1.0/config/cardDetailsInModal?format=json`,
url: `${Cypress.expose('baseUrl')}/ocs/v2.php/apps/deck/api/v1.0/config/cardDetailsInModal?format=json`,
auth,
body: { value: useModal },
}).then((response) => {
Expand Down Expand Up @@ -92,6 +92,7 @@ describe('Card actions', function () {

cy.get('.app-sidebar-header .action-item__menutoggle').click()
cy.get('.v-popper__popper button:contains("Move/copy card")').click()
cy.get('.vs__dropdown-toggle span[title="MyTestBoard"]').should('be.visible').click()
cy.get('.vs__dropdown-menu span[title="MyTestBoard"]').should('be.visible').click()
cy.wait(3000) // wait for select component to load stacks
cy.get('[data-cy="select-stack"] .vs__dropdown-toggle').should('be.visible').click()
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/cardColor.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ const user = randUser()
const boardData = sampleBoard()

const auth = {
user: user.userId,
username: user.userId,
password: user.password,
}

const useModal = (useModal) => {
return cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/ocs/v2.php/apps/deck/api/v1.0/config/cardDetailsInModal?format=json`,
url: `${Cypress.expose('baseUrl')}/ocs/v2.php/apps/deck/api/v1.0/config/cardDetailsInModal?format=json`,
auth,
body: { value: useModal },
}).then((response) => {
Expand Down
16 changes: 8 additions & 8 deletions cypress/e2e/cardFeatures.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ const user = randUser()
const boardData = sampleBoard()

const auth = {
user: user.userId,
username: user.userId,
password: user.password,
}

const useModal = (useModal) => {
return cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/ocs/v2.php/apps/deck/api/v1.0/config/cardDetailsInModal?format=json`,
url: `${Cypress.expose('baseUrl')}/ocs/v2.php/apps/deck/api/v1.0/config/cardDetailsInModal?format=json`,
auth,
body: { value: useModal },
}).then((response) => {
Expand All @@ -28,7 +28,7 @@ const useModal = (useModal) => {
const addCardsAtTop = (enabled) => {
return cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/ocs/v2.php/apps/deck/api/v1.0/config/stackAddCardAtTop?format=json`,
url: `${Cypress.expose('baseUrl')}/ocs/v2.php/apps/deck/api/v1.0/config/stackAddCardAtTop?format=json`,
auth,
body: { value: enabled },
}).then((response) => {
Expand Down Expand Up @@ -100,7 +100,7 @@ describe('Card', function () {
})

cy.get('[data-cy="navigation:settings"]').click()
cy.get('[data-cy="setting:add-card-at-top"] input[role="switch"]').check({ force: true })
cy.get('[data-cy="setting:add-card-at-top"]').click({ force: true })
cy.wait('@setCardPosition')
cy.visit(`/apps/deck/#/board/${boardId}`)

Expand All @@ -126,7 +126,7 @@ describe('Card', function () {
})

cy.get('[data-cy="navigation:settings"]').click()
cy.get('[data-cy="setting:add-card-at-top"] input[role="switch"]').uncheck({ force: true })
cy.get('[data-cy="setting:add-card-at-top"]').click({ force: true })
cy.wait('@setCardPosition')
cy.visit(`/apps/deck/#/board/${boardId}`)
cy.get('.board .stack').eq(0).within(() => {
Expand Down Expand Up @@ -160,7 +160,7 @@ describe('Card', function () {
cy.get('.modal-mask.card-selector .multiselect-list').should('be.visible').click()
cy.get('.vs__dropdown-menu span[title="TestList"]').should('be.visible').click()

cy.get('.modal-mask.card-selector button.button-vue--vue-primary').should('be.visible').click()
cy.get('.modal-mask.card-selector button.button-vue--primary').should('be.visible').click()
cy.wait('@save', { timeout: 7000 })

cy.reload()
Expand Down Expand Up @@ -263,7 +263,7 @@ describe('Card', function () {
cy.get('.file-picker__main').should('be.visible')
cy.get('.file-picker__main [data-filename="welcome.txt"]', { timeout: 30000 }).should('be.visible')
.click()
cy.get('.dialog__actions button.button-vue--vue-primary').click()
cy.get('.dialog__actions button.button-vue--primary').click()
cy.get('.attachment-list .filename').contains('welcome')
cy.get('.attachment-list .filename .extension').contains('txt')
})
Expand Down Expand Up @@ -307,7 +307,7 @@ describe('Card', function () {
cy.get('.reference-picker-modal--content .reference-picker .card-title').should('be.visible').click().type(newCardTitle)
cy.get('.reference-picker-modal--content .reference-picker .multiselect-board').should('be.visible').contains(boardData.title)
cy.get('.reference-picker-modal--content .reference-picker .multiselect-list').should('be.visible').contains(boardData.stacks[0].title)
cy.get('.reference-picker-modal--content .reference-picker button.button-vue--vue-primary').should('be.visible').click()
cy.get('.reference-picker-modal--content .reference-picker button.button-vue--primary').should('be.visible').click()
cy.wait('@save', { timeout: 7000 })
cy.get('.modal__card .ProseMirror').contains('/index.php/apps/deck/card/').should('have.length', 1)

Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/deckDashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Deck dashboard', function() {

const defaultBoard = 'Welcome to Nextcloud Deck!'

cy.get('.app-navigation-entry-wrapper[icon=icon-deck]')
cy.get('.app-navigation-entry-wrapper[data-cy-navigation-category="deck-navigation-all"]')
.find('ul.app-navigation-entry__children .app-navigation-entry:contains(' + defaultBoard + ')')
.first()
.contains(defaultBoard)
Expand Down
32 changes: 19 additions & 13 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { addCommands } from '@nextcloud/cypress'
import axios from '@nextcloud/axios'
import { addCommands } from '@nextcloud/e2e-test-server/cypress'

addCommands()

const url = Cypress.config('baseUrl').replace(/\/index.php\/?$/g, '')
Cypress.env('baseUrl', url)
Cypress.expose('baseUrl', url)

// prepare main cypress window so we can use axios there
// and it will successfully fetch csrf tokens when needed.
Expand Down Expand Up @@ -57,12 +56,12 @@ Cypress.Commands.add('deckCreateList', ({ user, password }, title) => {

Cypress.Commands.add('createExampleBoard', ({ user, board }) => {
const auth = {
user: user.userId,
username: user.userId,
password: user.password,
}
cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/index.php/apps/deck/api/v1.0/boards`,
url: `${Cypress.expose('baseUrl')}/index.php/apps/deck/api/v1.0/boards`,
auth,
body: { title: board.title, color: board.color ?? 'ff0000' },
}).then((boardResponse) => {
Expand All @@ -72,7 +71,7 @@ Cypress.Commands.add('createExampleBoard', ({ user, board }) => {
const stack = board.stacks[stackIndex]
cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/index.php/apps/deck/api/v1.0/boards/${boardData.id}/stacks`,
url: `${Cypress.expose('baseUrl')}/index.php/apps/deck/api/v1.0/boards/${boardData.id}/stacks`,
auth,
body: { title: stack.title, order: 0 },
}).then((stackResponse) => {
Expand All @@ -81,7 +80,7 @@ Cypress.Commands.add('createExampleBoard', ({ user, board }) => {
const card = stack.cards[cardIndex]
cy.request({
method: 'POST',
url: `${Cypress.env('baseUrl')}/index.php/apps/deck/api/v1.0/boards/${boardData.id}/stacks/${stackData.id}/cards`,
url: `${Cypress.expose('baseUrl')}/index.php/apps/deck/api/v1.0/boards/${boardData.id}/stacks/${stackData.id}/cards`,
auth,
body: { title: card.title, description: card.description ?? '' },
})
Expand All @@ -93,7 +92,7 @@ Cypress.Commands.add('createExampleBoard', ({ user, board }) => {
})

Cypress.Commands.add('getNavigationEntry', (boardTitle) => {
return cy.get('.app-navigation-entry-wrapper[icon=icon-deck]')
return cy.get('[data-cy-navigation-category="deck-navigation-all"]').parent()
.find('ul.app-navigation-entry__children .app-navigation-entry:contains(' + boardTitle + ')')
.find('a.app-navigation-entry-link')
})
Expand All @@ -116,9 +115,16 @@ Cypress.Commands.add('shareBoardWithUi', (query, userId=query) => {
})

Cypress.Commands.add('setUserEmail', (user, value) => {
Cypress.log()
return axios.put(
`${url}/ocs/v2.php/cloud/users/${user.userId}`,
{ key: 'email', value },
)
return cy.request({
method: 'PUT',
url: `${url}/ocs/v2.php/cloud/users/${user.userId}`,
auth: {
username: user.userId,
password: user.password,
},
headers: {
'OCS-APIRequest': 'true',
},
body: { key: 'email', value },
})
})
2 changes: 1 addition & 1 deletion cypress/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { User } from '@nextcloud/cypress'
import { User } from '@nextcloud/e2e-test-server/cypress'

export const randHash = () => Math.random().toString(36).replace(/[^a-z]+/g, '').slice(0, 10)
export const randUser = () => new User(randHash(), randHash())
36 changes: 19 additions & 17 deletions lib/Controller/CardOcsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public function removeLabel(?int $boardId, int $cardId, int $labelId): DataRespo

#[NoAdminRequired]
#[PublicPage]
public function update(int $id, string $title, int $stackId, string $type, int $order, string $description, $duedate, $deletedAt, int $boardId, array|string|null $owner = null, $archived = null, $startdate = null): DataResponse {
public function update(int $id, string $title, int $stackId, string $type, int $order, string $description, $duedate, $deletedAt, ?int $boardId, array|string|null $owner = null, $archived = null, $startdate = null): DataResponse {
$done = array_key_exists('done', $this->request->getParams())
? new OptionalNullableValue($this->request->getParam('done', null))
: null;
Expand All @@ -135,22 +135,24 @@ public function update(int $id, string $title, int $stackId, string $type, int $
}
}

$localBoard = $this->boardService->find($boardId, false);
if ($localBoard->getExternalId()) {
return new DataResponse($this->externalBoardService->updateCardOnRemote(
$localBoard,
$id,
$title,
$stackId,
$type,
$owner,
$description,
$order,
$duedate,
$deletedAt,
$archived,
$done
));
if ($boardId) {
$localBoard = $this->boardService->find($boardId, false);
if ($localBoard->getExternalId()) {
return new DataResponse($this->externalBoardService->updateCardOnRemote(
$localBoard,
$id,
$title,
$stackId,
$type,
$owner,
$description,
$order,
$duedate,
$deletedAt,
$archived,
$done
));
}
}

return new DataResponse($this->cardService->update($id,
Expand Down
Loading
Loading