Compare commits
106 Commits
develop
...
stable-5.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbe63a1ee1 | ||
|
|
f7f1068bf0 | ||
|
|
74c7a6b5f6 | ||
|
|
d1d67c3230 | ||
|
|
0fb34f24cf | ||
|
|
3b513dc670 | ||
|
|
76fe4ce0e7 | ||
|
|
cadb462208 | ||
|
|
fbc1e4a252 | ||
|
|
a7643fec73 | ||
|
|
439b17800f | ||
|
|
e50ba0aca5 | ||
|
|
85649f8894 | ||
|
|
927ecff993 | ||
|
|
7279cb88b5 | ||
|
|
7c718d9c18 | ||
|
|
9ff3d80f49 | ||
|
|
aeb3486602 | ||
|
|
ab37cfe972 | ||
|
|
81408f7e87 | ||
|
|
3f81df1925 | ||
|
|
bb80177a02 | ||
|
|
62ae0e9944 | ||
|
|
c38c4e6226 | ||
|
|
757a9b274e | ||
|
|
08934daaf3 | ||
|
|
321aa0ea4c | ||
|
|
5a6df7fc82 | ||
|
|
5995c0e676 | ||
|
|
ea163bb02f | ||
|
|
473cc70d3b | ||
|
|
79997ca992 | ||
|
|
e06d10978e | ||
|
|
d095cd6612 | ||
|
|
5fae57a8ce | ||
|
|
e00c2187a8 | ||
|
|
a19fee34f6 | ||
|
|
6f2f507385 | ||
|
|
49944a93e0 | ||
|
|
8042a609cd | ||
|
|
61f42f950f | ||
|
|
e552795183 | ||
|
|
13e3887dd8 | ||
|
|
ee6f1650cb | ||
|
|
e386190851 | ||
|
|
2c77e73c39 | ||
|
|
a969cd44d8 | ||
|
|
28c5b986d4 | ||
|
|
2cc110fd42 | ||
|
|
43aa552d8c | ||
|
|
54227e82ac | ||
|
|
652d2c27e9 | ||
|
|
bb7ff179ed | ||
|
|
339807b0a0 | ||
|
|
57f6b8ce6c | ||
|
|
07dd0e8c5a | ||
|
|
4ec64cf850 | ||
|
|
d71bd90ef9 | ||
|
|
6bdcbf933e | ||
|
|
858474dc4c | ||
|
|
177952f2f9 | ||
|
|
545289c29b | ||
|
|
bc7494dde2 | ||
|
|
88fc907599 | ||
|
|
f8e72c64c0 | ||
|
|
3cada0f15a | ||
|
|
52834f0d85 | ||
|
|
5bf0d6a106 | ||
|
|
cbf22c332d | ||
|
|
92d19a6221 | ||
|
|
b85bd1fe79 | ||
|
|
e667b48a1b | ||
|
|
8274bb8a11 | ||
|
|
0a3e7628b4 | ||
|
|
2844b6d95d | ||
|
|
74da7fa014 | ||
|
|
68a034e159 | ||
|
|
2c6710cd3f | ||
|
|
346ef5b3b2 | ||
|
|
68d7592610 | ||
|
|
94a467a2a3 | ||
|
|
7fad439870 | ||
|
|
49b73de11a | ||
|
|
772bf3516c | ||
|
|
a3a8661e90 | ||
|
|
62c527c772 | ||
|
|
9e1581d9b6 | ||
|
|
909715136e | ||
|
|
1e91639a4c | ||
|
|
83e9138014 | ||
|
|
740f8bf4d2 | ||
|
|
1049368fc7 | ||
|
|
f111d0cce3 | ||
|
|
58f3cd6737 | ||
|
|
76d8a83f0f | ||
|
|
2d6149234d | ||
|
|
2e02221535 | ||
|
|
cb90521e13 | ||
|
|
56ae3eb8e8 | ||
|
|
dcfe8759ff | ||
|
|
38f5768eb0 | ||
|
|
dbbd3095d7 | ||
|
|
1d344d5ec9 | ||
|
|
be44c36a02 | ||
|
|
8eb588a370 | ||
|
|
eefae45c2a |
@@ -12,6 +12,7 @@
|
||||
variables:
|
||||
ES_INDEX_RAND: "true"
|
||||
ES_URL: "http://elasticsearch:9200"
|
||||
ELASTICSEARCH_TAG: '7.16'
|
||||
|
||||
.variables_redis_memcached: &variables_redis_memcached
|
||||
variables:
|
||||
@@ -22,6 +23,7 @@
|
||||
variables:
|
||||
REMOTE_URL: "http://selenium-firefox:4444/wd/hub"
|
||||
BROWSER: "firefox"
|
||||
BROWSER_HEADLESS: "true"
|
||||
START_XVFB: "false" # not needed for headless mode
|
||||
SE_NODE_MAX_SESSIONS: "5"
|
||||
SE_NODE_OVERRIDE_MAX_SESSIONS: "true"
|
||||
@@ -30,6 +32,7 @@
|
||||
variables:
|
||||
REMOTE_URL: "http://selenium-chrome:4444/wd/hub"
|
||||
BROWSER: chrome
|
||||
BROWSER_HEADLESS: "true"
|
||||
START_XVFB: "false" # not needed for headless mode
|
||||
SE_NODE_MAX_SESSIONS: "5"
|
||||
SE_NODE_OVERRIDE_MAX_SESSIONS: "true"
|
||||
@@ -62,6 +65,11 @@
|
||||
tags:
|
||||
- docker
|
||||
|
||||
.tags_docker_low_concurrency: &tags_docker_low_concurrency
|
||||
tags:
|
||||
- docker
|
||||
- low_concurrency
|
||||
|
||||
# Workaround for blocked port 25 access on cloud provider infrastructure
|
||||
.tags_mail: &tags_mail
|
||||
tags:
|
||||
@@ -86,11 +94,11 @@
|
||||
alias: elasticsearch
|
||||
|
||||
.docker_selenium_chrome: &docker_selenium_chrome
|
||||
name: $CI_REGISTRY/docker/zammad-selenium-chrome:4
|
||||
name: $CI_REGISTRY/docker/zammad-selenium-chrome:stable
|
||||
alias: selenium-chrome
|
||||
|
||||
.docker_selenium_firefox: &docker_selenium_firefox
|
||||
name: $CI_REGISTRY/docker/zammad-selenium-firefox:4
|
||||
name: $CI_REGISTRY/docker/zammad-selenium-firefox:stable
|
||||
alias: selenium-firefox
|
||||
|
||||
.docker_imap: &docker_imap
|
||||
@@ -161,8 +169,6 @@
|
||||
- <<: *docker_imap
|
||||
|
||||
.services_mysql_postgresql_elasticsearch: &services_mysql_postgresql_elasticsearch
|
||||
variables:
|
||||
ELASTICSEARCH_TAG: 'stable'
|
||||
services:
|
||||
- <<: *docker_mysql
|
||||
- <<: *docker_postgresql
|
||||
@@ -171,8 +177,6 @@
|
||||
.services_mysql_postgresql_elasticsearch_selenium_chrome_imap: &services_mysql_postgresql_elasticsearch_selenium_chrome_imap
|
||||
extends:
|
||||
- .variables_selenium_chrome
|
||||
variables:
|
||||
ELASTICSEARCH_TAG: 'stable'
|
||||
services:
|
||||
- <<: *docker_mysql
|
||||
- <<: *docker_postgresql
|
||||
@@ -183,8 +187,6 @@
|
||||
.services_mysql_postgresql_elasticsearch_selenium_firefox_imap: &services_mysql_postgresql_elasticsearch_selenium_firefox_imap
|
||||
extends:
|
||||
- .variables_selenium_firefox
|
||||
variables:
|
||||
ELASTICSEARCH_TAG: 'stable'
|
||||
services:
|
||||
- <<: *docker_mysql
|
||||
- <<: *docker_postgresql
|
||||
@@ -196,8 +198,6 @@
|
||||
extends:
|
||||
- .variables_selenium_chrome
|
||||
- .variables_redis_memcached
|
||||
variables:
|
||||
ELASTICSEARCH_TAG: 'stable'
|
||||
services:
|
||||
- <<: *docker_mysql
|
||||
- <<: *docker_postgresql
|
||||
@@ -211,8 +211,6 @@
|
||||
extends:
|
||||
- .variables_selenium_firefox
|
||||
- .variables_redis_memcached
|
||||
variables:
|
||||
ELASTICSEARCH_TAG: 'stable'
|
||||
services:
|
||||
- <<: *docker_mysql
|
||||
- <<: *docker_postgresql
|
||||
|
||||
@@ -19,6 +19,7 @@ include:
|
||||
- .env_base
|
||||
- .variables_es
|
||||
- .variables_app_restart_cmd
|
||||
- .tags_docker_low_concurrency
|
||||
variables:
|
||||
RAILS_ENV: "production"
|
||||
script:
|
||||
@@ -46,6 +47,7 @@ include:
|
||||
extends:
|
||||
- .env_base
|
||||
- .variables_app_restart_cmd
|
||||
- .tags_docker_low_concurrency
|
||||
variables:
|
||||
RAILS_ENV: "production"
|
||||
AUTO_WIZARD_FILE: "contrib/auto_wizard_example.json"
|
||||
@@ -76,6 +78,7 @@ include:
|
||||
- .env_base
|
||||
- .variables_app_restart_cmd
|
||||
- .services_mysql_postgresql_redis_memcached
|
||||
- .tags_docker_low_concurrency
|
||||
variables:
|
||||
RAILS_ENV: "production"
|
||||
|
||||
@@ -87,6 +90,7 @@ include:
|
||||
- .env_base
|
||||
- .variables_es
|
||||
- .variables_rspec_slicing
|
||||
- .tags_docker_low_concurrency
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
script:
|
||||
|
||||
@@ -14,6 +14,7 @@ include:
|
||||
- .env_base
|
||||
- .variables_app_restart_cmd
|
||||
- .variables_es
|
||||
- .tags_docker_low_concurrency
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
script:
|
||||
@@ -40,6 +41,7 @@ include:
|
||||
- .env_base
|
||||
- .variables_app_restart_cmd
|
||||
- .services_postgresql_selenium_chrome
|
||||
- .tags_docker_low_concurrency
|
||||
variables:
|
||||
RAILS_ENV: "production"
|
||||
AUTO_WIZARD_FILE: "contrib/auto_wizard_test.json"
|
||||
@@ -58,6 +60,7 @@ include:
|
||||
extends:
|
||||
- .env_base
|
||||
- .services_postgresql_selenium_chrome
|
||||
- .tags_docker_low_concurrency
|
||||
variables:
|
||||
RAILS_ENV: "production"
|
||||
RAILS_SERVE_STATIC_FILES: "true"
|
||||
|
||||
@@ -9,7 +9,7 @@ otrs_chrome:
|
||||
services:
|
||||
- name: $CI_REGISTRY/docker/zammad-postgresql:stable
|
||||
alias: postgresql
|
||||
- name: $CI_REGISTRY/docker/zammad-selenium-chrome:4
|
||||
- name: $CI_REGISTRY/docker/zammad-selenium-chrome:stable
|
||||
alias: selenium-chrome
|
||||
- name: $CI_REGISTRY/docker/zammad-ci-otrsimport-db:otrs6
|
||||
alias: zammad-ci-otrsimport-db
|
||||
|
||||
@@ -14,14 +14,16 @@
|
||||
- bundle exec rails test test/integration/elasticsearch_test.rb
|
||||
- bundle exec rspec --tag searchindex --tag ~type:system --profile 10
|
||||
|
||||
"rspec:es:7":
|
||||
<<: *template_integration_es
|
||||
variables:
|
||||
ELASTICSEARCH_TAG: '7'
|
||||
RAILS_ENV: "test"
|
||||
|
||||
# Lowest supported version
|
||||
"rspec:es:7.8":
|
||||
<<: *template_integration_es
|
||||
variables:
|
||||
ELASTICSEARCH_TAG: '7.8.1'
|
||||
RAILS_ENV: "test"
|
||||
|
||||
# Highest supported version (except for newer releases that are not yet in CI)
|
||||
"rspec:es:7.16":
|
||||
<<: *template_integration_es
|
||||
variables:
|
||||
ELASTICSEARCH_TAG: '7.16'
|
||||
RAILS_ENV: "test"
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
- echo -e "\\e[0Ksection_end:`date +%s`:zammad_db_unseeded\\r\\e[0K"
|
||||
- bundle exec rails test test/integration/otrs_import_test.rb
|
||||
variables:
|
||||
FF_NETWORK_PER_BUILD: 1 # https://docs.gitlab.com/runner/configuration/feature-flags.html
|
||||
IMPORT_OTRS_ENDPOINT: "http://zammad-ci-otrsimport-app/otrs/public.pl?Action=ZammadMigrator"
|
||||
TZ: "Europe/Berlin" # Required for the zammad-ci-otrsimport-app containers
|
||||
FF_NETWORK_PER_BUILD: 1 # https://docs.gitlab.com/runner/configuration/feature-flags.html
|
||||
IMPORT_OTRS_ENDPOINT: 'http://zammad-ci-otrsimport-app/otrs/public.pl?Action=ZammadMigrator'
|
||||
TZ: 'Europe/Berlin' # Required for the zammad-ci-otrsimport-app containers
|
||||
|
||||
"minitest:integration:otrs:6":
|
||||
'minitest:integration:otrs:6':
|
||||
<<: *template_integration_otrs
|
||||
services:
|
||||
- name: $CI_REGISTRY/docker/zammad-mysql:stable
|
||||
@@ -23,7 +23,7 @@
|
||||
- name: $CI_REGISTRY/docker/zammad-ci-otrsimport-app:otrs6
|
||||
alias: zammad-ci-otrsimport-app
|
||||
|
||||
"minitest:integration:otrs:5":
|
||||
'minitest:integration:otrs:5':
|
||||
<<: *template_integration_otrs
|
||||
services:
|
||||
- name: $CI_REGISTRY/docker/zammad-mysql:stable
|
||||
@@ -35,7 +35,7 @@
|
||||
- name: $CI_REGISTRY/docker/zammad-ci-otrsimport-app:otrs5
|
||||
alias: zammad-ci-otrsimport-app
|
||||
|
||||
"minitest:integration:otrs:4":
|
||||
'minitest:integration:otrs:4':
|
||||
<<: *template_integration_otrs
|
||||
services:
|
||||
- name: $CI_REGISTRY/docker/zammad-mysql:stable
|
||||
@@ -47,7 +47,7 @@
|
||||
- name: $CI_REGISTRY/docker/zammad-ci-otrsimport-app:otrs4
|
||||
alias: zammad-ci-otrsimport-app
|
||||
|
||||
"minitest:integration:otrs:33":
|
||||
'minitest:integration:otrs:33':
|
||||
<<: *template_integration_otrs
|
||||
services:
|
||||
- name: $CI_REGISTRY/docker/zammad-mysql:stable
|
||||
@@ -59,7 +59,7 @@
|
||||
- name: $CI_REGISTRY/docker/zammad-ci-otrsimport-app:otrs33
|
||||
alias: zammad-ci-otrsimport-app
|
||||
|
||||
"minitest:integration:otrs:32":
|
||||
'minitest:integration:otrs:32':
|
||||
<<: *template_integration_otrs
|
||||
services:
|
||||
- name: $CI_REGISTRY/docker/zammad-mysql:stable
|
||||
@@ -71,7 +71,7 @@
|
||||
- name: $CI_REGISTRY/docker/zammad-ci-otrsimport-app:otrs32
|
||||
alias: zammad-ci-otrsimport-app
|
||||
|
||||
"minitest:integration:otrs:31":
|
||||
'minitest:integration:otrs:31':
|
||||
<<: *template_integration_otrs
|
||||
services:
|
||||
- name: $CI_REGISTRY/docker/zammad-mysql:stable
|
||||
|
||||
@@ -86,10 +86,12 @@
|
||||
# Executed on a dedicated runner.
|
||||
"push to github":
|
||||
<<: *template_pre
|
||||
tags:
|
||||
- deploy
|
||||
before_script:
|
||||
- '' # no RVM present in deploy ENV
|
||||
- test -d $HOME/.ssh || mkdir $HOME/.ssh
|
||||
- ssh-keyscan github.com >> $HOME/.ssh/known_hosts
|
||||
- eval $(ssh-agent -s)
|
||||
- echo "$PUSH_TO_GITHUB_SSH_PRIVATE_KEY" | ssh-add -
|
||||
- ssh-add -l
|
||||
script:
|
||||
- git fetch --unshallow
|
||||
- script/build/sync_repo.sh git@github.com:zammad/zammad.git
|
||||
|
||||
@@ -15,10 +15,15 @@ PreCommit:
|
||||
on_warn: fail
|
||||
CoffeeLint:
|
||||
# .coffeelint/rules/* not supported in YAML, specify all rules separately.
|
||||
flags: ['--reporter=csv', '--rules', './.coffeelint/rules/detect_translatable_string.coffee']
|
||||
flags:
|
||||
[
|
||||
'--reporter=csv',
|
||||
'--rules',
|
||||
'./.coffeelint/rules/detect_translatable_string.coffee',
|
||||
]
|
||||
enabled: true
|
||||
on_warn: fail
|
||||
exclude: public/assets/chat/**/*
|
||||
exclude: 'public/assets/chat/**/*'
|
||||
CustomScript:
|
||||
enabled: true
|
||||
description: 'Check if translation catalog is up-to-date'
|
||||
|
||||
@@ -412,16 +412,6 @@ RSpec/MessageSpies:
|
||||
- 'spec/lib/import/otrs/ticket_spec.rb'
|
||||
- 'spec/lib/import/otrs/user_factory_spec.rb'
|
||||
- 'spec/lib/import/otrs/user_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/base_examples.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/checkbox_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/date_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/decimal_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/dropdown_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/integer_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/regexp_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/tagger_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/text_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/textarea_spec.rb'
|
||||
- 'spec/lib/ldap/group_spec.rb'
|
||||
- 'spec/lib/ldap/guid_spec.rb'
|
||||
- 'spec/lib/ldap/user_spec.rb'
|
||||
@@ -483,16 +473,6 @@ RSpec/MultipleExpectations:
|
||||
- 'spec/lib/import/otrs/priority_factory_spec.rb'
|
||||
- 'spec/lib/import/otrs/requester_spec.rb'
|
||||
- 'spec/lib/import/otrs/state_factory_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/base_examples.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/checkbox_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/date_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/decimal_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/dropdown_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/integer_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/regexp_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/tagger_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/text_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/textarea_spec.rb'
|
||||
- 'spec/lib/ldap/group_spec.rb'
|
||||
- 'spec/lib/ldap/guid_spec.rb'
|
||||
- 'spec/lib/ldap/user_spec.rb'
|
||||
@@ -660,16 +640,6 @@ RSpec/VerifiedDoubles:
|
||||
- 'spec/db/migrate/issue_2460_fix_corrupted_twitter_ids_spec.rb'
|
||||
- 'spec/jobs/communicate_twitter_job_spec.rb'
|
||||
- 'spec/lib/external_sync_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/base_examples.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/checkbox_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/date_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/decimal_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/dropdown_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/integer_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/regexp_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/tagger_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/text_spec.rb'
|
||||
- 'spec/lib/import/zendesk/object_attribute/textarea_spec.rb'
|
||||
- 'spec/lib/ldap_spec.rb'
|
||||
- 'spec/lib/sequencer/sequence/import/ldap/users_spec.rb'
|
||||
- 'spec/lib/sequencer/unit/import/zendesk/sub_sequence/base_examples.rb'
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
},
|
||||
"ignoreFiles": [
|
||||
"public/assets/*.css",
|
||||
"public/assets/chat/chat.css",
|
||||
"public/assets/doorkeeper/**",
|
||||
"**/reset*.css",
|
||||
"**/bootstrap*.css",
|
||||
|
||||
192
CHANGELOG.md
192
CHANGELOG.md
@@ -1,15 +1,195 @@
|
||||
# Change Log
|
||||
|
||||
## [5.1.0](https://github.com/zammad/zammad/tree/5.1.0) (2021-xx-xx)
|
||||
## [5.1.1](https://github.com/zammad/zammad/tree/5.1.1) (2022-04-20)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/5.1.0...5.1.1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Allow reauthentication of Google / Microsoft 365 accounts [3240](https://github.com/zammad/zammad/issues/3240) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[channel](https://github.com/zammad/zammad/labels/channel)]
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Error on second migration of an microsoft365 channel undefined method `options' for nil:NilClass [4060](https://github.com/zammad/zammad/issues/4060) [[bug](https://github.com/zammad/zammad/labels/bug)] [[channel](https://github.com/zammad/zammad/labels/channel)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Freshdesk migration which doesn't support time entries runs in unwanted behaviour [4052](https://github.com/zammad/zammad/issues/4052) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Freshdesk-Migration does not like no Companies / Organisations within the source [4051](https://github.com/zammad/zammad/issues/4051) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Cannot encrypt if multiple S/MIME certificates exist and one is expired [4029](https://github.com/zammad/zammad/issues/4029) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Core Workflow: Does show wrong field list if you only have admin permissions and not ticket.agent permissions [4035](https://github.com/zammad/zammad/issues/4035) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Can't delete smime certificate - ERROR: duplicate key value violates unique constraint [4049](https://github.com/zammad/zammad/issues/4049) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Knowledge Base on-the-fly updating does not work [4026](https://github.com/zammad/zammad/issues/4026) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Core Workflow - Unable to select "has changed" logic when creating new workflow. It is also replaced with "is" in previously created workflows. [4046](https://github.com/zammad/zammad/issues/4046) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- undefined method `to_hash` on editing select fields in the admin interface after migration to 5.1 [4027](https://github.com/zammad/zammad/issues/4027) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- KB Public menus scroll bar positioning incorrect [4008](https://github.com/zammad/zammad/issues/4008) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- Problems with duplicate records in Translations table [4020](https://github.com/zammad/zammad/issues/4020) [[bug](https://github.com/zammad/zammad/labels/bug)] [[translation](https://github.com/zammad/zammad/labels/translation)]
|
||||
- Tree select value cannot be set to "-" (empty) with Trigger/Scheduler/Core workflow [4024](https://github.com/zammad/zammad/issues/4024) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Admin macros are not usable with admin permissions only [4032](https://github.com/zammad/zammad/issues/4032) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Admin SLA index view does not show update time if "for agent respond" is selected [4033](https://github.com/zammad/zammad/issues/4033) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Core Workflow: Stop after match is not saved [4034](https://github.com/zammad/zammad/issues/4034) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Freshdesk import error when a inline image source attribute contains no clean url [4028](https://github.com/zammad/zammad/issues/4028) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Mention history does not show properly who got added [3984](https://github.com/zammad/zammad/issues/3984) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[history](https://github.com/zammad/zammad/labels/history)]
|
||||
- Obsolete notice field in admin calendar view [4023](https://github.com/zammad/zammad/issues/4023) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)]
|
||||
- Error “customer_id required” on Macro execution [4022](https://github.com/zammad/zammad/issues/4022) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[macros](https://github.com/zammad/zammad/labels/macros)]
|
||||
- Translations are not available in API after syncing [4016](https://github.com/zammad/zammad/issues/4016) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Upgraded to 5.1.0: pending time doesn’t show a date [4018](https://github.com/zammad/zammad/issues/4018) [[bug](https://github.com/zammad/zammad/labels/bug)] [[translation](https://github.com/zammad/zammad/labels/translation)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- UI is not updated right after importing users csv file [3919](https://github.com/zammad/zammad/issues/3919) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- LDAP with many groups (<5k) and group role relation (>50) will crash in frontend [3994](https://github.com/zammad/zammad/issues/3994) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[LDAP](https://github.com/zammad/zammad/labels/LDAP)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
|
||||
|
||||
## [5.1.0](https://github.com/zammad/zammad/tree/5.1.0) (2022-03-14)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/5.0.0...5.1.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
|
||||
|
||||
- added russian translations to mail notifications [3780](https://github.com/zammad/zammad/pull/3780) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[notification](https://github.com/zammad/zammad/labels/notification)]
|
||||
- Draft Sharing: Add history entry for updating and deleting of a draft [3983](https://github.com/zammad/zammad/issues/3983) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[draft sharing](https://github.com/zammad/zammad/labels/draft%20sharing)]
|
||||
- Draft Sharing: Improve sidebar icon order for ticket creation [3982](https://github.com/zammad/zammad/issues/3982) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[draft sharing](https://github.com/zammad/zammad/labels/draft%20sharing)]
|
||||
- Make sidebar attachments unique [3930](https://github.com/zammad/zammad/issues/3930) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[ticket](https://github.com/zammad/zammad/labels/ticket)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Draft Sharing [629](https://github.com/zammad/zammad/issues/629) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[feature backlog](https://github.com/zammad/zammad/labels/feature%20backlog)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Limit access to KB Categories based on roles [2603](https://github.com/zammad/zammad/issues/2603) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- Enhance CTI integration texts [2753](https://github.com/zammad/zammad/issues/2753) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Show which escalation type escalated in ticket zoom [3928](https://github.com/zammad/zammad/issues/3928) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[ticket](https://github.com/zammad/zammad/labels/ticket)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Enable migration button feature for account migration MS365/Google channel [3960](https://github.com/zammad/zammad/issues/3960) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[needs verification](https://github.com/zammad/zammad/labels/needs%20verification)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Rename Third-Party login: Office 365 to Microsoft 365 [3245](https://github.com/zammad/zammad/issues/3245) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[third party issue](https://github.com/zammad/zammad/labels/third%20party%20issue)]
|
||||
- Zammad backups (database and filesystem) are world-readable by default [3893](https://github.com/zammad/zammad/issues/3893) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- Add confirmation dialog on visibility change of an article or in article creation [3924](https://github.com/zammad/zammad/issues/3924) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Be able to select more than one owner or organization in condition for overviews/triggers/schedulers like you can do it for state, priority or group [3900](https://github.com/zammad/zammad/issues/3900) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- Zammad misses "weeks" for relative time events [2371](https://github.com/zammad/zammad/issues/2371) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Note is not being updated because of the lack of lastname [2429](https://github.com/zammad/zammad/issues/2429) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[frontend / JS app](https://github.com/zammad/zammad/labels/frontend%20%2F%20JS%20app)]
|
||||
- Display callback urls for third-party applications [3622](https://github.com/zammad/zammad/issues/3622) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- SLA description only available in english [556](https://github.com/zammad/zammad/issues/556) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[translation](https://github.com/zammad/zammad/labels/translation)]
|
||||
- Add clear selection action or has changed condition [3821](https://github.com/zammad/zammad/issues/3821) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[specification required](https://github.com/zammad/zammad/labels/specification%20required)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Allow image popup and download within Chat [3210](https://github.com/zammad/zammad/issues/3210) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[chat](https://github.com/zammad/zammad/labels/chat)]
|
||||
- Display name not used [2275](https://github.com/zammad/zammad/issues/2275) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[frontend / JS app](https://github.com/zammad/zammad/labels/frontend%20%2F%20JS%20app)]
|
||||
- Possibility to specify the order of objects [294](https://github.com/zammad/zammad/issues/294) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[object manager attribute](https://github.com/zammad/zammad/labels/object%20manager%20attribute)]
|
||||
- Import for kayako during the setup [3698](https://github.com/zammad/zammad/issues/3698) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Login site wording could be better [3000](https://github.com/zammad/zammad/issues/3000) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[translation](https://github.com/zammad/zammad/labels/translation)]
|
||||
- Core Workflow: Add organization condition attributes for object User [3779](https://github.com/zammad/zammad/issues/3779) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- No script content (e. g. javascript) in emails [3365](https://github.com/zammad/zammad/issues/3365) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[mail processing](https://github.com/zammad/zammad/labels/mail%20processing)]
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
|
||||
|
||||
|
||||
- Report profile "new profile" button does not match coloring scheme [4007](https://github.com/zammad/zammad/issues/4007) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- "Note - visibility confirmation dialog" setting also requests confirmation for e.g. email and phone articles [4009](https://github.com/zammad/zammad/issues/4009) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
- Ensure 4 column selections within UI does not cover add/remove buttons [3609](https://github.com/zammad/zammad/issues/3609) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- KB RTL text direction has wrong spacing between some elements [3925](https://github.com/zammad/zammad/issues/3925) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[regression](https://github.com/zammad/zammad/labels/regression)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)] [[good first issue](https://github.com/zammad/zammad/labels/good%20first%20issue)]
|
||||
- Fixes: Fix knowledge base spacing and layout [3987](https://github.com/zammad/zammad/pull/3987)
|
||||
- Longer category names break boxes in mobile version [3665](https://github.com/zammad/zammad/issues/3665) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- KB: granular permissions misconfiguration is allowed by UI [3997](https://github.com/zammad/zammad/issues/3997) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- Can not start a row in a knowledge base article with a linked answer [3965](https://github.com/zammad/zammad/issues/3965) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- Long role names get broken due to bad overflow [3999](https://github.com/zammad/zammad/issues/3999) [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- Overviews are not shown if `group_by` is used with a tree select attribute [4004](https://github.com/zammad/zammad/issues/4004) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[overviews](https://github.com/zammad/zammad/labels/overviews)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Unable to upgrade to Zammad 5.1 [4000](https://github.com/zammad/zammad/issues/4000) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Select field in bulk operations out of view port [3995](https://github.com/zammad/zammad/issues/3995) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[overviews](https://github.com/zammad/zammad/labels/overviews)]
|
||||
- No longer public KB answers do not return http 404 [3915](https://github.com/zammad/zammad/issues/3915) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- Selecting custom ports for mail channel ends in 'host not reachable' [3964](https://github.com/zammad/zammad/issues/3964) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[channel](https://github.com/zammad/zammad/labels/channel)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Draft Sharing: Draft stays after new ticket creation [3981](https://github.com/zammad/zammad/issues/3981) [[bug](https://github.com/zammad/zammad/labels/bug)] [[question](https://github.com/zammad/zammad/labels/question)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[draft sharing](https://github.com/zammad/zammad/labels/draft%20sharing)]
|
||||
- Modal backdrop not covering some UI parts [3974](https://github.com/zammad/zammad/issues/3974) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)]
|
||||
- KB: Roles are displayed twice in permission dialog [3977](https://github.com/zammad/zammad/issues/3977) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- KB: Unpermitted categories are displayed after browsing [3978](https://github.com/zammad/zammad/issues/3978) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- Frequent “Lost connection to MySQL server during query” errors resulting in client-side Error 500 [3969](https://github.com/zammad/zammad/issues/3969) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Not translated text with forwarding e-mails [3920](https://github.com/zammad/zammad/issues/3920) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- S/MIME function buttons no longer working in tickets [3957](https://github.com/zammad/zammad/issues/3957) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)]
|
||||
- Migration of the MS365 account fails by upper and lower case differences in email address [3956](https://github.com/zammad/zammad/issues/3956) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Opening organization views throws console traces [3958](https://github.com/zammad/zammad/issues/3958) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)]
|
||||
- Elasticsearch-Rebuild does not index from new to old [3955](https://github.com/zammad/zammad/issues/3955) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Can not chose SSL yes and port 143 when setting up mail account [3921](https://github.com/zammad/zammad/issues/3921) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Uncaught TypeError in ticket zoom highlighter [3950](https://github.com/zammad/zammad/issues/3950)
|
||||
- New online notifications blocks data privacy user deletion [3942](https://github.com/zammad/zammad/issues/3942) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[data privacy](https://github.com/zammad/zammad/labels/data%20privacy)]
|
||||
- Multiselects shows wrong display values in overviews [3944](https://github.com/zammad/zammad/issues/3944) [[bug](https://github.com/zammad/zammad/labels/bug)] [[overviews](https://github.com/zammad/zammad/labels/overviews)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- dead lock on user update in high load environment [3940](https://github.com/zammad/zammad/issues/3940) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Zammad UI should silently discard Cache / apply2file errors [3685](https://github.com/zammad/zammad/issues/3685) [[bug](https://github.com/zammad/zammad/labels/bug)] [[waiting for feedback](https://github.com/zammad/zammad/labels/waiting%20for%20feedback)] [[can't reproduce](https://github.com/zammad/zammad/labels/can%27t%20reproduce)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Startup of Zammad does not synchronize the custom branding logo [3933](https://github.com/zammad/zammad/issues/3933) [[bug](https://github.com/zammad/zammad/labels/bug)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Postgresql Backup & Restore failing on default package installations [3865](https://github.com/zammad/zammad/issues/3865) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Multiselect field support [3917](https://github.com/zammad/zammad/issues/3917) [[feature backlog](https://github.com/zammad/zammad/labels/feature%20backlog)] [[API](https://github.com/zammad/zammad/labels/API)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[form](https://github.com/zammad/zammad/labels/form)]
|
||||
- JS error on editing textareas admin object manager attributes [3889](https://github.com/zammad/zammad/issues/3889) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[object manager attribute](https://github.com/zammad/zammad/labels/object%20manager%20attribute)]
|
||||
- Various translation fixes [3918](https://github.com/zammad/zammad/pull/3918)
|
||||
- Make form style for `customer`-input consistent [3886](https://github.com/zammad/zammad/pull/3886) [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Wrong size for textareas in triggers and core workflow [3909](https://github.com/zammad/zammad/issues/3909) [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[trigger](https://github.com/zammad/zammad/labels/trigger)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Placetel API v1 EOL within January 2022 [3910](https://github.com/zammad/zammad/issues/3910) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[third party issue](https://github.com/zammad/zammad/labels/third%20party%20issue)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Freshdesk import ends up in Zammad interface without navigation [3879](https://github.com/zammad/zammad/issues/3879) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Changing ticket status from "new" to any other status always results in uncommited status "closed" [3880](https://github.com/zammad/zammad/issues/3880) [[bug](https://github.com/zammad/zammad/labels/bug)] [[can't reproduce](https://github.com/zammad/zammad/labels/can%27t%20reproduce)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Usage of freshdesk import without freshdesk admin permission leads to an unstable system/missing data [3905](https://github.com/zammad/zammad/issues/3905) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Deactivation of signature does not clear it from groups [3129](https://github.com/zammad/zammad/issues/3129) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Ticket object does not get a rollback after failing bulk action [3817](https://github.com/zammad/zammad/issues/3817) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[bulk](https://github.com/zammad/zammad/labels/bulk)]
|
||||
- `/assets/fonts/` changed to `/fonts/` [3892](https://github.com/zammad/zammad/issues/3892) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Search is not triggered/updated if url of search is updated new search item or new search is triggered via global search [3873](https://github.com/zammad/zammad/issues/3873) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Overview select fields are sorted by key [3869](https://github.com/zammad/zammad/issues/3869) [[bug](https://github.com/zammad/zammad/labels/bug)] [[overviews](https://github.com/zammad/zammad/labels/overviews)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Text rendering does not work for e-mails (no new lines) received in Zammad [3870](https://github.com/zammad/zammad/issues/3870) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Zammad 5 mail template double signature [3816](https://github.com/zammad/zammad/issues/3816) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Missing ticket updates on high load in MariaDB/MySQL environments [3877](https://github.com/zammad/zammad/issues/3877) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- API creates empty tickets without articles if data is missing [2421](https://github.com/zammad/zammad/issues/2421) [[bug](https://github.com/zammad/zammad/labels/bug)] [[API](https://github.com/zammad/zammad/labels/API)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
- Wrong SLA is used (alphabetical order is ignored) [3871](https://github.com/zammad/zammad/issues/3871) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Provide meaningful modal if report profile tries to use dates out side the filtered date range [3616](https://github.com/zammad/zammad/issues/3616) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[reporting](https://github.com/zammad/zammad/labels/reporting)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Till label not assigned to corresponding input fields in calendar edit view [3793](https://github.com/zammad/zammad/issues/3793) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[frontend / JS app](https://github.com/zammad/zammad/labels/frontend%20%2F%20JS%20app)]
|
||||
- Date of datepicker is not localized [3866](https://github.com/zammad/zammad/issues/3866) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Simple quote characters (`'`) not properly displayed [3846](https://github.com/zammad/zammad/issues/3846) [[bug](https://github.com/zammad/zammad/labels/bug)] [[frontend / JS app](https://github.com/zammad/zammad/labels/frontend%20%2F%20JS%20app)]
|
||||
- Remove api user and password for sipgate integration [3848](https://github.com/zammad/zammad/issues/3848) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- No signature on new ticket if email is default message type [3844](https://github.com/zammad/zammad/issues/3844) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Forwarding no longer possible for email and web articles [3855](https://github.com/zammad/zammad/issues/3855) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Default values of new group dialog is different in german vs. english [3851](https://github.com/zammad/zammad/issues/3851) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- If no date is set the UI show it's shown as NaN.NaN.NaN. [3850](https://github.com/zammad/zammad/issues/3850) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Number of to show caller log entries is inconsistent setting wise [3852](https://github.com/zammad/zammad/issues/3852) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[integration](https://github.com/zammad/zammad/labels/integration)]
|
||||
- "Is required" untranslatable [2709](https://github.com/zammad/zammad/issues/2709) [[translation](https://github.com/zammad/zammad/labels/translation)]
|
||||
- Profile out of office toasters untranslatable [2666](https://github.com/zammad/zammad/issues/2666) [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[translation](https://github.com/zammad/zammad/labels/translation)]
|
||||
- obsolete / double translations [2665](https://github.com/zammad/zammad/issues/2665) [[translation](https://github.com/zammad/zammad/labels/translation)]
|
||||
- Missing translation for insufficient permissions for <object> [3275](https://github.com/zammad/zammad/issues/3275) [[translation](https://github.com/zammad/zammad/labels/translation)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
- Reply all: Duplicate email on changing recipient and cc in a certain way [3825](https://github.com/zammad/zammad/issues/3825) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Email address not shown inside forwarded email [3824](https://github.com/zammad/zammad/issues/3824) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Removing calendars via UI and API does not check for references [3845](https://github.com/zammad/zammad/issues/3845) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[escalation logic](https://github.com/zammad/zammad/labels/escalation%20logic)]
|
||||
- Removing tags from tickets return HTTP 201 [3842](https://github.com/zammad/zammad/issues/3842) [[bug](https://github.com/zammad/zammad/labels/bug)] [[API](https://github.com/zammad/zammad/labels/API)]
|
||||
- Wrong escalation update time in admin interface is shown [3837](https://github.com/zammad/zammad/issues/3837) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Zammad returns stack error when one tries to remove groups via API [3841](https://github.com/zammad/zammad/issues/3841) [[bug](https://github.com/zammad/zammad/labels/bug)] [[API](https://github.com/zammad/zammad/labels/API)]
|
||||
- Zammad ignores relative GitLab URLs [3830](https://github.com/zammad/zammad/issues/3830) [[bug](https://github.com/zammad/zammad/labels/bug)] [[integration](https://github.com/zammad/zammad/labels/integration)]
|
||||
- Ticket zoom will loose attachments on rerender [3831](https://github.com/zammad/zammad/issues/3831) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Invalid group and owner list for tickets created via customer profile [3835](https://github.com/zammad/zammad/issues/3835) [[bug](https://github.com/zammad/zammad/labels/bug)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Package installation creates database.yml as `root` and thus breaks the installation until next update [3834](https://github.com/zammad/zammad/issues/3834) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Ticket create screen will loose attachments by time [3827](https://github.com/zammad/zammad/issues/3827) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Zammad database credentials are world-readable [3828](https://github.com/zammad/zammad/issues/3828) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- If selected value is not part of the restriction of set_fixed_to it should recalculate it with the new value [3822](https://github.com/zammad/zammad/issues/3822) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Update time SLAs escalates tickets with agent response [3140](https://github.com/zammad/zammad/issues/3140) [[bug](https://github.com/zammad/zammad/labels/bug)] [[escalation logic](https://github.com/zammad/zammad/labels/escalation%20logic)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Allow `position` to determine an attributes position entirely [3594](https://github.com/zammad/zammad/issues/3594) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[object manager attribute](https://github.com/zammad/zammad/labels/object%20manager%20attribute)] [[specification required](https://github.com/zammad/zammad/labels/specification%20required)]
|
||||
- Not displayed fields should not impact the edit screen [3819](https://github.com/zammad/zammad/issues/3819) [[bug](https://github.com/zammad/zammad/labels/bug)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- When looking for customers, it is no longer possible to change into organizations [3815](https://github.com/zammad/zammad/issues/3815) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Default Priority on ticket creation not changeable [2852](https://github.com/zammad/zammad/issues/2852) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[ticket](https://github.com/zammad/zammad/labels/ticket)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[:construction: refactoring :construction:](https://github.com/zammad/zammad/labels/%3Aconstruction%3A%20refactoring%20%3Aconstruction%3A)]
|
||||
- When quoting, no breakout from div container possible [3094](https://github.com/zammad/zammad/issues/3094) [[bug](https://github.com/zammad/zammad/labels/bug)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
- Quoting not working cleanly, if content gets too much [2334](https://github.com/zammad/zammad/issues/2334) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[ticket](https://github.com/zammad/zammad/labels/ticket)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Owner should get cleared if not listed in changed group [3818](https://github.com/zammad/zammad/issues/3818) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Custom date and datetime attributes are filled with dates on creation of tickets/users after update from 4.1 to 5.x [3810](https://github.com/zammad/zammad/issues/3810) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- ActionController::UnknownHttpMethod FRAGE [3807](https://github.com/zammad/zammad/issues/3807) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[overviews](https://github.com/zammad/zammad/labels/overviews)] [[macros](https://github.com/zammad/zammad/labels/macros)]
|
||||
- [REVIEW] Fix/trigger variables missing [3225](https://github.com/zammad/zammad/pull/3225)
|
||||
- Adding private keys allows adding certificates [3727](https://github.com/zammad/zammad/issues/3727) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Agent role permissions are ignored when there is only a single group [3437](https://github.com/zammad/zammad/issues/3437) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Remote change of the group id does show it falsly as user change and not render the new value to the ticket [3801](https://github.com/zammad/zammad/issues/3801) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Able to create custom fields for existing relation (e. g. ticket.state) - will lead to non bootable Zammad [3811](https://github.com/zammad/zammad/issues/3811) [[bug](https://github.com/zammad/zammad/labels/bug)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Ticket owner selection is not updated if owner selection should be empty [3809](https://github.com/zammad/zammad/issues/3809) [[bug](https://github.com/zammad/zammad/labels/bug)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Job scheduling respects time zone [3802](https://github.com/zammad/zammad/issues/3802) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Chat can't be closed after timeout [2471](https://github.com/zammad/zammad/issues/2471) [[bug](https://github.com/zammad/zammad/labels/bug)] [[chat](https://github.com/zammad/zammad/labels/chat)]
|
||||
- Support workflow mechanism to do pending reminder state hide pending time use case [3790](https://github.com/zammad/zammad/issues/3790) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Cache.clear in postinstall.sh throws ugly errors on fresh installations [3808](https://github.com/zammad/zammad/issues/3808) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- OS package upgrade fails (activity_stream_object_id) [3797](https://github.com/zammad/zammad/issues/3797) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Simple quote characters (`'`) not properly displayed [3733](https://github.com/zammad/zammad/issues/3733) [[bug](https://github.com/zammad/zammad/labels/bug)] [[frontend / JS app](https://github.com/zammad/zammad/labels/frontend%20%2F%20JS%20app)]
|
||||
- Example payload in webhook view leads to 500 error [3794](https://github.com/zammad/zammad/issues/3794) [[bug](https://github.com/zammad/zammad/labels/bug)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Sort order group_by broken (alphabetical) [3800](https://github.com/zammad/zammad/issues/3800) [[bug](https://github.com/zammad/zammad/labels/bug)] [[overviews](https://github.com/zammad/zammad/labels/overviews)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Bug Report 4.1.x Overview Sort - Grouped by user [3737](https://github.com/zammad/zammad/issues/3737) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[overviews](https://github.com/zammad/zammad/labels/overviews)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Article box opening on tickets with no changes [3789](https://github.com/zammad/zammad/issues/3789) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- UploadCacheCleanupJob does not execute [3787](https://github.com/zammad/zammad/issues/3787) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- lib/fill_db.rb fails to work in production environments [3788](https://github.com/zammad/zammad/issues/3788) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Usage of inactive object attributes in SLAs will crash admin SLA interface [3769](https://github.com/zammad/zammad/issues/3769) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Inconstant alignment in the listing of attachments/submit button in new article area [3773](https://github.com/zammad/zammad/issues/3773) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Broken dialog whiling uploading oversized attachment [3774](https://github.com/zammad/zammad/issues/3774) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Improve contrasts in answer search for articles [3783](https://github.com/zammad/zammad/issues/3783) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- escaped 'Set fixed' workflows don't refresh set values on active ticket sessions [3757](https://github.com/zammad/zammad/issues/3757) [[bug](https://github.com/zammad/zammad/labels/bug)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- ObjectManager Attribute without screen attribute causes CoreWorkflows migration to fail [3781](https://github.com/zammad/zammad/issues/3781) [[bug](https://github.com/zammad/zammad/labels/bug)] [[migration / update](https://github.com/zammad/zammad/labels/migration%20%2F%20update)]
|
||||
- Force users to reload after system migration [3776](https://github.com/zammad/zammad/issues/3776) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Zammad preflight check warning output causes Syntax-Error in postinstall.sh and failing installation [2674](https://github.com/zammad/zammad/issues/2674) [[bug](https://github.com/zammad/zammad/labels/bug)] [[migration / update](https://github.com/zammad/zammad/labels/migration%20%2F%20update)]
|
||||
- Fix postinstall.sh getting es_url [3775](https://github.com/zammad/zammad/pull/3775)
|
||||
- Shared organization issue (Create your first ticket) [2780](https://github.com/zammad/zammad/issues/2780) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
- [BUG] miss spell in db/migrate/20210923172256_issue_2619_kb_header_link_color.rb [3777](https://github.com/zammad/zammad/issues/3777) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[migration / update](https://github.com/zammad/zammad/labels/migration%20%2F%20update)]
|
||||
- Unable to cancel attachment upload [2351](https://github.com/zammad/zammad/issues/2351) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- KB header and footer link-color not changeable [2619](https://github.com/zammad/zammad/issues/2619) [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)] [[specification required](https://github.com/zammad/zammad/labels/specification%20required)] [[theming / skinning](https://github.com/zammad/zammad/labels/theming%20%2F%20skinning)]
|
||||
- Syntax errors break scheduler job for good [3028](https://github.com/zammad/zammad/issues/3028) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Existing tickets: New article modal with padding-left: 0; padding-right: 0; [3772](https://github.com/zammad/zammad/issues/3772) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Fix polish translations [3760](https://github.com/zammad/zammad/pull/3760)
|
||||
- Possible race condition causing OTRS import to fail [3765](https://github.com/zammad/zammad/issues/3765) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Incorrect alignment in the listing of attachments when creating a ticket [3746](https://github.com/zammad/zammad/issues/3746) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Saved conditions break on selections without reloading [3758](https://github.com/zammad/zammad/issues/3758) [[bug](https://github.com/zammad/zammad/labels/bug)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Misleading view of user icons which are on vacation and disabled [3075](https://github.com/zammad/zammad/issues/3075) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
|
||||
4
Gemfile
4
Gemfile
@@ -94,6 +94,9 @@ gem 'omniauth-saml'
|
||||
gem 'omniauth-twitter'
|
||||
gem 'omniauth-weibo-oauth2'
|
||||
|
||||
# Rate limiting
|
||||
gem 'rack-attack'
|
||||
|
||||
# channels
|
||||
gem 'gmail_xoauth'
|
||||
gem 'koala'
|
||||
@@ -169,6 +172,7 @@ group :development, :test do
|
||||
# test frameworks
|
||||
gem 'rails-controller-testing'
|
||||
gem 'rspec-rails'
|
||||
gem 'rspec-retry'
|
||||
gem 'shoulda-matchers'
|
||||
gem 'test-unit'
|
||||
|
||||
|
||||
124
Gemfile.lock
124
Gemfile.lock
@@ -19,54 +19,54 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
PoParser (3.2.5)
|
||||
simple_po_parser (~> 1.1.2)
|
||||
PoParser (3.2.6)
|
||||
simple_po_parser (~> 1.1.6)
|
||||
aasm (5.2.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
actioncable (6.0.4.7)
|
||||
actionpack (= 6.0.4.7)
|
||||
actioncable (6.0.4.8)
|
||||
actionpack (= 6.0.4.8)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.0.4.7)
|
||||
actionpack (= 6.0.4.7)
|
||||
activejob (= 6.0.4.7)
|
||||
activerecord (= 6.0.4.7)
|
||||
activestorage (= 6.0.4.7)
|
||||
activesupport (= 6.0.4.7)
|
||||
actionmailbox (6.0.4.8)
|
||||
actionpack (= 6.0.4.8)
|
||||
activejob (= 6.0.4.8)
|
||||
activerecord (= 6.0.4.8)
|
||||
activestorage (= 6.0.4.8)
|
||||
activesupport (= 6.0.4.8)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.0.4.7)
|
||||
actionpack (= 6.0.4.7)
|
||||
actionview (= 6.0.4.7)
|
||||
activejob (= 6.0.4.7)
|
||||
actionmailer (6.0.4.8)
|
||||
actionpack (= 6.0.4.8)
|
||||
actionview (= 6.0.4.8)
|
||||
activejob (= 6.0.4.8)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.0.4.7)
|
||||
actionview (= 6.0.4.7)
|
||||
activesupport (= 6.0.4.7)
|
||||
actionpack (6.0.4.8)
|
||||
actionview (= 6.0.4.8)
|
||||
activesupport (= 6.0.4.8)
|
||||
rack (~> 2.0, >= 2.0.8)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.0.4.7)
|
||||
actionpack (= 6.0.4.7)
|
||||
activerecord (= 6.0.4.7)
|
||||
activestorage (= 6.0.4.7)
|
||||
activesupport (= 6.0.4.7)
|
||||
actiontext (6.0.4.8)
|
||||
actionpack (= 6.0.4.8)
|
||||
activerecord (= 6.0.4.8)
|
||||
activestorage (= 6.0.4.8)
|
||||
activesupport (= 6.0.4.8)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.0.4.7)
|
||||
activesupport (= 6.0.4.7)
|
||||
actionview (6.0.4.8)
|
||||
activesupport (= 6.0.4.8)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
activejob (6.0.4.7)
|
||||
activesupport (= 6.0.4.7)
|
||||
activejob (6.0.4.8)
|
||||
activesupport (= 6.0.4.8)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.0.4.7)
|
||||
activesupport (= 6.0.4.7)
|
||||
activerecord (6.0.4.7)
|
||||
activemodel (= 6.0.4.7)
|
||||
activesupport (= 6.0.4.7)
|
||||
activemodel (6.0.4.8)
|
||||
activesupport (= 6.0.4.8)
|
||||
activerecord (6.0.4.8)
|
||||
activemodel (= 6.0.4.8)
|
||||
activesupport (= 6.0.4.8)
|
||||
activerecord-import (1.3.0)
|
||||
activerecord (>= 4.2)
|
||||
activerecord-nulldb-adapter (0.8.0)
|
||||
@@ -77,12 +77,12 @@ GEM
|
||||
multi_json (~> 1.11, >= 1.11.2)
|
||||
rack (>= 2.0.8, < 3)
|
||||
railties (>= 5.2.4.1)
|
||||
activestorage (6.0.4.7)
|
||||
actionpack (= 6.0.4.7)
|
||||
activejob (= 6.0.4.7)
|
||||
activerecord (= 6.0.4.7)
|
||||
activestorage (6.0.4.8)
|
||||
actionpack (= 6.0.4.8)
|
||||
activejob (= 6.0.4.8)
|
||||
activerecord (= 6.0.4.8)
|
||||
marcel (~> 1.0.0)
|
||||
activesupport (6.0.4.7)
|
||||
activesupport (6.0.4.8)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
@@ -138,7 +138,7 @@ GEM
|
||||
json
|
||||
composite_primary_keys (12.0.10)
|
||||
activerecord (~> 6.0.0)
|
||||
concurrent-ruby (1.1.9)
|
||||
concurrent-ruby (1.1.10)
|
||||
crack (0.4.5)
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
@@ -172,7 +172,7 @@ GEM
|
||||
erubi (1.10.0)
|
||||
eventmachine (1.2.7)
|
||||
execjs (2.8.1)
|
||||
factory_bot (6.2.0)
|
||||
factory_bot (6.2.1)
|
||||
activesupport (>= 5.0.0)
|
||||
factory_bot_rails (6.2.0)
|
||||
factory_bot (~> 6.2.0)
|
||||
@@ -276,7 +276,7 @@ GEM
|
||||
logging (2.3.0)
|
||||
little-plugger (~> 1.1)
|
||||
multi_json (~> 1.14)
|
||||
loofah (2.14.0)
|
||||
loofah (2.16.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
lumberjack (1.2.8)
|
||||
@@ -305,7 +305,7 @@ GEM
|
||||
net-ldap (0.17.0)
|
||||
netrc (0.11.0)
|
||||
nio4r (2.5.8)
|
||||
nokogiri (1.13.3)
|
||||
nokogiri (1.13.6)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
racc (~> 1.4)
|
||||
nori (2.6.0)
|
||||
@@ -383,32 +383,34 @@ GEM
|
||||
binding_of_caller (~> 1.0)
|
||||
pry (~> 0.13)
|
||||
public_suffix (4.0.6)
|
||||
puma (4.3.11)
|
||||
puma (4.3.12)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.2.0)
|
||||
activesupport (>= 3.0.0)
|
||||
pundit-matchers (1.7.0)
|
||||
rspec-rails (>= 3.0.0)
|
||||
racc (1.6.0)
|
||||
rack (2.2.3)
|
||||
rack (2.2.3.1)
|
||||
rack-attack (6.6.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-livereload (0.3.17)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rails (6.0.4.7)
|
||||
actioncable (= 6.0.4.7)
|
||||
actionmailbox (= 6.0.4.7)
|
||||
actionmailer (= 6.0.4.7)
|
||||
actionpack (= 6.0.4.7)
|
||||
actiontext (= 6.0.4.7)
|
||||
actionview (= 6.0.4.7)
|
||||
activejob (= 6.0.4.7)
|
||||
activemodel (= 6.0.4.7)
|
||||
activerecord (= 6.0.4.7)
|
||||
activestorage (= 6.0.4.7)
|
||||
activesupport (= 6.0.4.7)
|
||||
rails (6.0.4.8)
|
||||
actioncable (= 6.0.4.8)
|
||||
actionmailbox (= 6.0.4.8)
|
||||
actionmailer (= 6.0.4.8)
|
||||
actionpack (= 6.0.4.8)
|
||||
actiontext (= 6.0.4.8)
|
||||
actionview (= 6.0.4.8)
|
||||
activejob (= 6.0.4.8)
|
||||
activemodel (= 6.0.4.8)
|
||||
activerecord (= 6.0.4.8)
|
||||
activestorage (= 6.0.4.8)
|
||||
activesupport (= 6.0.4.8)
|
||||
bundler (>= 1.3.0)
|
||||
railties (= 6.0.4.7)
|
||||
railties (= 6.0.4.8)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
@@ -419,9 +421,9 @@ GEM
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.4.2)
|
||||
loofah (~> 2.3)
|
||||
railties (6.0.4.7)
|
||||
actionpack (= 6.0.4.7)
|
||||
activesupport (= 6.0.4.7)
|
||||
railties (6.0.4.8)
|
||||
actionpack (= 6.0.4.8)
|
||||
activesupport (= 6.0.4.8)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.20.3, < 2.0)
|
||||
@@ -456,6 +458,8 @@ GEM
|
||||
rspec-expectations (~> 3.10)
|
||||
rspec-mocks (~> 3.10)
|
||||
rspec-support (~> 3.10)
|
||||
rspec-retry (0.6.2)
|
||||
rspec-core (> 3.3)
|
||||
rspec-support (3.11.0)
|
||||
rszr (0.5.2)
|
||||
rubocop (1.26.0)
|
||||
@@ -508,7 +512,7 @@ GEM
|
||||
shoulda-matchers (5.1.0)
|
||||
activesupport (>= 5.2.0)
|
||||
simple_oauth (0.3.1)
|
||||
simple_po_parser (1.1.5)
|
||||
simple_po_parser (1.1.6)
|
||||
slack-notifier (2.4.0)
|
||||
slack-ruby-client (1.0.0)
|
||||
faraday (>= 1.0)
|
||||
@@ -663,6 +667,7 @@ DEPENDENCIES
|
||||
puma (~> 4)
|
||||
pundit
|
||||
pundit-matchers
|
||||
rack-attack
|
||||
rack-livereload
|
||||
rails (~> 6.0.0)
|
||||
rails-controller-testing
|
||||
@@ -670,6 +675,7 @@ DEPENDENCIES
|
||||
rchardet (>= 1.8.0)
|
||||
redis
|
||||
rspec-rails
|
||||
rspec-retry
|
||||
rszr (= 0.5.2)
|
||||
rubocop
|
||||
rubocop-faker
|
||||
|
||||
@@ -100,7 +100,7 @@ class App.GenericHistory extends App.ControllerModal
|
||||
content += " '#{ @translateItemValue(item, item.value_from) }'"
|
||||
|
||||
if item.value_to
|
||||
if item.value_from
|
||||
if item.value_from || item.object is 'Mention'
|
||||
content += ' →'
|
||||
content += " '#{ @translateItemValue(item, item.value_to) }'"
|
||||
else if item.value_from
|
||||
@@ -114,6 +114,14 @@ class App.GenericHistory extends App.ControllerModal
|
||||
newItems
|
||||
|
||||
translateItemValue: ({object, attribute}, value) ->
|
||||
if object is 'Mention'
|
||||
result = '-'
|
||||
if value
|
||||
user = App.User.find(value)
|
||||
if user
|
||||
result = user.displayName()
|
||||
return result
|
||||
|
||||
localAttribute = @objectAttribute(object, attribute)
|
||||
if localAttribute && localAttribute.tag is 'datetime'
|
||||
return App.i18n.translateTimestamp(value)
|
||||
|
||||
@@ -95,10 +95,14 @@ class ChannelAccountOverview extends App.ControllerSubContent
|
||||
|
||||
channels.push channel
|
||||
|
||||
# auto redirect to gmail account linking if we have no account
|
||||
if @channel_id && channels.length < 1
|
||||
@new()
|
||||
return
|
||||
# on a channel migration we need to auto redirect
|
||||
# the user to the "Add Account" functionality after
|
||||
# the filled up the external credentials
|
||||
if @channel_id
|
||||
item = App.Channel.find(@channel_id)
|
||||
if item && item.area != 'Microsoft365::Account'
|
||||
@new()
|
||||
return
|
||||
|
||||
# get all unlinked email addresses
|
||||
not_used_email_addresses = []
|
||||
@@ -111,9 +115,14 @@ class ChannelAccountOverview extends App.ControllerSubContent
|
||||
not_used_email_addresses: not_used_email_addresses
|
||||
)
|
||||
|
||||
# on a channel creation we will auto open the edit
|
||||
# dialog after the redirect back to zammad to optional
|
||||
# change the inbound configuration, but not for
|
||||
# migrated channel because we guess that the inbound configuration
|
||||
# is already correct for them.
|
||||
if @channel_id
|
||||
item = App.Channel.find(@channel_id)
|
||||
if item && item.options && item.options.backup_imap_classic is undefined
|
||||
if item && item.area == 'Microsoft365::Account' && item.options && item.options.backup_imap_classic is undefined
|
||||
@editInbound(undefined, @channel_id, true)
|
||||
@channel_id = undefined
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@ class ConnectionWizard extends App.ControllerWizardModal
|
||||
|
||||
buildRowGroupRole: (source, dest) =>
|
||||
el = $(App.view('integration/ldap_group_role_row')())
|
||||
el.find('.js-ldapList').html(@createSelection('source', @wizardConfig.wizardData.backend_groups, source))
|
||||
el.find('.js-ldapList').html(@createAutocompletion('source', @wizardConfig.wizardData.backend_groups, source))
|
||||
el.find('.js-roleList').html(@createSelection('dest', @wizardConfig.wizardData.roles, dest))
|
||||
el
|
||||
|
||||
@@ -496,6 +496,34 @@ class ConnectionWizard extends App.ControllerWizardModal
|
||||
class: 'form-control--small'
|
||||
)
|
||||
|
||||
# LDAP with many groups (<5k) and group role relation (>50) will crash in frontend #3994
|
||||
createAutocompletion: (name, options, selected) ->
|
||||
return App.UiElement.autocompletion.render(
|
||||
id: "#{name}#{Math.floor( Math.random() * 999999 ).toString()}"
|
||||
name: name
|
||||
multiple: false
|
||||
null: false
|
||||
nulloption: false
|
||||
class: 'form-control--small'
|
||||
minLengt: -1 # show values without any value
|
||||
value: selected
|
||||
source: (request, response) ->
|
||||
data = Object.keys(options)
|
||||
counter = 0
|
||||
total = 200
|
||||
result = []
|
||||
for entry in data
|
||||
continue if !entry.includes(request.term)
|
||||
break if counter >= total
|
||||
result.push(
|
||||
id: entry
|
||||
label: entry
|
||||
value: entry
|
||||
)
|
||||
counter++
|
||||
response(result)
|
||||
, "#{name}_autocompletion_value_shown": selected)
|
||||
|
||||
removeRow: (e) ->
|
||||
e.preventDefault()
|
||||
$(e.target).closest('tr').remove()
|
||||
|
||||
@@ -49,9 +49,6 @@ class App.ManageKnowledgeBase extends App.ControllerTabs
|
||||
App.KnowledgeBase.find(@knowledge_base_id).remove(clear: true)
|
||||
@fetchAndRender()
|
||||
|
||||
release: ->
|
||||
@modal?.el.remove()
|
||||
|
||||
processLoaded: ->
|
||||
if @knowledge_base_id
|
||||
@renderLoaded()
|
||||
@@ -59,13 +56,18 @@ class App.ManageKnowledgeBase extends App.ControllerTabs
|
||||
@renderNonExistant()
|
||||
|
||||
renderNonExistant: ->
|
||||
@renderScreenError(detail: __('There is no Knowledge Base yet. Please create one.'), el: @$('.page-content'))
|
||||
@headerSwitchInput.prop('checked', false)
|
||||
@headerSwitchInput.attr('disabled', true)
|
||||
|
||||
@modal = new App.KnowledgeBaseNewModal(
|
||||
parentVC: @
|
||||
container: @el.closest('.main')
|
||||
)
|
||||
@tabs =[
|
||||
{
|
||||
name: __('Theme')
|
||||
target: 'style'
|
||||
controller: App.KnowledgeBaseNewController
|
||||
params: { parentVC: @ }
|
||||
}
|
||||
]
|
||||
|
||||
@render()
|
||||
|
||||
didChangeHeaderSwitch: ->
|
||||
@headerSwitchInput.prop('disabled', true)
|
||||
@@ -89,6 +91,8 @@ class App.ManageKnowledgeBase extends App.ControllerTabs
|
||||
)
|
||||
|
||||
renderLoaded: ->
|
||||
@headerSwitchInput.attr('disabled', false)
|
||||
|
||||
params = {
|
||||
knowledge_base_id: @knowledge_base_id
|
||||
parentVC: @
|
||||
|
||||
@@ -56,26 +56,32 @@ class ProfilePassword extends App.ControllerSubContent
|
||||
data: JSON.stringify(params)
|
||||
processData: true
|
||||
success: @success
|
||||
error: @error
|
||||
)
|
||||
|
||||
success: (data) =>
|
||||
if data.message is 'ok'
|
||||
@render()
|
||||
@notify(
|
||||
type: 'success'
|
||||
msg: App.i18n.translateContent( 'Password changed successfully!' )
|
||||
)
|
||||
else
|
||||
if data.notice
|
||||
@notify
|
||||
type: 'error'
|
||||
msg: App.i18n.translateContent( data.notice[0], data.notice[1] )
|
||||
removeAll: true
|
||||
else
|
||||
@notify
|
||||
type: 'error'
|
||||
msg: __('The password could not be set. Please contact your administrator.')
|
||||
removeAll: true
|
||||
@formEnable( @$('form') )
|
||||
success: =>
|
||||
@render()
|
||||
|
||||
@notify(
|
||||
type: 'success'
|
||||
msg: App.i18n.translateContent( 'Password changed successfully!' )
|
||||
)
|
||||
|
||||
error: (xhr, status, error) =>
|
||||
return if xhr.status != 422
|
||||
|
||||
data = xhr.responseJSON
|
||||
|
||||
message = if data.notice
|
||||
App.i18n.translateContent( data.notice[0], data.notice[1] )
|
||||
else
|
||||
__('The password could not be set. Please contact your administrator.')
|
||||
|
||||
@notify
|
||||
type: 'error'
|
||||
msg: message
|
||||
removeAll: true
|
||||
|
||||
@formEnable( @$('form') )
|
||||
|
||||
App.Config.set('Password', { prio: 2000, name: __('Password'), parent: '#profile', target: '#profile/password', controller: ProfilePassword, permission: ['user_preferences.password'] }, 'NavBarProfile')
|
||||
|
||||
@@ -79,6 +79,11 @@ class App.SettingsAreaTicketNumber extends App.Controller
|
||||
el = $(App.view("settings/#{preferences_setting}")(
|
||||
setting: setting
|
||||
))
|
||||
|
||||
for form_entry in setting.options['form']
|
||||
if form_entry['tag'] is 'boolean'
|
||||
form_entry['translate'] = true
|
||||
|
||||
new App.ControllerForm(
|
||||
el: el.find('.js-formItem'),
|
||||
model: { configure_attributes: setting.options['form'], className: '' }
|
||||
|
||||
@@ -94,10 +94,11 @@ class App.UiElement.ApplicationSelector
|
||||
operator: [__('is in working time'), __('is not in working time')]
|
||||
|
||||
else
|
||||
for row in App[groupMeta.model].configure_attributes
|
||||
attributesByObject = App.ObjectManagerAttribute.selectorAttributesByObject()
|
||||
configureAttributes = attributesByObject[groupMeta.model] || []
|
||||
for config in configureAttributes
|
||||
# ignore passwords and relations
|
||||
if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids' && row.searchable isnt false
|
||||
config = _.clone(row)
|
||||
if config.type isnt 'password' && config.name.substr(config.name.length-4,4) isnt '_ids' && config.searchable isnt false
|
||||
if config.tag is 'textarea'
|
||||
config.expanding = false
|
||||
if config.type is 'email' || config.type is 'tel'
|
||||
@@ -113,7 +114,7 @@ class App.UiElement.ApplicationSelector
|
||||
config.operator = operator
|
||||
elements["#{groupKey}.#{config.name}"] = config
|
||||
|
||||
if config.tag == 'select'
|
||||
if /^(tree_|multi)?select$/.test(config.tag)
|
||||
config.multiple = true
|
||||
|
||||
if attribute.out_of_office
|
||||
|
||||
@@ -282,3 +282,37 @@ class App.UiElement.ApplicationUiElement
|
||||
record.disabled = 'disabled'
|
||||
else
|
||||
record.disabled = ''
|
||||
|
||||
@findOption: (options, value) ->
|
||||
return if !_.isArray(options)
|
||||
for option in options
|
||||
return option if option.value is value
|
||||
if option.children
|
||||
result = @findOption(option.children, value)
|
||||
return result if result
|
||||
|
||||
# 1. If attribute.value is not among the current options, then search within historical options
|
||||
# 2. If attribute.value is not among current and historical options, then add the value itself as an option
|
||||
@addDeletedOptions: (attribute) ->
|
||||
return if !_.isEmpty(attribute.relation) # do not apply for attributes with relation, relations will fill options automatically
|
||||
return if attribute.rejectNonExistentValues
|
||||
value = attribute.value
|
||||
return if !value
|
||||
return if !attribute.options
|
||||
|
||||
values = value
|
||||
if !_.isArray(value)
|
||||
values = [value]
|
||||
|
||||
attribute.historical_options ||= {}
|
||||
if _.isArray(attribute.options)
|
||||
for value in values
|
||||
continue if @findOption(attribute.options, value)
|
||||
attribute.options.push(
|
||||
value: value
|
||||
name: attribute.historical_options[value] || value
|
||||
)
|
||||
else
|
||||
for value in values
|
||||
continue if attribute.options[value]
|
||||
attribute.options[value] = attribute.historical_options[value] || value
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.active extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# set attributes
|
||||
attribute.null = false
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.auth_provider
|
||||
@render: (attribute) ->
|
||||
@render: (attributeConfig) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
for key, value of App.Config.get('auth_provider_all')
|
||||
continue if value.config isnt attribute.provider
|
||||
attribute.value = "#{App.Config.get('http_type')}://#{App.Config.get('fqdn')}#{value.url}/callback"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes,no_interpolation_in_single_quotes
|
||||
class App.UiElement.autocompletion
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params = {}) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
if params[ attribute.name + '_autocompletion_value_shown' ]
|
||||
attribute.valueShown = params[ attribute.name + '_autocompletion_value_shown' ]
|
||||
@@ -48,5 +49,11 @@ class App.UiElement.autocompletion
|
||||
select: (event, ui) ->
|
||||
b(event, ui.item)
|
||||
)
|
||||
$(local_attribute_full).on('click', -> $(@).autocomplete('search', $(local_attribute_full).val()))
|
||||
if attribute.value
|
||||
$(local_attribute).val(attribute.value)
|
||||
if attribute.valueShown
|
||||
$(local_attribute_full).val(attribute.valueShown)
|
||||
|
||||
App.Delay.set(a, 280, undefined, 'form_autocompletion')
|
||||
item
|
||||
|
||||
@@ -15,7 +15,7 @@ class App.UiElement.autocompletion_ajax
|
||||
id: params.organization_id || attribute.id
|
||||
placeholder: App.i18n.translateInline('Search…')
|
||||
limit: 40
|
||||
object: attribute.relation
|
||||
relation: attribute.relation
|
||||
ajax: true
|
||||
multiple: attribute.multiple
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.autocompletion_ajax_search extends App.UiElement.autocompletion_ajax
|
||||
@render: (attributeOrig, params = {}, form) ->
|
||||
attribute = _.clone(attributeOrig)
|
||||
@render: (attributeConfig, params = {}, form) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
attribute.multiple = true
|
||||
super(attribute, params = {}, form)
|
||||
|
||||
@@ -4,8 +4,9 @@ class App.UiElement.basedate
|
||||
@templateName: ->
|
||||
throw 'Must override in a subclass'
|
||||
|
||||
@render: (attributeOrig) ->
|
||||
attribute = _.clone(attributeOrig)
|
||||
@render: (attributeConfig) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
attribute.nameRaw = attribute.name
|
||||
attribute.name = "{#{@templateName()}}#{attribute.name}"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.boolean extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# build options list
|
||||
if _.isEmpty(attribute.options)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.business_hours
|
||||
@render: (attributeOrig) ->
|
||||
@render: (attributeConfig) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
attribute = _.clone(attributeOrig)
|
||||
attribute.nameRaw = attribute.name
|
||||
attribute.name = "{business_hours}#{attribute.name}"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.checkbox extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# build options list based on config
|
||||
@getConfigOptionList( attribute, params )
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.checkboxTicketAttributes extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
attributeOptionsArray = []
|
||||
for name, row of App.Ticket.attributesGet()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.column_select extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# set multiple option
|
||||
attribute.multiple = 'multiple'
|
||||
|
||||
@@ -50,16 +50,16 @@ class App.UiElement.core_workflow_condition extends App.UiElement.ApplicationSel
|
||||
|
||||
operatorsType =
|
||||
'active$': [__('is')]
|
||||
'boolean$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
|
||||
'integer$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
|
||||
'^select$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
|
||||
'boolean$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
|
||||
'integer$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
|
||||
'^select$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
|
||||
'^multiselect$': [__('contains'), __('contains not'), __('contains all'), __('contains all not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
|
||||
'^tree_select$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
|
||||
'^(input|textarea|richtext)$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to'), __('regex match'), __('regex mismatch')]
|
||||
'^tree_select$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
|
||||
'^(input|textarea|richtext)$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to'), __('regex match'), __('regex mismatch')]
|
||||
|
||||
operatorsName =
|
||||
'_id$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
|
||||
'_ids$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
|
||||
'_id$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
|
||||
'_ids$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
|
||||
|
||||
# merge config
|
||||
elements = {}
|
||||
@@ -147,13 +147,14 @@ class App.UiElement.core_workflow_condition extends App.UiElement.ApplicationSel
|
||||
multiple: true
|
||||
}
|
||||
|
||||
for row in App[groupMeta.model].configure_attributes
|
||||
continue if !_.contains(['input', 'textarea', 'richtext', 'multiselect', 'select', 'integer', 'boolean', 'active', 'tree_select', 'autocompletion_ajax'], row.tag)
|
||||
continue if groupKey is 'ticket' && _.contains(['number', 'title'], row.name)
|
||||
attributesByObject = App.ObjectManagerAttribute.selectorAttributesByObject()
|
||||
configureAttributes = attributesByObject[groupMeta.model] || []
|
||||
for config in configureAttributes
|
||||
continue if !_.contains(['input', 'textarea', 'richtext', 'multiselect', 'select', 'integer', 'boolean', 'active', 'tree_select', 'autocompletion_ajax'], config.tag)
|
||||
continue if groupKey is 'ticket' && _.contains(['number', 'title'], config.name)
|
||||
|
||||
# ignore passwords and relations
|
||||
if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids' && row.searchable isnt false
|
||||
config = _.clone(row)
|
||||
if config.type isnt 'password' && config.name.substr(config.name.length-4,4) isnt '_ids' && config.searchable isnt false
|
||||
if config.tag is 'textarea'
|
||||
config.expanding = false
|
||||
if /^((multi)?select)$/.test(config.tag)
|
||||
|
||||
@@ -63,17 +63,18 @@ class App.UiElement.core_workflow_perform extends App.UiElement.ApplicationSelec
|
||||
elements['custom.module'] = { name: 'module', display: __('Module'), tag: 'select', multiple: true, options: options, null: false, operator: ['execute'] }
|
||||
continue
|
||||
|
||||
for row in App[groupMeta.model].configure_attributes
|
||||
continue if !_.contains(['input', 'textarea', 'select', 'multiselect', 'integer', 'boolean', 'tree_select', 'date', 'datetime'], row.tag)
|
||||
continue if _.contains(['created_at', 'updated_at'], row.name)
|
||||
continue if groupKey is 'ticket' && _.contains(['number', 'organization_id', 'title', 'escalation_at', 'first_response_escalation_at', 'update_escalation_at', 'close_escalation_at', 'last_contact_at', 'last_contact_agent_at', 'last_contact_customer_at', 'first_response_at', 'close_at'], row.name)
|
||||
attributesByObject = App.ObjectManagerAttribute.selectorAttributesByObject()
|
||||
configureAttributes = attributesByObject[groupMeta.model] || []
|
||||
for config in configureAttributes
|
||||
continue if !_.contains(['input', 'textarea', 'select', 'multiselect', 'integer', 'boolean', 'tree_select', 'date', 'datetime'], config.tag)
|
||||
continue if _.contains(['created_at', 'updated_at'], config.name)
|
||||
continue if groupKey is 'ticket' && _.contains(['number', 'organization_id', 'title', 'escalation_at', 'first_response_escalation_at', 'update_escalation_at', 'close_escalation_at', 'last_contact_at', 'last_contact_agent_at', 'last_contact_customer_at', 'first_response_at', 'close_at'], config.name)
|
||||
|
||||
# ignore passwords and relations
|
||||
if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids' && row.searchable isnt false
|
||||
config = _.clone(row)
|
||||
if config.type isnt 'password' && config.name.substr(config.name.length-4,4) isnt '_ids' && config.searchable isnt false
|
||||
if config.tag is 'boolean'
|
||||
config.tag = 'select'
|
||||
if /^((multi)?select)$/.test(config.tag)
|
||||
if /^(tree_|multi)?select$/.test(config.tag)
|
||||
config.multiple = true
|
||||
config.default = undefined
|
||||
if config.type is 'email' || config.type is 'tel'
|
||||
@@ -121,14 +122,14 @@ class App.UiElement.core_workflow_perform extends App.UiElement.ApplicationSelec
|
||||
currentOperator = elementRow.find('.js-operator option:selected').attr('value')
|
||||
name = @buildValueName(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
|
||||
|
||||
if !_.contains(['add_option', 'remove_option', 'set_fixed_to', 'select', 'multiselect', 'execute', 'fill_in', 'fill_in_empty'], currentOperator)
|
||||
if !_.contains(['add_option', 'remove_option', 'set_fixed_to', 'select', 'execute', 'fill_in', 'fill_in_empty'], currentOperator)
|
||||
elementRow.find('.js-value').addClass('hide').html('<input type="hidden" name="' + name + '" value="true" />')
|
||||
return
|
||||
|
||||
super(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
|
||||
|
||||
@buildValueConfigMultiple: (config, meta) ->
|
||||
if _.contains(['add_option', 'remove_option', 'set_fixed_to', 'select', 'multiselect'], meta.operator)
|
||||
if _.contains(['add_option', 'remove_option', 'set_fixed_to', 'select'], meta.operator)
|
||||
config.multiple = true
|
||||
config.nulloption = true
|
||||
else
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.datetime_search
|
||||
@render: (attributeOrig) ->
|
||||
attribute = _.clone(attributeOrig)
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
attribute.disable_feature = true
|
||||
attribute.null = false
|
||||
App.UiElement.datetime.render(attribute)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.integer
|
||||
@render: (attribute) ->
|
||||
@render: (attributeConfig) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
attribute.type = 'number'
|
||||
attribute.step = '1'
|
||||
item = $( App.view('generic/input')(attribute: attribute) )
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.multiselect extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params, form = {}) ->
|
||||
@render: (attributeConfig, params, form = {}) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# set multiple option
|
||||
attribute.multiple = 'multiple'
|
||||
@@ -37,34 +38,6 @@ class App.UiElement.multiselect extends App.UiElement.ApplicationUiElement
|
||||
# return item
|
||||
$( App.view('generic/select')(attribute: attribute) )
|
||||
|
||||
# 1. If attribute.value is not among the current options, then search within historical options
|
||||
# 2. If attribute.value is not among current and historical options, then add the value itself as an option
|
||||
@addDeletedOptions: (attribute) ->
|
||||
return if !_.isEmpty(attribute.relation) # do not apply for attributes with relation, relations will fill options automatically
|
||||
return if attribute.rejectNonExistentValues
|
||||
value = attribute.value
|
||||
return if !value
|
||||
return if _.isArray(value)
|
||||
return if !attribute.options
|
||||
return if !_.isObject(attribute.options)
|
||||
return if value of attribute.options
|
||||
return if value in (temp for own prop, temp of attribute.options)
|
||||
|
||||
if _.isArray(attribute.options)
|
||||
# Array of Strings (value)
|
||||
return if value of attribute.options
|
||||
|
||||
# Array of Objects (for ordering purposes)
|
||||
return if attribute.options.filter((elem) -> elem.value == value) isnt null
|
||||
else
|
||||
# regular Object
|
||||
return if value in (temp for own prop, temp of attribute.options)
|
||||
|
||||
if attribute.historical_options && value of attribute.historical_options
|
||||
attribute.options[value] = attribute.historical_options[value]
|
||||
else
|
||||
attribute.options[value] = value
|
||||
|
||||
@_selectedOptionsIsSelected: (value, record) ->
|
||||
if _.isArray(value)
|
||||
for valueItem in value
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.multiselect_search extends App.UiElement.ApplicationUiElement
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# set multiple option
|
||||
if attribute.multiple
|
||||
attribute.multiple = 'multiple'
|
||||
else
|
||||
attribute.multiple = ''
|
||||
|
||||
delete attribute.filter
|
||||
|
||||
# build options list based on config
|
||||
@getConfigOptionList(attribute, params)
|
||||
|
||||
# build options list based on relation
|
||||
@getRelationOptionList(attribute, params)
|
||||
|
||||
# add null selection if needed
|
||||
@addNullOption(attribute, params)
|
||||
|
||||
# sort attribute.options
|
||||
@sortOptions(attribute, params)
|
||||
|
||||
# find selected/checked item of list
|
||||
@selectedOptions(attribute, params)
|
||||
|
||||
# disable item of list
|
||||
@disabledOptions(attribute, params)
|
||||
|
||||
# filter attributes
|
||||
@filterOption(attribute, params)
|
||||
|
||||
# return item
|
||||
$( App.view('generic/select')(attribute: attribute) )
|
||||
@@ -2,7 +2,8 @@
|
||||
class App.UiElement.radio extends App.UiElement.ApplicationUiElement
|
||||
@template_name: 'radio'
|
||||
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# build options list based on config
|
||||
@getConfigOptionList(attribute, params)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.richtext
|
||||
@render: (attribute, params, form) ->
|
||||
@render: (attributeConfig, params, form) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
if _.isObject(attribute.value)
|
||||
attribute.attachments = attribute.value.attachments
|
||||
attribute.value = attribute.value.text
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.searchable_select extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# set multiple option
|
||||
if attribute.multiple
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.select extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params, form = {}) ->
|
||||
@render: (attributeConfig, params, form = {}) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# set multiple option
|
||||
if attribute.multiple
|
||||
@@ -59,7 +60,7 @@ class App.UiElement.select extends App.UiElement.ApplicationUiElement
|
||||
@shouldDisplayWarn: (selectedVal, attribute, params) ->
|
||||
return if !selectedVal
|
||||
return if !params
|
||||
|
||||
|
||||
params[attribute.name + '_is_display_warning'](selectedVal)
|
||||
|
||||
@toggleDisplayWarn: (warn_visible, attribute, item) ->
|
||||
@@ -73,30 +74,3 @@ class App.UiElement.select extends App.UiElement.ApplicationUiElement
|
||||
warn_elem.html(attribute.warn)
|
||||
item.append(warn_elem)
|
||||
|
||||
# 1. If attribute.value is not among the current options, then search within historical options
|
||||
# 2. If attribute.value is not among current and historical options, then add the value itself as an option
|
||||
@addDeletedOptions: (attribute) ->
|
||||
return if !_.isEmpty(attribute.relation) # do not apply for attributes with relation, relations will fill options automatically
|
||||
return if attribute.rejectNonExistentValues
|
||||
value = attribute.value
|
||||
return if !value
|
||||
return if _.isArray(value)
|
||||
return if !attribute.options
|
||||
return if !_.isObject(attribute.options)
|
||||
return if value of attribute.options
|
||||
return if value in (temp for own prop, temp of attribute.options)
|
||||
|
||||
if _.isArray(attribute.options)
|
||||
# Array of Strings (value)
|
||||
return if value of attribute.options
|
||||
|
||||
# Array of Objects (for ordering purposes)
|
||||
return if attribute.options.filter((elem) -> elem.value == value) isnt null
|
||||
else
|
||||
# regular Object
|
||||
return if value in (temp for own prop, temp of attribute.options)
|
||||
|
||||
if attribute.historical_options && value of attribute.historical_options
|
||||
attribute.options[value] = attribute.historical_options[value]
|
||||
else
|
||||
attribute.options[value] = value
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.selectTicketAttributes extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
attributeOptionsArray = []
|
||||
for name, row of App.Ticket.attributesGet()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.select_search extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# set multiple option
|
||||
if attribute.multiple
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.tag
|
||||
@render: (attribute) ->
|
||||
@render: (attributeConfig) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
if !attribute.id
|
||||
attribute.id = 'tag-' + new Date().getTime() + '-' + Math.floor(Math.random() * 999999)
|
||||
item = $( App.view('generic/input')(attribute: attribute) )
|
||||
@@ -11,7 +12,7 @@ class App.UiElement.tag
|
||||
createTokensOnBlur: true
|
||||
autocomplete: {
|
||||
source: source
|
||||
minLength: 2
|
||||
minLength: 1
|
||||
response: (e, ui) ->
|
||||
return if !ui
|
||||
return if !ui.content
|
||||
|
||||
@@ -64,7 +64,8 @@ class App.UiElement.ticket_perform_action
|
||||
item.find('.js-attributeSelector').prepend(selector)
|
||||
item
|
||||
|
||||
@render: (attribute, params = {}) ->
|
||||
@render: (attributeConfig, params = {}) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
[defaults, groups, elements] = @defaults(attribute)
|
||||
|
||||
@@ -319,6 +320,8 @@ class App.UiElement.ticket_perform_action
|
||||
config['value'] = _.clone(attribute.value[groupAndAttribute]['value'])
|
||||
config.multiple = false
|
||||
config.nulloption = config.null
|
||||
if config.tag is 'multiselect'
|
||||
config.multiple = true
|
||||
if config.tag is 'checkbox'
|
||||
config.tag = 'select'
|
||||
tagSearch = "#{config.tag}_search"
|
||||
@@ -450,7 +453,7 @@ class App.UiElement.ticket_perform_action
|
||||
name: "#{name}::internal"
|
||||
multiple: false
|
||||
null: false
|
||||
options: { true: 'internal', false: 'public' }
|
||||
options: { true: __('internal'), false: __('public') }
|
||||
value: meta.internal || 'false'
|
||||
translate: true
|
||||
)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.time_range
|
||||
@render: (attribute) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
ranges =
|
||||
minute: __('Minute(s)')
|
||||
hour: __('Hour(s)')
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.timer
|
||||
@render: (attribute) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
days =
|
||||
Mon: __('Monday')
|
||||
Tue: __('Tuesday')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.timezone extends App.UiElement.ApplicationUiElement
|
||||
@render: (attribute, params) ->
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
attribute.options = []
|
||||
timezones = App.Config.get('timezones')
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.tree_select extends App.UiElement.ApplicationUiElement
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# set multiple option
|
||||
if attribute.multiple
|
||||
attribute.multiple = 'multiple'
|
||||
else
|
||||
attribute.multiple = ''
|
||||
|
||||
# add deleted historical options if required
|
||||
@addDeletedOptions(attribute, params)
|
||||
|
||||
# build options list based on config
|
||||
@getConfigOptionList(attribute, params)
|
||||
|
||||
# build options list based on relation
|
||||
@getRelationOptionList(attribute, params)
|
||||
|
||||
# add null selection if needed
|
||||
@addNullOption(attribute, params)
|
||||
|
||||
# sort attribute.options
|
||||
@sortOptions(attribute, params)
|
||||
|
||||
# find selected/checked item of list
|
||||
if attribute.options
|
||||
@optionsSelect(attribute.options, attribute.value)
|
||||
|
||||
# disable item of list
|
||||
@disabledOptions(attribute, params)
|
||||
|
||||
# filter attributes
|
||||
@filterOption(attribute, params)
|
||||
|
||||
new App.SearchableSelect(attribute: attribute).element()
|
||||
|
||||
@optionsSelect: (children, value) ->
|
||||
return if !children
|
||||
for child in children
|
||||
@@ -37,34 +73,3 @@ class App.UiElement.tree_select extends App.UiElement.ApplicationUiElement
|
||||
@filterOptionArray: (attribute) ->
|
||||
attribute.options = @filterTreeOptions(attribute.filter, 0, attribute.options, attribute.null)
|
||||
|
||||
@render: (attribute, params) ->
|
||||
|
||||
# set multiple option
|
||||
if attribute.multiple
|
||||
attribute.multiple = 'multiple'
|
||||
else
|
||||
attribute.multiple = ''
|
||||
|
||||
# build options list based on config
|
||||
@getConfigOptionList(attribute, params)
|
||||
|
||||
# build options list based on relation
|
||||
@getRelationOptionList(attribute, params)
|
||||
|
||||
# add null selection if needed
|
||||
@addNullOption(attribute, params)
|
||||
|
||||
# sort attribute.options
|
||||
@sortOptions(attribute, params)
|
||||
|
||||
# find selected/checked item of list
|
||||
if attribute.options
|
||||
@optionsSelect(attribute.options, attribute.value)
|
||||
|
||||
# disable item of list
|
||||
@disabledOptions(attribute, params)
|
||||
|
||||
# filter attributes
|
||||
@filterOption(attribute, params)
|
||||
|
||||
new App.SearchableSelect(attribute: attribute).element()
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.tree_select_search extends App.UiElement.ApplicationUiElement
|
||||
@render: (localAttribute, params) ->
|
||||
|
||||
# clone original attribute
|
||||
attribute = clone(localAttribute)
|
||||
@render: (attributeConfig, params) ->
|
||||
attribute = $.extend(true, {}, attributeConfig)
|
||||
|
||||
# set multiple option
|
||||
attribute.multiple = 'multiple'
|
||||
|
||||
# add null selection if needed
|
||||
@addNullOption(attribute, params)
|
||||
|
||||
# sort attribute.options
|
||||
@sortOptions(attribute, params)
|
||||
|
||||
|
||||
@@ -246,7 +246,7 @@ class App.TicketCreate extends App.Controller
|
||||
|
||||
if _.isEmpty(params.ticket_id) && _.isEmpty(params.article_id)
|
||||
if !_.isEmpty(params.customer_id)
|
||||
@renderQueue(options: params)
|
||||
@renderQueue(options: _.omit(params, 'id'))
|
||||
return
|
||||
@renderQueue()
|
||||
return
|
||||
|
||||
@@ -119,7 +119,7 @@ class App.KnowledgeBaseContentCanBePublishedForm extends App.ControllerForm
|
||||
default: 'now'
|
||||
options: [
|
||||
value: 'now'
|
||||
name: 'now'
|
||||
name: __('now')
|
||||
,
|
||||
value: 'scheduled'
|
||||
name: __('Schedule for')
|
||||
|
||||
@@ -58,6 +58,10 @@ class App.KnowledgeBaseContentController extends App.Controller
|
||||
App.KnowledgeBaseFormController.compareParams(remoteParams, @startingParams)
|
||||
|
||||
objectRefreshed: ->
|
||||
if !@object.exists()
|
||||
@parentController.renderNotAvailableAnymore()
|
||||
return
|
||||
|
||||
@renderAvailabilityWidgets()
|
||||
|
||||
if @remoteDidntChangeSinceStart()
|
||||
|
||||
@@ -47,5 +47,5 @@ class App.KnowledgeBasePublicMenuManager extends App.Controller
|
||||
new App.KnowledgeBasePublicMenuForm(
|
||||
location: location,
|
||||
knowledge_base_id: @knowledge_base_id
|
||||
container: @el.closest('.main')
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
@@ -1502,7 +1502,7 @@ class InputsRef extends App.ControllerAppContent
|
||||
id: 'user-123'
|
||||
placeholder: __('Enter User')
|
||||
limt: 10
|
||||
object: 'User'
|
||||
relation: 'User'
|
||||
|
||||
@$('.searchableAjaxSelectPlaceholder').replaceWith( searchableAjaxSelectObject.element() )
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ class App.Search extends App.Controller
|
||||
tabModel = $(e.currentTarget).data('tab-content')
|
||||
tabs.find('.js-tab').removeClass('active')
|
||||
$(e.currentTarget).addClass('active')
|
||||
@renderTab(tabModel, @result[tabModel] || [])
|
||||
@renderTab(tabModel, @result?[tabModel] || [])
|
||||
|
||||
renderTab: (model, localList) =>
|
||||
|
||||
@@ -205,6 +205,7 @@ class App.Search extends App.Controller
|
||||
items.slice(startId+1, endId).find('[name="bulk"]').prop('checked', (-> !@checked))
|
||||
|
||||
@lastChecked = e.currentTarget
|
||||
@bulkForm.updateTicketIdsBulkForm(e)
|
||||
|
||||
ticket_ids = []
|
||||
for item in localList
|
||||
@@ -231,15 +232,16 @@ class App.Search extends App.Controller
|
||||
@search(true)
|
||||
@delay(callback, 100)
|
||||
|
||||
@bulkForm.releaseController() if @bulkForm
|
||||
@bulkForm = new App.TicketBulkForm(
|
||||
holder: localeEl
|
||||
view: @view
|
||||
callback: updateSearch
|
||||
el: @el.find('.bulkAction')
|
||||
holder: localeEl
|
||||
view: @view
|
||||
callback: updateSearch
|
||||
noSidebar: true
|
||||
)
|
||||
|
||||
# start bulk action observ
|
||||
@el.append(@bulkForm.el)
|
||||
localElement = @$('.js-content')
|
||||
if localElement.find('input[name="bulk"]:checked').length isnt 0
|
||||
@bulkForm.show()
|
||||
|
||||
@@ -959,7 +959,7 @@ class Table extends App.Controller
|
||||
ticketListShow.push App.Ticket.find(ticket.id)
|
||||
@overview = App.Overview.find(overview.id)
|
||||
@table.update(
|
||||
overviewAttributes: @overview.view.s
|
||||
overviewAttributes: @convertOverviewAttributesToArray(@overview.view.s)
|
||||
objects: ticketListShow
|
||||
groupBy: @overview.group_by
|
||||
groupDirection: @overview.group_direction
|
||||
@@ -977,7 +977,6 @@ class Table extends App.Controller
|
||||
return if !overview && !tickets
|
||||
|
||||
@view_mode = App.LocalStorage.get("mode:#{@view}", @Session.get('id')) || 's'
|
||||
console.log 'notice', 'view:', @view, @view_mode
|
||||
|
||||
App.WebSocket.send(event:'ticket_overview_select', data: { view: @view })
|
||||
|
||||
@@ -1107,8 +1106,7 @@ class Table extends App.Controller
|
||||
items.slice(startId+1, endId).find('[name="bulk"]').prop('checked', (-> !@checked))
|
||||
|
||||
@lastChecked = e.currentTarget
|
||||
|
||||
@updateTicketIdsBulkForm()
|
||||
@bulkForm.updateTicketIdsBulkForm(e)
|
||||
|
||||
callbackIconHeader = (headers) ->
|
||||
attribute =
|
||||
@@ -1178,7 +1176,7 @@ class Table extends App.Controller
|
||||
|
||||
tableArguments =
|
||||
tableId: "ticket_overview_#{@overview.id}"
|
||||
overview: @overview.view.s
|
||||
overview: @convertOverviewAttributesToArray(@overview.view.s)
|
||||
el: @$('.table-overview')
|
||||
model: App.Ticket
|
||||
objects: ticketListShow
|
||||
@@ -1212,13 +1210,14 @@ class Table extends App.Controller
|
||||
|
||||
@renderPopovers()
|
||||
|
||||
@bulkForm.releaseController() if @bulkForm
|
||||
@bulkForm = new App.TicketBulkForm(
|
||||
el: @el.find('.bulkAction')
|
||||
holder: @el
|
||||
view: @view
|
||||
view: @view
|
||||
)
|
||||
|
||||
# start bulk action observ
|
||||
@el.append(@bulkForm.el)
|
||||
localElement = @$('.table-overview')
|
||||
if localElement.find('input[name="bulk"]:checked').length isnt 0
|
||||
@bulkForm.show()
|
||||
@@ -1249,10 +1248,14 @@ class Table extends App.Controller
|
||||
bulkAll.prop('indeterminate', true)
|
||||
)
|
||||
|
||||
updateTicketIdsBulkForm: =>
|
||||
items = $('.content.active .table-overview .table').find('[name="bulk"]:checked')
|
||||
ticket_ids = _.map(items, (el) -> $(el).val() )
|
||||
@bulkForm.el.find('input[name=ticket_ids]').val(ticket_ids.join(',')).trigger('change')
|
||||
convertOverviewAttributesToArray: (overviewAttributes) ->
|
||||
# Ensure that the given attributes for the overview is an array,
|
||||
# otherwise some data might not be displayed.
|
||||
# For more details, see https://github.com/zammad/zammad/issues/3943.
|
||||
if !Array.isArray(overviewAttributes)
|
||||
overviewAttributes = [overviewAttributes]
|
||||
|
||||
overviewAttributes
|
||||
|
||||
renderCustomerNotTicketExistIfNeeded: (ticketListShow) =>
|
||||
user = App.User.current()
|
||||
@@ -1354,8 +1357,8 @@ class App.OverviewSettings extends App.ControllerModal
|
||||
null: false
|
||||
translate: true
|
||||
options:
|
||||
ASC: 'up'
|
||||
DESC: 'down'
|
||||
ASC: __('up')
|
||||
DESC: __('down')
|
||||
},
|
||||
{
|
||||
name: 'group_by'
|
||||
@@ -1375,8 +1378,8 @@ class App.OverviewSettings extends App.ControllerModal
|
||||
null: false
|
||||
translate: true
|
||||
options:
|
||||
ASC: 'up'
|
||||
DESC: 'down'
|
||||
ASC: __('up')
|
||||
DESC: __('down')
|
||||
},)
|
||||
|
||||
controller = new App.ControllerForm(
|
||||
|
||||
@@ -14,19 +14,23 @@ class App.TicketZoomArticleImageView extends App.ControllerModal
|
||||
constructor: ->
|
||||
super
|
||||
@unbindAll()
|
||||
$(document).on('keydown.image_preview', 'right', (e) =>
|
||||
nextElement = @parentElement.closest('.attachment').next('.attachment.attachment--preview')
|
||||
return if nextElement.length is 0
|
||||
@close()
|
||||
nextElement.find('img').trigger('click')
|
||||
)
|
||||
$(document).on('keydown.image_preview', 'left', (e) =>
|
||||
prevElement = @parentElement.closest('.attachment').prev('.attachment.attachment--preview')
|
||||
return if prevElement.length is 0
|
||||
@close()
|
||||
prevElement.find('img').trigger('click')
|
||||
$(document).on('keydown.image_preview', (e) =>
|
||||
return @nextRight() if e.keyCode is 39 # right
|
||||
return @nextLeft() if e.keyCode is 37 # left
|
||||
)
|
||||
|
||||
nextRight: =>
|
||||
nextElement = @parentElement.closest('.attachment').next('.attachment.attachment--preview')
|
||||
return if nextElement.length is 0
|
||||
@close()
|
||||
nextElement.find('img').trigger('click')
|
||||
|
||||
nextLeft: =>
|
||||
prevElement = @parentElement.closest('.attachment').prev('.attachment.attachment--preview')
|
||||
return if prevElement.length is 0
|
||||
@close()
|
||||
prevElement.find('img').trigger('click')
|
||||
|
||||
content: ->
|
||||
@image = @image.replace(/view=preview/, 'view=inline')
|
||||
"<div class=\"centered imagePreview\">#{@image}</div>"
|
||||
|
||||
@@ -483,6 +483,10 @@ class ArticleViewItem extends App.ControllerObserver
|
||||
@el.remove()
|
||||
|
||||
imageView: (e) ->
|
||||
# take care of images surrounded by a link
|
||||
if e.target && e.target.parentNode && e.target.parentNode.nodeName.toLowerCase() == 'a'
|
||||
return false
|
||||
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
new App.TicketZoomArticleImageView(image: $(e.target).get(0).outerHTML, parentElement: $(e.currentTarget))
|
||||
|
||||
@@ -18,8 +18,6 @@ class App.TicketZoomAttributeBar extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@secondaryAction = @getAction()
|
||||
|
||||
@subscribeId = App.Macro.subscribe(@checkMacroChanges)
|
||||
@render()
|
||||
|
||||
@@ -97,7 +95,7 @@ class App.TicketZoomAttributeBar extends App.Controller
|
||||
sharedDraftButtonShown: sharedDraftButtonShown
|
||||
))
|
||||
|
||||
@setSecondaryAction(@secondaryAction, localeEl)
|
||||
@setSecondaryAction(@getAction(), localeEl)
|
||||
|
||||
if @ticket.currentView() is 'agent'
|
||||
@taskbarWatcher = new App.TaskbarWatcher(
|
||||
|
||||
@@ -191,7 +191,11 @@ class App.FormHandlerCoreWorkflow
|
||||
return if _.isEmpty(data)
|
||||
|
||||
for field, values of data
|
||||
form.find('[name="' + field + '"]').val(data[field])
|
||||
fieldElement = $("div[data-attribute-name='" + field + "']")
|
||||
if fieldElement.hasClass('tree_select')
|
||||
fieldElement.find(".js-option[data-value='" + data[field] + "']").trigger('click')
|
||||
else
|
||||
form.find('[name="' + field + '"]').val(data[field])
|
||||
coreWorkflowParams[classname][field] = data[field]
|
||||
|
||||
# fill in data in input fields
|
||||
|
||||
@@ -50,6 +50,9 @@ class User extends App.ControllerSubContent
|
||||
@delay(@search, 220, 'search')
|
||||
)
|
||||
|
||||
# App.User.subscribe will clear model data so we use controllerBind (#4040)
|
||||
@controllerBind('User:create User:update User:touch User:destroy', => @delay(@search, 220, 'search'))
|
||||
|
||||
# show last 20 users
|
||||
@search()
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class App.WidgetLinkKbAnswer extends App.WidgetLink
|
||||
name: 'input'
|
||||
placeholder: App.i18n.translateInline('Search…')
|
||||
limit: 40
|
||||
object: 'KnowledgeBaseAnswerTranslation'
|
||||
relation: 'KnowledgeBaseAnswerTranslation'
|
||||
ajax: true
|
||||
).element())
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ class App.TicketBulkForm extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
return if !@permissionCheck('ticket.agent')
|
||||
|
||||
@configure_attributes_ticket = []
|
||||
|
||||
used_attributes = ['state_id', 'pending_time', 'priority_id', 'group_id', 'owner_id']
|
||||
@@ -241,3 +243,8 @@ class App.TicketBulkForm extends App.Controller
|
||||
@render()
|
||||
@hide()
|
||||
)
|
||||
|
||||
updateTicketIdsBulkForm: (e) ->
|
||||
items = $(e.target).closest('table').find('input[name="bulk"]:checked')
|
||||
ticket_ids = _.map(items, (el) -> $(el).val() )
|
||||
@el.find('input[name=ticket_ids]').val(ticket_ids.join(',')).trigger('change')
|
||||
|
||||
@@ -34,7 +34,8 @@ class App.MultiLocalesRow extends App.Controller
|
||||
name: name
|
||||
value: value
|
||||
null: false
|
||||
placeholder: __('Select locale…')
|
||||
translate: true
|
||||
placeholder: App.i18n.translatePlain('Select locale…')
|
||||
options: [] #formattedLocales
|
||||
class: 'form-control--small'
|
||||
)
|
||||
|
||||
@@ -41,7 +41,7 @@ class App.SearchableSelect extends Spine.Controller
|
||||
|
||||
tokens = ''
|
||||
if @attribute.multiple && @attribute.value
|
||||
object = @attribute.object
|
||||
relation = @attribute.relation
|
||||
|
||||
# fallback for if the value is not an array
|
||||
if typeof @attribute.value isnt 'object'
|
||||
@@ -50,8 +50,8 @@ class App.SearchableSelect extends Spine.Controller
|
||||
# create tokens and attribute values
|
||||
values = []
|
||||
for dataId in @attribute.value
|
||||
if App[object].exists dataId
|
||||
name = App[object].find(dataId).displayName()
|
||||
if App[relation] && App[relation].exists(dataId)
|
||||
name = App[relation].find(dataId).displayName()
|
||||
value = dataId
|
||||
values.push({name: name, value: value})
|
||||
tokens += App.view('generic/token')(
|
||||
@@ -160,6 +160,8 @@ class App.SearchableSelect extends Spine.Controller
|
||||
if !@input.val() && !@attribute.multiple
|
||||
@updateAttributeValueName()
|
||||
@input.val(@attribute.valueName)
|
||||
@input.trigger('change')
|
||||
@shadowInput.trigger('change')
|
||||
|
||||
onKeyUp: =>
|
||||
return if @input.val().trim() isnt '' || @attribute.multiple
|
||||
@@ -278,9 +280,7 @@ class App.SearchableSelect extends Spine.Controller
|
||||
@addValueToShadowInput(currentText, dataId)
|
||||
else
|
||||
@input.val currentText
|
||||
@input.trigger('change')
|
||||
@shadowInput.val dataId
|
||||
@shadowInput.trigger('change')
|
||||
|
||||
navigateIn: (event) ->
|
||||
event.stopPropagation()
|
||||
|
||||
@@ -948,7 +948,7 @@ class App.Utils
|
||||
tmp.find('blockquote').remove()
|
||||
text = tmp.text()
|
||||
|
||||
matchwords = ['Attachment', 'attachment', 'Attached', 'attached', 'Enclosed', 'enclosed', 'Enclosure', 'enclosure']
|
||||
matchwords = [__('Attachment'), __('attachment'), __('Attached'), __('attached'), __('Enclosed'), __('enclosed'), __('Enclosure'), __('enclosure')]
|
||||
for word in matchwords
|
||||
# en
|
||||
attachmentTranslatedRegExp = new RegExp("\\W#{word}\\W", 'i')
|
||||
|
||||
@@ -10,7 +10,7 @@ class App.SearchableAjaxSelect extends App.SearchableSelect
|
||||
|
||||
# convert requested object
|
||||
# e.g. Ticket to ticket or AnotherObject to another_object
|
||||
objectString = underscored(@options.attribute.object)
|
||||
objectString = underscored(@options.attribute.relation)
|
||||
|
||||
query = @input.val()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class App.Calendar extends App.Model
|
||||
@configure 'Calendar', 'name', 'timezone', 'default', 'business_hours', 'ical_url', 'public_holidays', 'note'
|
||||
@configure 'Calendar', 'name', 'timezone', 'default', 'business_hours', 'ical_url', 'public_holidays'
|
||||
@extend Spine.Model.Ajax
|
||||
@url: @apiPath + '/calendars'
|
||||
|
||||
@@ -9,7 +9,6 @@ class App.Calendar extends App.Model
|
||||
{ name: 'business_hours', display: __('Business Hours'), tag: 'business_hours', null: true }
|
||||
{ name: 'ical_url', display: __('Holidays iCalendar Feed'), tag: 'ical_feed', placeholder: 'http://example.com/public_holidays.ical', null: true }
|
||||
{ name: 'public_holidays',display: __('Holidays'), tag: 'holiday_selector', null: true }
|
||||
{ name: 'note', display: __('Note'), tag: 'textarea', limit: 250, null: true },
|
||||
{ name: 'created_by_id', display: __('Created by'), relation: 'User', readonly: 1 },
|
||||
{ name: 'created_at', display: __('Created'), tag: 'datetime', readonly: 1 },
|
||||
{ name: 'updated_by_id', display: __('Updated by'), relation: 'User', readonly: 1 },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class App.CoreWorkflow extends App.Model
|
||||
@configure 'CoreWorkflow', 'name', 'object', 'preferences', 'condition_saved', 'condition_selected', 'perform', 'priority', 'active'
|
||||
@configure 'CoreWorkflow', 'name', 'object', 'preferences', 'condition_saved', 'condition_selected', 'perform', 'stop_after_match', 'priority', 'active'
|
||||
@extend Spine.Model.Ajax
|
||||
@url: @apiPath + '/core_workflows'
|
||||
@configure_attributes = [
|
||||
|
||||
@@ -39,11 +39,11 @@ class App.Group extends App.Model
|
||||
cssClass: cssClass.join(' ')
|
||||
|
||||
@accesses: ->
|
||||
read: 'Read'
|
||||
create: 'Create'
|
||||
change: 'Change'
|
||||
overview: 'Overview'
|
||||
full: 'Full'
|
||||
read: __('Read')
|
||||
create: __('Create')
|
||||
change: __('Change')
|
||||
overview: __('Overview')
|
||||
full: __('Full')
|
||||
|
||||
signature_id_is_display_warning: (signature_id) ->
|
||||
!App.Signature.find(signature_id).active
|
||||
|
||||
@@ -6,7 +6,7 @@ class App.Macro extends App.Model
|
||||
{ name: 'name', display: __('Name'), tag: 'input', type: 'text', limit: 100, null: false },
|
||||
{ name: 'perform', display: __('Actions'), tag: 'ticket_perform_action', null: true
|
||||
},
|
||||
{ name: 'ux_flow_next_up', display: __('Once completed…'), tag: 'select', default: 'none', options: {
|
||||
{ name: 'ux_flow_next_up', display: __('Once completed…'), tag: 'select', default: 'none', translate: true, options: {
|
||||
none: __('Stay on tab'), next_task: __('Close tab'), next_task_on_close: __('Close tab on ticket close'), next_from_overview: __('Advance to next ticket from overview')
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,3 +11,30 @@ class App.ObjectManagerAttribute extends App.Model
|
||||
{ name: 'updated_at', display: __('Updated'), tag: 'datetime', readonly: 1 },
|
||||
{ name: 'position', display: __('Position'), tag: 'integer', type: 'number', limit: 100, null: true },
|
||||
]
|
||||
|
||||
# This function will return all attributes
|
||||
# based on the frontend model attributes combined
|
||||
# with object manager attributes which are merged like
|
||||
# in app/models/object_manager/element/backend.rb.
|
||||
@selectorAttributesByObject: ->
|
||||
result = {}
|
||||
for row in @all()
|
||||
continue if !row.object
|
||||
|
||||
config = _.clone(row)
|
||||
config.tag = config.data_type
|
||||
config = Object.assign({}, config, config.data_option) if config.data_option
|
||||
|
||||
result[config.object] ||= []
|
||||
result[config.object].push(config)
|
||||
|
||||
for object in Object.keys(result)
|
||||
continue if !App[object]
|
||||
continue if !App[object].configure_attributes
|
||||
|
||||
names = _.map(result[object], (row) -> row.name)
|
||||
for row in App[object].configure_attributes
|
||||
continue if _.contains(names, row.name)
|
||||
result[object].push(_.clone(row))
|
||||
|
||||
result
|
||||
|
||||
@@ -31,12 +31,12 @@ class App.Overview extends App.Model
|
||||
name: 'order::direction'
|
||||
display: __('Order by Direction')
|
||||
tag: 'select'
|
||||
default: 'down'
|
||||
default: 'DESC'
|
||||
null: false
|
||||
translate: true
|
||||
options:
|
||||
ASC: 'up'
|
||||
DESC: 'down'
|
||||
ASC: __('up')
|
||||
DESC: __('down')
|
||||
},
|
||||
{
|
||||
name: 'group_by'
|
||||
@@ -57,12 +57,12 @@ class App.Overview extends App.Model
|
||||
name: 'group_direction'
|
||||
display: __('Group by Direction')
|
||||
tag: 'select'
|
||||
default: 'down'
|
||||
default: 'DESC'
|
||||
null: false
|
||||
translate: true
|
||||
options:
|
||||
ASC: 'up'
|
||||
DESC: 'down'
|
||||
ASC: __('up')
|
||||
DESC: __('down')
|
||||
},
|
||||
{ name: 'active', display: __('Active'), tag: 'active', default: true },
|
||||
{ name: 'created_by_id', display: __('Created by'), relation: 'User', readonly: 1 },
|
||||
|
||||
@@ -164,7 +164,7 @@ class App.Ticket extends App.Model
|
||||
params.ticket[attributes[1]] = pendtil.toISOString()
|
||||
|
||||
# apply user changes
|
||||
else if attributes[1] is 'owner_id'
|
||||
else if attributes[1] is 'owner_id' || attributes[1] is 'customer_id'
|
||||
if content.pre_condition is 'current_user.id'
|
||||
params.ticket[attributes[1]] = App.Session.get('id')
|
||||
else
|
||||
|
||||
@@ -6,7 +6,7 @@ class App.Webhook extends App.Model
|
||||
{ name: 'name', display: __('Name'), tag: 'input', type: 'text', limit: 100, null: false },
|
||||
{ name: 'endpoint', display: __('Endpoint'), tag: 'input', type: 'text', limit: 300, null: false, placeholder: 'https://target.example.com/webhook' },
|
||||
{ name: 'signature_token', display: __('HMAC SHA1 Signature Token'), tag: 'input', type: 'text', limit: 100, null: true },
|
||||
{ name: 'ssl_verify', display: __('SSL Verify'), tag: 'boolean', null: true, options: { true: 'yes', false: 'no' }, default: true },
|
||||
{ name: 'ssl_verify', display: __('SSL Verify'), tag: 'boolean', null: true, translate: true, options: { true: 'yes', false: 'no' }, default: true },
|
||||
{ name: 'note', display: __('Note'), tag: 'textarea', note: '', limit: 250, null: true },
|
||||
{ name: 'active', display: __('Active'), tag: 'active', default: true },
|
||||
{ name: 'updated_at', display: __('Updated'), tag: 'datetime', readonly: 1 },
|
||||
|
||||
@@ -20,4 +20,6 @@
|
||||
|
||||
<div class="page-content">
|
||||
<div class="table-overview"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bulkAction hide"></div>
|
||||
|
||||
@@ -127,7 +127,7 @@ class App.KnowledgeBaseCustomAddressForm extends App.KnowledgeBaseForm
|
||||
button.disabled = false
|
||||
|
||||
new App.KnowledgeBaseServerSnippet(
|
||||
container: @el.closest('.main')
|
||||
container: @el.closest('.content')
|
||||
snippets: data.snippets
|
||||
address: data.address
|
||||
address_type: data.address_type
|
||||
@@ -140,6 +140,6 @@ class App.KnowledgeBaseCustomAddressForm extends App.KnowledgeBaseForm
|
||||
|
||||
new App.ControllerErrorModal(
|
||||
message: xhr.responseJSON.error
|
||||
container: @el.closest('.main')
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ class App.KnowledgeBaseDelete extends App.KnowledgeBaseForm
|
||||
formController.hideAlert()
|
||||
|
||||
loader = new App.ControllerModalLoading(
|
||||
container: @parentVC.el
|
||||
container: @parentVC.el.closest('.content')
|
||||
)
|
||||
|
||||
@ajax(
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
class App.KnowledgeBaseNewModal extends App.ControllerModal
|
||||
head: __('Create Knowledge Base')
|
||||
screen: 'admin_create'
|
||||
|
||||
buttonClose: false
|
||||
buttonCancel: false
|
||||
backdrop: 'static'
|
||||
keyboard: false
|
||||
class App.KnowledgeBaseNewController extends App.Controller
|
||||
events:
|
||||
'submit form': 'submit'
|
||||
|
||||
constructor: ->
|
||||
@formController = new App.ControllerForm(
|
||||
model: App.KnowledgeBase
|
||||
params: @item
|
||||
screen: @screen
|
||||
autofocus: false
|
||||
)
|
||||
|
||||
super
|
||||
|
||||
content: ->
|
||||
@formController.form
|
||||
@render()
|
||||
|
||||
render: ->
|
||||
@formController = new App.ControllerForm(
|
||||
model: App.KnowledgeBase
|
||||
screen: 'admin_create'
|
||||
autofocus: false
|
||||
formClass: 'settings-entry'
|
||||
fullForm: true
|
||||
fullFormSubmitLabel: __('Create Knowledge Base')
|
||||
fullFormButtonsContainerClass: 'justify-end'
|
||||
fullFormSubmitAdditionalClasses: 'btn--success'
|
||||
)
|
||||
|
||||
@el.html @formController.form
|
||||
|
||||
prepareParams: (params) ->
|
||||
for key, attribute of App.KnowledgeBase.attributesGet(@screen)
|
||||
for key, attribute of App.KnowledgeBase.attributesGet(@formController.screen)
|
||||
dom = @$(".#{attribute.tag}[data-attribute-name=#{attribute.name}]")
|
||||
App.UiElement[attribute.tag].prepareParams?(attribute, dom, params)
|
||||
|
||||
@@ -33,8 +34,10 @@ class App.KnowledgeBaseNewModal extends App.ControllerModal
|
||||
params['homepage_layout'] = 'grid'
|
||||
params['category_layout'] = 'grid'
|
||||
|
||||
onSubmit: (e) ->
|
||||
params = @formParams(@el)
|
||||
submit: (e) ->
|
||||
@preventDefaultAndStopPropagation(e)
|
||||
|
||||
params = @formParam(@el)
|
||||
@prepareParams(params)
|
||||
@applyDefaults(params)
|
||||
|
||||
@@ -47,8 +50,6 @@ class App.KnowledgeBaseNewModal extends App.ControllerModal
|
||||
|
||||
success: (data) =>
|
||||
@parentVC.fetchAndRender()
|
||||
@parentVC.modal = undefined
|
||||
@close()
|
||||
|
||||
error: (xhr) =>
|
||||
@formEnable(@el)
|
||||
@@ -24,3 +24,5 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="bulkAction hide"></div>
|
||||
|
||||
@@ -38,11 +38,11 @@
|
||||
<% end %>
|
||||
<% if sla.response_time: %>
|
||||
<br>
|
||||
<%- @time_duration_hh_mm(sla.response_time) %> <%- @T('hours') %> - <%- @T('Response Time') %>
|
||||
<%- @time_duration_hh_mm(sla.response_time) %> <%- @T('hours') %> - <%- @T('Update Time') %> (<%- @T('for an agent to respond') %>)
|
||||
<% end %>
|
||||
<% if sla.update_time: %>
|
||||
<br>
|
||||
<%- @time_duration_hh_mm(sla.update_time) %> <%- @T('hours') %> - <%- @T('Update Time') %>
|
||||
<%- @time_duration_hh_mm(sla.update_time) %> <%- @T('hours') %> - <%- @T('Update Time') %> (<%- @T('between agent updates') %>)
|
||||
<% end %>
|
||||
<% if sla.solution_time: %>
|
||||
<br>
|
||||
|
||||
@@ -62,16 +62,13 @@
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="userAction">
|
||||
<% if !@sharedDraftsDisabled: %>
|
||||
<li class="label" role="menuitem">
|
||||
<label>
|
||||
Draft
|
||||
|
||||
<li class="js-dropdownActionSaveDraft" role="menuitem">Save Draft
|
||||
<label><%- @T('Draft') %></label>
|
||||
<li class="js-dropdownActionSaveDraft" role="menuitem"><%- @T('Save Draft') %></li>
|
||||
<% end %>
|
||||
|
||||
<% if !@macroDisabled: %>
|
||||
<li class="label" role="menuitem">
|
||||
<label>
|
||||
Macros
|
||||
<label><%- @T('Macros') %></label>
|
||||
|
||||
<% for macro in @macros: %>
|
||||
<li class="js-dropdownActionMacro" role="menuitem" data-id="<%= macro.id %>"><%- macro.displayName() %>
|
||||
|
||||
@@ -13,7 +13,9 @@ class KnowledgeBase::Public::AnswersController < KnowledgeBase::Public::BaseCont
|
||||
private
|
||||
|
||||
def render_alternative
|
||||
@alternative = find_answer @knowledge_base.answers.eager_load(translations: :kb_locale), params[:answer], locale: false
|
||||
answers = @knowledge_base.answers.where(category: params[:category]).eager_load(translations: :kb_locale)
|
||||
|
||||
@alternative = find_answer(answers, params[:answer], locale: false)
|
||||
|
||||
raise ActiveRecord::RecordNotFound if !@alternative&.translations&.any?
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ class KnowledgeBasesController < KnowledgeBase::BaseController
|
||||
end
|
||||
|
||||
def visible_ids
|
||||
render json: KnowledgeBase::InternalAssets.new(current_user).visible_ids
|
||||
render json: calculate_visible_ids
|
||||
end
|
||||
|
||||
private
|
||||
@@ -22,6 +22,20 @@ class KnowledgeBasesController < KnowledgeBase::BaseController
|
||||
public_assets
|
||||
end
|
||||
|
||||
def calculate_visible_ids
|
||||
if KnowledgeBase.granular_permissions? && kb_permissions?
|
||||
return KnowledgeBase::InternalAssets.new(current_user).visible_ids
|
||||
end
|
||||
|
||||
if kb_permission_editor?
|
||||
editor_assets_visible_ids
|
||||
elsif kb_permission_reader?
|
||||
reader_assets_visible_ids
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
|
||||
def kb_permissions?
|
||||
current_user&.permissions?(%w[knowledge_base.editor knowledge_base.reader])
|
||||
end
|
||||
@@ -63,6 +77,13 @@ class KnowledgeBasesController < KnowledgeBase::BaseController
|
||||
assets
|
||||
end
|
||||
|
||||
def editor_assets_visible_ids
|
||||
{
|
||||
answer_ids: KnowledgeBase::Answer.pluck(:id),
|
||||
category_ids: KnowledgeBase::Category.pluck(:id)
|
||||
}
|
||||
end
|
||||
|
||||
def reader_assets(answer_translation_content_ids)
|
||||
assets = [
|
||||
KnowledgeBase,
|
||||
@@ -96,6 +117,13 @@ class KnowledgeBasesController < KnowledgeBase::BaseController
|
||||
assets
|
||||
end
|
||||
|
||||
def reader_assets_visible_ids
|
||||
{
|
||||
answer_ids: KnowledgeBase::Answer.internal.pluck(:id),
|
||||
category_ids: KnowledgeBase::Category.pluck(:id)
|
||||
}
|
||||
end
|
||||
|
||||
# assets for users who don't have KB permissions
|
||||
def public_assets
|
||||
return [] if !Setting.get('kb_active_publicly')
|
||||
|
||||
@@ -6,7 +6,8 @@ class TagsController < ApplicationController
|
||||
|
||||
# GET /api/v1/tag_search?term=abc
|
||||
def search
|
||||
list = Tag::Item.where('name_downcase LIKE ?', "%#{params[:term].strip.downcase}%").order(name: :asc).limit(params[:limit] || 10)
|
||||
list = get_tag_list(params[:term], params[:limit] || 10)
|
||||
|
||||
results = []
|
||||
list.each do |item|
|
||||
result = {
|
||||
@@ -95,4 +96,13 @@ class TagsController < ApplicationController
|
||||
render json: {}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_tag_list(term, limit)
|
||||
if term.blank?
|
||||
return Tag::Item.left_outer_joins(:tags).group(:id).order('COUNT(tags.tag_item_id) DESC, name ASC').limit(limit)
|
||||
end
|
||||
|
||||
Tag::Item.where('name_downcase LIKE ?', "%#{term.strip.downcase}%").order(name: :asc).limit(limit)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,6 +9,7 @@ class TicketOverviewsController < ApplicationController
|
||||
# get attributes to update
|
||||
attributes_to_change = Ticket::ScreenOptions.attributes_to_change(
|
||||
view: 'ticket_overview',
|
||||
screen: 'overview_bulk',
|
||||
current_user: current_user,
|
||||
)
|
||||
render json: attributes_to_change
|
||||
|
||||
@@ -557,26 +557,26 @@ curl http://localhost/api/v1/users/password_change -v -u #{login}:#{password} -H
|
||||
def password_change
|
||||
|
||||
# check old password
|
||||
if !params[:password_old]
|
||||
render json: { message: 'failed', notice: [__('Current password needed!')] }, status: :ok
|
||||
if !params[:password_old] || !PasswordPolicy::MaxLength.valid?(params[:password_old])
|
||||
render json: { message: 'failed', notice: [__('Current password needed!')] }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
current_password_verified = PasswordHash.verified?(current_user.password, params[:password_old])
|
||||
if !current_password_verified
|
||||
render json: { message: 'failed', notice: [__('Current password is wrong!')] }, status: :ok
|
||||
render json: { message: 'failed', notice: [__('Current password is wrong!')] }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
# set new password
|
||||
if !params[:password_new]
|
||||
render json: { message: 'failed', notice: [__('Please supply your new password!')] }, status: :ok
|
||||
render json: { message: 'failed', notice: [__('Please supply your new password!')] }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
result = PasswordPolicy.new(params[:password_new])
|
||||
if !result.valid?
|
||||
render json: { message: 'failed', notice: result.error }, status: :ok
|
||||
render json: { message: 'failed', notice: result.error }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@@ -12,49 +12,39 @@ class ChecksKbClientNotificationJob < ApplicationJob
|
||||
object = klass_name.constantize.find_by(id: object_id)
|
||||
return if object.blank?
|
||||
|
||||
level = needs_editor?(object) ? 'editor' : '*'
|
||||
|
||||
payload = {
|
||||
event: 'kb_data_changed',
|
||||
data: build_data(object, event)
|
||||
data: build_data(object)
|
||||
}
|
||||
|
||||
users_for(level).each { |user| notify(user, payload) }
|
||||
end
|
||||
|
||||
def build_data(object, event)
|
||||
timestamp = event == :destroy ? Time.zone.now : object.updated_at
|
||||
url = event == :destroy ? nil : object.try(:api_url)
|
||||
|
||||
{
|
||||
class: object.class.to_s,
|
||||
event: event,
|
||||
id: object.id,
|
||||
timestamp: timestamp,
|
||||
url: url
|
||||
}
|
||||
end
|
||||
|
||||
def needs_editor?(object)
|
||||
case object
|
||||
when KnowledgeBase::Answer
|
||||
object.can_be_published_aasm.draft?
|
||||
when KnowledgeBase::Category
|
||||
!object.internal_content?
|
||||
else
|
||||
false
|
||||
active_users.each do |user|
|
||||
notify(user, object, payload)
|
||||
end
|
||||
end
|
||||
|
||||
def notify(user, payload)
|
||||
PushMessages.send_to(user.id, payload)
|
||||
def build_data(object)
|
||||
{
|
||||
class: object.class.name,
|
||||
id: object.id,
|
||||
timestamp: object.updated_at,
|
||||
url: object.try(:api_url)
|
||||
}
|
||||
end
|
||||
|
||||
def users_for(permission_suffix)
|
||||
def notify(user, object, payload)
|
||||
return if !user.permissions? 'knowledge_base.*'
|
||||
|
||||
Pundit.authorize user, object, :show?
|
||||
|
||||
PushMessages.send_to(user.id, payload)
|
||||
rescue Pundit::NotAuthorizedError
|
||||
# do nothing if user is not authorized to access
|
||||
end
|
||||
|
||||
def active_users
|
||||
Sessions
|
||||
.sessions
|
||||
.filter_map { |client_id| Sessions.get(client_id)&.dig(:user, 'id') }
|
||||
.filter_map { |user_id| User.find_by(id: user_id) }
|
||||
.select { |user| user.permissions? "knowledge_base.#{permission_suffix}" }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,7 +10,7 @@ class TriggerWebhookJob::RecordPayload::Ticket::Article < TriggerWebhookJob::Rec
|
||||
end
|
||||
|
||||
def add_accounted_time(result)
|
||||
result['accounted_time'] = record.ticket_time_accounting&.time_unit.to_i
|
||||
result['accounted_time'] = record.ticket_time_accounting&.time_unit.to_f
|
||||
result
|
||||
end
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ class Channel::Driver::Imap < Channel::EmailParser
|
||||
FETCH_MSG_TIMEOUT = 4.minutes
|
||||
EXPUNGE_TIMEOUT = 16.minutes
|
||||
DEFAULT_TIMEOUT = 45.seconds
|
||||
CHECK_ONLY_TIMEOUT = 6.seconds
|
||||
CHECK_ONLY_TIMEOUT = 8.seconds
|
||||
|
||||
def fetchable?(_channel)
|
||||
true
|
||||
|
||||
@@ -18,7 +18,10 @@ module Channel::Filter::FollowUpCheck
|
||||
|
||||
# get ticket# from body
|
||||
if setting.include?('body')
|
||||
ticket = Ticket::Number.check(mail[:body].html2text)
|
||||
body = mail[:body]
|
||||
body = body.html2text if mail[:content_type] == 'text/html'
|
||||
|
||||
ticket = Ticket::Number.check(body)
|
||||
if ticket
|
||||
Rails.logger.debug { "Follow-up for '##{ticket.number}' in body." }
|
||||
mail[:'x-zammad-ticket-id'] = ticket.id
|
||||
|
||||
@@ -4,7 +4,9 @@ module Channel::Filter::ReplyToBasedSender
|
||||
|
||||
def self.run(_channel, mail, _transaction_params)
|
||||
|
||||
reply_to = mail[:'reply-to']
|
||||
return if mail[:'reply-to'].blank?
|
||||
|
||||
reply_to = mail[:'reply-to'].gsub('<>', '').strip
|
||||
return if reply_to.blank?
|
||||
|
||||
setting = Setting.get('postmaster_sender_based_on_reply_to')
|
||||
|
||||
@@ -30,6 +30,10 @@ module ChecksKbClientNotification
|
||||
def notify_kb_clients_after
|
||||
return if self.class.notify_kb_clients_suspend?
|
||||
|
||||
# do not leak details about deleted items. See ChecksKbClientVisibilityJob
|
||||
# after_commit does not allow on: :touch
|
||||
return if destroyed?
|
||||
|
||||
ChecksKbClientNotificationJob.perform_later(self.class.name, id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,6 +30,7 @@ class Mention < ApplicationModel
|
||||
{
|
||||
related_o_id: mentionable_id,
|
||||
related_history_object: mentionable_type,
|
||||
value_to: user.id,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -306,7 +306,6 @@ possible types
|
||||
=end
|
||||
|
||||
def self.add(data)
|
||||
|
||||
force = data[:force]
|
||||
data.delete(:force)
|
||||
|
||||
@@ -535,6 +534,31 @@ returns
|
||||
ObjectManager::Attribute.where('to_create = ? OR to_migrate = ? OR to_delete = ? OR to_config = ?', true, true, true, true)
|
||||
end
|
||||
|
||||
def self.attribute_historic_options(attribute)
|
||||
historical_options = attribute.data_option[:historical_options] || {}
|
||||
if attribute.data_option[:options].present?
|
||||
historical_options = historical_options.merge(data_options_hash(attribute.data_option[:options]))
|
||||
end
|
||||
if attribute.data_option_new[:options].present?
|
||||
historical_options = historical_options.merge(data_options_hash(attribute.data_option_new[:options]))
|
||||
end
|
||||
historical_options
|
||||
end
|
||||
|
||||
def self.data_options_hash(options, result = {})
|
||||
return options if options.is_a?(Hash)
|
||||
return {} if !options.is_a?(Array)
|
||||
|
||||
options.each do |option|
|
||||
result[ option[:value] ] = option[:name]
|
||||
if option[:children].present?
|
||||
data_options_hash(option[:children], result)
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
start migration of pending attribute migrations
|
||||
@@ -573,11 +597,8 @@ to send no browser reload event, pass false
|
||||
# config changes
|
||||
if attribute.to_config
|
||||
execute_config_count += 1
|
||||
if attribute.data_type == 'select' && attribute.data_option[:options]
|
||||
historical_options = attribute.data_option[:historical_options] || {}
|
||||
historical_options.update(attribute.data_option[:options])
|
||||
historical_options.update(attribute.data_option_new[:options])
|
||||
attribute.data_option_new[:historical_options] = historical_options
|
||||
if attribute.data_type =~ %r{^(multi|tree_)?select$} && attribute.data_option[:options]
|
||||
attribute.data_option_new[:historical_options] = attribute_historic_options(attribute)
|
||||
end
|
||||
attribute.data_option = attribute.data_option_new
|
||||
attribute.data_option_new = {}
|
||||
@@ -586,8 +607,8 @@ to send no browser reload event, pass false
|
||||
next if !attribute.to_create && !attribute.to_migrate && !attribute.to_delete
|
||||
end
|
||||
|
||||
if attribute.data_type == 'select' && attribute.data_option[:options]
|
||||
attribute.data_option[:historical_options] = attribute.data_option[:options]
|
||||
if %r{^(multi|tree_)?select$}.match?(attribute.data_type)
|
||||
attribute.data_option[:historical_options] = attribute_historic_options(attribute)
|
||||
end
|
||||
|
||||
data_type = nil
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
class SMIMECertificate < ApplicationModel
|
||||
default_scope { order('not_after_at DESC, not_before_at DESC, id DESC') }
|
||||
|
||||
validates :fingerprint, uniqueness: { case_sensitive: true }
|
||||
|
||||
def self.parts(raw)
|
||||
@@ -38,8 +40,8 @@ class SMIMECertificate < ApplicationModel
|
||||
# @return [SMIMECertificate, nil] The found certificate record or nil
|
||||
def self.for_sender_email_address(address)
|
||||
downcased_address = address.downcase
|
||||
where.not(private_key: nil).find_each.detect do |certificate|
|
||||
certificate.email_addresses.include?(downcased_address)
|
||||
where.not(private_key: nil).all.as_batches do |certificate|
|
||||
return certificate if certificate.email_addresses.include?(downcased_address)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -55,7 +57,7 @@ class SMIMECertificate < ApplicationModel
|
||||
def self.for_recipipent_email_addresses!(addresses)
|
||||
certificates = []
|
||||
remaining_addresses = addresses.map(&:downcase)
|
||||
find_each do |certificate|
|
||||
all.as_batches do |certificate|
|
||||
|
||||
# intersection of both lists
|
||||
cerfiticate_for = certificate.email_addresses & remaining_addresses
|
||||
|
||||
@@ -4,6 +4,10 @@ class Tag::Item < ApplicationModel
|
||||
validates :name, presence: true
|
||||
before_save :fill_namedowncase
|
||||
|
||||
has_many :tags, foreign_key: 'tag_item_id',
|
||||
inverse_of: :tag_item,
|
||||
dependent: :destroy
|
||||
|
||||
=begin
|
||||
|
||||
lookup by name and create tag item
|
||||
|
||||
@@ -69,6 +69,10 @@ module Ticket::Article::AddsMetadataEmail
|
||||
elsif Setting.get('ticket_define_email_from') == 'AgentName'
|
||||
sender = User.find(created_by_id)
|
||||
realname = "#{sender.firstname} #{sender.lastname}"
|
||||
|
||||
# avoid "-" as realname, see https://github.com/zammad/zammad/issues/3890
|
||||
realname = email_address.realname if sender.id == 1
|
||||
|
||||
self.from = Channel::EmailBuild.recipient_line(realname, email_address.email)
|
||||
else
|
||||
self.from = Channel::EmailBuild.recipient_line(email_address.realname, email_address.email)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user