Compare commits

..

1 Commits

Author SHA1 Message Date
Robin Appelman
8e2e21b190 fix: don't return cache entries with null paths
Signed-off-by: Robin Appelman <robin@icewind.nl>
2026-03-02 18:32:50 +01:00
2439 changed files with 23907 additions and 26531 deletions

8
.github/CODEOWNERS vendored
View File

@@ -24,7 +24,7 @@ package.json @nextcloud/server-dependabot @next
package-lock.json @nextcloud/server-dependabot
# App maintainers
/apps/admin_audit/appinfo/info.xml @luka-nextcloud @samin-z
/apps/admin_audit/appinfo/info.xml @luka-nextcloud @blizzz
/apps/cloud_federation_api/appinfo/info.xml @nfebe @mejo-
/apps/comments/appinfo/info.xml @edward-ly @sorbaugh
/apps/contactsinteraction/appinfo/info.xml @kesselb @SebastianKrupinski
@@ -46,16 +46,16 @@ package-lock.json @nextcloud/server-dependabot
/apps/files_versions/appinfo/info.xml @artonge @icewind1991
/apps/oauth2/appinfo/info.xml @julien-nc @ChristophWurst
/apps/provisioning_api/appinfo/info.xml @provokateurin @nickvergessen
/apps/settings/appinfo/info.xml @hweihwang @sorbaugh
/apps/settings/appinfo/info.xml @JuliaKirschenheuter @sorbaugh
/apps/sharebymail/appinfo/info.xml @Altahrim @skjnldsv
/apps/systemtags/appinfo/info.xml @Antreesy @marcelklehr
/apps/theming/appinfo/info.xml @skjnldsv @juliusknorr
/apps/twofactor_backupcodes/appinfo/info.xml @miaulalala @ChristophWurst
/apps/updatenotification/appinfo/info.xml @enjeck @sorbaugh
/apps/updatenotification/appinfo/info.xml @JuliaKirschenheuter @sorbaugh
/apps/user_ldap/appinfo/info.xml @come-nc @blizzz
/apps/user_status/appinfo/info.xml @Antreesy @nickvergessen
/apps/weather_status/appinfo/info.xml @julien-nc @juliusknorr
/apps/webhook_listeners/appinfo/info.xml @janepie @julien-nc
/apps/webhook_listeners/appinfo/info.xml @come-nc @julien-nc
/apps/workflowengine/appinfo/info.xml @blizzz @juliusknorr
# Files frontend expertise

View File

@@ -73,7 +73,7 @@ body:
options:
- "32"
- "33"
- "34 (master)"
- "master"
validations:
required: true
- type: dropdown

View File

@@ -20,7 +20,7 @@ jobs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -58,7 +58,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -74,9 +74,6 @@ jobs:
autocheckers:
runs-on: ubuntu-latest-low
needs: changes
if: needs.changes.outputs.src != 'false'
strategy:
matrix:
php-versions: ['8.2']
@@ -91,7 +88,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -128,4 +125,4 @@ jobs:
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && (needs.autocheckers.result != 'success' || needs.autoloader.result != 'success') }}; then exit 1; fi
run: if ${{ needs.autocheckers.result != 'success' || (needs.changes.outputs.src != 'false' && needs.autoloader.result != 'success') }}; then exit 1; fi

View File

@@ -21,7 +21,7 @@ jobs:
steps:
- name: Check requirement
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:

View File

@@ -1,45 +0,0 @@
# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
name: Auto-label bug reports
on:
issues:
types: [opened]
jobs:
add-version-label:
if: contains(github.event.issue.title, '[Bug]')
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Extract version number and apply label
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const body = context.payload.issue.body || '';
const normalizedBody = body.replace(/\r\n?/g, '\n');
let label = '';
// Extract Nextcloud Server version number from a block like:
// ### Nextcloud Server version
// 32
const versionMatch = normalizedBody.match(/### Nextcloud Server version\s*\n+([0-9]{1,3})\b/);
let nextcloudVersion = null;
if (versionMatch) {
nextcloudVersion = parseInt(versionMatch[1], 10);
label = nextcloudVersion + '-feedback';
}
if (label) {
try {
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: [label]
});
} catch (error) {
core.setFailed(`Failed to add label "${label}": ${error.message || error}`);
}
}

View File

@@ -37,13 +37,13 @@ jobs:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
uses: github/codeql-action/init@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
config-file: ./.github/codeql-config.yml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
uses: github/codeql-action/analyze@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
with:
category: "/language:${{matrix.language}}"

View File

@@ -124,7 +124,7 @@ jobs:
fallbackNpm: '^11.3'
- name: Set up node ${{ steps.package-engines-versions.outputs.nodeVersion }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ steps.package-engines-versions.outputs.nodeVersion }}
cache: npm

View File

@@ -14,7 +14,6 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: none
pull-requests: read
# On pull requests and if the comment starts with `/update-3rdparty`
if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/update-3rdparty')
@@ -28,25 +27,8 @@ jobs:
comment-id: ${{ github.event.comment.id }}
reactions: '+1'
# issue_comment events carry no pull_request context in their payload, so we
# must fetch the PR via the API. This also gives us base.ref for free, avoiding
# a second API call. The GITHUB_TOKEN needs pull-requests:read (granted above).
- name: Get pull request metadata
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
id: get-pr
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pull = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
core.setOutput('head_repo', pull.data.head.repo?.full_name ?? '');
core.setOutput('base_ref', pull.data.base.ref);
- name: Disabled on forks
if: steps.get-pr.outputs.head_repo != github.repository
if: ${{ github.event.pull_request.head.repo.full_name != github.repository }}
run: |
echo 'Can not execute /update-3rdparty on forks'
exit 1
@@ -64,17 +46,24 @@ jobs:
ref: ${{ steps.comment-branch.outputs.head_ref }}
- name: Register server reference to fallback to master branch
run: |
base_ref="${{ steps.get-pr.outputs.base_ref }}"
if [[ "$base_ref" == "main" || "$base_ref" == "master" ]]; then
echo "server_ref=master" >> "$GITHUB_ENV"
echo "Setting server_ref to master"
elif [[ "$base_ref" =~ ^stable[0-9]+$ ]]; then
echo "server_ref=$base_ref" >> "$GITHUB_ENV"
echo "Setting server_ref to $base_ref"
else
echo "Not based on master/main/stable*, so skipping pull 3rdparty command"
fi
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const baseRef = context.payload.pull_request.base.ref
if (baseRef === 'main' || baseRef === 'master') {
core.exportVariable('server_ref', 'master');
console.log('Setting server_ref to master');
} else {
const regex = /^stable(\d+)$/
const match = baseRef.match(regex)
if (match) {
core.exportVariable('server_ref', match[0]);
console.log('Setting server_ref to ' + match[0]);
} else {
console.log('Not based on master/main/stable*, so skipping pull 3rdparty command');
}
}
- name: Setup git
run: |

View File

@@ -41,6 +41,12 @@ jobs:
PUPPETEER_SKIP_DOWNLOAD: true
steps:
- name: Disabled on forks
if: ${{ github.event.pull_request.head.repo.full_name != github.repository }}
run: |
echo 'Can not run cypress on forks'
exit 1
- name: Checkout server
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
@@ -66,7 +72,7 @@ jobs:
fallbackNpm: '^11.3'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}
@@ -154,7 +160,7 @@ jobs:
path: ./
- name: Set up node ${{ needs.init.outputs.nodeVersion }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ needs.init.outputs.nodeVersion }}
@@ -165,11 +171,15 @@ jobs:
run: ./node_modules/cypress/bin/cypress install
- name: Run ${{ matrix.containers == 'component' && 'component' || 'E2E' }} cypress tests
uses: cypress-io/github-action@783cb3f07983868532cabaedaa1e6c00ff4786a8 # v7.1.9
uses: cypress-io/github-action@84d178e4bbce871e23f2ffa3085898cde0e4f0ec # v7.1.2
with:
# We already installed the dependencies in the init job
install: false
component: ${{ matrix.containers == 'component' }}
group: ${{ matrix.use-cypress-cloud && matrix.containers == 'component' && 'Run component' || matrix.use-cypress-cloud && 'Run E2E' || '' }}
# cypress env
ci-build-id: ${{ matrix.use-cypress-cloud && format('{0}-{1}', github.sha, github.run_number) || '' }}
tag: ${{ matrix.use-cypress-cloud && github.event_name || '' }}
env:
# Needs to be prefixed with CYPRESS_
CYPRESS_BRANCH: ${{ env.BRANCH }}
@@ -178,13 +188,14 @@ jobs:
# Needed for some specific code workarounds
TESTING: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
SPLIT: ${{ matrix.total-containers }}
SPLIT_INDEX: ${{ matrix.containers == 'component' && 0 || matrix.containers }}
SPLIT_RANDOM_SEED: ${{ github.run_id }}
SETUP_TESTING: ${{ matrix.containers == 'setup' && 'true' || '' }}
- name: Upload snapshots and videos
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
if: always()
with:
name: snapshots_${{ matrix.containers }}
@@ -207,7 +218,7 @@ jobs:
run: docker exec nextcloud-e2e-test-server_${{ env.APP_NAME }} tar -cvjf - data > data.tar
- name: Upload data archive
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
if: failure() && matrix.containers != 'component'
with:
name: nc_data_${{ matrix.containers }}

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -81,7 +81,7 @@ jobs:
if [[ "${{ matrix.ftpd }}" == 'pure-ftpd' ]]; then docker run --name ftp -d --net host -e "PUBLICHOST=localhost" -e FTP_USER_NAME=test -e FTP_USER_PASS=test -e FTP_USER_HOME=/home/test -v /tmp/ftp:/home/test -v /tmp/ftp:/etc/pure-ftpd/passwd stilliard/pure-ftpd; fi
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -115,7 +115,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-files-external-ftp

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -80,7 +80,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -115,7 +115,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-files-external-s3
@@ -169,7 +169,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -197,7 +197,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-files-external-s3

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -73,11 +73,11 @@ jobs:
- name: Set up sftpd
run: |
sudo mkdir /tmp/sftp
sudo chmod -R 0777 /tmp/sftp
sudo chown -R 0777 /tmp/sftp
if [[ '${{ matrix.sftpd }}' == 'openssh' ]]; then docker run -p 2222:22 --name sftp -d -v /tmp/sftp:/home/test atmoz/sftp 'test:test:::data'; fi
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -104,7 +104,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-files-external-sftp

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -81,7 +81,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -116,7 +116,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-files-external-smb

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -76,7 +76,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -108,7 +108,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-files-external-webdav

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -70,7 +70,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -97,7 +97,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-files-external-generic

