Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/spreed.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.drone.jsonnet144
-rw-r--r--.drone.yml2096
-rw-r--r--package-lock.json164
-rw-r--r--package.json2
-rw-r--r--src/components/Description/Description.vue41
-rw-r--r--src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue7
-rw-r--r--src/components/MessagesList/MessagesGroup/Message/Message.spec.js479
-rw-r--r--src/components/MessagesList/MessagesGroup/Message/Message.vue387
-rw-r--r--src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.spec.js437
-rw-r--r--src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue453
-rw-r--r--src/components/Quote.vue3
-rw-r--r--src/services/messagesService.js21
-rw-r--r--src/store/messagesStore.js101
-rw-r--r--src/store/messagesStore.spec.js7
-rw-r--r--src/store/reactionsStore.js103
-rw-r--r--src/store/storeConfig.js2
16 files changed, 2429 insertions, 2018 deletions
diff --git a/.drone.jsonnet b/.drone.jsonnet
new file mode 100644
index 000000000..ee60dc208
--- /dev/null
+++ b/.drone.jsonnet
@@ -0,0 +1,144 @@
+## 1. Download/install drone binary:
+## curl -L https://github.com/harness/drone-cli/releases/latest/download/drone_linux_amd64.tar.gz | tar zx
+## 2. Adjust the matrix as wished
+## 3. Run: ./drone jsonnet --stream --format yml
+## 4. Commit the result
+
+local Pipeline(test_set, database, services) = {
+ kind: "pipeline",
+ name: "int-"+database+"-"+test_set,
+ services: services,
+ steps: [
+ {
+ name: "integration-"+test_set,
+ image: "ghcr.io/nextcloud/continuous-integration-php8.0:latest",
+ environment: {
+ APP_NAME: "spreed",
+ CORE_BRANCH: "master",
+ GUESTS_BRANCH: "master",
+ DATABASEHOST: database
+ },
+ commands: [
+ "bash tests/drone-run-integration-tests.sh || exit 0",
+ "wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh",
+ "bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST",
+ "cd ../server",
+ "./occ app:enable $APP_NAME",
+ ] + (
+ if test_set == "conversation" || test_set == "conversation-2" then [
+ "git clone --depth 1 -b $GUESTS_BRANCH https://github.com/nextcloud/guests apps/guests"
+ ] else []
+ ) + [
+ "cd apps/$APP_NAME",
+ "cd tests/integration/",
+ "bash run.sh features/"+test_set
+ ]
+ }
+ ],
+ trigger: {
+ branch: [
+ "master",
+ "stable*"
+ ],
+ event: (
+ if database == "sqlite" then ["pull_request", "push"] else ["push"]
+ )
+ }
+};
+
+local PipelineSQLite(test_set) = Pipeline(
+ test_set,
+ "sqlite",
+ [
+ {
+ name: "cache",
+ image: "ghcr.io/nextcloud/continuous-integration-redis:latest"
+ }
+ ]
+);
+
+local PipelineMySQL(test_set) = Pipeline(
+ test_set,
+ "mysql",
+ [
+ {
+ name: "cache",
+ image: "ghcr.io/nextcloud/continuous-integration-redis:latest"
+ },
+ {
+ name: "mysql",
+ image: "ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4",
+ environment: {
+ MYSQL_ROOT_PASSWORD: "owncloud",
+ MYSQL_USER: "oc_autotest",
+ MYSQL_PASSWORD: "owncloud",
+ MYSQL_DATABASE: "oc_autotest"
+ },
+ command: [
+ "--innodb_large_prefix=true",
+ "--innodb_file_format=barracuda",
+ "--innodb_file_per_table=true"
+ ],
+ tmpfs: [
+ "/var/lib/mysql"
+ ]
+ }
+ ]
+);
+
+local PipelinePostgreSQL(test_set) = Pipeline(
+ test_set,
+ "pgsql",
+ [
+ {
+ name: "cache",
+ image: "ghcr.io/nextcloud/continuous-integration-redis:latest"
+ },
+ {
+ name: "pgsql",
+ image: "ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13",
+ environment: {
+ POSTGRES_USER: "oc_autotest",
+ POSTGRES_DB: "oc_autotest_dummy",
+ POSTGRES_HOST_AUTH_METHOD: "trust",
+ POSTGRES_PASSWORD: ""
+ },
+ tmpfs: [
+ "/var/lib/postgresql/data"
+ ]
+ }
+ ]
+);
+
+
+[
+ PipelineSQLite("callapi"),
+ PipelineSQLite("chat"),
+ PipelineSQLite("command"),
+ PipelineSQLite("conversation"),
+ PipelineSQLite("conversation-2"),
+ PipelineSQLite("federation"),
+ PipelineSQLite("reaction"),
+ PipelineSQLite("sharing"),
+ PipelineSQLite("sharing-2"),
+
+ PipelineMySQL("callapi"),
+ PipelineMySQL("chat"),
+ PipelineMySQL("command"),
+ PipelineMySQL("conversation"),
+ PipelineMySQL("conversation-2"),
+ PipelineMySQL("federation"),
+ PipelineMySQL("reaction"),
+ PipelineMySQL("sharing"),
+ PipelineMySQL("sharing-2"),
+
+ PipelinePostgreSQL("callapi"),
+ PipelinePostgreSQL("chat"),
+ PipelinePostgreSQL("command"),
+ PipelinePostgreSQL("conversation"),
+ PipelinePostgreSQL("conversation-2"),
+ PipelinePostgreSQL("federation"),
+ PipelinePostgreSQL("reaction"),
+ PipelinePostgreSQL("sharing"),
+ PipelinePostgreSQL("sharing-2"),
+]
diff --git a/.drone.yml b/.drone.yml
index 1d07dc769..0fb8eeedf 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -1,1464 +1,996 @@
+---
kind: pipeline
name: int-sqlite-callapi
-
-steps:
- - name: integration-callapi
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: sqlite
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/callapi
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/callapi
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: sqlite
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-callapi
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- - pull_request
- - push
-
+ - pull_request
+ - push
---
kind: pipeline
name: int-sqlite-chat
-
-steps:
- - name: integration-chat
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: sqlite
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/chat
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/chat
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: sqlite
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-chat
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- - pull_request
- - push
-
+ - pull_request
+ - push
---
kind: pipeline
name: int-sqlite-command
-
-steps:
- - name: integration-command
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: sqlite
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/command
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/command
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: sqlite
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-command
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- - pull_request
- - push
-
+ - pull_request
+ - push
---
kind: pipeline
name: int-sqlite-conversation
-
-steps:
- - name: integration-conversation
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- GUESTS_BRANCH: master
- DATABASEHOST: sqlite
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - git clone --depth 1 -b "$GUESTS_BRANCH" https://github.com/nextcloud/guests apps/guests
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/conversation
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - git clone --depth 1 -b $GUESTS_BRANCH https://github.com/nextcloud/guests apps/guests
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/conversation
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: sqlite
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-conversation
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- - pull_request
- - push
-
+ - pull_request
+ - push
---
kind: pipeline
name: int-sqlite-conversation-2
-
-steps:
- - name: integration-conversation-2
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- GUESTS_BRANCH: master
- DATABASEHOST: sqlite
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - git clone --depth 1 -b "$GUESTS_BRANCH" https://github.com/nextcloud/guests apps/guests
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/conversation-2
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - git clone --depth 1 -b $GUESTS_BRANCH https://github.com/nextcloud/guests apps/guests
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/conversation-2
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: sqlite
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-conversation-2
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- - pull_request
- - push
-
+ - pull_request
+ - push
---
kind: pipeline
-name: int-sqlite-reaction
-
-steps:
- - name: integration-reaction
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- GUESTS_BRANCH: master
- DATABASEHOST: sqlite
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - git clone --depth 1 -b "$GUESTS_BRANCH" https://github.com/nextcloud/guests apps/guests
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/reaction
-
+name: int-sqlite-federation
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/federation
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: sqlite
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-federation
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- - pull_request
- - push
-
+ - pull_request
+ - push
---
kind: pipeline
-name: int-sqlite-federation
-
-steps:
- - name: integration-federation
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: sqlite
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/federation
-
+name: int-sqlite-reaction
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/reaction
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: sqlite
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-reaction
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- - pull_request
- - push
-
+ - pull_request
+ - push
---
kind: pipeline
name: int-sqlite-sharing
-
-steps:
- - name: integration-sharing
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: sqlite
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/sharing
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/sharing
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: sqlite
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-sharing
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- - pull_request
- - push
-
+ - pull_request
+ - push
---
kind: pipeline
name: int-sqlite-sharing-2
-
-steps:
- - name: integration-sharing-2
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: sqlite
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/sharing-2
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/sharing-2
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: sqlite
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-sharing-2
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- - pull_request
- - push
-
+ - pull_request
+ - push
---
kind: pipeline
name: int-mysql-callapi
-
-steps:
- - name: integration-callapi
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: mysql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/callapi
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: mysql
- image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
- environment:
- MYSQL_ROOT_PASSWORD: owncloud
- MYSQL_USER: oc_autotest
- MYSQL_PASSWORD: owncloud
- MYSQL_DATABASE: oc_autotest
- command: [ "--innodb_large_prefix=true", "--innodb_file_format=barracuda", "--innodb_file_per_table=true" ]
- tmpfs:
- - /var/lib/mysql
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- command:
+ - --innodb_large_prefix=true
+ - --innodb_file_format=barracuda
+ - --innodb_file_per_table=true
+ environment:
+ MYSQL_DATABASE: oc_autotest
+ MYSQL_PASSWORD: owncloud
+ MYSQL_ROOT_PASSWORD: owncloud
+ MYSQL_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
+ name: mysql
+ tmpfs:
+ - /var/lib/mysql
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/callapi
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: mysql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-callapi
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-mysql-chat
-
-steps:
- - name: integration-chat
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: mysql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/chat
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: mysql
- image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
- environment:
- MYSQL_ROOT_PASSWORD: owncloud
- MYSQL_USER: oc_autotest
- MYSQL_PASSWORD: owncloud
- MYSQL_DATABASE: oc_autotest
- command: [ "--innodb_large_prefix=true", "--innodb_file_format=barracuda", "--innodb_file_per_table=true" ]
- tmpfs:
- - /var/lib/mysql
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- command:
+ - --innodb_large_prefix=true
+ - --innodb_file_format=barracuda
+ - --innodb_file_per_table=true
+ environment:
+ MYSQL_DATABASE: oc_autotest
+ MYSQL_PASSWORD: owncloud
+ MYSQL_ROOT_PASSWORD: owncloud
+ MYSQL_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
+ name: mysql
+ tmpfs:
+ - /var/lib/mysql
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/chat
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: mysql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-chat
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-mysql-command
-
-steps:
- - name: integration-command
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: mysql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/command
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: mysql
- image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
- environment:
- MYSQL_ROOT_PASSWORD: owncloud
- MYSQL_USER: oc_autotest
- MYSQL_PASSWORD: owncloud
- MYSQL_DATABASE: oc_autotest
- command: [ "--innodb_large_prefix=true", "--innodb_file_format=barracuda", "--innodb_file_per_table=true" ]
- tmpfs:
- - /var/lib/mysql
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- command:
+ - --innodb_large_prefix=true
+ - --innodb_file_format=barracuda
+ - --innodb_file_per_table=true
+ environment:
+ MYSQL_DATABASE: oc_autotest
+ MYSQL_PASSWORD: owncloud
+ MYSQL_ROOT_PASSWORD: owncloud
+ MYSQL_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
+ name: mysql
+ tmpfs:
+ - /var/lib/mysql
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/command
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: mysql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-command
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-mysql-conversation
-
-steps:
- - name: integration-conversation
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- GUESTS_BRANCH: master
- DATABASEHOST: mysql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - git clone --depth 1 -b "$GUESTS_BRANCH" https://github.com/nextcloud/guests apps/guests
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/conversation
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: mysql
- image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
- environment:
- MYSQL_ROOT_PASSWORD: owncloud
- MYSQL_USER: oc_autotest
- MYSQL_PASSWORD: owncloud
- MYSQL_DATABASE: oc_autotest
- command: [ "--innodb_large_prefix=true", "--innodb_file_format=barracuda", "--innodb_file_per_table=true" ]
- tmpfs:
- - /var/lib/mysql
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- command:
+ - --innodb_large_prefix=true
+ - --innodb_file_format=barracuda
+ - --innodb_file_per_table=true
+ environment:
+ MYSQL_DATABASE: oc_autotest
+ MYSQL_PASSWORD: owncloud
+ MYSQL_ROOT_PASSWORD: owncloud
+ MYSQL_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
+ name: mysql
+ tmpfs:
+ - /var/lib/mysql
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - git clone --depth 1 -b $GUESTS_BRANCH https://github.com/nextcloud/guests apps/guests
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/conversation
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: mysql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-conversation
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-mysql-conversation-2
-
-steps:
- - name: integration-conversation-2
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- GUESTS_BRANCH: master
- DATABASEHOST: mysql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - git clone --depth 1 -b "$GUESTS_BRANCH" https://github.com/nextcloud/guests apps/guests
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/conversation-2
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: mysql
- image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
- environment:
- MYSQL_ROOT_PASSWORD: owncloud
- MYSQL_USER: oc_autotest
- MYSQL_PASSWORD: owncloud
- MYSQL_DATABASE: oc_autotest
- command: [ "--innodb_large_prefix=true", "--innodb_file_format=barracuda", "--innodb_file_per_table=true" ]
- tmpfs:
- - /var/lib/mysql
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- command:
+ - --innodb_large_prefix=true
+ - --innodb_file_format=barracuda
+ - --innodb_file_per_table=true
+ environment:
+ MYSQL_DATABASE: oc_autotest
+ MYSQL_PASSWORD: owncloud
+ MYSQL_ROOT_PASSWORD: owncloud
+ MYSQL_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
+ name: mysql
+ tmpfs:
+ - /var/lib/mysql
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - git clone --depth 1 -b $GUESTS_BRANCH https://github.com/nextcloud/guests apps/guests
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/conversation-2
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: mysql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-conversation-2
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
-name: int-mysql-reaction
-
-steps:
- - name: integration-reaction
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- GUESTS_BRANCH: master
- DATABASEHOST: mysql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - git clone --depth 1 -b "$GUESTS_BRANCH" https://github.com/nextcloud/guests apps/guests
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/reaction
-
+name: int-mysql-federation
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: mysql
- image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
- environment:
- MYSQL_ROOT_PASSWORD: owncloud
- MYSQL_USER: oc_autotest
- MYSQL_PASSWORD: owncloud
- MYSQL_DATABASE: oc_autotest
- command: [ "--innodb_large_prefix=true", "--innodb_file_format=barracuda", "--innodb_file_per_table=true" ]
- tmpfs:
- - /var/lib/mysql
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- command:
+ - --innodb_large_prefix=true
+ - --innodb_file_format=barracuda
+ - --innodb_file_per_table=true
+ environment:
+ MYSQL_DATABASE: oc_autotest
+ MYSQL_PASSWORD: owncloud
+ MYSQL_ROOT_PASSWORD: owncloud
+ MYSQL_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
+ name: mysql
+ tmpfs:
+ - /var/lib/mysql
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/federation
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: mysql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-federation
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
-name: int-mysql-federation
-
-steps:
- - name: integration-federation
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: mysql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/federation
-
+name: int-mysql-reaction
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: mysql
- image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
- environment:
- MYSQL_ROOT_PASSWORD: owncloud
- MYSQL_USER: oc_autotest
- MYSQL_PASSWORD: owncloud
- MYSQL_DATABASE: oc_autotest
- command: [ "--innodb_large_prefix=true", "--innodb_file_format=barracuda", "--innodb_file_per_table=true" ]
- tmpfs:
- - /var/lib/mysql
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- command:
+ - --innodb_large_prefix=true
+ - --innodb_file_format=barracuda
+ - --innodb_file_per_table=true
+ environment:
+ MYSQL_DATABASE: oc_autotest
+ MYSQL_PASSWORD: owncloud
+ MYSQL_ROOT_PASSWORD: owncloud
+ MYSQL_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
+ name: mysql
+ tmpfs:
+ - /var/lib/mysql
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/reaction
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: mysql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-reaction
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- # - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-mysql-sharing
-
-steps:
- - name: integration-sharing
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: mysql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/sharing
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: mysql
- image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
- environment:
- MYSQL_ROOT_PASSWORD: owncloud
- MYSQL_USER: oc_autotest
- MYSQL_PASSWORD: owncloud
- MYSQL_DATABASE: oc_autotest
- command: [ "--innodb_large_prefix=true", "--innodb_file_format=barracuda", "--innodb_file_per_table=true" ]
- tmpfs:
- - /var/lib/mysql
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- command:
+ - --innodb_large_prefix=true
+ - --innodb_file_format=barracuda
+ - --innodb_file_per_table=true
+ environment:
+ MYSQL_DATABASE: oc_autotest
+ MYSQL_PASSWORD: owncloud
+ MYSQL_ROOT_PASSWORD: owncloud
+ MYSQL_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
+ name: mysql
+ tmpfs:
+ - /var/lib/mysql
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/sharing
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: mysql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-sharing
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-mysql-sharing-2
-
-steps:
- - name: integration-sharing-2
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: mysql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/sharing-2
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: mysql
- image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
- environment:
- MYSQL_ROOT_PASSWORD: owncloud
- MYSQL_USER: oc_autotest
- MYSQL_PASSWORD: owncloud
- MYSQL_DATABASE: oc_autotest
- command: [ "--innodb_large_prefix=true", "--innodb_file_format=barracuda", "--innodb_file_per_table=true" ]
- tmpfs:
- - /var/lib/mysql
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- command:
+ - --innodb_large_prefix=true
+ - --innodb_file_format=barracuda
+ - --innodb_file_per_table=true
+ environment:
+ MYSQL_DATABASE: oc_autotest
+ MYSQL_PASSWORD: owncloud
+ MYSQL_ROOT_PASSWORD: owncloud
+ MYSQL_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-mariadb-10.4:10.4
+ name: mysql
+ tmpfs:
+ - /var/lib/mysql
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/sharing-2
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: mysql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-sharing-2
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-pgsql-callapi
-
-steps:
- - name: integration-callapi
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: pgsql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/callapi
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: pgsql
- image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
- environment:
- POSTGRES_USER: oc_autotest
- POSTGRES_DB: oc_autotest_dummy
- POSTGRES_HOST_AUTH_METHOD: trust
- POSTGRES_PASSWORD:
- tmpfs:
- - /var/lib/postgresql/data
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- environment:
+ POSTGRES_DB: oc_autotest_dummy
+ POSTGRES_HOST_AUTH_METHOD: trust
+ POSTGRES_PASSWORD: ""
+ POSTGRES_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
+ name: pgsql
+ tmpfs:
+ - /var/lib/postgresql/data
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/callapi
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: pgsql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-callapi
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-pgsql-chat
-
-steps:
- - name: integration-chat
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: pgsql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/chat
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: pgsql
- image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
- environment:
- POSTGRES_USER: oc_autotest
- POSTGRES_DB: oc_autotest_dummy
- POSTGRES_HOST_AUTH_METHOD: trust
- POSTGRES_PASSWORD:
- tmpfs:
- - /var/lib/postgresql/data
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- environment:
+ POSTGRES_DB: oc_autotest_dummy
+ POSTGRES_HOST_AUTH_METHOD: trust
+ POSTGRES_PASSWORD: ""
+ POSTGRES_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
+ name: pgsql
+ tmpfs:
+ - /var/lib/postgresql/data
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/chat
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: pgsql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-chat
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-pgsql-command
-
-steps:
- - name: integration-command
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: pgsql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/command
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: pgsql
- image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
- environment:
- POSTGRES_USER: oc_autotest
- POSTGRES_DB: oc_autotest_dummy
- POSTGRES_HOST_AUTH_METHOD: trust
- POSTGRES_PASSWORD:
- tmpfs:
- - /var/lib/postgresql/data
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- environment:
+ POSTGRES_DB: oc_autotest_dummy
+ POSTGRES_HOST_AUTH_METHOD: trust
+ POSTGRES_PASSWORD: ""
+ POSTGRES_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
+ name: pgsql
+ tmpfs:
+ - /var/lib/postgresql/data
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/command
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: pgsql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-command
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-pgsql-conversation
-
-steps:
- - name: integration-conversation
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- GUESTS_BRANCH: master
- DATABASEHOST: pgsql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - git clone --depth 1 -b "$GUESTS_BRANCH" https://github.com/nextcloud/guests apps/guests
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/conversation
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: pgsql
- image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
- environment:
- POSTGRES_USER: oc_autotest
- POSTGRES_DB: oc_autotest_dummy
- POSTGRES_HOST_AUTH_METHOD: trust
- POSTGRES_PASSWORD:
- tmpfs:
- - /var/lib/postgresql/data
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- environment:
+ POSTGRES_DB: oc_autotest_dummy
+ POSTGRES_HOST_AUTH_METHOD: trust
+ POSTGRES_PASSWORD: ""
+ POSTGRES_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
+ name: pgsql
+ tmpfs:
+ - /var/lib/postgresql/data
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - git clone --depth 1 -b $GUESTS_BRANCH https://github.com/nextcloud/guests apps/guests
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/conversation
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: pgsql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-conversation
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-pgsql-conversation-2
-
-steps:
- - name: integration-conversation-2
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- GUESTS_BRANCH: master
- DATABASEHOST: pgsql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - git clone --depth 1 -b "$GUESTS_BRANCH" https://github.com/nextcloud/guests apps/guests
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/conversation-2
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: pgsql
- image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
- environment:
- POSTGRES_USER: oc_autotest
- POSTGRES_DB: oc_autotest_dummy
- POSTGRES_HOST_AUTH_METHOD: trust
- POSTGRES_PASSWORD:
- tmpfs:
- - /var/lib/postgresql/data
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- environment:
+ POSTGRES_DB: oc_autotest_dummy
+ POSTGRES_HOST_AUTH_METHOD: trust
+ POSTGRES_PASSWORD: ""
+ POSTGRES_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
+ name: pgsql
+ tmpfs:
+ - /var/lib/postgresql/data
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - git clone --depth 1 -b $GUESTS_BRANCH https://github.com/nextcloud/guests apps/guests
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/conversation-2
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: pgsql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-conversation-2
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
-name: int-pgsql-reaction
-
-steps:
- - name: integration-reaction
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- GUESTS_BRANCH: master
- DATABASEHOST: pgsql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - git clone --depth 1 -b "$GUESTS_BRANCH" https://github.com/nextcloud/guests apps/guests
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/reaction
-
+name: int-pgsql-federation
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: pgsql
- image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
- environment:
- POSTGRES_USER: oc_autotest
- POSTGRES_DB: oc_autotest_dummy
- POSTGRES_HOST_AUTH_METHOD: trust
- POSTGRES_PASSWORD:
- tmpfs:
- - /var/lib/postgresql/data
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- environment:
+ POSTGRES_DB: oc_autotest_dummy
+ POSTGRES_HOST_AUTH_METHOD: trust
+ POSTGRES_PASSWORD: ""
+ POSTGRES_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
+ name: pgsql
+ tmpfs:
+ - /var/lib/postgresql/data
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/federation
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: pgsql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-federation
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
-name: int-pgsql-federation
-
-steps:
- - name: integration-federation
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: pgsql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/federation
-
+name: int-pgsql-reaction
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: pgsql
- image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
- environment:
- POSTGRES_USER: oc_autotest
- POSTGRES_DB: oc_autotest_dummy
- POSTGRES_HOST_AUTH_METHOD: trust
- POSTGRES_PASSWORD:
- tmpfs:
- - /var/lib/postgresql/data
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- environment:
+ POSTGRES_DB: oc_autotest_dummy
+ POSTGRES_HOST_AUTH_METHOD: trust
+ POSTGRES_PASSWORD: ""
+ POSTGRES_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
+ name: pgsql
+ tmpfs:
+ - /var/lib/postgresql/data
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/reaction
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: pgsql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-reaction
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
- # - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-pgsql-sharing
-
-steps:
- - name: integration-sharing
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: pgsql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/sharing
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: pgsql
- image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
- environment:
- POSTGRES_USER: oc_autotest
- POSTGRES_DB: oc_autotest_dummy
- POSTGRES_HOST_AUTH_METHOD: trust
- POSTGRES_PASSWORD:
- tmpfs:
- - /var/lib/postgresql/data
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- environment:
+ POSTGRES_DB: oc_autotest_dummy
+ POSTGRES_HOST_AUTH_METHOD: trust
+ POSTGRES_PASSWORD: ""
+ POSTGRES_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
+ name: pgsql
+ tmpfs:
+ - /var/lib/postgresql/data
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/sharing
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: pgsql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-sharing
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
+ - push
---
kind: pipeline
name: int-pgsql-sharing-2
-
-steps:
- - name: integration-sharing-2
- image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
- environment:
- APP_NAME: spreed
- CORE_BRANCH: master
- DATABASEHOST: pgsql
- commands:
- - bash tests/drone-run-integration-tests.sh || exit 0
- - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
- - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
- - cd ../server
- - ./occ app:enable $APP_NAME
- - cd apps/$APP_NAME
-
- # Run integration tests
- - cd tests/integration/
- - bash run.sh features/sharing-2
-
services:
- - name: cache
- image: ghcr.io/nextcloud/continuous-integration-redis:latest
- - name: pgsql
- image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
- environment:
- POSTGRES_USER: oc_autotest
- POSTGRES_DB: oc_autotest_dummy
- POSTGRES_HOST_AUTH_METHOD: trust
- POSTGRES_PASSWORD:
- tmpfs:
- - /var/lib/postgresql/data
-
+- image: ghcr.io/nextcloud/continuous-integration-redis:latest
+ name: cache
+- environment:
+ POSTGRES_DB: oc_autotest_dummy
+ POSTGRES_HOST_AUTH_METHOD: trust
+ POSTGRES_PASSWORD: ""
+ POSTGRES_USER: oc_autotest
+ image: ghcr.io/nextcloud/continuous-integration-postgres-13:postgres-13
+ name: pgsql
+ tmpfs:
+ - /var/lib/postgresql/data
+steps:
+- commands:
+ - bash tests/drone-run-integration-tests.sh || exit 0
+ - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh
+ - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DATABASEHOST
+ - cd ../server
+ - ./occ app:enable $APP_NAME
+ - cd apps/$APP_NAME
+ - cd tests/integration/
+ - bash run.sh features/sharing-2
+ environment:
+ APP_NAME: spreed
+ CORE_BRANCH: master
+ DATABASEHOST: pgsql
+ GUESTS_BRANCH: master
+ image: ghcr.io/nextcloud/continuous-integration-php8.0:latest
+ name: integration-sharing-2
trigger:
branch:
- - master
- - stable*
+ - master
+ - stable*
event:
-# - pull_request
- - push
-
-#---
-#kind: pipeline
-#name: acc-sqlite-app-files
-#
-#steps:
-# - name: acceptance-app-files
-# image: nextcloudci/acceptance-php7.1:acceptance-php7.1-2
-# environment:
-# APP_NAME: spreed
-# CORE_BRANCH: master
-# SELENIUM_HOST: selenium
-# TESTS_ACCEPTANCE: app-files
-# commands:
-# - bash tests/drone-run-acceptance-tests.sh || exit 0
-# # Pre-setup steps
-# - git clone --depth 1 -b $CORE_BRANCH https://github.com/nextcloud/server ../server
-# - cp -R . ../server/apps/$APP_NAME
-# - cd ../server
-# - git submodule update --init
-# - ln --symbolic `pwd` /var/www/html
-#
-# # Run acceptance tests
-# - tests/acceptance/run-local.sh --acceptance-tests-dir apps/spreed/tests/acceptance --timeout-multiplier 10 --nextcloud-server-domain acceptance-$TESTS_ACCEPTANCE --selenium-server $SELENIUM_HOST:4444 allow-git-repository-modifications features/$TESTS_ACCEPTANCE.feature
-#
-#services:
-# - name: selenium
-# image: selenium/standalone-firefox:2.53.1-beryllium
-# environment:
-# # Reduce default log level for Selenium server (INFO) as it is too
-# # verbose.
-# JAVA_OPTS: -Dselenium.LOGGER.level=WARNING
-#
-#trigger:
-# branch:
-# - master
-# - stable*
-# event:
-# - pull_request
-# - push
-#
-#---
-#kind: pipeline
-#name: acc-sqlite-chat
-#
-#steps:
-# - name: acceptance-chat
-# image: nextcloudci/acceptance-php7.1:acceptance-php7.1-2
-# environment:
-# APP_NAME: spreed
-# CORE_BRANCH: master
-# SELENIUM_HOST: selenium
-# TESTS_ACCEPTANCE: chat
-# commands:
-# - bash tests/drone-run-acceptance-tests.sh || exit 0
-# # Pre-setup steps
-# - git clone --depth 1 -b $CORE_BRANCH https://github.com/nextcloud/server ../server
-# - cp -R . ../server/apps/$APP_NAME
-# - cd ../server
-# - git submodule update --init
-# - ln --symbolic `pwd` /var/www/html
-#
-# # Run acceptance tests
-# - tests/acceptance/run-local.sh --acceptance-tests-dir apps/spreed/tests/acceptance --timeout-multiplier 10 --nextcloud-server-domain acceptance-$TESTS_ACCEPTANCE --selenium-server $SELENIUM_HOST:4444 allow-git-repository-modifications features/$TESTS_ACCEPTANCE.feature
-#
-#services:
-# - name: cache
-# image: ghcr.io/nextcloud/continuous-integration-redis:latest
-# - name: selenium
-# image: selenium/standalone-firefox:2.53.1-beryllium
-# environment:
-# # Reduce default log level for Selenium server (INFO) as it is too
-# # verbose.
-# JAVA_OPTS: -Dselenium.LOGGER.level=WARNING
-#
-#trigger:
-# branch:
-# - master
-# - stable*
-# event:
-# - pull_request
-# - push
-#
-#---
-#kind: pipeline
-#name: acc-sqlite-conversation
-#
-#steps:
-# - name: acceptance-conversation
-# image: nextcloudci/acceptance-php7.1:acceptance-php7.1-2
-# environment:
-# APP_NAME: spreed
-# CORE_BRANCH: master
-# SELENIUM_HOST: selenium
-# TESTS_ACCEPTANCE: conversation
-# commands:
-# - bash tests/drone-run-acceptance-tests.sh || exit 0
-# # Pre-setup steps
-# - git clone --depth 1 -b $CORE_BRANCH https://github.com/nextcloud/server ../server
-# - cp -R . ../server/apps/$APP_NAME
-# - cd ../server
-# - git submodule update --init
-# - ln --symbolic `pwd` /var/www/html
-#
-# # Run acceptance tests
-# - tests/acceptance/run-local.sh --acceptance-tests-dir apps/spreed/tests/acceptance --timeout-multiplier 10 --nextcloud-server-domain acceptance-$TESTS_ACCEPTANCE --selenium-server $SELENIUM_HOST:4444 allow-git-repository-modifications features/$TESTS_ACCEPTANCE.feature
-#
-#services:
-# - name: cache
-# image: ghcr.io/nextcloud/continuous-integration-redis:latest
-# - name: selenium
-# image: selenium/standalone-firefox:2.53.1-beryllium
-# environment:
-# # Reduce default log level for Selenium server (INFO) as it is too
-# # verbose.
-# JAVA_OPTS: -Dselenium.LOGGER.level=WARNING
-#
-#trigger:
-# branch:
-# - master
-# - stable*
-# event:
-# - pull_request
-# - push
-#
-#---
-#kind: pipeline
-#name: acc-sqlite-conversation-public
-#
-#steps:
-# - name: acceptance-conversation-public
-# image: nextcloudci/acceptance-php7.1:acceptance-php7.1-2
-# environment:
-# APP_NAME: spreed
-# CORE_BRANCH: master
-# SELENIUM_HOST: selenium
-# TESTS_ACCEPTANCE: conversation-public
-# commands:
-# - bash tests/drone-run-acceptance-tests.sh || exit 0
-# # Pre-setup steps
-# - git clone --depth 1 -b $CORE_BRANCH https://github.com/nextcloud/server ../server
-# - cp -R . ../server/apps/$APP_NAME
-# - cd ../server
-# - git submodule update --init
-# - ln --symbolic `pwd` /var/www/html
-#
-# # Run acceptance tests
-# - tests/acceptance/run-local.sh --acceptance-tests-dir apps/spreed/tests/acceptance --timeout-multiplier 10 --nextcloud-server-domain acceptance-$TESTS_ACCEPTANCE --selenium-server $SELENIUM_HOST:4444 allow-git-repository-modifications features/$TESTS_ACCEPTANCE.feature
-#
-#services:
-# - name: cache
-# image: ghcr.io/nextcloud/continuous-integration-redis:latest
-# - name: selenium
-# image: selenium/standalone-firefox:2.53.1-beryllium
-# environment:
-# # Reduce default log level for Selenium server (INFO) as it is too
-# # verbose.
-# JAVA_OPTS: -Dselenium.LOGGER.level=WARNING
-#
-#trigger:
-# branch:
-# - master
-# - stable*
-# event:
-# - pull_request
-# - push
-#
-#---
-#kind: pipeline
-#name: acc-sqlite-lobby
-#
-#steps:
-# - name: acceptance-lobby
-# image: nextcloudci/acceptance-php7.1:acceptance-php7.1-2
-# environment:
-# APP_NAME: spreed
-# CORE_BRANCH: master
-# SELENIUM_HOST: selenium
-# TESTS_ACCEPTANCE: lobby
-# commands:
-# - bash tests/drone-run-acceptance-tests.sh || exit 0
-# # Pre-setup steps
-# - git clone --depth 1 -b $CORE_BRANCH https://github.com/nextcloud/server ../server
-# - cp -R . ../server/apps/$APP_NAME
-# - cd ../server
-# - git submodule update --init
-# - ln --symbolic `pwd` /var/www/html
-#
-# # Run acceptance tests
-# - tests/acceptance/run-local.sh --acceptance-tests-dir apps/spreed/tests/acceptance --timeout-multiplier 10 --nextcloud-server-domain acceptance-$TESTS_ACCEPTANCE --selenium-server $SELENIUM_HOST:4444 allow-git-repository-modifications features/$TESTS_ACCEPTANCE.feature
-#
-#services:
-# - name: selenium
-# image: selenium/standalone-firefox:2.53.1-beryllium
-# environment:
-# # Reduce default log level for Selenium server (INFO) as it is too
-# # verbose.
-# JAVA_OPTS: -Dselenium.LOGGER.level=WARNING
-#
-#trigger:
-# branch:
-# - master
-# - stable*
-# event:
-# - pull_request
-# - push
-#
-#---
-#kind: pipeline
-#name: acc-sqlite-public-share
-#
-#steps:
-# - name: acceptance-public-share
-# image: nextcloudci/acceptance-php7.1:acceptance-php7.1-2
-# environment:
-# APP_NAME: spreed
-# CORE_BRANCH: master
-# SELENIUM_HOST: selenium
-# TESTS_ACCEPTANCE: public-share
-# commands:
-# - bash tests/drone-run-acceptance-tests.sh || exit 0
-# # Pre-setup steps
-# - git clone --depth 1 -b $CORE_BRANCH https://github.com/nextcloud/server ../server
-# - cp -R . ../server/apps/$APP_NAME
-# - cd ../server
-# - git submodule update --init
-# - ln --symbolic `pwd` /var/www/html
-#
-# # Run acceptance tests
-# - tests/acceptance/run-local.sh --acceptance-tests-dir apps/spreed/tests/acceptance --timeout-multiplier 10 --nextcloud-server-domain acceptance-$TESTS_ACCEPTANCE --selenium-server $SELENIUM_HOST:4444 allow-git-repository-modifications features/$TESTS_ACCEPTANCE.feature
-#
-#services:
-# - name: cache
-# image: ghcr.io/nextcloud/continuous-integration-redis:latest
-# - name: selenium
-# image: selenium/standalone-firefox:2.53.1-beryllium
-# environment:
-# # Reduce default log level for Selenium server (INFO) as it is too
-# # verbose.
-# JAVA_OPTS: -Dselenium.LOGGER.level=WARNING
-#
-#trigger:
-# branch:
-# - master
-# - stable*
-# event:
-# - pull_request
-# - push
-#
-#---
-#kind: pipeline
-#name: acc-sqlite-public-share-auth
-#
-#steps:
-# - name: acceptance-public-share-auth
-# image: nextcloudci/acceptance-php7.1:acceptance-php7.1-2
-# environment:
-# APP_NAME: spreed
-# CORE_BRANCH: master
-# SELENIUM_HOST: selenium
-# TESTS_ACCEPTANCE: public-share-auth
-# commands:
-# - bash tests/drone-run-acceptance-tests.sh || exit 0
-# # Pre-setup steps
-# - git clone --depth 1 -b $CORE_BRANCH https://github.com/nextcloud/server ../server
-# - cp -R . ../server/apps/$APP_NAME
-# - cd ../server
-# - git submodule update --init
-# - ln --symbolic `pwd` /var/www/html
-#
-# # Run acceptance tests
-# - tests/acceptance/run-local.sh --acceptance-tests-dir apps/spreed/tests/acceptance --timeout-multiplier 10 --nextcloud-server-domain acceptance-$TESTS_ACCEPTANCE --selenium-server $SELENIUM_HOST:4444 allow-git-repository-modifications features/$TESTS_ACCEPTANCE.feature
-#
-#services:
-# - name: cache
-# image: ghcr.io/nextcloud/continuous-integration-redis:latest
-# - name: selenium
-# image: selenium/standalone-firefox:2.53.1-beryllium
-# environment:
-# # Reduce default log level for Selenium server (INFO) as it is too
-# # verbose.
-# JAVA_OPTS: -Dselenium.LOGGER.level=WARNING
-#
-#trigger:
-# branch:
-# - master
-# - stable*
-# event:
-# - pull_request
-# - push
-#
-#---
-#kind: pipeline
-#name: acc-sqlite-room-shares
-#
-#steps:
-# - name: acceptance-room-shares
-# image: nextcloudci/acceptance-php7.1:acceptance-php7.1-2
-# environment:
-# APP_NAME: spreed
-# CORE_BRANCH: master
-# SELENIUM_HOST: selenium
-# TESTS_ACCEPTANCE: room-shares
-# commands:
-# - bash tests/drone-run-acceptance-tests.sh || exit 0
-# # Pre-setup steps
-# - git clone --depth 1 -b $CORE_BRANCH https://github.com/nextcloud/server ../server
-# - cp -R . ../server/apps/$APP_NAME
-# - cd ../server
-# - git submodule update --init
-# - ln --symbolic `pwd` /var/www/html
-#
-# # Run acceptance tests
-# - tests/acceptance/run-local.sh --acceptance-tests-dir apps/spreed/tests/acceptance --timeout-multiplier 10 --nextcloud-server-domain acceptance-$TESTS_ACCEPTANCE --selenium-server $SELENIUM_HOST:4444 allow-git-repository-modifications features/$TESTS_ACCEPTANCE.feature
-#
-#services:
-# - name: cache
-# image: ghcr.io/nextcloud/continuous-integration-redis:latest
-# - name: selenium
-# image: selenium/standalone-firefox:2.53.1-beryllium
-# environment:
-# # Reduce default log level for Selenium server (INFO) as it is too
-# # verbose.
-# JAVA_OPTS: -Dselenium.LOGGER.level=WARNING
-#
-#trigger:
-# branch:
-# - master
-# - stable*
-# event:
-# - pull_request
-# - push
+ - push
diff --git a/package-lock.json b/package-lock.json
index a268da93a..6fb93af03 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -67,7 +67,7 @@
"@nextcloud/stylelint-config": "^2.1.2",
"@nextcloud/webpack-vue-config": "^5.0.0",
"@vue/cli-plugin-unit-jest": "^4.5.15",
- "@vue/cli-service": "^5.0.1",
+ "@vue/cli-service": "^5.0.3",
"@vue/test-utils": "^1.3.0",
"babel-loader-exclude-node-modules-except": "^1.2.1",
"babel-plugin-add-module-exports": "^1.0.4",
@@ -3859,27 +3859,27 @@
"dev": true
},
"node_modules/@vue/cli-overlay": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.1.tgz",
- "integrity": "sha512-8cLpHoQVYHoI4EjUG4+gbuUI9xxhkP5Vz/o/WLAkAAs//+1vE/A5AjCdLeQYGR9X6T4+b/kci2ArIpSSsRi8/Q==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.3.tgz",
+ "integrity": "sha512-LuEcVV8oOYcPnfoB3yBoE1fQ8p23ziFwV+BAXumXiDemIkg7piL5s+tqUgwV8fuOg3bileta+rtKQRNmcAoW6Q==",
"dev": true
},
"node_modules/@vue/cli-plugin-router": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-5.0.1.tgz",
- "integrity": "sha512-Eu56AQUEK0uULgIQotZwi5eijYNBS3+znMc0u/kaI1puW3+f/qP3YCtffp5CeVcG2Kxwrx66XBI6PMHg8hPdmA==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-5.0.3.tgz",
+ "integrity": "sha512-9GPewake2QhmnNe1p72Cejv0jyenH+gv3+3JlZf4kPR68ncqwF7YiUjxbnJnItWgq4Zep3+YqYmQ4PsIWjMPUQ==",
"dev": true,
"dependencies": {
- "@vue/cli-shared-utils": "^5.0.1"
+ "@vue/cli-shared-utils": "^5.0.3"
},
"peerDependencies": {
"@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0"
}
},
"node_modules/@vue/cli-plugin-router/node_modules/@vue/cli-shared-utils": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.1.tgz",
- "integrity": "sha512-oL164c3yDhdLHgiFvSkXuP7z0eEY8gqTYzHHbvQJCIBtRZ/0H9Q7xICpAeMZ63lJvS2+fA5bQfv+kPII/kcjmQ==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.3.tgz",
+ "integrity": "sha512-xAHxFDYVohHWXOLdmGvka3ffQcRgKdACempFQkGJX74Q7OBf0zPf5WH+vQXhlR17eA3LmWdY+Nv8OfsIGim6Fg==",
"dev": true,
"dependencies": {
"chalk": "^4.1.2",
@@ -3888,7 +3888,7 @@
"launch-editor": "^2.2.1",
"lru-cache": "^6.0.0",
"node-fetch": "^2.6.7",
- "node-ipc": "^9.1.1",
+ "node-ipc": "9.2.1",
"open": "^8.0.2",
"ora": "^5.3.0",
"read-pkg": "^5.1.1",
@@ -4179,28 +4179,28 @@
}
},
"node_modules/@vue/cli-plugin-vuex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.1.tgz",
- "integrity": "sha512-5J/n+Ht4r2eVuncwCXcZPHzYCz/2haktle4WcggWiKeg3jSQVUJbjviPBs6sOo3y/LG3CEfZMP9bPJjVDbexpQ==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.3.tgz",
+ "integrity": "sha512-QlrtXH+Z7YyER6r1Iz54yT6WoWyjr2rpFpIAcJP+KbXMvY8J97aupAkXYhw7Lg4zX4O2FhLKztZrjJT2Gx6ZSQ==",
"dev": true,
"peerDependencies": {
"@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0"
}
},
"node_modules/@vue/cli-service": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-5.0.1.tgz",
- "integrity": "sha512-lhTW1d8waZv1VaRSvhE5pWWfkdmAgRTRSluDfyxkehZHMAWi//rd7a9zppN3k9Zr4X3oYVii+u7wR/RcTlr9cQ==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-5.0.3.tgz",
+ "integrity": "sha512-Mj41sc6VlPTwejZK4RTh17H3JLdJwKgeKHEgr17E4Vb6rZiByj29EYbr6lD9eEbbgCp/PwBkY4uPrMstCavcZQ==",
"dev": true,
"dependencies": {
"@babel/helper-compilation-targets": "^7.12.16",
"@soda/friendly-errors-webpack-plugin": "^1.8.0",
"@soda/get-current-script": "^1.0.2",
"@types/minimist": "^1.2.0",
- "@vue/cli-overlay": "^5.0.1",
- "@vue/cli-plugin-router": "^5.0.1",
- "@vue/cli-plugin-vuex": "^5.0.1",
- "@vue/cli-shared-utils": "^5.0.1",
+ "@vue/cli-overlay": "^5.0.3",
+ "@vue/cli-plugin-router": "^5.0.3",
+ "@vue/cli-plugin-vuex": "^5.0.3",
+ "@vue/cli-shared-utils": "^5.0.3",
"@vue/component-compiler-utils": "^3.3.0",
"@vue/vue-loader-v15": "npm:vue-loader@^15.9.7",
"@vue/web-component-wrapper": "^1.3.0",
@@ -4287,9 +4287,9 @@
}
},
"node_modules/@vue/cli-service/node_modules/@vue/cli-shared-utils": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.1.tgz",
- "integrity": "sha512-oL164c3yDhdLHgiFvSkXuP7z0eEY8gqTYzHHbvQJCIBtRZ/0H9Q7xICpAeMZ63lJvS2+fA5bQfv+kPII/kcjmQ==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.3.tgz",
+ "integrity": "sha512-xAHxFDYVohHWXOLdmGvka3ffQcRgKdACempFQkGJX74Q7OBf0zPf5WH+vQXhlR17eA3LmWdY+Nv8OfsIGim6Fg==",
"dev": true,
"dependencies": {
"chalk": "^4.1.2",
@@ -4298,7 +4298,7 @@
"launch-editor": "^2.2.1",
"lru-cache": "^6.0.0",
"node-fetch": "^2.6.7",
- "node-ipc": "^9.1.1",
+ "node-ipc": "9.2.1",
"open": "^8.0.2",
"ora": "^5.3.0",
"read-pkg": "^5.1.1",
@@ -10098,9 +10098,9 @@
"dev": true
},
"node_modules/easy-stack": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz",
- "integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz",
+ "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==",
"dev": true,
"engines": {
"node": ">=6.0.0"
@@ -15175,21 +15175,21 @@
}
},
"node_modules/js-message": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz",
- "integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=",
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz",
+ "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==",
"dev": true,
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/js-queue": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz",
- "integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.2.tgz",
+ "integrity": "sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA==",
"dev": true,
"dependencies": {
- "easy-stack": "^1.0.0"
+ "easy-stack": "^1.0.1"
},
"engines": {
"node": ">=1.0.0"
@@ -16620,17 +16620,17 @@
"dev": true
},
"node_modules/node-ipc": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz",
- "integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==",
+ "version": "9.2.1",
+ "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.2.1.tgz",
+ "integrity": "sha512-mJzaM6O3xHf9VT8BULvJSbdVbmHUKRNOH7zDDkCrA1/T+CVjq2WVIDfLt0azZRXpgArJtl3rtmEozrbXPZ9GaQ==",
"dev": true,
"dependencies": {
"event-pubsub": "4.3.0",
- "js-message": "1.0.5",
- "js-queue": "2.0.0"
+ "js-message": "1.0.7",
+ "js-queue": "2.0.2"
},
"engines": {
- "node": ">=4.0.0"
+ "node": ">=8.0.0"
}
},
"node_modules/node-modules-regexp": {
@@ -27369,24 +27369,24 @@
"dev": true
},
"@vue/cli-overlay": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.1.tgz",
- "integrity": "sha512-8cLpHoQVYHoI4EjUG4+gbuUI9xxhkP5Vz/o/WLAkAAs//+1vE/A5AjCdLeQYGR9X6T4+b/kci2ArIpSSsRi8/Q==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.3.tgz",
+ "integrity": "sha512-LuEcVV8oOYcPnfoB3yBoE1fQ8p23ziFwV+BAXumXiDemIkg7piL5s+tqUgwV8fuOg3bileta+rtKQRNmcAoW6Q==",
"dev": true
},
"@vue/cli-plugin-router": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-5.0.1.tgz",
- "integrity": "sha512-Eu56AQUEK0uULgIQotZwi5eijYNBS3+znMc0u/kaI1puW3+f/qP3YCtffp5CeVcG2Kxwrx66XBI6PMHg8hPdmA==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-5.0.3.tgz",
+ "integrity": "sha512-9GPewake2QhmnNe1p72Cejv0jyenH+gv3+3JlZf4kPR68ncqwF7YiUjxbnJnItWgq4Zep3+YqYmQ4PsIWjMPUQ==",
"dev": true,
"requires": {
- "@vue/cli-shared-utils": "^5.0.1"
+ "@vue/cli-shared-utils": "^5.0.3"
},
"dependencies": {
"@vue/cli-shared-utils": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.1.tgz",
- "integrity": "sha512-oL164c3yDhdLHgiFvSkXuP7z0eEY8gqTYzHHbvQJCIBtRZ/0H9Q7xICpAeMZ63lJvS2+fA5bQfv+kPII/kcjmQ==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.3.tgz",
+ "integrity": "sha512-xAHxFDYVohHWXOLdmGvka3ffQcRgKdACempFQkGJX74Q7OBf0zPf5WH+vQXhlR17eA3LmWdY+Nv8OfsIGim6Fg==",
"dev": true,
"requires": {
"chalk": "^4.1.2",
@@ -27395,7 +27395,7 @@
"launch-editor": "^2.2.1",
"lru-cache": "^6.0.0",
"node-fetch": "^2.6.7",
- "node-ipc": "^9.1.1",
+ "node-ipc": "9.2.1",
"open": "^8.0.2",
"ora": "^5.3.0",
"read-pkg": "^5.1.1",
@@ -27610,26 +27610,26 @@
}
},
"@vue/cli-plugin-vuex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.1.tgz",
- "integrity": "sha512-5J/n+Ht4r2eVuncwCXcZPHzYCz/2haktle4WcggWiKeg3jSQVUJbjviPBs6sOo3y/LG3CEfZMP9bPJjVDbexpQ==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.3.tgz",
+ "integrity": "sha512-QlrtXH+Z7YyER6r1Iz54yT6WoWyjr2rpFpIAcJP+KbXMvY8J97aupAkXYhw7Lg4zX4O2FhLKztZrjJT2Gx6ZSQ==",
"dev": true,
"requires": {}
},
"@vue/cli-service": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-5.0.1.tgz",
- "integrity": "sha512-lhTW1d8waZv1VaRSvhE5pWWfkdmAgRTRSluDfyxkehZHMAWi//rd7a9zppN3k9Zr4X3oYVii+u7wR/RcTlr9cQ==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-5.0.3.tgz",
+ "integrity": "sha512-Mj41sc6VlPTwejZK4RTh17H3JLdJwKgeKHEgr17E4Vb6rZiByj29EYbr6lD9eEbbgCp/PwBkY4uPrMstCavcZQ==",
"dev": true,
"requires": {
"@babel/helper-compilation-targets": "^7.12.16",
"@soda/friendly-errors-webpack-plugin": "^1.8.0",
"@soda/get-current-script": "^1.0.2",
"@types/minimist": "^1.2.0",
- "@vue/cli-overlay": "^5.0.1",
- "@vue/cli-plugin-router": "^5.0.1",
- "@vue/cli-plugin-vuex": "^5.0.1",
- "@vue/cli-shared-utils": "^5.0.1",
+ "@vue/cli-overlay": "^5.0.3",
+ "@vue/cli-plugin-router": "^5.0.3",
+ "@vue/cli-plugin-vuex": "^5.0.3",
+ "@vue/cli-shared-utils": "^5.0.3",
"@vue/component-compiler-utils": "^3.3.0",
"@vue/vue-loader-v15": "npm:vue-loader@^15.9.7",
"@vue/web-component-wrapper": "^1.3.0",
@@ -27680,9 +27680,9 @@
},
"dependencies": {
"@vue/cli-shared-utils": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.1.tgz",
- "integrity": "sha512-oL164c3yDhdLHgiFvSkXuP7z0eEY8gqTYzHHbvQJCIBtRZ/0H9Q7xICpAeMZ63lJvS2+fA5bQfv+kPII/kcjmQ==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.3.tgz",
+ "integrity": "sha512-xAHxFDYVohHWXOLdmGvka3ffQcRgKdACempFQkGJX74Q7OBf0zPf5WH+vQXhlR17eA3LmWdY+Nv8OfsIGim6Fg==",
"dev": true,
"requires": {
"chalk": "^4.1.2",
@@ -27691,7 +27691,7 @@
"launch-editor": "^2.2.1",
"lru-cache": "^6.0.0",
"node-fetch": "^2.6.7",
- "node-ipc": "^9.1.1",
+ "node-ipc": "9.2.1",
"open": "^8.0.2",
"ora": "^5.3.0",
"read-pkg": "^5.1.1",
@@ -32166,9 +32166,9 @@
"dev": true
},
"easy-stack": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz",
- "integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz",
+ "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==",
"dev": true
},
"ecc-jsbn": {
@@ -36153,18 +36153,18 @@
}
},
"js-message": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz",
- "integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=",
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz",
+ "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==",
"dev": true
},
"js-queue": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz",
- "integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.2.tgz",
+ "integrity": "sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA==",
"dev": true,
"requires": {
- "easy-stack": "^1.0.0"
+ "easy-stack": "^1.0.1"
}
},
"js-tokens": {
@@ -37368,14 +37368,14 @@
"dev": true
},
"node-ipc": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz",
- "integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==",
+ "version": "9.2.1",
+ "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.2.1.tgz",
+ "integrity": "sha512-mJzaM6O3xHf9VT8BULvJSbdVbmHUKRNOH7zDDkCrA1/T+CVjq2WVIDfLt0azZRXpgArJtl3rtmEozrbXPZ9GaQ==",
"dev": true,
"requires": {
"event-pubsub": "4.3.0",
- "js-message": "1.0.5",
- "js-queue": "2.0.0"
+ "js-message": "1.0.7",
+ "js-queue": "2.0.2"
}
},
"node-modules-regexp": {
diff --git a/package.json b/package.json
index 533ea9ebf..d20a5fa63 100644
--- a/package.json
+++ b/package.json
@@ -75,7 +75,7 @@
"@nextcloud/stylelint-config": "^2.1.2",
"@nextcloud/webpack-vue-config": "^5.0.0",
"@vue/cli-plugin-unit-jest": "^4.5.15",
- "@vue/cli-service": "^5.0.1",
+ "@vue/cli-service": "^5.0.3",
"@vue/test-utils": "^1.3.0",
"babel-loader-exclude-node-modules-except": "^1.2.1",
"babel-plugin-add-module-exports": "^1.0.4",
diff --git a/src/components/Description/Description.vue b/src/components/Description/Description.vue
index 038b03e89..498b74803 100644
--- a/src/components/Description/Description.vue
+++ b/src/components/Description/Description.vue
@@ -35,21 +35,25 @@
@keydown.esc="handleCancelEditing" />
<template v-if="!loading">
<template v-if="editing">
- <button class="nc-button nc-button__main description__action"
+ <Button type="tertiary"
:aria-label="t('spreed', 'Cancel editing description')"
@click="handleCancelEditing">
- <Close decorative
- title=""
- :size="16" />
- </button>
- <button class="nc-button nc-button__main primary description__action"
+ <template #icon>
+ <Close decorative
+ title=""
+ :size="20" />
+ </template>
+ </Button>
+ <Button type="primary"
:aria-label="t('spreed', 'Submit conversation description')"
:disabled="!canSubmit"
@click="handleSubmitDescription">
- <Check decorative
- title=""
- :size="16" />
- </button>
+ <template #icon>
+ <Check decorative
+ title=""
+ :size="20" />
+ </template>
+ </Button>
<div v-if="showCountDown"
v-tooltip.auto="countDownWarningText"
class="counter"
@@ -58,14 +62,16 @@
<span>{{ charactersCountDown }}</span>
</div>
</template>
- <button v-if="!editing && editable"
- class="nc-button nc-button__main"
+ <Button v-if="!editing && editable"
+ type="tertiary"
:aria-label="t('spreed', 'Edit conversation description')"
@click="handleEditDescription">
- <Pencil decorative
- title=""
- :size="16" />
- </button>
+ <template #icon>
+ <Pencil decorative
+ title=""
+ :size="20" />
+ </template>
+ </Button>
</template>
<div v-if="loading" class="icon-loading-small spinner" />
</div>
@@ -77,6 +83,7 @@ import Check from 'vue-material-design-icons/Check'
import Close from 'vue-material-design-icons/Close'
import RichContentEditable from '@nextcloud/vue/dist/Components/RichContenteditable'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'
+import Button from '@nextcloud/vue/dist/Components/Button'
export default {
name: 'Description',
@@ -85,6 +92,7 @@ export default {
Check,
Close,
RichContentEditable,
+ Button,
},
directives: {
@@ -281,7 +289,6 @@ export default {
&__action {
margin: 0 0 4px 4px;
-
}
}
diff --git a/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue b/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue
index 7d29fedec..cc4c3bcca 100644
--- a/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue
+++ b/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue
@@ -87,6 +87,7 @@
<Button v-if="page===0"
type="primary"
:disabled="disabled"
+ class="navigation__button-right"
@click="handleSetConversationName">
{{ t('spreed', 'Add participants') }}
</Button>
@@ -98,12 +99,14 @@
</Button>
<Button v-if="page===1"
type="primary"
+ class="navigation__button-right"
@click="handleCreateConversation">
{{ t('spreed', 'Create conversation') }}
</Button>
<!-- Third page -->
<Button v-if="page===2 && (error || isPublic)"
type="primary"
+ class="navigation__button-right"
@click="closeModal">
{{ t('spreed', 'Close') }}
</Button>
@@ -406,6 +409,10 @@ it back */
box-shadow: 0 -10px 5px var(--color-main-background);
z-index: 1;
width: 100%;
+
+ &__button-right {
+ margin-left:auto;
+ }
}
.wrapper {
diff --git a/src/components/MessagesList/MessagesGroup/Message/Message.spec.js b/src/components/MessagesList/MessagesGroup/Message/Message.spec.js
index 02017389f..608fe10a8 100644
--- a/src/components/MessagesList/MessagesGroup/Message/Message.spec.js
+++ b/src/components/MessagesList/MessagesGroup/Message/Message.spec.js
@@ -1,21 +1,21 @@
-import Vuex from 'vuex'
-import { createLocalVue, shallowMount } from '@vue/test-utils'
+import Vuex, { Store } from 'vuex'
+import { createLocalVue, mount, shallowMount } from '@vue/test-utils'
import { cloneDeep } from 'lodash'
import { EventBus } from '../../../../services/EventBus'
import storeConfig from '../../../../store/storeConfig'
-import { CONVERSATION, PARTICIPANT, ATTENDEE } from '../../../../constants'
+import { CONVERSATION, ATTENDEE } from '../../../../constants'
import Check from 'vue-material-design-icons/Check'
import CheckAll from 'vue-material-design-icons/CheckAll'
import Quote from '../../../Quote'
-import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
import Mention from './MessagePart/Mention'
import FilePreview from './MessagePart/FilePreview'
import DeckCard from './MessagePart/DeckCard'
import Location from './MessagePart/Location'
import DefaultParameter from './MessagePart/DefaultParameter'
-import { findActionButton } from '../../../../test-helpers'
+import MessageButtonsBar from './MessageButtonsBar/MessageButtonsBar.vue'
import Message from './Message'
+import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
// needed because of https://github.com/vuejs/vue-test-utils/issues/1507
const RichTextStub = {
@@ -75,6 +75,20 @@ describe('Message.vue', () => {
systemMessage: '',
messageType: 'comment',
}
+
+ // Dummy message getter so that the message component is always
+ // properly mounted.
+ testStoreConfig.modules.messagesStore.getters.message
+ = jest.fn().mockReturnValue(() => {
+ return {
+ reactions: '',
+ }
+ })
+
+ // Dummy hasReactions getter so that the message component is always
+ // properly mounted.
+ testStoreConfig.modules.messagesStore.getters.hasReactions
+ = jest.fn().mockReturnValue(() => false)
})
afterEach(() => {
@@ -83,7 +97,7 @@ describe('Message.vue', () => {
describe('message rendering', () => {
beforeEach(() => {
- store = new Vuex.Store(testStoreConfig)
+ store = new Store(testStoreConfig)
})
test('renders rich text message', async () => {
@@ -126,7 +140,7 @@ describe('Message.vue', () => {
message: 'message two',
}]
})
- store = new Vuex.Store(testStoreConfig)
+ store = new Store(testStoreConfig)
})
test('shows join call button on last message when a call is in progress', () => {
@@ -246,12 +260,13 @@ describe('Message.vue', () => {
messageParameters: {},
token: TOKEN,
parentId: -1,
+ reactions: '',
}
messageProps.parent = 120
const messageGetterMock = jest.fn().mockReturnValue(parentMessage)
testStoreConfig.modules.messagesStore.getters.message = jest.fn(() => messageGetterMock)
- store = new Vuex.Store(testStoreConfig)
+ store = new Store(testStoreConfig)
const wrapper = shallowMount(Message, {
localVue,
@@ -482,7 +497,7 @@ describe('Message.vue', () => {
describe('author rendering', () => {
const AUTHOR_SELECTOR = '.message-body__author'
beforeEach(() => {
- store = new Vuex.Store(testStoreConfig)
+ store = new Store(testStoreConfig)
})
test('renders author if first message', async () => {
@@ -511,10 +526,9 @@ describe('Message.vue', () => {
})
describe('actions', () => {
- const ACTIONS_SELECTOR = '.message__buttons-bar'
beforeEach(() => {
- store = new Vuex.Store(testStoreConfig)
+ store = new Store(testStoreConfig)
})
test('does not render actions for system messages are available', async () => {
@@ -528,8 +542,8 @@ describe('Message.vue', () => {
await wrapper.vm.$nextTick()
- const actionsEl = wrapper.find(ACTIONS_SELECTOR)
- expect(actionsEl.exists()).toBe(false)
+ const messageButtonsBar = wrapper.findComponent(MessageButtonsBar)
+ expect(messageButtonsBar.exists()).toBe(false)
})
test('does not render actions for temporary messages', async () => {
@@ -543,13 +557,13 @@ describe('Message.vue', () => {
await wrapper.vm.$nextTick()
- const actionsEl = wrapper.find(ACTIONS_SELECTOR)
- expect(actionsEl.exists()).toBe(false)
+ const messageButtonsBar = wrapper.findComponent(MessageButtonsBar)
+ expect(messageButtonsBar.exists()).toBe(false)
})
test('actions become visible on mouse over', async () => {
messageProps.sendingFailure = 'timeout'
- const wrapper = shallowMount(Message, {
+ const wrapper = mount(Message, {
localVue,
store,
propsData: messageProps,
@@ -557,437 +571,76 @@ describe('Message.vue', () => {
await wrapper.vm.$nextTick()
- const actionsEl = wrapper.find(ACTIONS_SELECTOR)
+ const messageButtonsBar = wrapper.findComponent(MessageButtonsBar)
- expect(wrapper.vm.showActions).toBe(false)
- expect(actionsEl.isVisible()).toBe(false)
+ expect(wrapper.vm.showMessageButtonsBar).toBe(false)
+ expect(messageButtonsBar.isVisible()).toBe(false)
await wrapper.find('.message-body').trigger('mouseover')
- expect(wrapper.vm.showActions).toBe(true)
- expect(actionsEl.isVisible()).toBe(true)
+ expect(wrapper.vm.showMessageButtonsBar).toBe(true)
+ expect(messageButtonsBar.isVisible()).toBe(true)
await wrapper.find('.message-body').trigger('mouseleave')
- expect(wrapper.vm.showActions).toBe(false)
- expect(actionsEl.isVisible()).toBe(false)
+ expect(wrapper.vm.showMessageButtonsBar).toBe(false)
+ expect(messageButtonsBar.isVisible()).toBe(false)
// actions are always present and rendered
const actions = wrapper.findAllComponents({ name: 'Actions' })
expect(actions.length).toBe(2)
})
+ })
- describe('reply action', () => {
- test('replies to message', async () => {
- const replyAction = jest.fn()
- testStoreConfig.modules.quoteReplyStore.actions.addMessageToBeReplied = replyAction
- store = new Vuex.Store(testStoreConfig)
-
- const wrapper = shallowMount(Message, {
- localVue,
- store,
- stubs: {
- ActionButton,
- },
- propsData: messageProps,
- })
-
- await wrapper.find('.message-body').trigger('mouseover')
- const actionButton = findActionButton(wrapper, 'Reply')
- expect(actionButton.exists()).toBe(true)
- expect(actionButton.isVisible()).toBe(true)
- await actionButton.find('button').trigger('click')
-
- expect(replyAction).toHaveBeenCalledWith(expect.anything(), {
- id: 123,
- actorId: 'user-id-1',
- actorType: 'users',
- actorDisplayName: 'user-display-name-1',
- message: 'test message',
- messageParameters: {},
- messageType: 'comment',
- systemMessage: '',
- timestamp: new Date('2020-05-07 09:23:00').getTime() / 1000,
- token: TOKEN,
- })
- })
-
- test('hides reply button when not replyable', async () => {
- messageProps.isReplyable = false
- store = new Vuex.Store(testStoreConfig)
-
- const wrapper = shallowMount(Message, {
- localVue,
- store,
- stubs: {
- ActionButton,
- },
- propsData: messageProps,
- })
-
- const actionButton = findActionButton(wrapper, 'Reply')
- expect(actionButton.isVisible()).toBe(false)
- })
- })
-
- describe('private reply action', () => {
- test('creates a new conversation when replying to message privately', async () => {
- const routerPushMock = jest.fn().mockResolvedValue()
- const createOneToOneConversation = jest.fn()
- testStoreConfig.modules.conversationsStore.actions.createOneToOneConversation = createOneToOneConversation
- store = new Vuex.Store(testStoreConfig)
-
- messageProps.actorId = 'another-user'
-
- const wrapper = shallowMount(Message, {
- localVue,
- store,
- mocks: {
- $router: {
- push: routerPushMock,
- },
- },
- stubs: {
- ActionButton,
- },
- propsData: messageProps,
- })
-
- const actionButton = findActionButton(wrapper, 'Reply privately')
- expect(actionButton.exists()).toBe(true)
-
- createOneToOneConversation.mockResolvedValueOnce({
- token: 'new-token',
- })
-
- await actionButton.find('button').trigger('click')
-
- expect(createOneToOneConversation).toHaveBeenCalledWith(expect.anything(), 'another-user')
-
- expect(routerPushMock).toHaveBeenCalledWith({
- name: 'conversation',
- params: {
- token: 'new-token',
- },
- })
- })
-
- /**
- * @param {boolean} visible Whether or not the reply-private action is visible
- */
- function testPrivateReplyActionVisible(visible) {
- store = new Vuex.Store(testStoreConfig)
-
- const wrapper = shallowMount(Message, {
- localVue,
- store,
- stubs: {
- ActionButton,
- },
- propsData: messageProps,
- })
-
- const actionButton = findActionButton(wrapper, 'Reply privately')
- expect(actionButton.exists()).toBe(visible)
- }
-
- test('hides private reply action for own messages', async () => {
- // using default message props which have the
- // actor id set to the current user
- testPrivateReplyActionVisible(false)
- })
-
- test('hides private reply action for one to one conversation type', async () => {
- messageProps.actorId = 'another-user'
- conversationProps.type = CONVERSATION.TYPE.ONE_TO_ONE
- testPrivateReplyActionVisible(false)
- })
-
- test('hides private reply action for guest messages', async () => {
- messageProps.actorId = 'guest-user'
- messageProps.actorType = ATTENDEE.ACTOR_TYPE.GUESTS
- testPrivateReplyActionVisible(false)
- })
-
- test('hides private reply action when current user is a guest', async () => {
- messageProps.actorId = 'another-user'
- getActorTypeMock.mockClear().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.GUESTS)
- testPrivateReplyActionVisible(false)
- })
- })
-
- describe('delete action', () => {
- test('deletes message', async () => {
- let resolveDeleteMessage
- const deleteMessage = jest.fn().mockReturnValue(new Promise((resolve, reject) => { resolveDeleteMessage = resolve }))
- testStoreConfig.modules.messagesStore.actions.deleteMessage = deleteMessage
- store = new Vuex.Store(testStoreConfig)
-
- // need to mock the date to be within 6h
- const mockDate = new Date('2020-05-07 10:00:00')
- jest.spyOn(global.Date, 'now')
- .mockImplementation(() => mockDate)
-
- const wrapper = shallowMount(Message, {
- localVue,
- store,
- stubs: {
- ActionButton,
- },
- propsData: messageProps,
- })
-
- const actionButton = findActionButton(wrapper, 'Delete')
- expect(actionButton.exists()).toBe(true)
-
- await actionButton.find('button').trigger('click')
-
- expect(deleteMessage).toHaveBeenCalledWith(expect.anything(), {
- message: {
- token: TOKEN,
- id: 123,
- },
- placeholder: expect.anything(),
- })
-
- await wrapper.vm.$nextTick()
- expect(wrapper.vm.isDeleting).toBe(true)
- expect(wrapper.find('.icon-loading-small').exists()).toBe(true)
-
- resolveDeleteMessage(200)
- // needs two updates...
- await wrapper.vm.$nextTick()
- await wrapper.vm.$nextTick()
-
- expect(wrapper.vm.isDeleting).toBe(false)
- expect(wrapper.find('.icon-loading-small').exists()).toBe(false)
- })
-
- /**
- * @param {boolean} visible Whether or not the delete action is visible
- * @param {Date} mockDate The message date (deletion only works within 6h)
- * @param {number} participantType The participant type of the user
- */
- function testDeleteMessageVisible(visible, mockDate, participantType = PARTICIPANT.TYPE.USER) {
- store = new Vuex.Store(testStoreConfig)
-
- // need to mock the date to be within 6h
- if (!mockDate) {
- mockDate = new Date('2020-05-07 10:00:00')
- }
-
- jest.spyOn(global.Date, 'now')
- .mockImplementation(() => mockDate)
-
- const wrapper = shallowMount(Message, {
- localVue,
- store,
- stubs: {
- ActionButton,
- },
- mixins: [{
- computed: {
- participant: () => {
- return {
- actorId: 'user-id-1',
- actorType: ATTENDEE.ACTOR_TYPE.USERS,
- participantType,
- }
- },
- },
- }],
- propsData: messageProps,
- })
-
- const actionButton = findActionButton(wrapper, 'Delete')
- expect(actionButton.exists()).toBe(visible)
- }
-
- test('hides delete action when message is older than 6 hours', () => {
- testDeleteMessageVisible(false, new Date('2020-05-07 15:24:00'))
- })
-
- test('hides delete action when the conversation is read-only', () => {
- conversationProps.readOnly = CONVERSATION.STATE.READ_ONLY
- testDeleteMessageVisible(false)
- })
-
- test('hides delete action for file messages', () => {
- messageProps.message = '{file}'
- messageProps.messageParameters.file = {}
- testDeleteMessageVisible(false)
- })
-
- test('hides delete action on other people messages for non-moderators', () => {
- messageProps.actorId = 'another-user'
- conversationProps.type = CONVERSATION.TYPE.GROUP
- testDeleteMessageVisible(false)
- })
-
- test('shows delete action on other people messages for moderators', () => {
- messageProps.actorId = 'another-user'
- conversationProps.type = CONVERSATION.TYPE.GROUP
- testDeleteMessageVisible(true, null, PARTICIPANT.TYPE.MODERATOR)
- })
-
- test('shows delete action on other people messages for owner', () => {
- messageProps.actorId = 'another-user'
- conversationProps.type = CONVERSATION.TYPE.PUBLIC
- testDeleteMessageVisible(true, null, PARTICIPANT.TYPE.OWNER)
- })
-
- test('does not show delete action even for guest moderators', () => {
- messageProps.actorId = 'another-user'
- conversationProps.type = CONVERSATION.TYPE.PUBLIC
- testDeleteMessageVisible(false, null, PARTICIPANT.TYPE.GUEST_MODERATOR)
- })
-
- test('does not show delete action on other people messages in one to one conversations', () => {
- messageProps.actorId = 'another-user'
- conversationProps.type = CONVERSATION.TYPE.ONE_TO_ONE
- testDeleteMessageVisible(false)
- })
- })
-
- test('marks message as unread', async () => {
- const updateLastReadMessageAction = jest.fn().mockResolvedValueOnce()
- const fetchConversationAction = jest.fn().mockResolvedValueOnce()
- testStoreConfig.modules.conversationsStore.actions.updateLastReadMessage = updateLastReadMessageAction
- testStoreConfig.modules.conversationsStore.actions.fetchConversation = fetchConversationAction
- store = new Vuex.Store(testStoreConfig)
-
- messageProps.previousMessageId = 100
-
- // appears even with more restrictive conditions
- conversationProps.readOnly = CONVERSATION.STATE.READ_ONLY
- messageProps.actorId = 'another-user'
-
- const wrapper = shallowMount(Message, {
- localVue,
- store,
- stubs: {
- ActionButton,
- },
- mixins: [{
- computed: {
- participant: () => {
- return {
- actorId: 'guest-id-1',
- actorType: ATTENDEE.ACTOR_TYPE.GUESTS,
- participantType: PARTICIPANT.TYPE.GUEST,
- }
- },
- },
- }],
- propsData: messageProps,
- })
-
- const actionButton = findActionButton(wrapper, 'Mark as unread')
- expect(actionButton.exists()).toBe(true)
-
- await actionButton.find('button').trigger('click')
- // needs two updates...
- await wrapper.vm.$nextTick()
- await wrapper.vm.$nextTick()
-
- expect(updateLastReadMessageAction).toHaveBeenCalledWith(expect.anything(), {
- token: TOKEN,
- id: 100,
- updateVisually: true,
- })
-
- expect(fetchConversationAction).toHaveBeenCalledWith(expect.anything(), {
- token: TOKEN,
- })
- })
-
- test('copies message link', async () => {
- const copyTextMock = jest.fn()
+ describe('delete action', () => {
+ test('deletes message', async () => {
+ let resolveDeleteMessage
+ const deleteMessage = jest.fn().mockReturnValue(new Promise((resolve, reject) => { resolveDeleteMessage = resolve }))
+ testStoreConfig.modules.messagesStore.actions.deleteMessage = deleteMessage
+ store = new Store(testStoreConfig)
- // appears even with more restrictive conditions
- conversationProps.readOnly = CONVERSATION.STATE.READ_ONLY
- messageProps.actorId = 'another-user'
+ // need to mock the date to be within 6h
+ const mockDate = new Date('2020-05-07 10:00:00')
+ jest.spyOn(global.Date, 'now')
+ .mockImplementation(() => mockDate)
- const wrapper = shallowMount(Message, {
+ const wrapper = mount(Message, {
localVue,
store,
- mocks: {
- $copyText: copyTextMock,
- },
stubs: {
ActionButton,
+ MessageButtonsBar,
},
- mixins: [{
- computed: {
- participant: () => {
- return {
- actorId: 'guest-id-1',
- actorType: ATTENDEE.ACTOR_TYPE.GUESTS,
- participantType: PARTICIPANT.TYPE.GUEST,
- }
- },
- },
- }],
propsData: messageProps,
})
- const actionButton = findActionButton(wrapper, 'Copy message link')
- expect(actionButton.exists()).toBe(true)
-
- await actionButton.find('button').trigger('click')
+ wrapper.find(MessageButtonsBar).vm.$emit('delete')
- expect(copyTextMock).toHaveBeenCalledWith('http://localhost/nc-webroot/call/XXTOKENXX#message_123')
- })
-
- test('renders clickable custom actions', async () => {
- const handler = jest.fn()
- const handler2 = jest.fn()
- const actionsGetterMock = jest.fn().mockReturnValue([{
- label: 'first action',
- icon: 'some-icon',
- callback: handler,
- }, {
- label: 'second action',
- icon: 'some-icon2',
- callback: handler2,
- }])
- testStoreConfig.modules.messageActionsStore.getters.messageActions = actionsGetterMock
- testStoreConfig.modules.messagesStore.getters.message = jest.fn(() => () => messageProps)
- store = new Vuex.Store(testStoreConfig)
- const wrapper = shallowMount(Message, {
- localVue,
- store,
- stubs: {
- ActionButton,
+ expect(deleteMessage).toHaveBeenCalledWith(expect.anything(), {
+ message: {
+ token: TOKEN,
+ id: 123,
},
- propsData: messageProps,
+ placeholder: expect.anything(),
})
- const actionButton = findActionButton(wrapper, 'first action')
- expect(actionButton.exists()).toBe(true)
- await actionButton.find('button').trigger('click')
-
- expect(handler).toHaveBeenCalledWith({
- apiVersion: 'v3',
- message: messageProps,
- metadata: conversationProps,
- })
+ await wrapper.vm.$nextTick()
+ expect(wrapper.vm.isDeleting).toBe(true)
+ expect(wrapper.find('.icon-loading-small').exists()).toBe(true)
- const actionButton2 = findActionButton(wrapper, 'second action')
- expect(actionButton2.exists()).toBe(true)
- await actionButton2.find('button').trigger('click')
+ resolveDeleteMessage(200)
+ // needs two updates...
+ await wrapper.vm.$nextTick()
+ await wrapper.vm.$nextTick()
- expect(handler2).toHaveBeenCalledWith({
- apiVersion: 'v3',
- message: messageProps,
- metadata: conversationProps,
- })
+ expect(wrapper.vm.isDeleting).toBe(false)
+ expect(wrapper.find('.icon-loading-small').exists()).toBe(false)
})
})
describe('status', () => {
beforeEach(() => {
- store = new Vuex.Store(testStoreConfig)
+ store = new Store(testStoreConfig)
})
test('lets user retry sending a timed out message', async () => {
diff --git a/src/components/MessagesList/MessagesGroup/Message/Message.vue b/src/components/MessagesList/MessagesGroup/Message/Message.vue
index 280b231e3..8cbe9650f 100644
--- a/src/components/MessagesList/MessagesGroup/Message/Message.vue
+++ b/src/components/MessagesList/MessagesGroup/Message/Message.vue
@@ -67,6 +67,7 @@ the main body of the message as well as a quote.
class="date"
:style="{'visibility': hasDate ? 'visible' : 'hidden'}"
:class="{'date--self': showSentIcon}">{{ messageTime }}</span>
+
<!-- Message delivery status indicators -->
<div v-if="sendingFailure"
v-tooltip.auto="sendingErrorIconTooltip"
@@ -78,13 +79,13 @@ the main body of the message as well as a quote.
@focus="showReloadButton = true"
@mouseleave="showReloadButton = true"
@blur="showReloadButton = true">
- <button v-if="sendingErrorCanRetry && showReloadButton"
+ <Button v-if="sendingErrorCanRetry && showReloadButton"
class="nc-button nc-button__main--dark"
@click="handleRetry">
<Reload decorative
title=""
:size="16" />
- </button>
+ </Button>
<AlertCircle v-else
decorative
title=""
@@ -112,90 +113,58 @@ the main body of the message as well as a quote.
</div>
</div>
</div>
- <!-- Message Actions -->
- <div v-if="hasActions"
- v-show="showActions"
- class="message__buttons-bar">
- <Actions v-show="isReplyable">
- <ActionButton icon="icon-reply"
- @click.stop="handleReply">
- {{ t('spreed', 'Reply') }}
- </ActionButton>
- </Actions>
- <Actions :force-menu="true"
- :container="container"
- :boundaries-element="containerElement">
- <ActionButton v-if="isPrivateReplyable"
- icon="icon-user"
- :close-after-click="true"
- @click.stop="handlePrivateReply">
- {{ t('spreed', 'Reply privately') }}
- </ActionButton>
- <ActionButton icon="icon-external"
- :close-after-click="true"
- @click.stop.prevent="handleCopyMessageLink">
- {{ t('spreed', 'Copy message link') }}
- </ActionButton>
- <ActionButton :close-after-click="true"
- @click.stop="handleMarkAsUnread">
- <template #icon>
- <EyeOffOutline decorative
- title=""
- :size="16" />
- </template>
- {{ t('spreed', 'Mark as unread') }}
- </ActionButton>
- <ActionLink v-if="linkToFile"
- icon="icon-text"
- :href="linkToFile">
- {{ t('spreed', 'Go to file') }}
- </ActionLink>
- <ActionButton v-if="!isCurrentGuest && !isFileShare"
- :close-after-click="true"
- @click.stop="showForwarder = true">
- <Share slot="icon"
- :size="16"
- decorative
- title="" />
- {{ t('spreed', 'Forward message') }}
- </ActionButton>
- <ActionSeparator v-if="messageActions.length > 0" />
- <template v-for="action in messageActions">
- <ActionButton :key="action.label"
- :icon="action.icon"
- :close-after-click="true"
- @click="action.callback(messageAPIData)">
- {{ action.label }}
- </ActionButton>
- </template>
- <template v-if="isDeleteable">
- <ActionSeparator />
- <ActionButton icon="icon-delete"
- :close-after-click="true"
- @click.stop="handleDelete">
- {{ t('spreed', 'Delete') }}
- </ActionButton>
- </template>
- </Actions>
+
+ <!-- reactions buttons and popover with details -->
+ <div v-if="hasReactions"
+ class="message-body__reactions"
+ @mouseover="handleReactionsMouseOver">
+ <Popover v-for="reaction in Object.keys(simpleReactions)"
+ :key="reaction"
+ :delay="200"
+ trigger="hover">
+ <button v-if="simpleReactions[reaction]!== 0"
+ slot="trigger"
+ class="reaction-button"
+ @click="handleReactionClick(reaction)">
+ <span class="reaction-button__emoji"> {{ reaction }} </span>
+ <span> {{ simpleReactions[reaction] }} </span>
+ </button>
+ <div v-if="detailedReactions" class="reaction-details">
+ <p v-for="detailedReaction in detailedReactions[reaction]" :key="detailedReaction.actorDisplayName">
+ {{ detailedReaction.actorDisplayName }}
+ </p>
+ </div>
+ </Popover>
+
+ <!-- More reactions picker -->
+ <EmojiPicker :per-line="5" @select="addReactionToMessage">
+ <button class="reaction-button">
+ <EmoticonOutline :size="15" />
+ </button>
+ </EmojiPicker>
</div>
</div>
+
+ <!-- Message actions -->
+ <MessageButtonsBar v-if="hasMessageButtonsBar"
+ v-show="showMessageButtonsBar"
+ ref="messageButtonsBar"
+ :message-api-data="messageApiData"
+ :message-object="messageObject"
+ v-bind="$props"
+ :previous-message-id="previousMessageId"
+ :participant="participant"
+ @delete="handleDelete" />
<div v-if="isLastReadMessage"
v-observe-visibility="lastReadMessageVisibilityChanged">
<div class="new-message-marker">
<span>{{ t('spreed', 'Unread messages') }}</span>
</div>
</div>
- <Forwarder v-if="showForwarder"
- :message-object="messageObject"
- @close="showForwarder = false" />
</li>
</template>
<script>
-import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
-import ActionLink from '@nextcloud/vue/dist/Components/ActionLink'
-import Actions from '@nextcloud/vue/dist/Components/Actions'
-import ActionSeparator from '@nextcloud/vue/dist/Components/ActionSeparator'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'
import CallButton from '../../../TopBar/CallButton'
import DeckCard from './MessagePart/DeckCard'
@@ -206,26 +175,20 @@ import RichText from '@juliushaertl/vue-richtext'
import AlertCircle from 'vue-material-design-icons/AlertCircle'
import Check from 'vue-material-design-icons/Check'
import CheckAll from 'vue-material-design-icons/CheckAll'
-import EyeOffOutline from 'vue-material-design-icons/EyeOffOutline'
import Reload from 'vue-material-design-icons/Reload'
-import Share from 'vue-material-design-icons/Share'
import Quote from '../../../Quote'
import isInCall from '../../../../mixins/isInCall'
import participant from '../../../../mixins/participant'
import { EventBus } from '../../../../services/EventBus'
import emojiRegex from 'emoji-regex'
-import { PARTICIPANT, CONVERSATION, ATTENDEE } from '../../../../constants'
import moment from '@nextcloud/moment'
-import {
- showError,
- showSuccess,
- showWarning,
- TOAST_DEFAULT_TIMEOUT,
-} from '@nextcloud/dialogs'
-import { generateUrl } from '@nextcloud/router'
import Location from './MessagePart/Location'
import Contact from './MessagePart/Contact.vue'
-import Forwarder from './MessagePart/Forwarder'
+import MessageButtonsBar from './MessageButtonsBar/MessageButtonsBar.vue'
+import EmojiPicker from '@nextcloud/vue/dist/Components/EmojiPicker'
+import EmoticonOutline from 'vue-material-design-icons/EmoticonOutline.vue'
+import Popover from '@nextcloud/vue/dist/Components/Popover'
+import { showError, showSuccess, showWarning, TOAST_DEFAULT_TIMEOUT } from '@nextcloud/dialogs'
export default {
name: 'Message',
@@ -235,20 +198,17 @@ export default {
},
components: {
- Actions,
- ActionButton,
- ActionLink,
CallButton,
Quote,
RichText,
AlertCircle,
Check,
CheckAll,
- EyeOffOutline,
Reload,
- Share,
- ActionSeparator,
- Forwarder,
+ MessageButtonsBar,
+ EmojiPicker,
+ EmoticonOutline,
+ Popover,
},
mixins: [
@@ -388,16 +348,15 @@ export default {
data() {
return {
- showActions: false,
+ showMessageButtonsBar: false,
// Is tall enough for both actions and date upon hovering
isTallEnough: false,
showReloadButton: false,
isDeleting: false,
// whether the message was seen, only used if this was marked as last read message
seen: false,
- // Shows/hides the message forwarder component
- showForwarder: false,
isActionMenuOpen: false,
+ detailedReactionsRequested: false,
}
},
@@ -418,10 +377,6 @@ export default {
return this.$store.getters.message(this.token, this.id)
},
- isConversationReadOnly() {
- return this.conversation.readOnly === CONVERSATION.STATE.READ_ONLY
- },
-
isSystemMessage() {
return this.systemMessage !== ''
},
@@ -547,21 +502,13 @@ export default {
return false
}
- return this.isSystemMessage || !this.showActions || this.isTallEnough
+ return this.isSystemMessage || !this.showMessageButtonsBar || this.isTallEnough
},
- hasActions() {
+ hasMessageButtonsBar() {
return !this.isSystemMessage && !this.isTemporary
},
- container() {
- return this.$store.getters.getMainContainerSelector()
- },
-
- containerElement() {
- return document.querySelector(this.container)
- },
-
isTemporaryUpload() {
return this.isTemporary && this.messageParameters.file
},
@@ -595,55 +542,11 @@ export default {
return t('spreed', 'You cannot send messages to this conversation at the moment')
},
- isMyMsg() {
- return this.actorId === this.$store.getters.getActorId()
- && this.actorType === this.$store.getters.getActorType()
- },
-
- isFileShare() {
- return this.message === '{file}' && this.messageParameters?.file
- },
-
- linkToFile() {
- if (this.isFileShare) {
- return this.messageParameters?.file?.link
- }
- return ''
- },
-
- isDeleteable() {
- if (this.isConversationReadOnly) {
- return false
- }
-
- const isObjectShare = this.message === '{object}'
- && this.messageParameters?.object
-
- return (moment(this.timestamp * 1000).add(6, 'h')) > moment()
- && this.messageType === 'comment'
- && !this.isDeleting
- && !this.isFileShare
- && !isObjectShare
- && (this.isMyMsg
- || (this.conversation.type !== CONVERSATION.TYPE.ONE_TO_ONE
- && (this.participant.participantType === PARTICIPANT.TYPE.OWNER
- || this.participant.participantType === PARTICIPANT.TYPE.MODERATOR)))
- },
-
- isPrivateReplyable() {
- return this.isReplyable
- && (this.conversation.type === CONVERSATION.TYPE.PUBLIC
- || this.conversation.type === CONVERSATION.TYPE.GROUP)
- && !this.isMyMsg
- && this.actorType === ATTENDEE.ACTOR_TYPE.USERS
- && this.$store.getters.getActorType() === ATTENDEE.ACTOR_TYPE.USERS
- },
-
messageActions() {
return this.$store.getters.messageActions
},
- messageAPIData() {
+ messageApiData() {
return {
message: this.messageObject,
metadata: this.conversation,
@@ -651,8 +554,16 @@ export default {
}
},
- isCurrentGuest() {
- return this.$store.getters.getActorType() === 'guests'
+ hasReactions() {
+ return this.$store.getters.hasReactions(this.token, this.id)
+ },
+
+ simpleReactions() {
+ return this.messageObject.reactions
+ },
+
+ detailedReactions() {
+ return this.$store.getters.reactions(this.token, this.id)
},
},
@@ -696,27 +607,74 @@ export default {
// again another time
this.$refs.message.classList.remove('highlight-animation')
},
+
handleRetry() {
if (this.sendingErrorCanRetry) {
EventBus.$emit('retry-message', this.id)
EventBus.$emit('focus-chat-input')
}
},
- handleReply() {
- this.$store.dispatch('addMessageToBeReplied', {
- id: this.id,
- actorId: this.actorId,
- actorType: this.actorType,
- actorDisplayName: this.actorDisplayName,
- timestamp: this.timestamp,
- systemMessage: this.systemMessage,
- messageType: this.messageType,
- message: this.message,
- messageParameters: this.messageParameters,
- token: this.token,
- })
- EventBus.$emit('focus-chat-input')
+
+ handleMouseover() {
+ this.showMessageButtonsBar = true
+
+ },
+
+ handleReactionsMouseOver() {
+ if (this.hasReactions && !this.detailedReactionsRequested) {
+ this.getReactions()
+ }
+ },
+
+ handleMouseleave() {
+ if (!this.isActionMenuOpen) {
+ this.showMessageButtonsBar = false
+ }
+ },
+
+ async getReactions() {
+ try {
+ /**
+ * Get reaction details when the message is hovered for the first
+ * time. After that we rely on system messages to update the
+ * reactions.
+ */
+ this.detailedReactionsRequested = true
+ await this.$store.dispatch('getReactions', {
+ token: this.token,
+ messageId: this.id,
+ })
+ } catch {
+ this.detailedReactionsRequested = false
+ }
+ },
+
+ async handleReactionClick(clickedEmoji) {
+ if (!this.detailedReactionsRequested) {
+ await this.getReactions()
+ }
+ // Check if current user has already added this reaction to the message
+ const currentUserHasReacted = this.$store.getters.userHasReacted(this.actorId, this.token, this.id, clickedEmoji)
+
+ if (!currentUserHasReacted) {
+ console.debug('adding reaction')
+ this.$store.dispatch('addReactionToMessage', {
+ token: this.token,
+ messageId: this.id,
+ selectedEmoji: clickedEmoji,
+ actorId: this.actorId,
+ })
+ } else {
+ console.debug('user has already reacted, removing reaction')
+ this.$store.dispatch('removeReactionFromMessage', {
+ token: this.token,
+ messageId: this.id,
+ selectedEmoji: clickedEmoji,
+ actorId: this.actorId,
+ })
+ }
},
+
async handleDelete() {
this.isDeleting = true
try {
@@ -751,50 +709,19 @@ export default {
this.isDeleting = false
},
- handleMouseover() {
- this.showActions = true
- },
-
- handleMouseleave() {
- if (!this.isActionMenuOpen) {
- this.showActions = false
- }
- },
- handleActionMenuUpdate(type) {
- if (type === 'open') {
- this.isActionMenuOpen = true
- } else if (type === 'close') {
- this.isActionMenuOpen = false
- this.showActions = false
- }
- },
- async handlePrivateReply() {
- // open the 1:1 conversation
- const conversation = await this.$store.dispatch('createOneToOneConversation', this.actorId)
- this.$router.push({ name: 'conversation', params: { token: conversation.token } }).catch(err => console.debug(`Error while pushing the new conversation's route: ${err}`))
- },
-
- async handleCopyMessageLink() {
- try {
- const link = window.location.protocol + '//' + window.location.host + generateUrl('/call/' + this.token) + '#message_' + this.id
- await this.$copyText(link)
- showSuccess(t('spreed', 'Message link copied to clipboard.'))
- } catch (error) {
- console.error('Error copying link: ', error)
- showError(t('spreed', 'The link could not be copied.'))
+ addReactionToMessage(selectedEmoji) {
+ // Add reaction only if user hasn't reacted yet
+ if (!this.$store.getters.userHasReacted(this.actorId, this.token, this.messageObject.id, selectedEmoji)) {
+ this.$store.dispatch('addReactionToMessage', {
+ token: this.token,
+ messageId: this.messageObject.id,
+ selectedEmoji,
+ actorId: this.actorId,
+ })
+ } else {
+ console.debug('Current user has already reacted')
}
- },
-
- async handleMarkAsUnread() {
- // update in backend + visually
- await this.$store.dispatch('updateLastReadMessage', {
- token: this.token,
- id: this.previousMessageId,
- updateVisually: true,
- })
- // reload conversation to update additional attributes that have computed values
- await this.$store.dispatch('fetchConversation', { token: this.token })
},
},
}
@@ -811,6 +738,10 @@ export default {
}
}
+.message {
+ position: relative;
+}
+
.message-body {
padding: 4px;
font-size: $chat-font-size;
@@ -874,6 +805,10 @@ export default {
padding: 0 8px 0 8px;
}
}
+ &__reactions {
+ display: flex;
+ margin: 4px 0 4px -2px;
+ }
}
.date {
@@ -939,18 +874,26 @@ export default {
}
}
-.message__buttons-bar {
- display: flex;
- right: 14px;
- bottom: -4px;
- position: absolute;
- z-index: 100000;
+.reaction-button {
+ // Clear server rules
+ min-height: 0 !important;
+ padding: 0 8px !important;
+ font-weight: normal !important;
+
+ margin: 0 2px;
+ height: 26px;
background-color: var(--color-main-background);
- border-radius: calc($clickable-area / 2);
- box-shadow: 0 0 4px 0px var(--color-box-shadow);
- & h6 {
- margin-left: auto;
+ &__emoji {
+ margin: 0 4px 0 0;
}
+
+ &:hover {
+ background-color: var(--color-primary-element-lighter);
+ }
+}
+
+.reaction-details {
+ padding: 8px;
}
</style>
diff --git a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.spec.js b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.spec.js
new file mode 100644
index 000000000..78d91b6ec
--- /dev/null
+++ b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.spec.js
@@ -0,0 +1,437 @@
+import Vuex, { Store } from 'vuex'
+import { createLocalVue, shallowMount } from '@vue/test-utils'
+import { cloneDeep } from 'lodash'
+import storeConfig from '../../../../../store/storeConfig'
+import { CONVERSATION, PARTICIPANT, ATTENDEE } from '../../../../../constants'
+import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
+import { findActionButton } from '../../../../../test-helpers'
+import MessageButtonsBar from './../MessageButtonsBar/MessageButtonsBar.vue'
+
+describe('MessageButtonsBar.vue', () => {
+ const TOKEN = 'XXTOKENXX'
+ let localVue
+ let testStoreConfig
+ let store
+ let messageProps
+ let conversationProps
+ let getActorTypeMock
+
+ beforeEach(() => {
+ localVue = createLocalVue()
+ localVue.use(Vuex)
+
+ conversationProps = {
+ token: TOKEN,
+ lastCommonReadMessage: 0,
+ type: CONVERSATION.TYPE.GROUP,
+ readOnly: CONVERSATION.STATE.READ_WRITE,
+ }
+
+ testStoreConfig = cloneDeep(storeConfig)
+ testStoreConfig.modules.tokenStore.getters.getToken
+ = jest.fn().mockReturnValue(() => TOKEN)
+ testStoreConfig.modules.conversationsStore.getters.conversation
+ = jest.fn().mockReturnValue((token) => conversationProps)
+ testStoreConfig.modules.actorStore.getters.getActorId
+ = jest.fn().mockReturnValue(() => 'user-id-1')
+ getActorTypeMock = jest.fn().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.USERS)
+ testStoreConfig.modules.actorStore.getters.getActorType = getActorTypeMock
+
+ messageProps = {
+ message: 'test message',
+ actorType: ATTENDEE.ACTOR_TYPE.USERS,
+ actorId: 'user-id-1',
+ actorDisplayName: 'user-display-name-1',
+ messageParameters: {},
+ id: 123,
+ isTemporary: false,
+ isFirstMessage: true,
+ isReplyable: true,
+ timestamp: new Date('2020-05-07 09:23:00').getTime() / 1000,
+ token: TOKEN,
+ systemMessage: '',
+ messageType: 'comment',
+ previousMessageId: 100,
+ messageObject: {},
+ messageApiData: {
+ apiDummyData: 1,
+ },
+ participant: {
+ actorId: 'user-id-1',
+ actorType: ATTENDEE.ACTOR_TYPE.USERS,
+ participantType: PARTICIPANT.TYPE.USER,
+ },
+ }
+ })
+
+ afterEach(() => {
+ jest.clearAllMocks()
+ })
+
+ describe('actions', () => {
+
+ beforeEach(() => {
+ store = new Store(testStoreConfig)
+ })
+
+ describe('reply action', () => {
+ test('replies to message', async () => {
+ const replyAction = jest.fn()
+ testStoreConfig.modules.quoteReplyStore.actions.addMessageToBeReplied = replyAction
+ store = new Store(testStoreConfig)
+
+ const wrapper = shallowMount(MessageButtonsBar, {
+ localVue,
+ store,
+ stubs: {
+ ActionButton,
+ },
+ propsData: messageProps,
+ })
+
+ const actionButton = findActionButton(wrapper, 'Reply')
+ expect(actionButton.exists()).toBe(true)
+ expect(actionButton.isVisible()).toBe(true)
+ await actionButton.find('button').trigger('click')
+
+ expect(replyAction).toHaveBeenCalledWith(expect.anything(), {
+ id: 123,
+ actorId: 'user-id-1',
+ actorType: 'users',
+ actorDisplayName: 'user-display-name-1',
+ message: 'test message',
+ messageParameters: {},
+ messageType: 'comment',
+ systemMessage: '',
+ timestamp: new Date('2020-05-07 09:23:00').getTime() / 1000,
+ token: TOKEN,
+ previousMessageId: 100,
+ })
+ })
+
+ test('hides reply button when not replyable', async () => {
+ messageProps.isReplyable = false
+ store = new Store(testStoreConfig)
+
+ const wrapper = shallowMount(MessageButtonsBar, {
+ localVue,
+ store,
+ stubs: {
+ ActionButton,
+ },
+ propsData: messageProps,
+ })
+
+ const actionButton = findActionButton(wrapper, 'Reply')
+ expect(actionButton.isVisible()).toBe(false)
+ })
+ })
+
+ describe('private reply action', () => {
+ test('creates a new conversation when replying to message privately', async () => {
+ const routerPushMock = jest.fn().mockResolvedValue()
+ const createOneToOneConversation = jest.fn()
+ testStoreConfig.modules.conversationsStore.actions.createOneToOneConversation = createOneToOneConversation
+ store = new Store(testStoreConfig)
+
+ messageProps.actorId = 'another-user'
+
+ const wrapper = shallowMount(MessageButtonsBar, {
+ localVue,
+ store,
+ mocks: {
+ $router: {
+ push: routerPushMock,
+ },
+ },
+ stubs: {
+ ActionButton,
+ },
+ propsData: messageProps,
+ })
+
+ const actionButton = findActionButton(wrapper, 'Reply privately')
+ expect(actionButton.exists()).toBe(true)
+
+ createOneToOneConversation.mockResolvedValueOnce({
+ token: 'new-token',
+ })
+
+ await actionButton.find('button').trigger('click')
+
+ expect(createOneToOneConversation).toHaveBeenCalledWith(expect.anything(), 'another-user')
+
+ expect(routerPushMock).toHaveBeenCalledWith({
+ name: 'conversation',
+ params: {
+ token: 'new-token',
+ },
+ })
+ })
+
+ /**
+ * @param {boolean} visible Whether or not the reply-private action is visible
+ */
+ function testPrivateReplyActionVisible(visible) {
+ store = new Store(testStoreConfig)
+
+ const wrapper = shallowMount(MessageButtonsBar, {
+ localVue,
+ store,
+ stubs: {
+ ActionButton,
+ },
+ propsData: messageProps,
+ })
+
+ const actionButton = findActionButton(wrapper, 'Reply privately')
+ expect(actionButton.exists()).toBe(visible)
+ }
+
+ test('hides private reply action for own messages', async () => {
+ // using default message props which have the
+ // actor id set to the current user
+ testPrivateReplyActionVisible(false)
+ })
+
+ test('hides private reply action for one to one conversation type', async () => {
+ messageProps.actorId = 'another-user'
+ conversationProps.type = CONVERSATION.TYPE.ONE_TO_ONE
+ testPrivateReplyActionVisible(false)
+ })
+
+ test('hides private reply action for guest messages', async () => {
+ messageProps.actorId = 'guest-user'
+ messageProps.actorType = ATTENDEE.ACTOR_TYPE.GUESTS
+ testPrivateReplyActionVisible(false)
+ })
+
+ test('hides private reply action when current user is a guest', async () => {
+ messageProps.actorId = 'another-user'
+ getActorTypeMock.mockClear().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.GUESTS)
+ testPrivateReplyActionVisible(false)
+ })
+ })
+
+ describe('delete action', () => {
+ test('emits delete event', async () => {
+ // need to mock the date to be within 6h
+ const mockDate = new Date('2020-05-07 10:00:00')
+ jest.spyOn(global.Date, 'now')
+ .mockImplementation(() => mockDate)
+ const wrapper = shallowMount(MessageButtonsBar, {
+ localVue,
+ store,
+ stubs: {
+ ActionButton,
+ },
+ propsData: messageProps,
+ })
+
+ const actionButton = findActionButton(wrapper, 'Delete')
+ expect(actionButton.exists()).toBe(true)
+
+ await actionButton.find('button').trigger('click')
+
+ expect(wrapper.emitted().delete).toBeTruthy()
+ })
+
+ /**
+ * @param {boolean} visible Whether or not the delete action is visible
+ * @param {Date} mockDate The message date (deletion only works within 6h)
+ * @param {number} participantType The participant type of the user
+ */
+ function testDeleteMessageVisible(visible, mockDate, participantType = PARTICIPANT.TYPE.USER) {
+ store = new Store(testStoreConfig)
+
+ // need to mock the date to be within 6h
+ if (!mockDate) {
+ mockDate = new Date('2020-05-07 10:00:00')
+ }
+
+ jest.spyOn(global.Date, 'now')
+ .mockImplementation(() => mockDate)
+
+ messageProps.participant.participantType = participantType
+
+ const wrapper = shallowMount(MessageButtonsBar, {
+ localVue,
+ store,
+ stubs: {
+ ActionButton,
+ },
+ propsData: messageProps,
+ })
+
+ const actionButton = findActionButton(wrapper, 'Delete')
+ expect(actionButton.exists()).toBe(visible)
+ }
+
+ test('hides delete action when message is older than 6 hours', () => {
+ testDeleteMessageVisible(false, new Date('2020-05-07 15:24:00'))
+ })
+
+ test('hides delete action when the conversation is read-only', () => {
+ conversationProps.readOnly = CONVERSATION.STATE.READ_ONLY
+ testDeleteMessageVisible(false)
+ })
+
+ test('hides delete action for file messages', () => {
+ messageProps.message = '{file}'
+ messageProps.messageParameters.file = {}
+ testDeleteMessageVisible(false)
+ })
+
+ test('hides delete action on other people messages for non-moderators', () => {
+ messageProps.actorId = 'another-user'
+ conversationProps.type = CONVERSATION.TYPE.GROUP
+ testDeleteMessageVisible(false)
+ })
+
+ test('shows delete action on other people messages for moderators', () => {
+ messageProps.actorId = 'another-user'
+ conversationProps.type = CONVERSATION.TYPE.GROUP
+ testDeleteMessageVisible(true, null, PARTICIPANT.TYPE.MODERATOR)
+ })
+
+ test('shows delete action on other people messages for owner', () => {
+ messageProps.actorId = 'another-user'
+ conversationProps.type = CONVERSATION.TYPE.PUBLIC
+ testDeleteMessageVisible(true, null, PARTICIPANT.TYPE.OWNER)
+ })
+
+ test('does not show delete action even for guest moderators', () => {
+ messageProps.actorId = 'another-user'
+ conversationProps.type = CONVERSATION.TYPE.PUBLIC
+ testDeleteMessageVisible(false, null, PARTICIPANT.TYPE.GUEST_MODERATOR)
+ })
+
+ test('does not show delete action on other people messages in one to one conversations', () => {
+ messageProps.actorId = 'another-user'
+ conversationProps.type = CONVERSATION.TYPE.ONE_TO_ONE
+ testDeleteMessageVisible(false)
+ })
+ })
+
+ test('marks message as unread', async () => {
+ const updateLastReadMessageAction = jest.fn().mockResolvedValueOnce()
+ const fetchConversationAction = jest.fn().mockResolvedValueOnce()
+ testStoreConfig.modules.conversationsStore.actions.updateLastReadMessage = updateLastReadMessageAction
+ testStoreConfig.modules.conversationsStore.actions.fetchConversation = fetchConversationAction
+ store = new Store(testStoreConfig)
+
+ messageProps.previousMessageId = 100
+
+ // appears even with more restrictive conditions
+ conversationProps.readOnly = CONVERSATION.STATE.READ_ONLY
+ messageProps.actorId = 'another-user'
+ messageProps.participant = {
+ actorId: 'guest-id-1',
+ actorType: ATTENDEE.ACTOR_TYPE.GUESTS,
+ participantType: PARTICIPANT.TYPE.GUEST,
+ }
+
+ const wrapper = shallowMount(MessageButtonsBar, {
+ localVue,
+ store,
+ stubs: {
+ ActionButton,
+ },
+
+ propsData: messageProps,
+ })
+
+ const actionButton = findActionButton(wrapper, 'Mark as unread')
+ expect(actionButton.exists()).toBe(true)
+
+ await actionButton.find('button').trigger('click')
+ // needs two updates...
+ await wrapper.vm.$nextTick()
+ await wrapper.vm.$nextTick()
+
+ expect(updateLastReadMessageAction).toHaveBeenCalledWith(expect.anything(), {
+ token: TOKEN,
+ id: 100,
+ updateVisually: true,
+ })
+
+ expect(fetchConversationAction).toHaveBeenCalledWith(expect.anything(), {
+ token: TOKEN,
+ })
+ })
+
+ test('copies message link', async () => {
+ const copyTextMock = jest.fn()
+
+ // appears even with more restrictive conditions
+ conversationProps.readOnly = CONVERSATION.STATE.READ_ONLY
+ messageProps.actorId = 'another-user'
+ messageProps.participant = {
+ actorId: 'guest-id-1',
+ actorType: ATTENDEE.ACTOR_TYPE.GUESTS,
+ participantType: PARTICIPANT.TYPE.GUEST,
+ }
+
+ const wrapper = shallowMount(MessageButtonsBar, {
+ localVue,
+ store,
+ mocks: {
+ $copyText: copyTextMock,
+ },
+ stubs: {
+ ActionButton,
+ },
+
+ propsData: messageProps,
+ })
+
+ const actionButton = findActionButton(wrapper, 'Copy message link')
+ expect(actionButton.exists()).toBe(true)
+
+ await actionButton.find('button').trigger('click')
+
+ expect(copyTextMock).toHaveBeenCalledWith('http://localhost/nc-webroot/call/XXTOKENXX#message_123')
+ })
+
+ test('renders clickable custom actions', async () => {
+ const handler = jest.fn()
+ const handler2 = jest.fn()
+ const actionsGetterMock = jest.fn().mockReturnValue([{
+ label: 'first action',
+ icon: 'some-icon',
+ callback: handler,
+ }, {
+ label: 'second action',
+ icon: 'some-icon2',
+ callback: handler2,
+ }])
+ testStoreConfig.modules.messageActionsStore.getters.messageActions = actionsGetterMock
+ testStoreConfig.modules.messagesStore.getters.message = jest.fn(() => () => messageProps)
+ store = new Store(testStoreConfig)
+ const wrapper = shallowMount(MessageButtonsBar, {
+ localVue,
+ store,
+ stubs: {
+ ActionButton,
+ },
+ propsData: messageProps,
+ })
+
+ const actionButton = findActionButton(wrapper, 'first action')
+ expect(actionButton.exists()).toBe(true)
+ await actionButton.find('button').trigger('click')
+
+ expect(handler).toHaveBeenCalledWith({
+ apiDummyData: 1,
+ },)
+
+ const actionButton2 = findActionButton(wrapper, 'second action')
+ expect(actionButton2.exists()).toBe(true)
+ await actionButton2.find('button').trigger('click')
+
+ expect(handler2).toHaveBeenCalledWith({
+ apiDummyData: 1,
+ })
+ })
+ })
+})
diff --git a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue
new file mode 100644
index 000000000..d1dc56aeb
--- /dev/null
+++ b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue
@@ -0,0 +1,453 @@
+<!--
+ - @copyright Copyright (c) 2021 Marco Ambrosini <marcoambrosini@pm.me>
+ -
+ - @author Marco Ambrosini <marcoambrosini@pm.me>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<template>
+ <!-- Message Actions -->
+ <div class="message-buttons-bar">
+ <template v-if="page === 0">
+ <Button type="tertiary"
+ @click="page = 1">
+ <template #icon>
+ <EmoticonOutline :size="20" />
+ </template>
+ </Button>
+ <Actions v-show="isReplyable">
+ <ActionButton icon="icon-reply"
+ @click.stop="handleReply">
+ {{ t('spreed', 'Reply') }}
+ </ActionButton>
+ </Actions>
+ <Actions :force-menu="true"
+ :container="container"
+ :boundaries-element="containerElement">
+ <ActionButton v-if="isPrivateReplyable"
+ icon="icon-user"
+ :close-after-click="true"
+ @click.stop="handlePrivateReply">
+ {{ t('spreed', 'Reply privately') }}
+ </ActionButton>
+ <ActionButton icon="icon-external"
+ :close-after-click="true"
+ @click.stop.prevent="handleCopyMessageLink">
+ {{ t('spreed', 'Copy message link') }}
+ </ActionButton>
+ <ActionButton :close-after-click="true"
+ @click.stop="handleMarkAsUnread">
+ <template #icon>
+ <EyeOffOutline decorative
+ title=""
+ :size="16" />
+ </template>
+ {{ t('spreed', 'Mark as unread') }}
+ </ActionButton>
+ <ActionLink v-if="linkToFile"
+ icon="icon-text"
+ :href="linkToFile">
+ {{ t('spreed', 'Go to file') }}
+ </ActionLink>
+ <ActionButton v-if="!isCurrentGuest && !isFileShare"
+ :close-after-click="true"
+ @click.stop="showForwarder = true">
+ <Share slot="icon"
+ :size="16"
+ decorative
+ title="" />
+ {{ t('spreed', 'Forward message') }}
+ </ActionButton>
+ <ActionSeparator v-if="messageActions.length > 0" />
+ <template v-for="action in messageActions">
+ <ActionButton :key="action.label"
+ :icon="action.icon"
+ :close-after-click="true"
+ @click="action.callback(messageApiData)">
+ {{ action.label }}
+ </ActionButton>
+ </template>
+ <template v-if="isDeleteable">
+ <ActionSeparator />
+ <ActionButton icon="icon-delete"
+ :close-after-click="true"
+ @click.stop="handleDelete">
+ {{ t('spreed', 'Delete') }}
+ </ActionButton>
+ </template>
+ </Actions>
+ </template>
+
+ <template v-if="page === 1">
+ <Button type="tertiary"
+ @click="page = 0">
+ <template #icon>
+ <ArrowLeft :size="20" />
+ </template>
+ </Button>
+ <Button type="tertiary"
+ @click="addReactionToMessage('👍')">
+ <template #icon>
+ <span>👍</span>
+ </template>
+ </Button>
+ <Button type="tertiary"
+ @click="addReactionToMessage('❤️')">
+ <template #icon>
+ <span>❤️</span>
+ </template>
+ </Button>
+ <EmojiPicker @select="addReactionToMessage">
+ <Button type="tertiary">
+ <template #icon>
+ <Plus :size="20" />
+ </template>
+ </Button>
+ </EmojiPicker>
+ </template>
+ <Forwarder v-if="showForwarder"
+ :message-object="messageObject"
+ @close="showForwarder = false" />
+ </div>
+</template>
+
+<script>
+import { PARTICIPANT, CONVERSATION, ATTENDEE } from '../../../../../constants'
+import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
+import ActionLink from '@nextcloud/vue/dist/Components/ActionLink'
+import Actions from '@nextcloud/vue/dist/Components/Actions'
+import ActionSeparator from '@nextcloud/vue/dist/Components/ActionSeparator'
+import EyeOffOutline from 'vue-material-design-icons/EyeOffOutline'
+import EmoticonOutline from 'vue-material-design-icons/EmoticonOutline.vue'
+import ArrowLeft from 'vue-material-design-icons/ArrowLeft.vue'
+import Plus from 'vue-material-design-icons/Plus.vue'
+import Share from 'vue-material-design-icons/Share'
+import moment from '@nextcloud/moment'
+import { EventBus } from '../../../../../services/EventBus'
+import { generateUrl } from '@nextcloud/router'
+import {
+ showError,
+ showSuccess,
+} from '@nextcloud/dialogs'
+import Forwarder from '../MessagePart/Forwarder'
+import Button from '@nextcloud/vue/dist/Components/Button'
+import EmojiPicker from '@nextcloud/vue/dist/Components/EmojiPicker'
+
+export default {
+ name: 'MessageButtonsBar',
+
+ components: {
+ Actions,
+ ActionButton,
+ ActionLink,
+ EyeOffOutline,
+ Share,
+ ActionSeparator,
+ Forwarder,
+ Button,
+ EmoticonOutline,
+ ArrowLeft,
+ Plus,
+ EmojiPicker,
+ },
+
+ props: {
+ token: {
+ type: String,
+ required: true,
+ },
+
+ previousMessageId: {
+ type: [String, Number],
+ required: true,
+ },
+
+ isReplyable: {
+ type: Boolean,
+ required: true,
+ },
+
+ messageObject: {
+ type: Object,
+ required: true,
+ },
+
+ actorId: {
+ type: String,
+ required: true,
+ },
+
+ actorType: {
+ type: String,
+ required: true,
+ },
+
+ /**
+ * The display name of the sender of the message.
+ */
+ actorDisplayName: {
+ type: String,
+ required: true,
+ },
+
+ /**
+ * The parameters of the rich object message
+ */
+ messageParameters: {
+ type: [Array, Object],
+ required: true,
+ },
+
+ /**
+ * The message timestamp.
+ */
+ timestamp: {
+ type: Number,
+ default: 0,
+ },
+
+ /**
+ * The message id.
+ */
+ id: {
+ type: [String, Number],
+ required: true,
+ },
+
+ /**
+ * The parent message's id.
+ */
+ parent: {
+ type: Number,
+ default: 0,
+ },
+
+ /**
+ * The message or quote text.
+ */
+ message: {
+ type: String,
+ required: true,
+ },
+
+ /**
+ * The type of system message
+ */
+ systemMessage: {
+ type: String,
+ required: true,
+ },
+
+ /**
+ * The type of the message.
+ */
+ messageType: {
+ type: String,
+ required: true,
+ },
+
+ /**
+ * The participant object.
+ */
+ participant: {
+ type: Object,
+ required: true,
+ },
+
+ messageApiData: {
+ type: Object,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ // Shows/hides the message forwarder component
+ showForwarder: false,
+
+ // The pagination of the buttons menu
+ page: 0,
+ }
+ },
+
+ computed: {
+ conversation() {
+ return this.$store.getters.conversation(this.token)
+ },
+
+ container() {
+ return this.$store.getters.getMainContainerSelector()
+ },
+
+ containerElement() {
+ return document.querySelector(this.container)
+ },
+
+ isDeleteable() {
+ if (this.isConversationReadOnly) {
+ return false
+ }
+
+ const isObjectShare = this.message === '{object}'
+ && this.messageParameters?.object
+
+ return (moment(this.timestamp * 1000).add(6, 'h')) > moment()
+ && this.messageType === 'comment'
+ && !this.isDeleting
+ && !this.isFileShare
+ && !isObjectShare
+ && (this.isMyMsg
+ || (this.conversation.type !== CONVERSATION.TYPE.ONE_TO_ONE
+ && (this.participant.participantType === PARTICIPANT.TYPE.OWNER
+ || this.participant.participantType === PARTICIPANT.TYPE.MODERATOR)))
+ },
+
+ isPrivateReplyable() {
+ return this.isReplyable
+ && (this.conversation.type === CONVERSATION.TYPE.PUBLIC
+ || this.conversation.type === CONVERSATION.TYPE.GROUP)
+ && !this.isMyMsg
+ && this.actorType === ATTENDEE.ACTOR_TYPE.USERS
+ && this.$store.getters.getActorType() === ATTENDEE.ACTOR_TYPE.USERS
+ },
+
+ messageActions() {
+ return this.$store.getters.messageActions
+ },
+
+ linkToFile() {
+ if (this.isFileShare) {
+ return this.messageParameters?.file?.link
+ }
+ return ''
+ },
+
+ isFileShare() {
+ return this.message === '{file}' && this.messageParameters?.file
+ },
+
+ isCurrentGuest() {
+ return this.$store.getters.getActorType() === 'guests'
+ },
+
+ isMyMsg() {
+ return this.actorId === this.$store.getters.getActorId()
+ && this.actorType === this.$store.getters.getActorType()
+ },
+
+ isConversationReadOnly() {
+ return this.conversation.readOnly === CONVERSATION.STATE.READ_ONLY
+ },
+ },
+
+ methods: {
+ handleReply() {
+ this.$store.dispatch('addMessageToBeReplied', {
+ id: this.id,
+ actorId: this.actorId,
+ actorType: this.actorType,
+ actorDisplayName: this.actorDisplayName,
+ timestamp: this.timestamp,
+ systemMessage: this.systemMessage,
+ messageType: this.messageType,
+ message: this.message,
+ messageParameters: this.messageParameters,
+ token: this.token,
+ previousMessageId: this.previousMessageId,
+ })
+ EventBus.$emit('focus-chat-input')
+ },
+
+ handleActionMenuUpdate(type) {
+ if (type === 'open') {
+ this.isActionMenuOpen = true
+ } else if (type === 'close') {
+ this.isActionMenuOpen = false
+ this.showActions = false
+ }
+ },
+
+ async handlePrivateReply() {
+ // open the 1:1 conversation
+ const conversation = await this.$store.dispatch('createOneToOneConversation', this.actorId)
+ this.$router.push({ name: 'conversation', params: { token: conversation.token } }).catch(err => console.debug(`Error while pushing the new conversation's route: ${err}`))
+ },
+
+ async handleCopyMessageLink() {
+ try {
+ const link = window.location.protocol + '//' + window.location.host + generateUrl('/call/' + this.token) + '#message_' + this.id
+ await this.$copyText(link)
+ showSuccess(t('spreed', 'Message link copied to clipboard.'))
+ } catch (error) {
+ console.error('Error copying link: ', error)
+ showError(t('spreed', 'The link could not be copied.'))
+ }
+ },
+
+ async handleMarkAsUnread() {
+ // update in backend + visually
+ await this.$store.dispatch('updateLastReadMessage', {
+ token: this.token,
+ id: this.previousMessageId,
+ updateVisually: true,
+ })
+
+ // reload conversation to update additional attributes that have computed values
+ await this.$store.dispatch('fetchConversation', { token: this.token })
+ },
+
+ addReactionToMessage(selectedEmoji) {
+ // Add reaction only if user hasn't reacted yet
+ if (!this.$store.getters.userHasReacted(this.actorId, this.token, this.messageObject.id, selectedEmoji)) {
+ this.$store.dispatch('addReactionToMessage', {
+ token: this.token,
+ messageId: this.messageObject.id,
+ selectedEmoji,
+ actorId: this.actorId,
+ })
+ } else {
+ console.debug('Current user has already reacted')
+ }
+
+ },
+
+ handleDelete() {
+ this.$emit('delete')
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../../../../assets/variables';
+
+.message-buttons-bar {
+ display: flex;
+ right: 14px;
+ bottom: -4px;
+ position: absolute;
+ z-index: 100000;
+ background-color: var(--color-main-background);
+ border-radius: calc($clickable-area / 2);
+ box-shadow: 0 0 4px 0px var(--color-box-shadow);
+
+ & h6 {
+ margin-left: auto;
+ }
+}
+
+</style>
diff --git a/src/components/Quote.vue b/src/components/Quote.vue
index d4a0e573d..6a19bc504 100644
--- a/src/components/Quote.vue
+++ b/src/components/Quote.vue
@@ -81,6 +81,9 @@ export default {
type: String,
required: true,
},
+ /**
+ * The display name of the sender of the message.
+ */
actorDisplayName: {
type: String,
required: true,
diff --git a/src/services/messagesService.js b/src/services/messagesService.js
index 938a35130..3a211a7e5 100644
--- a/src/services/messagesService.js
+++ b/src/services/messagesService.js
@@ -132,6 +132,24 @@ const updateLastReadMessage = async function(token, lastReadMessage) {
})
}
+const addReactionToMessage = async function(token, messageId, selectedEmoji) {
+ return axios.post(generateOcsUrl('apps/spreed/api/v1/reaction/{token}/{messageId}', { token, messageId }), {
+ reaction: selectedEmoji,
+ })
+}
+
+const removeReactionFromMessage = async function(token, messageId, selectedEmoji) {
+ return axios.delete(generateOcsUrl('apps/spreed/api/v1/reaction/{token}/{messageId}', { token, messageId }), {
+ params: {
+ reaction: selectedEmoji,
+ },
+ })
+}
+
+const getReactionsDetails = async function(token, messageId) {
+ return axios.get(generateOcsUrl('apps/spreed/api/v1/reaction/{token}/{messageId}', { token, messageId }))
+}
+
export {
fetchMessages,
lookForNewMessages,
@@ -139,4 +157,7 @@ export {
deleteMessage,
postRichObjectToConversation,
updateLastReadMessage,
+ addReactionToMessage,
+ removeReactionFromMessage,
+ getReactionsDetails,
}
diff --git a/src/store/messagesStore.js b/src/store/messagesStore.js
index 3c08544e3..3dd4833d3 100644
--- a/src/store/messagesStore.js
+++ b/src/store/messagesStore.js
@@ -27,6 +27,8 @@ import {
lookForNewMessages,
postNewMessage,
postRichObjectToConversation,
+ addReactionToMessage,
+ removeReactionFromMessage,
} from '../services/messagesService'
import SHA256 from 'crypto-js/sha256'
@@ -138,7 +140,14 @@ const getters = {
*/
messagesList: (state) => (token) => {
if (state.messages[token]) {
- return Object.values(state.messages[token])
+ return Object.values(state.messages[token]).filter(message => {
+ // Filter out reaction messages
+ if (message.systemMessage === 'reaction' || message.systemMessage === 'reaction_deleted' || message.systemMessage === 'reaction_revoked') {
+ return false
+ } else {
+ return true
+ }
+ })
}
return []
},
@@ -191,6 +200,11 @@ const getters = {
// the cancel handler only exists when a message is being sent
return Object.keys(state.cancelPostNewMessage).length !== 0
},
+
+ // Returns true if the message has reactions
+ hasReactions: (state) => (token, messageId) => {
+ return Object.keys(state.messages[token][messageId].reactions).length !== 0
+ },
}
const mutations = {
@@ -333,6 +347,24 @@ const mutations = {
Vue.delete(state.messages, token)
}
},
+
+ // Increases reaction count for a particular reaction on a message
+ addReactionToMessage(state, { token, messageId, reaction }) {
+ if (!state.messages[token][messageId].reactions[reaction]) {
+ Vue.set(state.messages[token][messageId].reactions, reaction, 0)
+ }
+ const reactionCount = state.messages[token][messageId].reactions[reaction] + 1
+ Vue.set(state.messages[token][messageId].reactions, reaction, reactionCount)
+ },
+
+ // Decreases reaction count for a particular reaction on a message
+ removeReactionFromMessage(state, { token, messageId, reaction }) {
+ const reactionCount = state.messages[token][messageId].reactions[reaction] - 1
+ Vue.set(state.messages[token][messageId].reactions, reaction, reactionCount)
+ if (state.messages[token][messageId].reactions[reaction] <= 0) {
+ Vue.delete(state.messages[token][messageId].reactions, reaction)
+ }
+ },
}
const actions = {
@@ -442,6 +474,7 @@ const actions = {
token,
isReplyable: false,
sendingFailure: '',
+ reactions: {},
referenceId: Hex.stringify(SHA256(tempId)),
})
@@ -931,6 +964,72 @@ const actions = {
const response = await postRichObjectToConversation(token, richObject)
return response
},
+
+ /**
+ * Adds a single reaction to a message for the current user.
+ *
+ * @param {*} context the context object
+ * @param {*} param1 conversation token, message id and selected emoji (string)
+ */
+ async addReactionToMessage(context, { token, messageId, selectedEmoji }) {
+ try {
+ context.commit('addReactionToMessage', {
+ token,
+ messageId,
+ reaction: selectedEmoji,
+ })
+ // The response return an array with the reaction details for this message
+ const response = await addReactionToMessage(token, messageId, selectedEmoji)
+ // We replace the reaction details in the reactions store and wipe the old
+ // values
+ context.dispatch('updateReactions', {
+ token,
+ messageId,
+ reactionsDetails: response.data.ocs.data,
+ })
+ } catch (error) {
+ // Restore the previous state if the request fails
+ context.commit('removeReactionFromMessage', {
+ token,
+ messageId,
+ reaction: selectedEmoji,
+ })
+ console.debug(error)
+ }
+ },
+
+ /**
+ * Removes a single reaction from a message for the current user.
+ *
+ * @param {*} context the context object
+ * @param {*} param1 conversation token, message id and selected emoji (string)
+ */
+ async removeReactionFromMessage(context, { token, messageId, selectedEmoji }) {
+ try {
+ context.commit('removeReactionFromMessage', {
+ token,
+ messageId,
+ reaction: selectedEmoji,
+ })
+ // The response return an array with the reaction details for this message
+ const response = await removeReactionFromMessage(token, messageId, selectedEmoji)
+ // We replace the reaction details in the reactions store and wipe the old
+ // values
+ context.dispatch('updateReactions', {
+ token,
+ messageId,
+ reactionsDetails: response.data.ocs.data,
+ })
+ } catch (error) {
+ // Restore the previous state if the request fails
+ context.commit('addReactionToMessage', {
+ token,
+ messageId,
+ reaction: selectedEmoji,
+ })
+ console.debug(error)
+ }
+ },
}
export default { state, mutations, getters, actions }
diff --git a/src/store/messagesStore.spec.js b/src/store/messagesStore.spec.js
index 354d5e579..f7d715aee 100644
--- a/src/store/messagesStore.spec.js
+++ b/src/store/messagesStore.spec.js
@@ -313,6 +313,7 @@ describe('messagesStore', () => {
token: TOKEN,
isReplyable: false,
sendingFailure: '',
+ reactions: {},
referenceId: expect.stringMatching(/^[a-zA-Z0-9]{64}$/),
})
})
@@ -345,6 +346,7 @@ describe('messagesStore', () => {
token: TOKEN,
isReplyable: false,
sendingFailure: '',
+ reactions: {},
referenceId: expect.stringMatching(/^[a-zA-Z0-9]{64}$/),
parent: 123,
})
@@ -389,6 +391,7 @@ describe('messagesStore', () => {
token: TOKEN,
isReplyable: false,
sendingFailure: '',
+ reactions: {},
referenceId: expect.stringMatching(/^[a-zA-Z0-9]{64}$/),
})
})
@@ -418,6 +421,7 @@ describe('messagesStore', () => {
token: TOKEN,
isReplyable: false,
sendingFailure: '',
+ reactions: {},
referenceId: expect.stringMatching(/^[a-zA-Z0-9]{64}$/),
}])
@@ -440,6 +444,7 @@ describe('messagesStore', () => {
token: TOKEN,
isReplyable: false,
sendingFailure: '',
+ reactions: {},
referenceId: expect.stringMatching(/^[a-zA-Z0-9]{64}$/),
}])
})
@@ -473,6 +478,7 @@ describe('messagesStore', () => {
token: TOKEN,
isReplyable: false,
sendingFailure: 'failure-reason',
+ reactions: {},
referenceId: expect.stringMatching(/^[a-zA-Z0-9]{64}$/),
}])
})
@@ -518,6 +524,7 @@ describe('messagesStore', () => {
token: TOKEN,
isReplyable: false,
sendingFailure: '',
+ reactions: {},
referenceId: expect.stringMatching(/^[a-zA-Z0-9]{64}$/),
}])
})
diff --git a/src/store/reactionsStore.js b/src/store/reactionsStore.js
new file mode 100644
index 000000000..821e6c60a
--- /dev/null
+++ b/src/store/reactionsStore.js
@@ -0,0 +1,103 @@
+/**
+ * @copyright Copyright (c) 2022 Marco Ambrosini <marcoambrosini@pm.me>
+ *
+ * @author Marco Ambrosini <marcoambrosini@pm.me>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+import Vue from 'vue'
+import {
+ getReactionsDetails,
+} from '../services/messagesService'
+
+const state = {
+ /**
+ * Structure:
+ * reactions.token.messageId
+ */
+ reactions: {},
+}
+
+const getters = {
+ reactions: (state) => (token, messageId) => {
+ if (state.reactions?.[token]?.[messageId]) {
+ return state.reactions[token][messageId]
+ } else {
+ return undefined
+ }
+ },
+
+ // Checks if a user has already reacted to a message with a particular reaction
+ userHasReacted: (state) => (actorId, token, messageId, reaction) => {
+ if (!state?.reactions?.[token]?.[messageId]?.[reaction]) {
+ return false
+ }
+ return state?.reactions?.[token]?.[messageId]?.[reaction].filter(item => {
+ return item.actorId === actorId
+ }).length !== 0
+ },
+}
+
+const mutations = {
+ addReactions(state, { token, messageId, reactions }) {
+ if (!state.reactions[token]) {
+ Vue.set(state.reactions, token, {})
+
+ }
+ Vue.set(state.reactions[token], messageId, reactions)
+ },
+}
+
+const actions = {
+ /**
+ * Updates reactions for a given message.
+ *
+ * @param {*} context The context object
+ * @param {*} param1 conversation token, message id
+ */
+ async updateReactions(context, { token, messageId, reactionsDetails }) {
+ context.commit('addReactions', {
+ token,
+ messageId,
+ reactions: reactionsDetails,
+ })
+ },
+
+ /**
+ * Gets the full reactions array for a given message.
+ *
+ * @param {*} context the context object
+ * @param {*} param1 conversation token, message id
+ */
+ async getReactions(context, { token, messageId }) {
+ console.debug('getting reactions details')
+ try {
+ const response = await getReactionsDetails(token, messageId)
+ context.commit('addReactions', {
+ token,
+ messageId,
+ reactions: response.data.ocs.data,
+ })
+
+ return response
+ } catch (error) {
+ console.debug(error)
+ }
+ },
+}
+
+export default { state, mutations, getters, actions }
diff --git a/src/store/storeConfig.js b/src/store/storeConfig.js
index 16b8b6db4..8d772fa26 100644
--- a/src/store/storeConfig.js
+++ b/src/store/storeConfig.js
@@ -38,6 +38,7 @@ import tokenStore from './tokenStore'
import uiModeStore from './uiModeStore'
import windowVisibilityStore from './windowVisibilityStore'
import messageActionsStore from './messageActionsStore'
+import reactionsStore from './reactionsStore'
export default {
modules: {
@@ -59,6 +60,7 @@ export default {
uiModeStore,
windowVisibilityStore,
messageActionsStore,
+ reactionsStore,
},
mutations: {},