View File

@@ -73,7 +73,7 @@ jobs:
fi
- name: Set up php 8.2
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: 8.2

View File

@@ -19,7 +19,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -52,69 +52,69 @@ jobs:
name: ${{ matrix.service }} (${{ matrix.endpoint }} endpoint) php${{ matrix.php-versions }}
steps:
- name: Checkout server
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
submodules: true
- name: Checkout server
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: 'none'
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
# https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, redis, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
coverage: 'none'
ini-file: development
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Python
uses: LizardByte/actions/actions/setup_python@0affa4f7bcb27562658960eee840eff8ff844578 # v2026.328.161128
with:
python-version: '2.7'
- name: Set up Python
uses: LizardByte/actions/actions/setup_python@9bf3ef783775e17fe6b8dde3585d94ec570b93c2 # v2026.212.22356
with:
python-version: '2.7'
- name: Set up CalDAVTester
run: |
git clone --depth=1 https://github.com/apple/ccs-caldavtester.git CalDAVTester
git clone --depth=1 https://github.com/apple/ccs-pycalendar.git pycalendar
- name: Set up CalDAVTester
run: |
git clone --depth=1 https://github.com/apple/ccs-caldavtester.git CalDAVTester
git clone --depth=1 https://github.com/apple/ccs-pycalendar.git pycalendar
- name: Set up Nextcloud
run: |
mkdir data
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
# disable the trashbin, so recurrent deletion of the same object works
./occ config:app:set dav calendarRetentionObligation --value=0
# Prepare users
OC_PASS=user01 ./occ user:add --password-from-env user01
OC_PASS=user02 ./occ user:add --password-from-env user02
# Prepare calendars
./occ dav:create-calendar user01 calendar
./occ dav:create-calendar user01 shared
./occ dav:create-calendar user02 calendar
# Prepare address books
./occ dav:create-addressbook user01 addressbook
./occ dav:create-addressbook user02 addressbook
- name: Set up Nextcloud
run: |
mkdir data
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
# disable the trashbin, so recurrent deletion of the same object works
./occ config:app:set dav calendarRetentionObligation --value=0
# Prepare users
OC_PASS=user01 ./occ user:add --password-from-env user01
OC_PASS=user02 ./occ user:add --password-from-env user02
# Prepare calendars
./occ dav:create-calendar user01 calendar
./occ dav:create-calendar user01 shared
./occ dav:create-calendar user02 calendar
# Prepare address books
./occ dav:create-addressbook user01 addressbook
./occ dav:create-addressbook user02 addressbook
- name: Run Nextcloud
run: |
php -S localhost:8888 &
- name: Run Nextcloud
run: |
php -S localhost:8888 &
- name: Run CalDAVTester
run: |
cp "apps/dav/tests/testsuits/caldavtest/serverinfo-${{ matrix.endpoint }}${{ matrix.endpoint == 'old' && (matrix.service == 'CardDAV' && '-carddav' || '-caldav') || '' }}-endpoint.xml" "apps/dav/tests/testsuits/caldavtest/serverinfo.xml"
pushd CalDAVTester
PYTHONPATH="../pycalendar/src" python testcaldav.py --print-details-onfail --basedir "../apps/dav/tests/testsuits/caldavtest" -o cdt.txt \
"${{ matrix.service }}/current-user-principal.xml" \
"${{ matrix.service }}/sync-report.xml" \
${{ matrix.endpoint == 'new' && format('{0}/sharing-{1}.xml', matrix.service, matrix.service == 'CalDAV' && 'calendars' || 'addressbooks') || ';' }}
popd
- name: Run CalDAVTester
run: |
cp "apps/dav/tests/testsuits/caldavtest/serverinfo-${{ matrix.endpoint }}${{ matrix.endpoint == 'old' && (matrix.service == 'CardDAV' && '-carddav' || '-caldav') || '' }}-endpoint.xml" "apps/dav/tests/testsuits/caldavtest/serverinfo.xml"
pushd CalDAVTester
PYTHONPATH="../pycalendar/src" python testcaldav.py --print-details-onfail --basedir "../apps/dav/tests/testsuits/caldavtest" -o cdt.txt \
"${{ matrix.service }}/current-user-principal.xml" \
"${{ matrix.service }}/sync-report.xml" \
${{ matrix.endpoint == 'new' && format('{0}/sharing-{1}.xml', matrix.service, matrix.service == 'CalDAV' && 'calendars' || 'addressbooks') || ';' }}
popd
- name: Print Nextcloud logs
if: always()
run: |
cat data/nextcloud.log
- name: Print Nextcloud logs
if: always()
run: |
cat data/nextcloud.log
caldav-integration-summary:
permissions:

View File

@@ -19,7 +19,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -58,7 +58,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}

View File

@@ -19,7 +19,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -82,7 +82,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -95,6 +95,7 @@ jobs:
- name: Wait for S3
run: |
sleep 10
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready
- name: Set up Nextcloud

View File

@@ -25,7 +25,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -121,7 +121,7 @@ jobs:
ref: ${{ matrix.activity-versions }}
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}

View File

@@ -28,7 +28,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -68,7 +68,7 @@ jobs:
fallbackNpm: '^11.3'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}

View File

@@ -25,7 +25,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -44,9 +44,6 @@ jobs:
lint:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
name: php-cs
steps:
@@ -56,7 +53,7 @@ jobs:
persist-credentials: false
- name: Set up php
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: 8.2

View File

@@ -23,7 +23,7 @@ jobs:
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -58,7 +58,7 @@ jobs:
persist-credentials: false
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}

View File

@@ -18,37 +18,9 @@ concurrency:
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
permissions:
contents: read
pull-requests: read
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '**/src/**'
- '**/appinfo/info.xml'
- 'package.json'
- 'package-lock.json'
- '**.css'
- '**.scss'
- '**.vue'
lint:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src != 'false'
name: stylelint
steps:
@@ -65,7 +37,7 @@ jobs:
fallbackNpm: '^11.3'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}
@@ -79,18 +51,3 @@ jobs:
- name: Lint
run: npm run stylelint
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, lint]
if: always()
# This is the summary, we just avoid to rename it so that branch protection rules still match
name: stylelint
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.lint.result != 'success' }}; then exit 1; fi

View File

@@ -29,7 +29,7 @@ jobs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -71,7 +71,7 @@ jobs:
fallbackNpm: '^11.3'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}

View File

@@ -31,7 +31,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -70,7 +70,7 @@ jobs:
fallbackNpm: '^11.3'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}
@@ -83,11 +83,14 @@ jobs:
run: |
npm ci
# - name: Test
# run: npm run test --if-present
- name: Test and process coverage
run: npm run test:coverage
- name: Collect coverage
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./coverage/lcov.info,./coverage/legacy/lcov.info

View File

@@ -28,7 +28,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -68,7 +68,7 @@ jobs:
fallbackNpm: '^11.3'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}

View File

@@ -49,7 +49,7 @@ jobs:
fallbackNpm: '^11.3'
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ steps.versions.outputs.nodeVersion }}

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -85,7 +85,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -117,7 +117,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-azure

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -86,7 +86,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -111,6 +111,7 @@ jobs:
- name: Wait for S3
run: |
sleep 10
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready
- name: PHPUnit
@@ -122,7 +123,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-s3

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -83,7 +83,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -113,7 +113,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-swift

View File

@@ -31,7 +31,7 @@ jobs:
persist-credentials: false
- name: Set up php
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: '8.2'

View File

@@ -15,13 +15,7 @@ jobs:
performance-testing:
runs-on: ubuntu-latest
# Skip entirely on fork PRs so the job result is 'skipped' rather than
# 'failure'. The profiler action uses github.event.pull_request.head.repo.clone_url
# and GITHUB_TOKEN in ways that do not work reliably from forks, and a
# clean skip is far less confusing for contributors than a mid-run error.
if: >-
github.repository_owner != 'nextcloud-gmbh' &&
github.event.pull_request.head.repo.full_name == github.repository
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
permissions:
pull-requests: write
@@ -34,6 +28,11 @@ jobs:
name: performance-${{ matrix.php-versions }}
steps:
- name: Disabled on forks
if: ${{ github.event.pull_request.head.repo.full_name != github.repository }}
run: |
echo 'Can not run performance tests on forks'
exit 1
- name: Checkout server before PR
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -43,7 +42,7 @@ jobs:
ref: ${{ github.event.pull_request.base.ref }}
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -64,7 +63,7 @@ jobs:
ref: ${{ github.event.pull_request.head.ref }}
- name: Run before measurements
uses: nextcloud/profiler@6a74c915048285b35b8e1cd96c0835a635945044
uses: nextcloud/profiler@6801ee10fc80f10b444388fb6ca9b36ad8a2ea83
with:
run: |
curl -s -X PROPFIND -u test:test http://localhost:8080/remote.php/dav/files/test
@@ -86,7 +85,7 @@ jobs:
- name: Run after measurements
id: compare
uses: nextcloud/profiler@6a74c915048285b35b8e1cd96c0835a635945044
uses: nextcloud/profiler@6801ee10fc80f10b444388fb6ca9b36ad8a2ea83
with:
run: |
curl -s -X PROPFIND -u test:test http://localhost:8080/remote.php/dav/files/test
@@ -100,7 +99,7 @@ jobs:
- name: Upload profiles
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
with:
name: profiles
path: |

View File

@@ -9,7 +9,6 @@ on:
- ".github/workflows/phpunit-32bits.yml"
- "tests/phpunit-autotest.xml"
- "lib/private/Snowflake/*"
- "tests/lib/Preview/PreviewMapperTest.php"
workflow_dispatch:
schedule:
- cron: "15 1 * * 1-6"
@@ -57,4 +56,4 @@ jobs:
- name: PHPUnit
uses: docker://ghcr.io/nextcloud/continuous-integration-php8.4-32bit:latest
with:
args: /bin/sh -c "composer run test -- --exclude-group PRIMARY-azure --exclude-group PRIMARY-s3 --exclude-group PRIMARY-swift --exclude-group Memcached --exclude-group Redis --exclude-group RoutingWeirdness"
args: /bin/sh -c "composer run test -- --exclude-group PRIMARY-azure,PRIMARY-s3,PRIMARY-swift,Memcached,Redis,RoutingWeirdness"

View File

@@ -31,7 +31,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -98,7 +98,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -132,7 +132,7 @@ jobs:
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.db.xml
flags: phpunit-mariadb

View File

@@ -28,7 +28,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -78,7 +78,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -104,7 +104,7 @@ jobs:
- name: Upload code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.xml
flags: phpunit-memcached

View File

@@ -28,7 +28,7 @@ jobs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -127,7 +127,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -162,7 +162,7 @@ jobs:
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.db.xml
flags: phpunit-mysql

View File

@@ -31,7 +31,7 @@ jobs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -98,7 +98,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -132,7 +132,7 @@ jobs:
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.db.xml
flags: phpunit-mysql

View File

@@ -30,7 +30,7 @@ jobs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -81,7 +81,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -110,7 +110,7 @@ jobs:
- name: Upload nodb code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.nodb.xml
flags: phpunit-nodb

View File

@@ -21,7 +21,7 @@ jobs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -78,7 +78,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -104,7 +104,7 @@ jobs:
curl -f -m 1 --retry-connrefused --retry 10 --retry-delay 10 http://localhost:9000/minio/health/ready
- name: PHPUnit
run: composer run test:db -- --log-junit junit.xml
run: composer run test:db
- name: S3 logs
if: always()

View File

@@ -31,7 +31,7 @@ jobs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -105,7 +105,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -132,7 +132,7 @@ jobs:
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.db.xml
flags: phpunit-oci

View File

@@ -31,7 +31,7 @@ jobs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -98,7 +98,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -127,7 +127,7 @@ jobs:
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.db.xml
flags: phpunit-postgres

View File

@@ -31,7 +31,7 @@ jobs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
@@ -81,7 +81,7 @@ jobs:
submodules: true
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
timeout-minutes: 5
with:
php-version: ${{ matrix.php-versions }}
@@ -114,7 +114,7 @@ jobs:
- name: Upload db code coverage
if: ${{ !cancelled() && matrix.coverage }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ./clover.db.xml
flags: phpunit-sqlite

View File

@@ -37,7 +37,7 @@ jobs:
ref: ${{ github.event.repository.default_branch }}
- name: Set up php${{ matrix.php-versions }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.36.0
with:
php-version: ${{ matrix.php-versions }}
extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
@@ -50,7 +50,6 @@ jobs:
run: |
composer remove nextcloud/ocp --dev --no-scripts
composer i
git restore lib/composer/composer
- name: Rector
run: composer run rector

View File

@@ -13,34 +13,10 @@ concurrency:
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src}}
steps:
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/lib/**'
- '**/tests/**'
- '**/vendor-bin/**'
- '.php-cs-fixer.dist.php'
- 'composer.json'
- 'composer.lock'
- '**.php'
strict:
runs-on: ubuntu-latest
needs: changes
if: ${{ needs.changes.outputs.src != 'false' && github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
if: ${{ github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
steps:
- name: Checkout
@@ -50,7 +26,7 @@ jobs:
submodules: true
- name: Set up php
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
with:
php-version: '8.2'
extensions: apcu,ctype,curl,dom,fileinfo,ftp,gd,imagick,intl,json,ldap,mbstring,openssl,pdo_sqlite,posix,sqlite,xml,zip
@@ -67,17 +43,3 @@ jobs:
- name: Show changes
if: always()
run: git diff --exit-code -- . ':!lib/composer'
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, strict]
if: always()
name: rector-summary
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && needs.strict.result != 'success' }}; then exit 1; fi

View File

@@ -20,7 +20,7 @@ jobs:
issues: write
steps:
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v9
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v9
with:
repo-token: ${{ secrets.COMMAND_BOT_PAT }}
stale-issue-message: >

View File

@@ -21,35 +21,10 @@ concurrency:
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest-low
outputs:
src: ${{ steps.changes.outputs.src }}
steps:
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
continue-on-error: true
with:
filters: |
src:
- '.github/workflows/**'
- '3rdparty/**'
- '**/appinfo/**'
- '**/lib/**'
- '**/templates/**'
- 'vendor/**'
- 'vendor-bin/**'
- 'composer.json'
- 'composer.lock'
- '**.php'
static-code-analysis:
runs-on: ubuntu-latest
needs: changes
if: ${{ needs.changes.outputs.src != 'false' && github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
if: ${{ github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
steps:
- name: Checkout
@@ -59,7 +34,7 @@ jobs:
submodules: true
- name: Set up php
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: '8.2'
@@ -81,8 +56,7 @@ jobs:
static-code-analysis-security:
runs-on: ubuntu-latest
needs: changes
if: ${{ needs.changes.outputs.src != 'false' && github.repository_owner != 'nextcloud-gmbh' }}
if: ${{ github.repository_owner != 'nextcloud-gmbh' }}
permissions:
security-events: write
@@ -95,7 +69,7 @@ jobs:
submodules: true
- name: Set up php
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: '8.2'
@@ -114,15 +88,14 @@ jobs:
- name: Upload Security Analysis results to GitHub
if: always()
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v3
uses: github/codeql-action/upload-sarif@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v3
with:
sarif_file: results.sarif
static-code-analysis-ocp:
runs-on: ubuntu-latest
needs: changes
if: ${{ needs.changes.outputs.src != 'false' && github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
if: ${{ github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
steps:
- name: Checkout
@@ -132,7 +105,7 @@ jobs:
submodules: true
- name: Set up php
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: '8.2'
@@ -154,8 +127,7 @@ jobs:
static-code-analysis-ncu:
runs-on: ubuntu-latest
needs: changes
if: ${{ needs.changes.outputs.src != 'false' && github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
if: ${{ github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
steps:
- name: Checkout
@@ -165,7 +137,7 @@ jobs:
submodules: true
- name: Set up php
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
timeout-minutes: 5
with:
php-version: '8.2'
@@ -183,8 +155,7 @@ jobs:
static-code-analysis-strict:
runs-on: ubuntu-latest
needs: changes
if: ${{ needs.changes.outputs.src != 'false' && github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
if: ${{ github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
steps:
- name: Checkout
@@ -194,7 +165,7 @@ jobs:
submodules: true
- name: Set up php
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f #v2.37.0
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 #v2.36.0
with:
php-version: '8.2'
extensions: ctype,curl,dom,fileinfo,gd,imagick,intl,json,mbstring,openssl,pdo_sqlite,posix,sqlite,xml,zip
@@ -207,28 +178,3 @@ jobs:
- name: Psalm
run: composer run psalm:strict -- --threads=1 --monochrome --no-progress --output-format=github
summary:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, static-code-analysis, static-code-analysis-security, static-code-analysis-ocp, static-code-analysis-ncu, static-code-analysis-strict]
if: always()
name: static-code-analysis-summary
steps:
- name: Summary status
run: |
if ${{ needs.changes.outputs.src != 'false' && (
needs.static-code-analysis-security.result != 'success' ||
(github.event_name != 'push' && (
needs.static-code-analysis.result != 'success' ||
needs.static-code-analysis-ocp.result != 'success' ||
needs.static-code-analysis-ncu.result != 'success' ||
needs.static-code-analysis-strict.result != 'success'
))
) }}; then
exit 1
fi

View File

@@ -115,7 +115,7 @@ jobs:
committer: GitHub <noreply@github.com>
author: nextcloud-command <nextcloud-command@users.noreply.github.com>
signoff: true
branch: "automated/noid/update-min-supported-desktop-version"
branch: "automated/noid/${{ matrix.branches }}-update-min-supported-desktop-version"
title: "chore: Update minimum supported desktop version to ${{ steps.extract-version.outputs.VERSION }}"
base: "master"
body: |

View File

@@ -129,10 +129,11 @@
## Rule: Map /remote* --> /remote.php* including the query string
##
## Context:
## - XXX: `QSA` seems unnecessary (no-op) here (query string is passed by default when the replacement URI doesn't contain a query string)
## - XXX: Is this even used anymore? Seems a relic from <NC12
##
RewriteRule ^remote/(.*) remote.php [L]
RewriteRule ^remote/(.*) remote.php [QSA,L]
##
## Rule: Prevent access to non-public files
@@ -147,19 +148,21 @@
## - Intentionally excludes URIs used for HTTPS certificate verifications
## - RFC 8555 / ACME HTTP Challenges (acme-challenge)
## - File-based Validations (pki-validation)
## - XXX: `QSA` seems unnecessary (no-op) here (query string is passed by default when the replacement URI doesn't contain a query string)
## - XXX: Sometimes we are using `/index.php` and other times `index.php` as our replacement URI; this may be incorrect
##
RewriteRule ^\.well-known/(?!acme-challenge|pki-validation) /index.php [L]
RewriteRule ^\.well-known/(?!acme-challenge|pki-validation) /index.php [QSA,L]
##
## Rule: Map the ocm-provider handling to our main frontend controller (/index.php)
##
## Context:
## - XXX: `QSA` seems unnecessary (no-op) here (query string is passed by default when the replacement URI doesn't contain a query string)
## - XXX: Sometimes we are using `/index.php` and other times `index.php` as our replacement URI; this may be incorrect
##
RewriteRule ^ocm-provider/?$ index.php [L]
RewriteRule ^ocm-provider/?$ index.php [QSA,L]
##
## Rule: Prevent access to more non-public files

View File

@@ -4,7 +4,6 @@
# Global exclude
.editorconfig
.envrc
.git
.git-blame-ignore-revs
.gitattributes
@@ -12,44 +11,12 @@
.gitignore
.gitmodules
.idea
.jshint
.jshintrc
.l10nignore
.mailmap
.nextcloudignore
.noopenapi
.npmignore
.php-cs-fixer*
.pre-commit-config.yaml
.tag
.tx
CHANGELOG.md
CODE_OF_CONDUCT.md
COPYING-README
DESIGN.md
Makefile
README.md
SECURITY.md
codecov.yml
cs-fixer
csfixer
custom.d.ts
cypress
cypress.config.ts
eslint.config.js
flake.lock
flake.nix
openapi-extractor
phpunit
psalm
psalm*.xml
rector
stylelint.config.js
tests
tsconfig.json
vite.config.ts
vitest.config.ts
window.d.ts
# Server specific
/.devcontainer
@@ -60,5 +27,3 @@ window.d.ts
/config/config.php
/contribute
/data
/openapi.json
/vendor-bin

View File

@@ -1,7 +0,0 @@
OC.L10N.register(
"admin_audit",
{
"Auditing / Logging" : "নিরীক্ষা",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "নেক্সটক্লাউডের নিরীক্ষামূলক সক্ষমতা প্রদান করে যেমন লগিং ফাইল অ্যাক্সেস বা অন্য কোনো জরুরী পদক্ষেপসমূহ"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -1,5 +0,0 @@
{ "translations": {
"Auditing / Logging" : "নিরীক্ষা",
"Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "নেক্সটক্লাউডের নিরীক্ষামূলক সক্ষমতা প্রদান করে যেমন লগিং ফাইল অ্যাক্সেস বা অন্য কোনো জরুরী পদক্ষেপসমূহ"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -32,6 +32,6 @@ OC.L10N.register(
"Comment deleted" : "Kommentar gelöscht",
"An error occurred while trying to delete the comment" : "Es ist ein Fehler beim Löschen des Kommentars aufgetreten",
"An error occurred while trying to create the comment" : "Es ist ein Fehler beim Erstellen des Kommentars aufgetreten",
"Write a comment …" : "Einen Kommentar schreiben …"
"Write a comment …" : "Einen Kommentar schreiben …"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -30,6 +30,6 @@
"Comment deleted" : "Kommentar gelöscht",
"An error occurred while trying to delete the comment" : "Es ist ein Fehler beim Löschen des Kommentars aufgetreten",
"An error occurred while trying to create the comment" : "Es ist ein Fehler beim Erstellen des Kommentars aufgetreten",
"Write a comment …" : "Einen Kommentar schreiben …"
"Write a comment …" : "Einen Kommentar schreiben …"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -32,6 +32,6 @@ OC.L10N.register(
"Comment deleted" : "Kommentar gelöscht",
"An error occurred while trying to delete the comment" : "Es ist ein Fehler beim Löschen des Kommentars aufgetreten",
"An error occurred while trying to create the comment" : "Es ist ein Fehler beim Erstellen des Kommentars aufgetreten",
"Write a comment …" : "Einen Kommentar schreiben …"
"Write a comment …" : "Schreiben Sie einen Kommentar …"
},
"nplurals=2; plural=(n != 1);");

View File

@@ -30,6 +30,6 @@
"Comment deleted" : "Kommentar gelöscht",
"An error occurred while trying to delete the comment" : "Es ist ein Fehler beim Löschen des Kommentars aufgetreten",
"An error occurred while trying to create the comment" : "Es ist ein Fehler beim Erstellen des Kommentars aufgetreten",
"Write a comment …" : "Einen Kommentar schreiben …"
"Write a comment …" : "Schreiben Sie einen Kommentar …"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

View File

@@ -1,37 +1,32 @@
OC.L10N.register(
"comments",
{
"Comments" : "კომენტარები",
"You commented" : "თქვენი კომენტარი",
"{author} commented" : "{author}-ის კომენტარი",
"You commented on %1$s" : "თქვენი კომენტარი %1$s-ზე",
"You commented on {file}" : "თქვენი კომენტარი {file}-ზე",
"%1$s commented on %2$s" : "%1$s-მა დატოვა კომენტარი %2$s-ზე",
"{author} commented on {file}" : "{author}-მა დატოვა კომენტარი {file}-ზე",
"<strong>Comments</strong> for files" : "<strong>კომენტარები</strong> ფაილებისთვის",
"Files" : "ფაილები",
"You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "თქვენ გახსენეს \"{file}\"-ის კომენტარში ანგარიშიდან, რომელიც მის შემდეგ წაიშალა",
"{user} mentioned you in a comment on \"{file}\"" : "{user}-მა გახსენათ კომენტარში ფაილზე \"{file}\"",
"Files app plugin to add comments to files" : "Files აპის დამატება ფაილებზე კომენტარების დასამატებლად",
"Edit comment" : "კომენტარის ჩასწორება",
"Delete comment" : "კომენტარის წაშლა",
"Cancel edit" : "ჩასწორების გაუქმება",
"New comment" : "ახალი კომენტარი",
"Write a comment …" : "კომენტარის დაწერა …",
"Post comment" : "კომენტარის დაპოსტვა",
"@ for mentions, : for emoji, / for smart picker" : "@ ხსენებისთვის, : ემოჯისთვის, / ჭკვიანი ამრჩევისთვის",
"Could not reload comments" : "კომენტარების თავიდან ჩატვირთვა შეუძლებელია",
"Failed to mark comments as read" : "კომენტარების წაკითხულად მონიშვნა ჩავარდა",
"Unable to load the comments list" : "კომენტარების სიის ჩატვირთვა ჩავარდა",
"No comments yet, start the conversation!" : "ჯერ კომენტარები არაა. დაიწყეთ საუბარი!",
"No more messages" : "მეტი შეტყობინება აღარაა",
"Retry" : "თავიდან ცდა",
"_1 new comment_::_{unread} new comments_" : ["1 ახალი კომენტარი","{unread} ახალი კომენტარი"],
"Comment" : "კომენტარი",
"An error occurred while trying to edit the comment" : "კომენტარის ჩასწორებისას აღმოჩენილია შეცდომა",
"Comment deleted" : "კომენტარი წაიშალა",
"An error occurred while trying to delete the comment" : "კომენტარის წაშლისას აღმოჩენილია შეცდომა",
"An error occurred while trying to create the comment" : "კომენტარის შექმნისას აღმოჩენილია შეცდომა",
"Write a comment …" : "კომენტარის დაწერა …"
"Comments" : "Comments",
"You commented" : "You commented",
"{author} commented" : "{author} commented",
"You commented on %1$s" : "You commented on %1$s",
"You commented on {file}" : "You commented on {file}",
"%1$s commented on %2$s" : "%1$s commented on %2$s",
"{author} commented on {file}" : "{author} commented on {file}",
"<strong>Comments</strong> for files" : "<strong>Comments</strong> for files",
"{user} mentioned you in a comment on \"{file}\"" : "{user} mentioned you in a comment on \"{file}\"",
"Files app plugin to add comments to files" : "Files app plugin to add comments to files",
"Edit comment" : "Edit comment",
"Delete comment" : "Delete comment",
"Cancel edit" : "Cancel edit",
"Post comment" : "Post comment",
"@ for mentions, : for emoji, / for smart picker" : "@ for mentions, : for emoji, / for smart picker",
"Could not reload comments" : "Could not reload comments",
"Failed to mark comments as read" : "Failed to mark comments as read",
"Unable to load the comments list" : "Unable to load the comments list",
"No comments yet, start the conversation!" : "No comments yet, start the conversation!",
"No more messages" : "No more messages",
"Retry" : "Retry",
"_1 new comment_::_{unread} new comments_" : ["1 new comment","{unread} new comments"],
"Comment" : "Comment",
"An error occurred while trying to edit the comment" : "An error occurred while trying to edit the comment",
"Comment deleted" : "Comment deleted",
"An error occurred while trying to delete the comment" : "An error occurred while trying to delete the comment",
"An error occurred while trying to create the comment" : "An error occurred while trying to create the comment"
},
"nplurals=2; plural=(n!=1);");

View File

@@ -1,35 +1,30 @@
{ "translations": {
"Comments" : "კომენტარები",
"You commented" : "თქვენი კომენტარი",
"{author} commented" : "{author}-ის კომენტარი",
"You commented on %1$s" : "თქვენი კომენტარი %1$s-ზე",
"You commented on {file}" : "თქვენი კომენტარი {file}-ზე",
"%1$s commented on %2$s" : "%1$s-მა დატოვა კომენტარი %2$s-ზე",
"{author} commented on {file}" : "{author}-მა დატოვა კომენტარი {file}-ზე",
"<strong>Comments</strong> for files" : "<strong>კომენტარები</strong> ფაილებისთვის",
"Files" : "ფაილები",
"You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "თქვენ გახსენეს \"{file}\"-ის კომენტარში ანგარიშიდან, რომელიც მის შემდეგ წაიშალა",
"{user} mentioned you in a comment on \"{file}\"" : "{user}-მა გახსენათ კომენტარში ფაილზე \"{file}\"",
"Files app plugin to add comments to files" : "Files აპის დამატება ფაილებზე კომენტარების დასამატებლად",
"Edit comment" : "კომენტარის ჩასწორება",
"Delete comment" : "კომენტარის წაშლა",
"Cancel edit" : "ჩასწორების გაუქმება",
"New comment" : "ახალი კომენტარი",
"Write a comment …" : "კომენტარის დაწერა …",
"Post comment" : "კომენტარის დაპოსტვა",
"@ for mentions, : for emoji, / for smart picker" : "@ ხსენებისთვის, : ემოჯისთვის, / ჭკვიანი ამრჩევისთვის",
"Could not reload comments" : "კომენტარების თავიდან ჩატვირთვა შეუძლებელია",
"Failed to mark comments as read" : "კომენტარების წაკითხულად მონიშვნა ჩავარდა",
"Unable to load the comments list" : "კომენტარების სიის ჩატვირთვა ჩავარდა",
"No comments yet, start the conversation!" : "ჯერ კომენტარები არაა. დაიწყეთ საუბარი!",
"No more messages" : "მეტი შეტყობინება აღარაა",
"Retry" : "თავიდან ცდა",
"_1 new comment_::_{unread} new comments_" : ["1 ახალი კომენტარი","{unread} ახალი კომენტარი"],
"Comment" : "კომენტარი",
"An error occurred while trying to edit the comment" : "კომენტარის ჩასწორებისას აღმოჩენილია შეცდომა",
"Comment deleted" : "კომენტარი წაიშალა",
"An error occurred while trying to delete the comment" : "კომენტარის წაშლისას აღმოჩენილია შეცდომა",
"An error occurred while trying to create the comment" : "კომენტარის შექმნისას აღმოჩენილია შეცდომა",
"Write a comment …" : "კომენტარის დაწერა …"
"Comments" : "Comments",
"You commented" : "You commented",
"{author} commented" : "{author} commented",
"You commented on %1$s" : "You commented on %1$s",
"You commented on {file}" : "You commented on {file}",
"%1$s commented on %2$s" : "%1$s commented on %2$s",
"{author} commented on {file}" : "{author} commented on {file}",
"<strong>Comments</strong> for files" : "<strong>Comments</strong> for files",
"{user} mentioned you in a comment on \"{file}\"" : "{user} mentioned you in a comment on \"{file}\"",
"Files app plugin to add comments to files" : "Files app plugin to add comments to files",
"Edit comment" : "Edit comment",
"Delete comment" : "Delete comment",
"Cancel edit" : "Cancel edit",
"Post comment" : "Post comment",
"@ for mentions, : for emoji, / for smart picker" : "@ for mentions, : for emoji, / for smart picker",
"Could not reload comments" : "Could not reload comments",
"Failed to mark comments as read" : "Failed to mark comments as read",
"Unable to load the comments list" : "Unable to load the comments list",
"No comments yet, start the conversation!" : "No comments yet, start the conversation!",
"No more messages" : "No more messages",
"Retry" : "Retry",
"_1 new comment_::_{unread} new comments_" : ["1 new comment","{unread} new comments"],
"Comment" : "Comment",
"An error occurred while trying to edit the comment" : "An error occurred while trying to edit the comment",
"Comment deleted" : "Comment deleted",
"An error occurred while trying to delete the comment" : "An error occurred while trying to delete the comment",
"An error occurred while trying to create the comment" : "An error occurred while trying to create the comment"
},"pluralForm" :"nplurals=2; plural=(n!=1);"
}

View File

@@ -10,28 +10,20 @@ OC.L10N.register(
"{author} commented on {file}" : "{author} pakomentavo {file}",
"<strong>Comments</strong> for files" : "Failų <strong>komentarai</strong>",
"Files" : "Failai",
"You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "Buvote paminėtas „{file}“, komentare, kuris buvo parašytas iš paskyros, kuri vėliau buvo ištrinta.",
"{user} mentioned you in a comment on \"{file}\"" : "{user} minėjo jus \"{file}\" komentare",
"Files app plugin to add comments to files" : "Failų programėlės įskiepis, skirtas prie failų pridėti komentarus",
"Edit comment" : "Taisyti komentarą",
"Delete comment" : "Ištrinti komentarą",
"Cancel edit" : "Atsisakyti taisymo",
"New comment" : "Naujas komentaras",
"Write a comment …" : "Rašyti komentarą ...",
"Post comment" : "Paskelbti komentarą",
"@ for mentions, : for emoji, / for smart picker" : "@ paminėjimams, : jaustukams, / išmaniajam rinkikliui",
"Could not reload comments" : "Nepavyko įkelti komentarų iš naujo",
"Failed to mark comments as read" : "Nepavyko pažymėti komentarų kaip perskaitytų",
"Unable to load the comments list" : "Nepavyko įkelti komentarų sąrašo",
"No comments yet, start the conversation!" : "Komentarų kol kas nėra, pradėkite pokalbį!",
"No more messages" : "Daugiau jokių pranešimų",
"Retry" : "Bandyti dar kartą",
"_1 new comment_::_{unread} new comments_" : ["1 neskaitytas komentaras","{unread} neskaityti komentarai","{unread} neskaitytų komentarų","{unread} neskaitytas komentaras"],
"Comment" : "Komentaras",
"An error occurred while trying to edit the comment" : "Bandant taisyti komentarą, įvyko klaida",
"Comment deleted" : "Komentaras ištrintas",
"An error occurred while trying to delete the comment" : "Bandant ištrinti komentarą, įvyko klaida",
"An error occurred while trying to create the comment" : "Bandant sukurti komentarą, įvyko klaida",
"Write a comment …" : "Rašyti komentarą..."
"An error occurred while trying to create the comment" : "Bandant sukurti komentarą, įvyko klaida"
},
"nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);");

View File

@@ -8,28 +8,20 @@
"{author} commented on {file}" : "{author} pakomentavo {file}",
"<strong>Comments</strong> for files" : "Failų <strong>komentarai</strong>",
"Files" : "Failai",
"You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "Buvote paminėtas „{file}“, komentare, kuris buvo parašytas iš paskyros, kuri vėliau buvo ištrinta.",
"{user} mentioned you in a comment on \"{file}\"" : "{user} minėjo jus \"{file}\" komentare",
"Files app plugin to add comments to files" : "Failų programėlės įskiepis, skirtas prie failų pridėti komentarus",
"Edit comment" : "Taisyti komentarą",
"Delete comment" : "Ištrinti komentarą",
"Cancel edit" : "Atsisakyti taisymo",
"New comment" : "Naujas komentaras",
"Write a comment …" : "Rašyti komentarą ...",
"Post comment" : "Paskelbti komentarą",
"@ for mentions, : for emoji, / for smart picker" : "@ paminėjimams, : jaustukams, / išmaniajam rinkikliui",
"Could not reload comments" : "Nepavyko įkelti komentarų iš naujo",
"Failed to mark comments as read" : "Nepavyko pažymėti komentarų kaip perskaitytų",
"Unable to load the comments list" : "Nepavyko įkelti komentarų sąrašo",
"No comments yet, start the conversation!" : "Komentarų kol kas nėra, pradėkite pokalbį!",
"No more messages" : "Daugiau jokių pranešimų",
"Retry" : "Bandyti dar kartą",
"_1 new comment_::_{unread} new comments_" : ["1 neskaitytas komentaras","{unread} neskaityti komentarai","{unread} neskaitytų komentarų","{unread} neskaitytas komentaras"],
"Comment" : "Komentaras",
"An error occurred while trying to edit the comment" : "Bandant taisyti komentarą, įvyko klaida",
"Comment deleted" : "Komentaras ištrintas",
"An error occurred while trying to delete the comment" : "Bandant ištrinti komentarą, įvyko klaida",
"An error occurred while trying to create the comment" : "Bandant sukurti komentarą, įvyko klaida",
"Write a comment …" : "Rašyti komentarą..."
"An error occurred while trying to create the comment" : "Bandant sukurti komentarą, įvyko klaida"
},"pluralForm" :"nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);"
}

View File

@@ -10,20 +10,20 @@ OC.L10N.register(
"{author} commented on {file}" : "{author} reageerde op {file}",
"<strong>Comments</strong> for files" : "<strong>Reacties</strong> voor bestanden",
"Files" : "Bestanden",
"You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "Je werd genoemd op \"{file}\", in een reactie van een account dat intussen is verwijderd",
"You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "Je werd genoemd op \"{file}\", in een opmerking van een account dat intussen is verwijderd",
"{user} mentioned you in a comment on \"{file}\"" : "{user} noemde jou in een reactie op \"{file}\"",
"Files app plugin to add comments to files" : "Bestanden app plugin om reacties aan bestanden toe te voegen",
"Edit comment" : "Reactie bewerken",
"Delete comment" : "Reactie verwijderen",
"Cancel edit" : "Bewerking annuleren",
"New comment" : "Nieuwe reactie",
"Write a comment …" : "Schrijf een reactie …",
"Write a comment …" : "Schrijf een commentaar …",
"Post comment" : "Reactie plaatsen",
"@ for mentions, : for emoji, / for smart picker" : "@ voor vermeldingen, : voor emoji, / voor Smart Picker",
"Could not reload comments" : "Kon reactie niet opnieuw laden",
"Failed to mark comments as read" : "Kon reacties niet als gelezen markeren",
"Unable to load the comments list" : "Kan reactielijst niet laden",
"No comments yet, start the conversation!" : "Nog geen reacties, start het gesprek!",
"No comments yet, start the conversation!" : "Nog geen reacties, start de discussie!",
"No more messages" : "Geen berichten meer",
"Retry" : "Opnieuw proberen",
"_1 new comment_::_{unread} new comments_" : ["1 nieuwe reactie","{unread} nieuwe reacties"],

View File

@@ -8,20 +8,20 @@
"{author} commented on {file}" : "{author} reageerde op {file}",
"<strong>Comments</strong> for files" : "<strong>Reacties</strong> voor bestanden",
"Files" : "Bestanden",
"You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "Je werd genoemd op \"{file}\", in een reactie van een account dat intussen is verwijderd",
"You were mentioned on \"{file}\", in a comment by an account that has since been deleted" : "Je werd genoemd op \"{file}\", in een opmerking van een account dat intussen is verwijderd",
"{user} mentioned you in a comment on \"{file}\"" : "{user} noemde jou in een reactie op \"{file}\"",
"Files app plugin to add comments to files" : "Bestanden app plugin om reacties aan bestanden toe te voegen",
"Edit comment" : "Reactie bewerken",
"Delete comment" : "Reactie verwijderen",
"Cancel edit" : "Bewerking annuleren",
"New comment" : "Nieuwe reactie",
"Write a comment …" : "Schrijf een reactie …",
"Write a comment …" : "Schrijf een commentaar …",
"Post comment" : "Reactie plaatsen",
"@ for mentions, : for emoji, / for smart picker" : "@ voor vermeldingen, : voor emoji, / voor Smart Picker",
"Could not reload comments" : "Kon reactie niet opnieuw laden",
"Failed to mark comments as read" : "Kon reacties niet als gelezen markeren",
"Unable to load the comments list" : "Kan reactielijst niet laden",
"No comments yet, start the conversation!" : "Nog geen reacties, start het gesprek!",
"No comments yet, start the conversation!" : "Nog geen reacties, start de discussie!",
"No more messages" : "Geen berichten meer",
"Retry" : "Opnieuw proberen",
"_1 new comment_::_{unread} new comments_" : ["1 nieuwe reactie","{unread} nieuwe reacties"],

View File

@@ -34,8 +34,7 @@ class LoadSidebarScripts implements IEventListener {
$this->commentsManager->load();
$this->initialState->provideInitialState('activityEnabled', $this->appManager->isEnabledForUser('activity'));
// Add comments sidebar tab script/style
Util::addStyle(Application::APP_ID, 'comments-tab');
// Add comments sidebar tab script
Util::addScript(Application::APP_ID, 'comments-tab', 'files');
}
}

View File

@@ -7,7 +7,7 @@ import type { IFolder, IView } from '@nextcloud/files'
import { File, Permission } from '@nextcloud/files'
import { describe, expect, test, vi } from 'vitest'
import logger from '../logger.ts'
import logger from '../logger.js'
import { action } from './inlineUnreadCommentsAction.ts'
const view = {

View File

@@ -8,8 +8,8 @@ import type { IFileAction } from '@nextcloud/files'
import CommentProcessingSvg from '@mdi/svg/svg/comment-processing.svg?raw'
import { getSidebar } from '@nextcloud/files'
import { n, t } from '@nextcloud/l10n'
import logger from '../logger.ts'
import { isUsingActivityIntegration } from '../utils/activity.ts'
import logger from '../logger.js'
import { isUsingActivityIntegration } from '../utils/activity.js'
export const action: IFileAction = {
id: 'comments-unread',

View File

@@ -4,40 +4,46 @@
*/
import type { INode } from '@nextcloud/files'
import type { App } from 'vue'
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import logger from './logger.ts'
import { getComments } from './services/GetComments.ts'
import moment from '@nextcloud/moment'
import { createPinia, PiniaVuePlugin } from 'pinia'
import Vue, { type ComponentPublicInstance } from 'vue'
import logger from './logger.js'
import { getComments } from './services/GetComments.js'
Vue.use(PiniaVuePlugin)
let ActivityTabPluginView
let ActivityTabPluginInstance
/**
* Register the comments plugins for the Activity sidebar
*/
export function registerCommentsPlugins() {
let app: App
window.OCA.Activity.registerSidebarAction({
mount: async (el: HTMLElement, { node, reload }: { node: INode, reload: () => void }) => {
const pinia = createPinia()
if (!app) {
if (!ActivityTabPluginView) {
const { default: ActivityCommentAction } = await import('./views/ActivityCommentAction.vue')
app = createApp(
ActivityCommentAction,
{
reloadCallback: reload,
resourceId: node.fileid,
},
)
// @ts-expect-error Types are broken for Vue2
ActivityTabPluginView = Vue.extend(ActivityCommentAction)
}
app.use(pinia)
app.mount(el)
ActivityTabPluginInstance = new ActivityTabPluginView({
el,
pinia,
propsData: {
reloadCallback: reload,
resourceId: node.fileid,
},
})
logger.info('Comments plugin mounted in Activity sidebar action', { node })
},
unmount: () => {
// destroy previous instance if available
app?.unmount()
if (ActivityTabPluginInstance) {
ActivityTabPluginInstance.$destroy()
}
},
})
@@ -51,26 +57,26 @@ export function registerCommentsPlugins() {
)
logger.debug('Loaded comments', { node, comments })
const { default: CommentView } = await import('./views/ActivityCommentEntry.vue')
// @ts-expect-error Types are broken for Vue2
const CommentsViewObject = Vue.extend(CommentView)
return comments.map((comment) => ({
_CommentsViewInstance: undefined as App | undefined,
_CommentsViewInstance: undefined as ComponentPublicInstance | undefined,
timestamp: Date.parse(comment.props?.creationDateTime as string | undefined ?? ''),
timestamp: moment(comment.props?.creationDateTime).toDate().getTime(),
mount(element: HTMLElement, { reload }) {
const app = createApp(
CommentView,
{
this._CommentsViewInstance = new CommentsViewObject({
el: element,
propsData: {
comment,
resourceId: node.fileid,
reloadCallback: reload,
},
)
app.mount(element)
this._CommentsViewInstance = app
})
},
unmount() {
this._CommentsViewInstance?.unmount()
this._CommentsViewInstance?.$destroy()
},
}))
})

View File

@@ -3,8 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import logger from './logger.ts'
import CommentsInstance from './services/CommentsInstance.ts'
import logger from './logger.js'
import CommentsInstance from './services/CommentsInstance.js'
// Init Comments
if (window.OCA && !window.OCA.Comments) {

View File

@@ -13,7 +13,7 @@
<!-- Author -->
<NcAvatar
class="comment__avatar"
:displayName="actorDisplayName"
:display-name="actorDisplayName"
:user="actorId"
:size="32" />
</div>
@@ -26,7 +26,7 @@
<NcActions v-if="isOwnComment && id && !loading" class="comment__actions">
<template v-if="!editing">
<NcActionButton
closeAfterClick
close-after-click
@click="onEdit">
<template #icon>
<IconPencilOutline :size="20" />
@@ -35,7 +35,7 @@
</NcActionButton>
<NcActionSeparator />
<NcActionButton
closeAfterClick
close-after-click
@click="onDeleteWithUndo">
<template #icon>
<IconTrashCanOutline :size="20" />
@@ -60,7 +60,7 @@
v-else-if="creationDateTime"
class="comment__timestamp"
:timestamp="timestamp"
:ignoreSeconds="true" />
:ignore-seconds="true" />
</div>
<!-- Message editor -->
@@ -68,14 +68,14 @@
<div class="comment__editor-group">
<NcRichContenteditable
ref="editor"
v-model="localMessage"
:autoComplete
:auto-complete="autoComplete"
:contenteditable="!loading"
:label="editor ? t('comments', 'New comment') : t('comments', 'Edit comment')"
:placeholder="t('comments', 'Write a comment ')"
:userData
:model-value="localMessage"
:user-data="userData"
aria-describedby="tab-comments__editor-description"
@update:modelValue="submitted = false"
@update:value="updateLocalMessage"
@submit="onSubmit" />
<div class="comment__submit">
<NcButton
@@ -103,8 +103,8 @@
:class="{ 'comment__message--expanded': expanded }"
:text="richContent.message"
:arguments="richContent.mentions"
useMarkdown
@click="onExpand" />
use-markdown
@click.native="onExpand" />
</div>
</component>
</template>
@@ -113,7 +113,6 @@
import { getCurrentUser } from '@nextcloud/auth'
import { translate as t } from '@nextcloud/l10n'
import { mapStores } from 'pinia'
import { defineAsyncComponent } from 'vue'
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
import NcActions from '@nextcloud/vue/components/NcActions'
import NcActionSeparator from '@nextcloud/vue/components/NcActionSeparator'
@@ -126,12 +125,12 @@ import IconArrowRight from 'vue-material-design-icons/ArrowRight.vue'
import IconClose from 'vue-material-design-icons/Close.vue'
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
import CommentMixin from '../mixins/CommentMixin.ts'
import { useDeletedCommentLimbo } from '../store/deletedCommentLimbo.ts'
import CommentMixin from '../mixins/CommentMixin.js'
import { useDeletedCommentLimbo } from '../store/deletedCommentLimbo.js'
// Dynamic loading
const NcRichContenteditable = defineAsyncComponent(() => import('@nextcloud/vue/components/NcRichContenteditable'))
const NcRichText = defineAsyncComponent(() => import('@nextcloud/vue/components/NcRichText'))
const NcRichContenteditable = () => import('@nextcloud/vue/components/NcRichContenteditable')
const NcRichText = () => import('@nextcloud/vue/components/NcRichText')
export default {
/* eslint vue/multi-word-component-names: "warn" */

View File

@@ -4,13 +4,17 @@
*/
import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
import { getCSPNonce } from '@nextcloud/auth'
import { registerSidebarTab } from '@nextcloud/files'
import { t } from '@nextcloud/l10n'
import { createPinia } from 'pinia'
import { defineCustomElement } from 'vue'
import wrap from '@vue/web-component-wrapper'
import { createPinia, PiniaVuePlugin } from 'pinia'
import Vue from 'vue'
import { registerCommentsPlugins } from './comments-activity-tab.ts'
import { isUsingActivityIntegration } from './utils/activity.ts'
__webpack_nonce__ = getCSPNonce()
const tagName = 'comments_files-sidebar-tab'
if (isUsingActivityIntegration()) {
@@ -28,15 +32,17 @@ if (isUsingActivityIntegration()) {
async onInit() {
const { default: FilesSidebarTab } = await import('./views/FilesSidebarTab.vue')
const FilesSidebarTabElement = defineCustomElement(FilesSidebarTab, {
configureApp(app) {
const pinia = createPinia()
app.use(pinia)
},
shadowRoot: false,
Vue.use(PiniaVuePlugin)
Vue.mixin({ pinia: createPinia() })
const webComponent = wrap(Vue, FilesSidebarTab)
// In Vue 2, wrap doesn't support disabling shadow. Disable with a hack
Object.defineProperty(webComponent.prototype, 'attachShadow', {
value() { return this },
})
window.customElements.define(tagName, FilesSidebarTabElement)
Object.defineProperty(webComponent.prototype, 'shadowRoot', {
get() { return this },
})
window.customElements.define(tagName, webComponent)
},
})
}

View File

@@ -5,11 +5,11 @@
import { showError, showUndo, TOAST_UNDO_TIMEOUT } from '@nextcloud/dialogs'
import { mapStores } from 'pinia'
import logger from '../logger.ts'
import DeleteComment from '../services/DeleteComment.ts'
import EditComment from '../services/EditComment.ts'
import NewComment from '../services/NewComment.ts'
import { useDeletedCommentLimbo } from '../store/deletedCommentLimbo.ts'
import logger from '../logger.js'
import DeleteComment from '../services/DeleteComment.js'
import EditComment from '../services/EditComment.js'
import NewComment from '../services/NewComment.js'
import { useDeletedCommentLimbo } from '../store/deletedCommentLimbo.js'
export default {
props: {

View File

@@ -0,0 +1,53 @@
/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { getCSPNonce } from '@nextcloud/auth'
import { n, t } from '@nextcloud/l10n'
import { createPinia, PiniaVuePlugin } from 'pinia'
import Vue from 'vue'
import CommentsApp from '../views/Comments.vue'
import logger from '../logger.js'
Vue.use(PiniaVuePlugin)
__webpack_nonce__ = getCSPNonce()
// Add translates functions
Vue.mixin({
data() {
return {
logger,
}
},
methods: {
t,
n,
},
})
export default class CommentInstance {
/**
* Initialize a new Comments instance for the desired type
*
* @param {string} resourceType the comments endpoint type
* @param {object} options the vue options (propsData, parent, el...)
*/
constructor(resourceType = 'files', options = {}) {
const pinia = createPinia()
// Merge options and set `resourceType` property
options = {
...options,
propsData: {
...(options.propsData ?? {}),
resourceType,
},
pinia,
}
// Init Comments component
const View = Vue.extend(CommentsApp)
return new View(options)
}
}

View File

@@ -1,94 +0,0 @@
/*!
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { App, ComponentPublicInstance } from 'vue'
import { n, t } from '@nextcloud/l10n'
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import CommentsApp from '../views/CommentsApp.vue'
import logger from '../logger.ts'
export interface CommentsInstanceOptions {
el?: HTMLElement
props?: Record<string, unknown>
/** @deprecated use `props` instead */
propsData?: Record<string, unknown>
}
export default class CommentInstance {
private app: App
private instance: ComponentPublicInstance<typeof CommentsApp> | undefined
/**
* Initialize a new Comments instance for the desired type
*
* @param resourceType - The comments endpoint type
* @param options - The vue options (props, parent, el...)
*/
constructor(resourceType = 'files', options: CommentsInstanceOptions = {}) {
const pinia = createPinia()
this.app = createApp(
CommentsApp,
{
...(options.propsData ?? {}),
...(options.props ?? {}),
resourceType,
},
)
// Add translates functions
this.app.mixin({
data() {
return {
logger,
}
},
methods: {
t,
n,
},
})
this.app.use(pinia)
if (options.el) {
this.instance = this.app.mount(options.el)
}
}
/**
* Mount the Comments instance to a new element.
*
* @param el - The element to mount the instance on
*/
$mount(el: HTMLElement | string) {
if (this.instance) {
this.app.unmount()
}
this.instance = this.app.mount(el)
}
/**
* Unmount the Comments instance from the DOM and destroy it.
*/
$unmount() {
this.app.unmount()
this.instance = undefined
}
/**
* Update the current resource id.
*
* @param id - The new resource id to load the comments for
*/
update(id: string | number) {
if (this.instance) {
this.instance.update(id)
}
}
}

View File

@@ -5,7 +5,7 @@
import { getRequestToken, onRequestTokenUpdate } from '@nextcloud/auth'
import { createClient } from 'webdav'
import { getRootPath } from '../utils/davUtils.ts'
import { getRootPath } from '../utils/davUtils.js'
// init webdav client
const client = createClient(getRootPath())

View File

@@ -3,16 +3,16 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import client from './DavClient.ts'
import client from './DavClient.js'
/**
* Delete a comment
*
* @param resourceType the resource type
* @param resourceId the resource ID
* @param commentId the comment iD
* @param {string} resourceType the resource type
* @param {number} resourceId the resource ID
* @param {number} commentId the comment iD
*/
export default async function(resourceType: string, resourceId: number, commentId: number) {
export default async function(resourceType, resourceId, commentId) {
const commentPath = ['', resourceType, resourceId, commentId].join('/')
// Fetch newly created comment data

View File

@@ -3,17 +3,17 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import client from './DavClient.ts'
import client from './DavClient.js'
/**
* Edit an existing comment
*
* @param resourceType the resource type
* @param resourceId the resource ID
* @param commentId the comment iD
* @param message the message content
* @param {string} resourceType the resource type
* @param {number} resourceId the resource ID
* @param {number} commentId the comment iD
* @param {string} message the message content
*/
export default async function(resourceType: string, resourceId: number, commentId: number, message: string) {
export default async function(resourceType, resourceId, commentId, message) {
const commentPath = ['', resourceType, resourceId, commentId].join('/')
return await client.customRequest(commentPath, {

View File

@@ -8,7 +8,7 @@ import type { DAVResult, FileStat, ResponseDataDetailed } from 'webdav'
import { parseXML } from 'webdav'
import { processResponsePayload } from 'webdav/dist/node/response.js'
import { prepareFileFromProps } from 'webdav/dist/node/tools/dav.js'
import client from './DavClient.ts'
import client from './DavClient.js'
export const DEFAULT_LIMIT = 20

View File

@@ -5,24 +5,24 @@
import { getCurrentUser } from '@nextcloud/auth'
import axios from '@nextcloud/axios'
import { getRootPath } from '../utils/davUtils.ts'
import { decodeHtmlEntities } from '../utils/decodeHtmlEntities.ts'
import client from './DavClient.ts'
import { getRootPath } from '../utils/davUtils.js'
import { decodeHtmlEntities } from '../utils/decodeHtmlEntities.js'
import client from './DavClient.js'
/**
* Retrieve the comments list
*
* @param resourceType the resource type
* @param resourceId the resource ID
* @param message the message
* @return The new comment
* @param {string} resourceType the resource type
* @param {number} resourceId the resource ID
* @param {string} message the message
* @return {object} the new comment
*/
export default async function(resourceType: string, resourceId: number, message: string) {
export default async function(resourceType, resourceId, message) {
const resourcePath = ['', resourceType, resourceId].join('/')
const response = await axios.post(getRootPath() + resourcePath, {
actorDisplayName: getCurrentUser()!.displayName,
actorId: getCurrentUser()!.uid,
actorDisplayName: getCurrentUser().displayName,
actorId: getCurrentUser().uid,
actorType: 'users',
creationDateTime: (new Date()).toUTCString(),
message,

View File

@@ -5,7 +5,7 @@
import type { Response } from 'webdav'
import client from './DavClient.ts'
import client from './DavClient.js'
/**
* Mark comments older than the date timestamp as read

View File

@@ -6,20 +6,20 @@
/**
* Creates a cancelable axios 'request object'.
*
* @param request the axios promise request
* @return
* @param {Function} request the axios promise request
* @return {object}
*/
function cancelableRequest(request: (url: string, options?: Record<string, unknown>) => Promise<unknown>) {
function cancelableRequest(request) {
const controller = new AbortController()
const signal = controller.signal
/**
* Execute the request
*
* @param url the url to send the request to
* @param [options] optional config for the request
* @param {string} url the url to send the request to
* @param {object} [options] optional config for the request
*/
const fetch = async function(url: string, options?: Record<string, unknown>) {
const fetch = async function(url, options) {
const response = await request(
url,
{ signal, ...options },

View File

@@ -4,10 +4,10 @@
*/
/**
* @param value - the string to decode
* @param passes - the number of times to decode the string, default is 1
* @param {any} value -
* @param {any} passes -
*/
export function decodeHtmlEntities(value: string, passes = 1) {
export function decodeHtmlEntities(value, passes = 1) {
const parser = new DOMParser()
let decoded = value
for (let i = 0; i < passes; i++) {

View File

@@ -6,11 +6,11 @@
<template>
<Comment
v-bind="editorData"
:autoComplete="autoComplete"
:resourceType="resourceType"
:auto-complete="autoComplete"
:resource-type="resourceType"
:editor="true"
:userData="userData"
:resourceId="resourceId"
:user-data="userData"
:resource-id="resourceId"
class="comments-action"
@new="onNewComment" />
</template>
@@ -20,8 +20,8 @@ import { showError } from '@nextcloud/dialogs'
import { t } from '@nextcloud/l10n'
import { defineComponent } from 'vue'
import Comment from '../components/Comment.vue'
import logger from '../logger.ts'
import CommentView from '../mixins/CommentView.ts'
import logger from '../logger.js'
import CommentView from '../mixins/CommentView.js'
export default defineComponent({
components: {

View File

@@ -8,11 +8,11 @@
ref="comment"
tag="li"
v-bind="comment.props"
:autoComplete="autoComplete"
:resourceType="resourceType"
:auto-complete="autoComplete"
:resource-type="resourceType"
:message="commentMessage"
:resourceId="resourceId"
:userData="genMentionsData(comment.props.mentions)"
:resource-id="resourceId"
:user-data="genMentionsData(comment.props.mentions)"
class="comments-activity"
@delete="reloadCallback()" />
</template>

View File

@@ -11,11 +11,11 @@
<!-- Editor -->
<Comment
v-bind="editorData"
editor
:autoComplete
:resourceType
:userData
:resourceId="currentResourceId"
:auto-complete="autoComplete"
:resource-type="resourceType"
:editor="true"
:user-data="userData"
:resource-id="currentResourceId"
class="comments__writer"
@new="onNewComment" />
@@ -33,13 +33,13 @@
<Comment
v-for="comment in comments"
:key="comment.props.id"
v-model="comment.props.message"
tag="li"
v-bind="comment.props"
:autoComplete
:resourceType
:resourceId="currentResourceId"
:userData="genMentionsData(comment.props.mentions)"
:auto-complete="autoComplete"
:resource-type="resourceType"
:message.sync="comment.props.message"
:resource-id="currentResourceId"
:user-data="genMentionsData(comment.props.mentions)"
class="comments__list"
@delete="onDelete" />
</ul>
@@ -79,14 +79,15 @@ import IconAlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline
import IconMessageReplyTextOutline from 'vue-material-design-icons/MessageReplyTextOutline.vue'
import IconRefresh from 'vue-material-design-icons/Refresh.vue'
import Comment from '../components/Comment.vue'
import logger from '../logger.ts'
import logger from '../logger.js'
import CommentView from '../mixins/CommentView.ts'
import { DEFAULT_LIMIT, getComments } from '../services/GetComments.ts'
import { markCommentsAsRead } from '../services/ReadComments.ts'
import cancelableRequest from '../utils/cancelableRequest.ts'
import cancelableRequest from '../utils/cancelableRequest.js'
export default {
name: 'CommentsApp',
/* eslint vue/multi-word-component-names: "warn" */
name: 'Comments',
components: {
Comment,
@@ -103,8 +104,6 @@ export default {
mixins: [CommentView],
expose: ['update'],
data() {
return {
error: '',

View File

@@ -7,7 +7,7 @@
import type { IFolder, INode, IView } from '@nextcloud/files'
import { computed } from 'vue'
import CommentsApp from './CommentsApp.vue'
import Comments from './Comments.vue'
const props = defineProps<{
node?: INode
@@ -24,9 +24,9 @@ const resourceId = computed(() => props.node?.fileid)
</script>
<template>
<CommentsApp
<Comments
v-if="resourceId !== undefined"
:key="resourceId"
:resourceId="resourceId"
resourceType="files" />
:resource-id="resourceId"
resource-type="files" />
</template>

View File

@@ -2,8 +2,6 @@ OC.L10N.register(
"contactsinteraction",
{
"Recently contacted" : "Paskiausiai susisiekta",
"Contacts Interaction" : "Sąveika su adresatais",
"Manages interaction between accounts and contacts" : "Tvarko sąveiką tarp paskyrų ir kontaktų",
"Collect data about accounts and contacts interactions and provide an address book for the data" : "Rinkti duomenis apie klientų ir kontaktų sąveiką ir pateikti adresų knygą duomenims"
"Contacts Interaction" : "Sąveika su adresatais"
},
"nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);");

View File

@@ -1,7 +1,5 @@
{ "translations": {
"Recently contacted" : "Paskiausiai susisiekta",
"Contacts Interaction" : "Sąveika su adresatais",
"Manages interaction between accounts and contacts" : "Tvarko sąveiką tarp paskyrų ir kontaktų",
"Collect data about accounts and contacts interactions and provide an address book for the data" : "Rinkti duomenis apie klientų ir kontaktų sąveiką ir pateikti adresų knygą duomenims"
"Contacts Interaction" : "Sąveika su adresatais"
},"pluralForm" :"nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);"
}

View File

@@ -3,7 +3,6 @@ OC.L10N.register(
{
"Dashboard" : "Skydelis",
"Dashboard app" : "Skydelio programėlė",
"Start your day informed\n\nThe Nextcloud Dashboard is your starting point of the day, giving you an overview of your upcoming appointments, urgent emails, chat messages, incoming tickets, latest tweets and much more! People can add the widgets they like and change the background to their liking." : "Pradėkite dieną informuotai\n\n„Nextcloud“ ataskaitų sritis yra jūsų dienos atspirties taškas, kuriame pateikiama artėjančių susitikimų, skubių el. laiškų, pokalbių žinučių, gaunamų bilietų, naujausių tviterio žinučių ir daug daugiau apžvalga! Žmonės gali pridėti norimus valdiklius ir pakeisti foną pagal savo skonį.",
"Weather" : "Orai",
"Status" : "Būsena",
"Good morning" : "Labas rytas",
@@ -20,7 +19,6 @@ OC.L10N.register(
"Edit widgets" : "Taisyti valdiklius",
"Get more widgets from the App Store" : "Parsisiųsti įskiepių iš App Store",
"Weather service" : "Orų tarnyba",
"For your privacy, the weather data is requested by your {productName} server on your behalf so the weather service receives no personal information." : "Dėl jūsų privatumo, {productName} serveris jūsų vardu užklausė orų duomenis, todėl orų tarnyba negauna jokios asmeninės informacijos.",
"Weather data from Met.no" : "Orų duomenys iš Met.no",
"geocoding with Nominatim" : "geografinis kodavimas naudojant Nominatim",
"elevation data from OpenTopoData" : "aukščio duomenys iš OpenTopoData"

View File

@@ -1,7 +1,6 @@
{ "translations": {
"Dashboard" : "Skydelis",
"Dashboard app" : "Skydelio programėlė",
"Start your day informed\n\nThe Nextcloud Dashboard is your starting point of the day, giving you an overview of your upcoming appointments, urgent emails, chat messages, incoming tickets, latest tweets and much more! People can add the widgets they like and change the background to their liking." : "Pradėkite dieną informuotai\n\n„Nextcloud“ ataskaitų sritis yra jūsų dienos atspirties taškas, kuriame pateikiama artėjančių susitikimų, skubių el. laiškų, pokalbių žinučių, gaunamų bilietų, naujausių tviterio žinučių ir daug daugiau apžvalga! Žmonės gali pridėti norimus valdiklius ir pakeisti foną pagal savo skonį.",
"Weather" : "Orai",
"Status" : "Būsena",
"Good morning" : "Labas rytas",
@@ -18,7 +17,6 @@
"Edit widgets" : "Taisyti valdiklius",
"Get more widgets from the App Store" : "Parsisiųsti įskiepių iš App Store",
"Weather service" : "Orų tarnyba",
"For your privacy, the weather data is requested by your {productName} server on your behalf so the weather service receives no personal information." : "Dėl jūsų privatumo, {productName} serveris jūsų vardu užklausė orų duomenis, todėl orų tarnyba negauna jokios asmeninės informacijos.",
"Weather data from Met.no" : "Orų duomenys iš Met.no",
"geocoding with Nominatim" : "geografinis kodavimas naudojant Nominatim",
"elevation data from OpenTopoData" : "aukščio duomenys iš OpenTopoData"

View File

@@ -19,7 +19,7 @@ OC.L10N.register(
"Customize" : "Aanpassen",
"Edit widgets" : "Widgets bewerken",
"Get more widgets from the App Store" : "Haal meer widgets op uit de App Store",
"Weather service" : "Weer dienst",
"Weather service" : "Weerberichten",
"For your privacy, the weather data is requested by your {productName} server on your behalf so the weather service receives no personal information." : "Voor je privacy worden de weergegevens namens jou opgevraagd door je {productName} server, zodat de weer dienst geen persoonlijke informatie ontvangt.",
"Weather data from Met.no" : "Weerbericht via Met.no",
"geocoding with Nominatim" : "geocoding met Nominatim",

View File

@@ -17,7 +17,7 @@
"Customize" : "Aanpassen",
"Edit widgets" : "Widgets bewerken",
"Get more widgets from the App Store" : "Haal meer widgets op uit de App Store",
"Weather service" : "Weer dienst",
"Weather service" : "Weerberichten",
"For your privacy, the weather data is requested by your {productName} server on your behalf so the weather service receives no personal information." : "Voor je privacy worden de weergegevens namens jou opgevraagd door je {productName} server, zodat de weer dienst geen persoonlijke informatie ontvangt.",
"Weather data from Met.no" : "Weerbericht via Met.no",
"geocoding with Nominatim" : "geocoding met Nominatim",

View File

@@ -202,7 +202,6 @@ class DashboardApiController extends OCSController {
#[NoAdminRequired]
#[ApiRoute(verb: 'POST', url: '/api/v3/layout')]
public function updateLayout(array $layout): DataResponse {
$layout = $this->service->sanitizeLayout($layout);
$this->userConfig->setValueString($this->userId, 'dashboard', 'layout', implode(',', $layout));
return new DataResponse(['layout' => $layout]);
}

View File

@@ -31,30 +31,12 @@ class DashboardService {
*/
public function getLayout(): array {
$systemDefault = $this->appConfig->getAppValueString('layout', 'recommendations,spreed,mail,calendar');
return $this->sanitizeLayout(
return array_values(array_filter(
explode(',', $this->userConfig->getValueString($this->userId, 'dashboard', 'layout', $systemDefault)),
fn (string $value) => $value !== '')
);
}
/**
* @param list<string> $layout
* @return list<string>
*/
public function sanitizeLayout(array $layout): array {
$seen = [];
$result = [];
foreach ($layout as $value) {
if ($value === '' || isset($seen[$value])) {
continue;
}
$seen[$value] = true;
$result[] = $value;
}
return $result;
}
/**
* @return list<string>
*/

View File

@@ -5,7 +5,7 @@
<template>
<main id="app-dashboard">
<h2>{{ greeting.text }}</h2>
<ul v-if="sortedRegisteredStatus.length > 0" class="statuses">
<ul class="statuses">
<li
v-for="status in sortedRegisteredStatus"
:id="'status-' + status"

View File

@@ -44,25 +44,6 @@ class DashboardServiceTest extends TestCase {
);
}
public function testGetLayoutRemovesEmptyAndDuplicateEntries(): void {
$this->appConfig->method('getAppValueString')
->with('layout', 'recommendations,spreed,mail,calendar')
->willReturn('recommendations,spreed,mail,calendar');
$this->userConfig->method('getValueString')
->with('alice', 'dashboard', 'layout', 'recommendations,spreed,mail,calendar')
->willReturn('spreed,,mail,mail,calendar,spreed');
$layout = $this->service->getLayout();
$this->assertSame(['spreed', 'mail', 'calendar'], $layout);
}
public function testSanitizeLayoutRemovesEmptyAndDuplicateEntries(): void {
$layout = $this->service->sanitizeLayout(['files', 'calendar', 'files', '', 'mail', 'calendar']);
$this->assertSame(['files', 'calendar', 'mail'], $layout);
}
public function testGetBirthdate(): void {
$user = $this->createMock(IUser::class);
$this->userManager->method('get')

View File

@@ -10,7 +10,7 @@
<name>WebDAV</name>
<summary>WebDAV endpoint</summary>
<description>WebDAV endpoint</description>
<version>1.38.0</version>
<version>1.37.0</version>
<licence>agpl</licence>
<author>owncloud.org</author>
<namespace>DAV</namespace>

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