From 553bcd9ba47c8a0b02fd03e0b238b70740650786 Mon Sep 17 00:00:00 2001 From: ulferts Date: Fri, 6 Nov 2020 10:20:00 +0100 Subject: [PATCH 01/20] Bumped version to 11.0.3 [ci skip] --- lib/open_project/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/open_project/version.rb b/lib/open_project/version.rb index c687a5cda4..fd0c451e4b 100644 --- a/lib/open_project/version.rb +++ b/lib/open_project/version.rb @@ -34,7 +34,7 @@ module OpenProject module VERSION #:nodoc: MAJOR = 11 MINOR = 0 - PATCH = 2 + PATCH = 3 TINY = PATCH # Redmine compat class << self From 54d2f477f1fbf84d29a81fb73624c6cf5f3ede6b Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Fri, 6 Nov 2020 09:39:46 +0000 Subject: [PATCH 02/20] update locales from crowdin [ci skip] --- config/locales/crowdin/tr.yml | 4 ++-- config/locales/crowdin/zh-CN.yml | 2 +- modules/boards/config/locales/crowdin/js-zh-CN.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/locales/crowdin/tr.yml b/config/locales/crowdin/tr.yml index 0efdacd4c9..88446b9b6e 100644 --- a/config/locales/crowdin/tr.yml +++ b/config/locales/crowdin/tr.yml @@ -2302,8 +2302,8 @@ tr: text_work_package_category_destroy_question: "Bu kategoriye bazı iş paketleri ( %{count}) atanmıştır. Ne yapmak istiyorsun?" text_work_package_category_reassign_to: "İş paketlerini bu kategoriye yeniden ata" text_work_package_updated: "%{id} iş paketi %{author} tarafından güncellendi." - text_work_package_watcher_added: "%{id} tarafından %{watcher_changer}. Work paketine izleyici olarak eklendi" - text_work_package_watcher_removed: "%{id} tarafından %{watcher_changer}. Work paketi saatlerinden çıkarıldınız" + text_work_package_watcher_added: "%{id} iş paketine %{watcher_changer} tarafından izleyici olarak eklendiniz." + text_work_package_watcher_removed: "%{id} iş paketinden, %{watcher_changer} tarafından izleyicilikten çıkarıldınız." text_work_packages_destroy_confirmation: "Seçilen çalışma paket(ler) ini silmek istediğinizden emin misiniz?" text_work_packages_ref_in_commit_messages: "İş paketlerini taahhüt mesajlarında referans ve sabitleme" text_journal_added: "%{value} %{label} eklendi" diff --git a/config/locales/crowdin/zh-CN.yml b/config/locales/crowdin/zh-CN.yml index 552e370a56..e862f89876 100644 --- a/config/locales/crowdin/zh-CN.yml +++ b/config/locales/crowdin/zh-CN.yml @@ -531,7 +531,7 @@ zh-CN: invalid_url: '不是有效的 URL。' invalid_url_scheme: '不是受支持的协议(允许:%{allowed_schemes})。' less_than_or_equal_to: "必须小于或等于 %{count}。" - not_current_user: "is not the current user." + not_current_user: "不是当前用户。" not_a_date: "不是有效的日期。" not_a_datetime: "不是有效的日期时间。" not_a_number: "不是一个数字。" diff --git a/modules/boards/config/locales/crowdin/js-zh-CN.yml b/modules/boards/config/locales/crowdin/js-zh-CN.yml index 8e62a18b4c..545409f80a 100644 --- a/modules/boards/config/locales/crowdin/js-zh-CN.yml +++ b/modules/boards/config/locales/crowdin/js-zh-CN.yml @@ -63,7 +63,7 @@ zh-CN: version: 版本 subproject: 子项目 subtasks: 父子 - basic: 基本 + basic: 基础 select_attribute: "操作属性" add_list_modal: labels: @@ -77,7 +77,7 @@ zh-CN: 目前没有可用的状态。
可能没有问题,或者它们已被全部添加到问题板中。 assignee: 没有任何成员与您的筛选值匹配。
- no_member: 此项目当前没有可以添加的任何成员。
+ no_member: 此项目目前没有可以添加的成员。
add_members: 向此项目添加一个新成员以重新选择用户。 configuration_modal: title: '配置此面板' From f3fc64c19b609764ddc46566a47377aae9043875 Mon Sep 17 00:00:00 2001 From: Cyril Rohr Date: Fri, 6 Nov 2020 13:44:43 +0100 Subject: [PATCH 03/20] BIM is now available for Ubuntu 18.04 as well (#8830) --- docs/installation-and-operations/installation/packaged/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/installation-and-operations/installation/packaged/README.md b/docs/installation-and-operations/installation/packaged/README.md index 0fb1d6cd49..bd9f6a2438 100644 --- a/docs/installation-and-operations/installation/packaged/README.md +++ b/docs/installation-and-operations/installation/packaged/README.md @@ -286,6 +286,7 @@ This wizard step is only available on the following distributions: * RHEL/CentOS 8 * Ubuntu 20.04 +* Ubuntu 18.04 * Debian 10 On older distributions, this wizard step won't be displayed, and the installation will default to the default edition. From 6b0f25f655c20a32d8628bb8cadef75315523cbc Mon Sep 17 00:00:00 2001 From: ML-OpenP Date: Fri, 6 Nov 2020 14:53:38 +0100 Subject: [PATCH 04/20] typos [ci skip] --- docs/development/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/development/README.md b/docs/development/README.md index 39cbaba751..a0e58063b5 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -4,7 +4,7 @@ We are pleased that you are thinking about contributing to OpenProject! This gui ## Get in touch -Please get in touch with us using our [develompment forum](https://community.openproject.com/projects/openproject/forums/7) or send us an email to info@openproject.org. +Please get in touch with us using our [development forum](https://community.openproject.com/projects/openproject/forums/7) or send us an email to info@openproject.org. @@ -60,11 +60,11 @@ Please also use `[ci skip]` in your commit message to suppress builds which are ## Inactive pull requests -We want to keep the Pull request list as cleaned up as possible - we will aim close pull requests after an **inactivity period of 30 days** (no comments, no further pushes) which are not labelled as `work in progress` by us. +We want to keep the Pull request list as cleaned up as possible - we will aim close pull requests after an **inactivity period of 30 days** (no comments, no further pushes) which are not labeled as `work in progress` by us. ## Security -If you notice a security issue in OpenProject, please send us a gpg encrypted email to security@openproject.com and describe the issue you found. Download our public gpg key BDCF E01E DE84 EA19 9AE1 72CE 7D66 9C6D 4753 3958 [here](https://keys.openpgp.org/vks/v1/by-fingerprint/BDCFE01EDE84EA199AE172CE7D669C6D47533958). +If you notice a security issue in OpenProject, please send us a GPG encrypted email to security@openproject.com and describe the issue you found. Download our public GPG key BDCF E01E DE84 EA19 9AE1 72CE 7D66 9C6D 4753 3958 [here](https://keys.openpgp.org/vks/v1/by-fingerprint/BDCFE01EDE84EA199AE172CE7D669C6D47533958). Please include a description on how to reproduce the issue if possible. Our security team will get your email and will attempt to reproduce and fix the issue as soon as possible. From b0cfd2a80c819d9969fc74d76457cc747c817040 Mon Sep 17 00:00:00 2001 From: ML-OpenP Date: Mon, 9 Nov 2020 17:45:51 +0100 Subject: [PATCH 05/20] fixed link and typo in docs [ci skip] --- docs/user-guide/wysiwyg/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/user-guide/wysiwyg/README.md b/docs/user-guide/wysiwyg/README.md index f56353a48f..a5a7471b7e 100644 --- a/docs/user-guide/wysiwyg/README.md +++ b/docs/user-guide/wysiwyg/README.md @@ -3,7 +3,7 @@ sidebar_navigation: title: Rich text editor description: Find out about the CKEditor5 WYSIWYG editor in OpenProject robots: index, follow -keywords: WYSIWYG, CKEditor +keywords: WYSIWYG, CKEditor, Links to OpenProject resources --- # Rich text (WYSIWYG) editor in OpenProject @@ -158,7 +158,7 @@ You can embed specific attributes of work packages or projects using the followi -You can also embed attribute values and [their help texts](https://docs.openproject.org/system-admin-guide/manage-work-packages/attribute-help-texts/#manage-attribute-help-texts-premium-feature) by using `workPackageLabel` instead: `workPackageLabel:1234:status` would output the translated label for "Status" and (if exists), the corresponding help text for it. +You can also embed attribute values and [their help texts](../../system-admin-guide/attribute-help-texts/) by using `workPackageLabel` instead: `workPackageLabel:1234:status` would output the translated label for "Status" and (if exists), the corresponding help text for it. Note that these macros will only be expanded in the frontend. For each individual user, the correct permissions will be checked and the macro will result in an error if the user is not allowed to view the respective resource. @@ -192,7 +192,7 @@ The following list contains all suppported attribute names for the `workPackageV **Available attributes for projects** -The following list contains all suppported attribute names for the `projectValue` and `projectLabel` macros. The examples all show references to the _current_ project the document is rendered in. They can also reference another project with `projectValue:"Identifier of the project":attribute`. +The following list contains all supported attribute names for the `projectValue` and `projectLabel` macros. The examples all show references to the _current_ project the document is rendered in. They can also reference another project with `projectValue:"Identifier of the project":attribute`. | **Attribute** | Usage example | | ------------------------- | ------------------------------------------------- | From 317d90444f7d7ec47b2b9f1e5e62bf85ba4a9410 Mon Sep 17 00:00:00 2001 From: ulferts Date: Tue, 10 Nov 2020 08:54:39 +0100 Subject: [PATCH 06/20] only embed direct relations in wp representer (#8831) * only embed direct relations in wp representer * add integration tests for embedded relations --- .../work_packages/work_package_representer.rb | 1 + .../work_package_representer_spec.rb | 2 +- .../api/v3/work_package_resource_spec.rb | 29 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/api/v3/work_packages/work_package_representer.rb b/lib/api/v3/work_packages/work_package_representer.rb index 8596390a14..84e5980a45 100644 --- a/lib/api/v3/work_packages/work_package_representer.rb +++ b/lib/api/v3/work_packages/work_package_representer.rb @@ -535,6 +535,7 @@ module API self_path = api_v3_paths.work_package_relations(represented.id) visible_relations = represented .visible_relations(current_user) + .direct .non_hierarchy .includes(::API::V3::Relations::RelationCollectionRepresenter.to_eager_load) diff --git a/spec/lib/api/v3/work_packages/work_package_representer_spec.rb b/spec/lib/api/v3/work_packages/work_package_representer_spec.rb index 7a3a73c98d..3e7d023788 100644 --- a/spec/lib/api/v3/work_packages/work_package_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/work_package_representer_spec.rb @@ -1073,7 +1073,7 @@ describe ::API::V3::WorkPackages::WorkPackageRepresenter do before do allow(work_package) - .to receive_message_chain(:visible_relations, :non_hierarchy, :includes) + .to receive_message_chain(:visible_relations, :direct, :non_hierarchy, :includes) .and_return([relation]) end diff --git a/spec/requests/api/v3/work_package_resource_spec.rb b/spec/requests/api/v3/work_package_resource_spec.rb index 01db2aba6b..e3daa475bd 100644 --- a/spec/requests/api/v3/work_package_resource_spec.rb +++ b/spec/requests/api/v3/work_package_resource_spec.rb @@ -310,6 +310,35 @@ describe 'API v3 Work package resource', .at_path('derivedDueDate') end end + + describe 'relations' do + let(:directly_related_wp) do + FactoryBot.create(:work_package, project_id: project.id) + end + let(:transitively_related_wp) do + FactoryBot.create(:work_package, project_id: project.id) + end + + let(:work_package) do + FactoryBot.create(:work_package, + project_id: project.id, + description: 'lorem ipsum').tap do |wp| + + FactoryBot.create(:relation, relates: 1, from: wp, to: directly_related_wp) + FactoryBot.create(:relation, relates: 1, from: directly_related_wp, to: transitively_related_wp) + end + end + + it 'embeds all direct relations' do + expect(subject) + .to be_json_eql(1.to_json) + .at_path('_embedded/relations/total') + + expect(subject) + .to be_json_eql(api_v3_paths.work_package(directly_related_wp.id).to_json) + .at_path('_embedded/relations/_embedded/elements/0/_links/to/href') + end + end end context 'requesting nonexistent work package' do From 1c8e7cfd4991b19c5e114023c6d2851b190f0cea Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Tue, 10 Nov 2020 07:55:56 +0000 Subject: [PATCH 07/20] Updated bundler --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 53d637d382..b59db0a409 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ ARG GITHUB_OAUTH_TOKEN ARG DEBIAN_FRONTEND=noninteractive ENV NODE_VERSION="12.18.3" -ENV BUNDLER_VERSION="2.0.2" +ENV BUNDLER_VERSION="2.1.4" ENV BUNDLE_PATH__SYSTEM=false ENV APP_USER=app ENV APP_PATH=/app From 73f57f3a342844ff1276b4ec1750c928f5501228 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Tue, 10 Nov 2020 10:15:15 +0000 Subject: [PATCH 08/20] update locales from crowdin [ci skip] --- config/locales/crowdin/el.yml | 2 +- config/locales/crowdin/js-el.yml | 2 +- modules/boards/config/locales/crowdin/js-el.yml | 4 ++-- modules/job_status/config/locales/crowdin/js-el.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/locales/crowdin/el.yml b/config/locales/crowdin/el.yml index be45836816..2e60fc9928 100644 --- a/config/locales/crowdin/el.yml +++ b/config/locales/crowdin/el.yml @@ -2654,7 +2654,7 @@ el: pre_authorization: status: 'Πριν την εξουσιοδότηση' auth_url: 'Auth URL' - access_token_url: 'Access token URL' + access_token_url: 'Token πρόσβασης' errors: messages: #Common error messages diff --git a/config/locales/crowdin/js-el.yml b/config/locales/crowdin/js-el.yml index 120c8dbb69..af55150f8f 100644 --- a/config/locales/crowdin/js-el.yml +++ b/config/locales/crowdin/js-el.yml @@ -200,7 +200,7 @@ el: status_confirmed: "επιβεβαιωμένο" status_waiting: "το email απεστάλη - αναμονή για επιβεβαίωση" test_ee: "Δοκιμάστε την Έκδοση για Επιχειρήσεις για 14 ημέρες δωρεάν " - quick_overview: "Get a quick overview of project management and team collaboration with OpenProject Enterprise Edition." + quick_overview: "Λάβετε μια γρήγορη επισκόπηση της διαχείρισης έργων και της ομαδικής συνεργασίας με το OpenProject." upsale: become_hero: "Γίνετε ήρωας!" benefits: diff --git a/modules/boards/config/locales/crowdin/js-el.yml b/modules/boards/config/locales/crowdin/js-el.yml index f47c1dd550..d480874d5f 100644 --- a/modules/boards/config/locales/crowdin/js-el.yml +++ b/modules/boards/config/locales/crowdin/js-el.yml @@ -52,7 +52,7 @@ el: action_text_version: > Board with automated columns based on the version attribute. Ideal for planning product development. action_type: - assignee: assignee + assignee: Αναθέτης status: κατάσταση version: έκδοση subproject: subproject @@ -63,7 +63,7 @@ el: version: Έκδοση subproject: Υποέργο subtasks: Parent-Child - basic: Basic + basic: Βασικό select_attribute: "Χαρακτηριστικό ενέργειας" add_list_modal: labels: diff --git a/modules/job_status/config/locales/crowdin/js-el.yml b/modules/job_status/config/locales/crowdin/js-el.yml index 1d8edf9b2d..43736dcf2f 100644 --- a/modules/job_status/config/locales/crowdin/js-el.yml +++ b/modules/job_status/config/locales/crowdin/js-el.yml @@ -2,7 +2,7 @@ el: js: job_status: download_starts: 'The download should start automatically.' - click_to_download: 'Or click here to download.' + click_to_download: 'Πατήστε εδώ για λήψη' title: 'Background job status' redirect: 'You are being redirected.' redirect_link: 'Please click here to continue.' From fd53203a462b91cef942c2a29c12a2bb7626b16e Mon Sep 17 00:00:00 2001 From: ML-OpenP Date: Tue, 10 Nov 2020 16:42:47 +0100 Subject: [PATCH 09/20] small changes in meetings docs [ci skip] --- docs/user-guide/meetings/README.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/docs/user-guide/meetings/README.md b/docs/user-guide/meetings/README.md index 0700cc2693..e788758c88 100644 --- a/docs/user-guide/meetings/README.md +++ b/docs/user-guide/meetings/README.md @@ -2,7 +2,7 @@ sidebar_navigation: title: Meetings priority: 760 -description: Manage meetings with agenda and meeting minutes in OpenProject. +description: Manage meetings with agenda and meeting minutes in OpenProject. robots: index, follow keywords: meetings --- @@ -11,14 +11,16 @@ keywords: meetings Meetings in OpenProject allow you to manage and document your project meetings at one central place, prepare a meeting agenda together with your team and document and share meeting minutes with your meeting attendees at one central place. -
**Meetings** is defined as a module that allows the organization of meetings. The module has to be activated in the project settings in order to be displayed in the side navigation.
+
**Meetings** is defined as a module that allows the organization of meetings. The module has to be activated in the project settings in order to be displayed in the side navigation.
-| Feature | Documentation for | + + +| Topic | Content | | ------------------------------------------------------------ | ------------------------------------------- | | [Meetings in OpenProject](#meetings-in-OpenProject) | How to open meetings in OpenProject? | | [Create a new meeting](#create-a-new-meeting) | How to create a new meeting in OpenProject? | | [Edit a meeting](#edit-a-meeting) | How to edit an existing meeting? | -| [Add meeting participants](#add-meeting-participants) | How to add participants to a meeting? | +| [Add meeting participants](#add-meeting-participants) | How to invite people to a meeting? | | [Create or edit the meeting agenda](#create-or-edit-the-meeting-agenda) | How to create or edit the agenda? | | [Copy a meeting (recurring meetings)](#copy-a-meeting-(recurring meetings)) | How to create recurring meetings? | @@ -26,15 +28,13 @@ Meetings in OpenProject allow you to manage and document your project meetings a By selecting **Meetings** in the project menu on the left, you get an overview of all project meetings sorted by date. By clicking on a meeting name you can view further details of the meeting. -Note: in order to be able to use the meetings plugin, the Meetings module needs to be activated in the [Project Settings](../projects). +**Note:** in order to be able to use the meetings plugin, the **Meetings module needs to be activated** in the [Project Settings](../projects/project-settings/modules/). ![meetings](1567598397931.png) ## Create a new meeting -To create a new meeting, click on Meetings in the project menu (Meetings needs to be activated in the Project settings to be displayed). - -Click the green **+ Meeting** button. +To create a new meeting, click on Meetings in the project menu. Click the green **+ Meeting** button. ![create-meeting](create-meeting.png) @@ -75,18 +75,25 @@ Click on the **Save** button to secure the changes made by you. After creating a meeting, you can set up a **meeting agenda**. 1. Prior to starting the meeting all participants can add their input to the agenda by simply clicking the Edit button. -2. With the toolbar you can make changes to the text format or edit macros, e.g. table of contents or work package tables (see [Wiki](#wiki) for details). + +2. With the toolbar you can make changes to the text format or edit macros, e.g. table of contents or work package tables (see the [documentation for the WYSIWYG editor](../wysiwyg) for details). + 3. All changes made to the agenda are tracked. You can click the **History** button to get an overview of all the changes including the persons who made the changes. + 4. Click the **Send for review** button to quickly notify participants about the meeting and send them a link to the meeting. + 5. Press the **Send iCalendar** button to send a calendar entry to the participants. The users can then quickly add the meeting to their calendar by accepting the invitation / importing the iCal file attached to the email notification. + 6. At the beginning of the meeting, **Close** the agenda to prevent any other changes and provide the same basis for all meeting participants. After closing the agenda, the meeting minutes are displayed to capture the results of the meeting. -7. ![meeting-agenda](meeting-agenda.png) + + + ![meeting-agenda](meeting-agenda.png) ## Create or edit meeting minutes The **meeting minutes** are automatically created when closing the agenda in the details view of the meeting and selecting the [Close](#create-or-edit-the-meeting-agenda) option. -The agenda is closed and copied to the meeting minutes page as a basis. You can start editing the minutes now. The same as in the [wiki](#wiki) pages, you can format the text, link minutes to work packages, documents, include work package lists or other macros. +The agenda is closed and copied to the meeting minutes page as a basis. You can start editing the minutes now. The same way as in the [wiki](../wiki) pages, you can format the text, link minutes to work packages, documents, include work package lists or other macros. Don’t forget to **Save** your data. From 57864b93104bc2f16ec0db8f5ab9d9741d3b7bbd Mon Sep 17 00:00:00 2001 From: ML-OpenP <70652047+ML-OpenP@users.noreply.github.com> Date: Tue, 10 Nov 2020 17:31:54 +0100 Subject: [PATCH 10/20] 11.0/macros, wysiwyg, etc (#8836) * changes in WYSIWYG docs [ci skip] * Updating some minor changes in the PR. [ci skip] * correction of attribute naming in docs for embedding attributes [ci skip] Co-authored-by: birthe --- .../attribute-help-texts/README.md | 11 ++- docs/user-guide/work-packages/README.md | 8 ++- .../create-work-package/README.md | 2 +- docs/user-guide/wysiwyg/README.md | 64 +++++++++++------- .../wysiwyg/image-20201109183018255.png | Bin 0 -> 14763 bytes 5 files changed, 53 insertions(+), 32 deletions(-) create mode 100644 docs/user-guide/wysiwyg/image-20201109183018255.png diff --git a/docs/system-admin-guide/attribute-help-texts/README.md b/docs/system-admin-guide/attribute-help-texts/README.md index 1f8ea17e17..f980b49e24 100644 --- a/docs/system-admin-guide/attribute-help-texts/README.md +++ b/docs/system-admin-guide/attribute-help-texts/README.md @@ -28,6 +28,7 @@ This way you will reduce wrong entries for attributes. This is especially releva | [Editing or deleting Attribute help texts](#editing-or-deleting-attribute-help-texts) | How to edit and how to delete an Attribute help text. | | [Work packages](#work-packages) | Where will Attribute help texts for work packages be used? | | [Projects](#projects) | Where will Attribute help texts for projects be used? | +| [WYSIWYG editor](#wysiwyg-editor) | Where can Attribute help texts be displayed? | Navigate to -> *Administration* -> *Attribute help texts* to set up help texts for attributes and custom fields in work packages and projects. Here you can add, edit and delete Attribute help texts. @@ -81,8 +82,14 @@ The Attribute help texts for projects will be displayed in the Project details w They will help the users (e.g. the project managers) understand what kind of information to put in which fields. -![image-20201007112035870](image-20201007112035870.png) +![Attribute help texts project overview](image-20201007112035870.png) -![image-20201007112741049](image-20201007112741049.png) \ No newline at end of file +![Attribute help texts project information](image-20201007112741049.png) + + + +## WYSIWYG editor + +The Attribute help texts can also be displayed in the WYSIWYG text editor by using a certain syntax. Find out more [here](../../user-guide/wysiwyg/#embedding-of-work-package-attributes-and-project-attributes). \ No newline at end of file diff --git a/docs/user-guide/work-packages/README.md b/docs/user-guide/work-packages/README.md index 3505abd272..3f755f4cba 100644 --- a/docs/user-guide/work-packages/README.md +++ b/docs/user-guide/work-packages/README.md @@ -15,10 +15,12 @@ keywords: work packages Work packages have a **type**, an **ID**, a **subject** and may have various additional attributes, such as **status**, **assignee**, **priority**, **due date**. -
**Work package ID** is defined as a unique integer assigned to a newly created work package. Work package IDs cannot be changed and are numbered across all projects of an OpenProject instance (therefore, the numbering within a project may not be sequential).
+
**Work package ID** is defined as a unique integer assigned to a newly created work package. Work package IDs cannot be changed and are numbered across all projects of an OpenProject instance (therefore, the numbering within a project may not be sequential).
+
-**Types** are the different items a work package can represent, such as task, feature, bug, phase, milestone. The work package types can be configured in the system administration. -
+**Types** are the different items a work package can represent, such as task, feature, bug, phase, milestone. The work package types can be configured in the system administration. + + Work packages can be displayed in a projects timeline, e.g. as a milestone or a phase. In order to use the work packages, the work package module has to be activated in the project settings. diff --git a/docs/user-guide/work-packages/create-work-package/README.md b/docs/user-guide/work-packages/create-work-package/README.md index 0db28dd3b2..4af2c07ab9 100644 --- a/docs/user-guide/work-packages/create-work-package/README.md +++ b/docs/user-guide/work-packages/create-work-package/README.md @@ -9,7 +9,7 @@ keywords: create Work packages # Create Work packages -| Feature | Documentation for | +| Topic | Content | | ------------------------------------------------------------ | ---------------------------------------------- | | [Create Work packages](#how-to-create-work-packages) | How to create a new Work package in a project? | | [Add attachments to a Work package](#add-attachments-to-work-packages) | How to add attachments to a Work package? | diff --git a/docs/user-guide/wysiwyg/README.md b/docs/user-guide/wysiwyg/README.md index a5a7471b7e..b171ca9b3b 100644 --- a/docs/user-guide/wysiwyg/README.md +++ b/docs/user-guide/wysiwyg/README.md @@ -8,24 +8,38 @@ keywords: WYSIWYG, CKEditor, Links to OpenProject resources # Rich text (WYSIWYG) editor in OpenProject -Starting with version 8.0.0, OpenProject features a quasi-WYSIWYG editor, powered by [CKSource CKEditor5](https://ckeditor5.github.io/). The underlying format is GitHub-flavored CommonMark ([GFM](https://github.github.com/gfm/)). All previous textile-based content will be migrated when upgrading to OpenProject 8.0. +Starting with version 8.0.0, OpenProject features a quasi-WYSIWYG editor, powered by [CKSource CKEditor5](https://ckeditor5.github.io/). The underlying format is GitHub-flavored CommonMark ([GFM](https://github.github.com/gfm/)). All previous textile-based content will be migrated when upgrading to OpenProject 8.0. + + + + + +| Topic | Content | +| ------------------------------------------------------------ | -------------------------------------------------------- | +| [Basic formating](#basic-formatting) | Basic formatting elements in the WYSIWYG editor | +| [Image handling](#image-handling) | How to add images in the WYSIWYG editor? | +| [Macros](#macros) | Available macros in the WYSIWYG editor | +| [Links to OpenProject resources](#links-to-openproject-resources) | How to link to resources like wikis, projects, meetings? | +| [Embedding of work package attributes and project attributes](#embedding-of-work-package-attributes-and-project-attributes) | How to embed attributes and attribute help texts? | ## Basic formatting The CKEditor5 build in OpenProject supports basic text styles, such as bold and italic formatting, headings, -strikethrough, inline code, and quotes as well as inline image handling. Pasting content such as images or rich text is also supported, while unsupported styling will be stripped by the editor. +strike-through, inline code, and quotes as well as inline image handling. Pasting content such as images or rich text is also supported, while unsupported styling will be stripped by the editor. -### Linebreaks +### Line breaks Instead of creating a new paragraph with Enter, you can also press `SHIFT+Enter` to create a line break without creating a new paragraph. ### Links -Create hyperlinks by pressing the toolbar (optionally with some selected text), or by pressing `CTRL+k` to open a popup to enter the link href. +Create hyperlinks by pressing the tool-bar (optionally with some selected text), or by pressing `CTRL+k` to open a popup to enter the link href. ### Widgets and Newlines -CKEditor usese widgets to display block elements such as images, tables, and other elements that are not inline. You can select most widgets by pressing on it - The only exception to that is the table widget, it has a little select knob at the top left to select the entire table. +CKEditor uses widgets to display block elements such as images, tables, and other elements that are not inline. You can select most widgets by pressing on it - The only exception to that is the table widget, it has a little select knob at the top left to select the entire table. When you have a widget selected, you can remove or cut it. You can create a newline below it by selecting the widget and pressing `ENTER` or `↓ (ARROW DOWN)`, or a newline above it by pressing `SHIFT+enter` or `↑ (ARROW UP)`. This is especially needed when the widget is the first or last element on the page to insert a line below or above it. @@ -34,14 +48,10 @@ When you have a widget selected, you can remove or cut it. You can create a newl As CKEditor5 currently does not provide support for code blocks, OpenProject can display, but not edit code blocks within the CKEditor instance. A code block can be edited through a modal window within a `CodeMirror` editor instance. This has the advantage of providing syntax highlighting and code sensing ([for supported languages](https://codemirror.net/mode/)). - - ### Tables The GFM extension of the CommonMark specs adds a definition for table syntax which the CKEditor build of OpenProject supports. This definition requires all tables to have a heading row. For tables created with CKEditor without heading rows, a HTML table is output instead. This matches the behavior of, e.g., GitHub. - - ### Autoformatting CKEditor5 allows certain CommonMark-like [autoformatting keyboard strokes](https://ckeditor5.github.io/docs/nightly/ckeditor5/latest/features/autoformat.html): @@ -51,7 +61,6 @@ CKEditor5 allows certain CommonMark-like [autoformatting keyboard strokes](https - Create a bulleted list by starting the line with `* ` or `-` and a space - Create a numbered list by starting the line with `1.` or `1)` and a space - ## Image handling @@ -71,6 +80,9 @@ The attachment will be automatically uploaded and stored as an attachment. OpenProject has supported macros on textile formatted pages and continues to do so with the WYSIWYG editor. Note that macros are not expanded while editing the page, instead a placeholder is shown. +You can find the macros here in the text editor: +![Macros text editor](image-20201109183018255.png) + ### Table of contents @@ -102,9 +114,6 @@ The rendered page will then fetch the work package table results dynamically, re Use it to embed views in other pages, create reporting of multiple results, or to embed a Gantt chart view. -## Full vs constrained editor - -In some resources such as work packages or comments, the editor does not exhibit all functionality such as macros or image upload. ## Links to OpenProject resources @@ -130,7 +139,7 @@ As with the textile formatting syntax, you can link to other resources within Op - **commit by hash:** `commit:f30e13e4` - **To a source file in the repository**: `source:"some/file"` -To avoid processing these items, precede them with a bang `!` character such as `!#12` will prevent linking to a work package with ID 12. +To avoid processing these items, preceding them with a bang `!` character such as `!#12` will prevent linking to a work package with ID 12. @@ -140,16 +149,15 @@ For work packages and users, typing `#` or `@` will open an autocompleter for vi -## Embedding of work package and project attributes +## Embedding of work package attributes and project attributes -You can embed specific attributes of work packages or projects using the following syntax: +You can embed specific attributes of work packages or projects using a certain syntax. +Examples: - **Linking to the subject of work package with id #1234**: `workPackageValue:1234:subject` - **Linking to the current project's status**: `projectValue:status` - **Linking to the subject of work package with subject "Project start"**: `workPackageValue:"Project start":subject` - - - +### Embedding attribute help texts You can also embed attribute values and [their help texts](../../system-admin-guide/attribute-help-texts/) by using `workPackageLabel` instead: `workPackageLabel:1234:status` would output the translated label for "Status" and (if exists), the corresponding help text for it. -Note that these macros will only be expanded in the frontend. For each individual user, the correct permissions will be checked and the macro will result in an error if the user is not allowed to view the respective resource. + + +**Note**: these macros will only be expanded in the frontend. For each individual user, the correct permissions will be checked and the macro will result in an error if the user is not allowed to view the respective resource. + + -**Available attributes for work packages** +### Available attributes for work packages -The following list contains all suppported attribute names for the `workPackageValue` and `workPackageLabel` macros. +The following list contains all supported attribute names for the `workPackageValue` and `workPackageLabel` macros, where `1234` stands for the [work package ID](../work-packages). | **Attribute** | Usage example | | ------------------- | ------------------------------------------------------------ | +| *Custom Fields* | `workPackageValue:1234:"Name of the work package custom field"` | | Assigned user | `workPackageValue:1234:assignee` | | Author | `workPackageValue:1234:author` | | Category | `workPackageValue:1234:category` | @@ -179,7 +192,7 @@ The following list contains all suppported attribute names for the `workPackageV | Parent work package | `workPackageValue:1234:parent` | | Priority | `workPackageValue:1234:priority` | | Project | `workPackageValue:1234:project` | -| Remaining Time | `workPackageValue:1234:remainingTime` | +| Remaining hours | `workPackageValue:1234:remainingTime` (sic!) | | Responsible user | `workPackageValue:1234:responsible` | | Spent time | `workPackageValue:1234:spentTime` | | Start date | `workPackageValue:1234:startDate` | @@ -188,14 +201,14 @@ The following list contains all suppported attribute names for the `workPackageV | Work package type | `workPackageValue:1234:type` | | Date of last update | `workPackageValue:1234:updatedAt` | | Version | `workPackageValue:1234:version` | -| *Custom Fields* | `workPackageValue:1234:"Name of the work package custom field"` | -**Available attributes for projects** +### Available attributes for projects The following list contains all supported attribute names for the `projectValue` and `projectLabel` macros. The examples all show references to the _current_ project the document is rendered in. They can also reference another project with `projectValue:"Identifier of the project":attribute`. | **Attribute** | Usage example | | ------------------------- | ------------------------------------------------- | +| *Custom Fields* | `projectValue:"Name of the project custom field"` | | Project active? (boolean) | `projectValue:active` | | Description | `projectValue:description` | | Identifier of the project | `projectValue:identifier` | @@ -204,5 +217,4 @@ The following list contains all supported attribute names for the `projectValue` | Status description | `projectValue:statusExplanation` | | Parent project | `projectValue:parent` | | Project public? (boolean) | `projectValue:public` | -| *Custom Fields* | `projectValue:"Name of the project custom field"` | diff --git a/docs/user-guide/wysiwyg/image-20201109183018255.png b/docs/user-guide/wysiwyg/image-20201109183018255.png new file mode 100644 index 0000000000000000000000000000000000000000..03a7383eeb66c7085fe4767690ca547995aafa3e GIT binary patch literal 14763 zcmZvDcOaK-_^<3_Cn1|8*;(0pg(OKxcJ|Jm+1VpxkAx7iWp9;`z4zWEGSBt&p7T5B zkJBG7@7KfgJokN#&$#XoRTVir910v16cjuKd1*Bi6tpb(UH}^t{=2dzBZh)Pi=rSc zq3)8hmFlXaK6H8c(qU(_wS?nKH`5zQpDbFF7{zKM6Rqc3&uOZ7M!Ie*pXb&5K0njZ zV${~LFA~)<*GN+HWaYPiNsNw;s{Y4V57XrQd~PAdgs@)^ld$(-Z#Hw%z2->7VMk=8 zp2oM^h}*YWkCO}+bAj&8^6^3u8)`OQ^!Vw>FsW~|>4wrFXf-<1THIXlKJZlK!YgdvTfcH1Zge%9QjMO!;?#;0Qgb+T z6CuIDXfxn?*lUcux!+zNJ!z=6HoEM+mTfUVeeG>dX$;gWN=(q<@8*=)+g=SJE6yX5J5 zu_|-jj{N6lz3SXL0>K}Iutrv-MH<(NG%VivYBG~ZvXW}|l>E1Hb~eFwuS73njOn#o z`ncaK<>lx5s^p^e9)wf8ajU16%_braLAS4&{Pg{Kk`j~p)29$bJZ>uR1ZgXD3E$~R za3(6azTrZ2^fM8KNFT4|rtdaho)gGsmp-3LfQ^b%yshi8C*$w$FP=N_{PC}eD1~8< zH}@&Rx9m~5F2h(`epJ6)Z=^Z8rah6;>|#sjP^D22ppu)t!_{d=7}`!4BF&e2FF=y+ z)2B}*b_=o}K77z?^0~6wm)T0S5F$?NqgyPerA48VCLGe$CI2H;=q5Ea^$`!{4py|h z|NOiG>x){F1df;1uXhaN5p_2TNx;O^`*9XNB=$b=rkfP)XC7btkCN z67sCeScLozISEvG=yqK@w6Ku1%ZU5;+5i^!`$C1IloeMJQquW^mtGQ&9}`JRN*1!; z+1no;9+oT^QnUG}!~`q1#eRF#l&7+WiD-FEy=d=6Y% z*>rpLgarue6|(zhmwS>0?B>zgb*fRqWzkS+0$fTE?Nbv9sgip}>ov7Qyjr_W66T(hC1rzPwjric3h4%2A_ZVZjmZeU-%Y+IEF*&J|BI-HLBrC)v%Kow;%nyrT9+H@oBHZ@%>-G!@zui&8NQq2U z%`NKpLNZ#}Uee4Y^b8DWH8nN14h~Y{;wYP&n_5G3lGAdjDsqkK@v_u<@Q=oA!Z&8>T(5UV(#YxS&xvU{s~3;7c6VPbEiJ{y#kIWumW(Un zmOU*`W#pdiF0FvFbRy>_`D2L{FGO=$RwBo7c)C5svN9=YX>|D6+}hgJ4C7ynJq%x# zCoJu(_LUMZCzT@t7f~-XzE}}8GptNDdW-SdOo!Fh3Zi3RNYF>mc7)&3th6L2CMM=| z-8XV^b$x#O_NWoJM2?z7@yNglQEazkuM(<5l3^1LI_ig<9DRr|Y&ok%^rr@A z;S{_$#SJH)o^JSdIlO%K3=6U$S{^-L-L2CLs#k@UXQ!71EeX!!=g&j7CaMfaKEF^F zY?RHGkd#C<=}nuWH@rAk)z-cSzZN2m`d-O|3*W3lOa0k1DVBFy=ch*Hp6I9&$v-Ia z3CJ0WM4V$?XV3l~xa`y)MZJF?0k0}AC_dS8kp|!6*<22K`1AepYp~H#ncpeOGsa*V6Jn#U z4&)M$vT6C}JWMdy8m~a{X={@fT&cR5WEC9an71)fZ1^+fL7#cWU_k*iNa7Gq?+Xvd zjo~d{PTB62?w+1@p`ALvrv)0#Gcz+xyvDc>yPO-nFTHfWI^hwAv>EiFT8lmLzW95G z`~LmtgoGgS`z9GuLHK<2VwiqcBqSsf1?=eGhK81Uo;sxnIpcet{%Mb*lbYS$j_B)C zO_shL^5uLf;ibVur4`) ze%d z)2G^EJGc?=_qi@RN@y6S6s`sa^dHpBvdO8IFGoyykoIJIxc+o-aImSnyPM@LJ{R}p z$p#0dh#SeBM`_ZHUgx`;WxbNcBifsnTU9f*^KDl{&xa*x2{TGc2;aYduUarfy22EF z?rv33P#|S(&2I1D(4Q%VRnR?5(sh3NXTqk`HEEjcZQS?kXB zzq_oYIwxN2Mu{(P?C;x?+_;fx*crjs6KBrCC{q6A3-QIpg~t8Q*p!`fCx;uFr3M(E zUwp-!b)vA2q!#JRmLqU+ch82)^7HfM6%>56iUPHYI_6q~n(Zh_IdmsK;kn6I={$P$ zD2zsoS}u}WMnNHDs94JK!`BCr4SFH217%r3u z!l%lsnrjQWu32M$8wpwHr6}>&xgL-H7|8!|hwgxc+M&0?m4$Opm&XfVq`@5#>sp7=p#z?8njHu)0C=q1X?%`q1+eMqk z^T5SLBb{p7D=%stp*2-1jAPc&2&Ur0QrJ2=O6RJi(h`T*ZVa;-85`4aauSM)it>3s zlJ_qwFDGGnhXdIg^?ix?-aRR0WxUDBN!o<(R%sd>Bsg~PE1P3wSP>Bsi9BY+wT^2B zc0c^DURPCD_iqg%$bOVA8XOvG@#po?&P-&w_XRm+C*AGa7}3$u(DRxv&QD9NCiup0 zl+XbbhMpA#aoyl~%J*C%UNJ|NnS?aj1Yk(L`;o!GM`g(L@NaNuE{A0$Tr$oK1#Z|3 zB$=TSVD%pGxG#nCPy0a4fBW`riPyOs1Pli}wX;YhY;%(@8W&XJ>gsBqF%$-~X2`IP z(Ne>?#l^wd8o-W_MbYoxVT8;2MMV+XQU*Z_4vni=mQ3M>*4SD5dIK_s(`i%l_iDf2 z&ni@3lshUZP2&|7fZ@21k2l8#m=>@?PR7T^pcMF8kC;~g^o;5@3b%feug*4ob5@t| zJwOh7dwW7cLKI(dpI^V!&JIUj!X;t6qodnm6B3SR*l_Q3pNhehKF?zf8GYI4MP+7YhHOxk^;DtB zafmcMAQ_~@Lml>kRtU)L$s>_~{3p4;)aWA?`iftQ!82cn+Up0nP9?V${&b1+j;`?0 zq(hOpW%NdjT^?`N#0L^qc6R*hOiE4bLj`-^IT|zIR#EbdR_4N%_!>n-H$vNYcXxdX z3hqr!H+p+h3cC>U&ab>YX8)j|CrfMnax^j!pOrQ<5l|lD;^M>$hQ{l%6J3*LAS>p! zw(uaillkT51n}3^)~a0(n3z;jf}xmSbA?9TSMZDj0?L;1RqT!rv*f#X?;t*~oOY(e z@1(h)UcaN_4{zypdG74-XY3X9>W*@=fxeuFH7R3YNc#On1q8q0 z1fW7%N*!%atqE{I`B)#ki+pTfLphN9sA|;43i3*wj&8ym=D^%iGi> zj#9M}^yLdeCxW~ZAPJ$hMc~m#W82rHP()}Ikv@I;l=Hn3AY4FiXtoo~#RUa^D!G2D z%>K|x%eB~eZH>9ffl;N>@KWHxqfL#BS4>oPOv>BjF}7+P^i3Ua6gTdk?lejjk1z-d zQt0aH;;mzaue}(awH}i|FVzf#Xo2Q83;Y`}&gxJ>g3MdjC&kxL9z1v;;J8ZYGhrAF zhzc4TygSsPsMOSOl~lpzo*q0v)WPB5?T}}AM5pIRGlsKGzU2{Ryj%oc6_{;wOPiax znX04gW%slSE!g)e0bI|P^@?W4S_7H+_$VC->B1LZNue57R8(kwbz)RaKmgTupWXpLU=sj}J7sf&J{wd&xb{+$M8!(Wn4=fw*vQVdJ^_}{-BAs1<( zjyO3v@$pJ3kj(V=6G6yz{rDjbv}bc`YwZa1hq=v7%RT2|OMF>M4k%{FyR8IvC%?_w zIy)DT_$w>B|JzLj6OY0_CWaX4IX3l&q#u>uzw!4+U)TF$5+_$YvT!ux-I<&2g;Svw zzPHfHARs`-6nhom4cw{?c%t3bIImJ7=M`UHUyXF}F83_8eA?J<1fnM`YXKetq)E@p zid$U&hXSRKN7F($8#sKnY&gOsAY9yzw(%enQ&obXNuXn4@oOa;={_8vysDh3s=7jH zJHd&EgCi*}E*{zir4RH z0?~~d7$7Mi#q38SS8!xxC$!w%xgeVP{M@uR>MSxKwsb^Lg#wicmZrCysKf&b)UgmL z7BM)eUUzwMO2%hNhKh!Uz+hY&QA&ti0sBR4gfasFgoZW`jo4+c{U(>ot{!wr%c8n-g;pW1pm0^~$&)>3ip`L2Hg$WL4HqXC<1Wj+VwY`DaS-&U3LCwsXxcF5jhi=HO?k9FQ1IOVA)-bn0&wXQ zhEHB@Gxc$wPYx@UC2|M!_ZPc)dg96A*zTe!?9fMGJLF>7sZTwkDrCDa`eWlG9wr*} z6<%E^QIk_snd&S>g6UDELcF{;h=_Q%az1{f7ZyH?IImPRTM@t?8X96| zV+#P3WN~W7ljLrFkAtIeMM%j=40;LB(!E~~IhqFsV$%@XGUIW82QYOH-kL|N(_Jj; zbPc#@*{j}Pg8c6k16Ef}A^!UfpFDYzf4>*DoW^7Kir3km91=!Y1k`P?l_e%U6hMLu zLFhPMFDNcC>Ly-XSwS``^d^U_tu3e5@f?=N(UdbHlBA@j?seZupS`@;x!g^^Ji`Kx z(GJmEVm81;7B0Iv_4Ow5NC-h?|9!(j{^M}S^*gpeI}!Q@yAJplh%pofxVbb`en_pO zNJ{cclC+h_k01Nqd-hoz?oe{Qb#QR7`@3&E zzPo4L2}+6iBs?yZu#osj9vNx?(VsrCfTq+jUkjRXj@lelR}>$}(@cwz&yI~XQZaE_ z@M9#R`9^l+6?wbA4VqW*DxQf{-gMe1_yPPcP;Jh0Vd)VcM45{V|Lv^ zhf#LF9Z(I-i4XQupNFE(==YcS2m$U2Zh53s7Xb||PF z;+d+mdz~~v2?;j?@u}WIRaAX05FrIP28a_t;1ah(bGI~TAOJR@CTj)l7ki&y1JVEm zpG?$4;PcDIh@>P6s1A%wOlmnVi$|&olCE(R8k?BR_hm}Ks>;jD16pnwDtNZH{dH#^ zBA$%Ll#uFJTa7PmB|0U=GSdez3dqHDkj)F7k-2YWA9g!#Pd-5LNl#DjQPWpAKY(&? z2jqNoY%CLMJIK^P0b7>7Czz4E_28F&|GB8B9SRLdrURS732-wY)QAw$*50oFE$%MQ z`464vw_oD|h(KOU^zY(zq?7>&N_^nJDz-XZM8e+ixfmwy@n{pky^|xyQ%Eyg5HTGCba$ zD}V2!m?NpEh(k$5wdOpc({-eL@ul4FILCO?!0hg1y}~nqx$s*DK|Ga zAvLv1YCW=9(b_R4)TE@CA<}PvgjRq3I$#J1S^}J&VhOZj=DT+#IwPp|CLMYuSl(48 z3w}8P;jKsmDaH7ZMu?yZB2w`9xYj1@F=WK}u$3W`azNX1h`? z-4XES4eH|3QYO?F5V!*T{G`eT3;@6(Q3#x;X?mJ^Zf*`w&@W^=cgQ>%N--$<$U|8# z^hEm=X7u+t<*0>#o=?tEw~M-H{{T!QC|pQvU8~u4!nct6{Osw|fQJd}bAZbvy}U$m zu3ZDI4v>*gMg}b|l_1IV^fc*0HJdU0nB=m9CrCBBAgh7LQuXz=4rJr{q1z``r`5h@ zdYQL%*wAqU0s;_i74#|4l6jB2O1HPSQLOI~wYRrx);iv0xpyx=0TIN7geF=h*b=_4 zN!eE&)SYgBMYNW*$HYY-ErRIrAsprG{5(1-Nl{zbd2=*6ZN*FYoPZco0Z@s{Mp0FX z$-bPhb@l$*Lew-rgN(`tN`m29&u}#?$*Lx*fXJ=q#9dK)e zIRd!Tu8TCH2T=()zqr0W9sG%W!ygp8!jW-tBnY$ws3Gg<$m27?TOj1T4Wt=MHjGT- z))$Y{tttWcKdcBH23DbIwQqV&Hl8;tX}GB_rD>RV;wTiroU7{tg#NANbeCMx?s9~w=Jyz~x-h~#zi;+7-0#fJ-_ zJ6dhW0K@_sj{i>MC3U*zA94^nxxCI?lKu|pfb0p$4g!M@w8ShBa=|>6R8@@%@Kc9i z0MRL#&+3g@zBE`r1_lPI5R{OY=0@P~Fq7b*cnh5(5IS1kv>1nmhQ>`7VCLw=1OxOY za9;oox4_2c4S0^1n*kuTeunQjyJHy)G#VGUE}{>Wm=Cc)B|usbLe9XB0pg5X8(3CE zEBFd(B&-o)vLV@1Q}g(|lny{1l1?*Tr+83~fJ#0qTgHOcsH+?CJ%OXOx%o;+NJ#nO zC(#euNA00E5rrB$TmKgt?eJ8i%}|IV;IyD9AuZl=rhy95f~`S`{yhhXo`C?f$pG|% z&4-re`R6%sm4OZg*z-0}*ARu)0Kh5eYkcnM!R*eU;Q`xh`u_bIEVzuZ@oj+lZ%axz zlWI(Rhzo~1KIPY-`p!m}$TZEgH^8%MmYWip^dtoY2V+A!HvF?W*0*su$jL}xC@YIO z?YctsBjv$$kocIHnVW#9LGuLdMOn!5N|g}JbhRCtTYXxCV_PU<8(>@`)jRpUwmMvN z3sEwkmznfqfg_*!@ne(g@m&-YauZ}0Aduw*S_=~H()4D76VtkgIWS&v4^&&F@W(O3 z4{WA|5mmNm-jfa!gNvtI@(}6-xFanPPKYewaq)L0k>4h5XxOywmQfQ6P~n*dPb)z^ z$iJ97=^in%=oI^=>yCnyf{xe_X=DPnv>?8isb|;BVC26Bf02HDeLX5AB@B85qC^j( z@NmqpxKe}QfT%=&wx_NE{RV33%NJ?JP7#h-T(^(&#?P-*zZLUGGCx6asx^un&+)OFwDJ^uTbj)S9kjGGWZ^)>Jb+uGVx1DpT=BR0y{orZ@A z`=DBZCWSy)5OfSGWYHE+nT|4Y!qpDq*tzX0X9k)W-v_sY{M!n8f5Vqs?w1jkwPW%-5I{?`gRs^p$S zG!U$Sw@;QTGsQl)bg;JvbD&L+6X^(-CnJq0D9HK(98`Vs#1Gg^-Qln{>`>LXj)Wt6 zfTSjM}dKx(ylD+TM=A%gc*m{VFr+xA?D; z;0$#ZI?_-`4dtqL@$p%oKH)$;&I7jq#GyU#6ePi(eei%B6b&##QlE-iX#2$pg;730 z>hvu>%cc(sv8vCW1wlB?!PSB3=`Tac=00qTfU2#QPlCW48t=0!rJ72&NQdN@NkD`{ z`}y-Hq6Ydb7j-J9!1gZzVF^r4ec`u*Oa8T3xBe~cx_@9G@;)HfYLIujrZp~%-6p(~ zsZr1l3Jap0tn=I#`&jCriKa%N$bAV_6d|fetpjII3eYbMTNTV4G-+cY(0=XjWu}~Dgp`zF z07wlNyP}UlCr1{CQphQc<;)*o5vz73E@Jh%xCm$zYD%QjSm4G%${UoDMT-0(gO7Yc zs4LVgMWyjN1{;nA+>PCpbZ>+HEExf}-^>UDhpvN;iK$gYga^z4(d_x2;OP8}XN8;y8@=n>x0au&LeYR!0kgX` z#K$!2kp9|T0IP1a-ktvfyfFasNxTllG!_&^jQ3uFB61A%R~3X+5L-O zxR?H1O8}H9>OVU(k2c0FegB@*-hFXt)L3Cm$D0N9eK45*FeBXRYdXba)DV`2KjRi; zB5pj2ii&+zHZRTnwZ3zLCH`9n_9ibcuL*d5*mS-7z`4;_5}-WLPRrm6tRXI}6gWDF zh7AjBH`jszdH#=W1M|z@HqxzyvL2L`MNiRPYdeQpS67F0Rhx#tn4zR>S@`t(18Hy{ zZ~@4;4A6DG&tC)YL>O11n78QJ*_oEQGo4!@z!vb%i6|%(%k0))MMiNYOV=xu{7%6mLY$MBM4e*|K2BBQ;3KX|pNsadwIIlpuf?{O8Y~Z*@?Ynujw# zXUP$5YbBzh3Wt`cC3kYX5Xr#J9pjYl2pH0PrrzBdfYd@!)pS;;th96n0BMjpkB=HJ z!(~EA^}&I0S&Wv;b5@{_)=aqrQVKN2L?LH(K!6DL0U-<=_JQGDD00Zh&}NYF8qj(& z%F73{7#MpGNE@r}1apnoIJ^R;LLA(eRQe*eSg?Zp{Ll~x1q{>!bR;C+bY12!!l*?k zR8&;tm6hAU){0I~j|8RC5CDYZ8i@sd+@izj>FGib|BN(XnTFGCA!Hr_+&ux?Srib~ zk&FX45K19pA-OH`zIw_20W@b^&_46kae$m~G#sNMcoF!m5%>F{Fc9+mffFEO4`2Ww zV-FzgqR%>+be*$ap(n&Py)*MsM~s7m0Lpw7MqijX z{;1SlLRQ$?*+~GX6FpgFfZ+jD;5Qm^T_kccn z4F0+;j8z~75g-kU_=smwaae_%R+em>cvydbwj6_~C^cjWFr~6j_n)&T40O;@2{}m{ z88Je_A$0BNyAd~Fd|>Iwbb`xv%}QT|#WT=Svp#;r^! z>MS`UK;aR90cD93tW0clZ|5EiAH-w=&A#O!M?E@-3edjvLD4D_4Vs{+*M-4~Hz41D z=7kEnxueKNyvAS%`_kf~^w$Y~^$r7Yk)Y+Jq)^7i$E&p#)$~jlag(Q{q(sHWqKS!# z2?z*iI{Mw_j*(SBDNO2@To*SqG%R&kQ3*A!lOI`!egktnr~t8GV2m{V{n^a-@1gPa zny1t;DC!y-q)_1GQprD@p1~-JnJof|fwJxH@3(;A^%!t8bf>wB5#6#RU2xKYmhDcv z@92Z9hp+=ub{%YZg3urL;lD^L147^V2ICs16uE z6En$M%sbxmOSBI^qhwgSdq$pWl^v5I~kx&uRn7qa&D+|u+!=H}+MAZ>sk z1q5gTgw&7U(skH7LEzjLh}2{a1b4IFR61SMb9Y$V#&^ZFb~{CyzPXdeTWJYoq2@rm zTdac8m3O-QA5nX$g^p4r7S}rgGBM?$80W15Y2;rcbZ~$-%gWBS(kNEIwEpF|45LuKCz(K#L8Dzu6|IJ+71wMn+R`Zl(g4yAZkStJm#E@65 zbqubNc)i#~E;P3zceRe>R037u|?E#JIzmcofTQ+r9fGEKb zhCY0L43r(L`5iZEa9(`Tuna&hg}gM=C|9D7rUexgnX^%R_>c|P6EYtR97<7-MA;)4 zGX3`L8=`FhQ+C{$uJ0cC9NBOBfm{Lo%l5|kW)()|XQHA=*h45z8uj6anxss3^RmpwG%iQY$A| zp;(K_L1z>O=6J=&W)KWI{IYZnAtECu4|(Z*egg(T-he>`Ru&PE{~5G5uGvx+5SBCnO^a29K#_WaK8oqd=;GT9U^KgBTDHE&v9shSw5TYXNN`5462|90wRaXnZ6lE58&0uvPN*Wk*h4E`Lpba4bO$dXI(AWnYtq+JL zp?E;r=(h$wmYW(b(k7yzd6Yd%z@iZz925WB**#N!G>vDUcCFN?kMq(U+C!#ZY|xld zZN16}c$~<{gz$bBgMjyiFf=TnL@=;Ax4JsI>Kc4hQ(K#);t1oSq&<2rX;o3V7du-- z`!!l$$FLMiL4`ozdApCbF4pqgobO7SJ3d^>=Xw>yB`7FZpjboQ=^IZ0&5J=yj0QkU zd21OP)W+4p{OcWI=7Evs8HJBen1tc9#;R{WA_vpyxSH){VDiDw6 z044#mqqxbT+Xllw`3_9N!j!O2CA~&;5ab2_S7PR$MXgXy#oMPxx5)$N+dw7iWMk2jnXc&>_pre40T&|@)2=ogc z4=nEADX{r451JFGB6T`7IZ44gnJo2iFnBoV$5CZsFYt|?+Uk)V;a&vYG|e2`BQJn8 z8+zI0Wx(@&$v)J9cwy*F^S~3l^M=snQ)*1D36!EoQl3;{vJA*rnYlSwqkUzs9>GZC zb1N%1utqpII1rj$?X*P!X}h}bd=%5GwdyD+ASh@6psE_cB1oC5htPZ=K~N(WW?>%v z)vH$kFIDTcLFoq%7`A`++)qr1yQ3;VE%@|~CL=Av4Iv;RTw+X5%NQ6l5M05;r z5WKv+5(QtgfNoRBo(#e&)1$O7j>a=$z@sg7t_QO_JC9EBu+giYslmRDes$)EXMO$# zqHF=mlJ)iXp*`*9fy`Wl+cJh|hUbmN-mH%U>+9>IqoRC3cFC@+jAtj3N+KKb7N@9X zdK?3?Ff^9>N>}B)8sVeUztoOe4up3&j-WNEYG}xgG<{01orBBQ%5&@e z*;tIkAw5_O2OX46Gk0Z|iR87}UKw6UaXu^WVzjy7KfIi#Ks?-&69Ys~zdS!ed@i6c zS->2a+1X{mSp>xonT|>pzyeiHHk<+jDm2W^{@$KS{zwww?@ucrFq+k^H@T<;c>`D*Jwq~j}jf^CiZ1Q0JTD623b7vi(*OKfBhVXrPeCdT(jK1DA zaM1zxm_Anmo;7HGC{o3nOW;$qTz<0SWY{?K(3`g6!%?lQVQ0(&jbl#vgYp{;<#h70 zFTt=PA|a6uzh<#c(AGS+ylgU8M}!l=b}|KxAJ)L&;_NTt6`G0|g6|nY`QQ!MVF=ZM zS(@_hJS8S6(0lfllWipFqep*)7;usS15-#CcZC)T9OW$_J3Sy005v55v76B(!IEUz z%rqo&>Z87>n$|iB9b6O=5YU6$AVVBL@3=gUZCN!-P#%dKk`&RfgVg1HaX_;rbpPowSai5|?frlC)4SxA{*Oc|csLwB1-hHEY8zbq>)hhbfLqRs|I~fEm zo{pB*XZYGQ2M}@X$S1Tjp)z%-(-T7KI>uNXm&+SrF~1<*bLu%&yQ+(kwwj*pK`Zi$0Z0%AD= z-G8QwMZ#bS7|DR=4UmZx?QFIV)q~rP!BRbSTxzUEJVP-o$?o)oBE9Dq5cC^(|> zP7wom3+QkZ6_sUW*^iGt(nCE09|^F0CcrnCWXQ!U0v_vI=>)8&XAG=?yNFeHvR(iUs$}(xQal~^GvN&zII93uAEI7HRkcql`hA;e zV|m=;(Q&sc-J1K*Hen17S!qf!FG`U4VX78DC~^t`&|H6!Hot(7(7-fXWmLe5D>^zl zEjW@eQUmdg6Y$2w5e_V5!a$)5bVasb`t1gLFGe2Ou(U;=!ys_0QSB6=J@7M_mh)|F z6w@fy4TmsB>>p(AMKK3afUVl(8*(ctSkH2WqXL<2cS8Pnxh9%3QL4ul4)ZGfCJS7(mTXm7MlN&C(7;fIcjWe4$-D~UqVTKB0+ij+DC z+_j7hkbW>>q{H3YMyrBm@$EJt_U!5^HbfONviBo=+(94) zKmeE{0cg_v#rQjnn~od5pGC8PgG^z6!od@Q36H(i>`1NlU1FR7*bxn?HX7L#acze_ z&T-MUM3N9`<CV9+m`Tj*!8qdrKcW>x%8XUgZraMDWiAbRIMR zcfXY&H5@${mh_O#&;}=~;#-U~+m-v$aE>ZDps>e`ZG1!gr(XGMt*^I);B=Qr*Xc}B z#6;z+027t_hS1`A?)WgrSF_%qFOl%RQ^%r{m2;e4sQp_Y;R_C(+PO7oFq}kY#lfm~TydOfy7n%d7Bm#%%s6T;D zG5#kBIfA!^1tTLcR@rxXpA1*_p~Nr+J|14qiw$xDCOD)uiaTtb4wsE{Fj9Q$aD@X^ zzeoV?FiN$*R+IX1YcLn<7O3Rw}66=8q9 z#0|7Ev!!~haqIs%V~DHWpYi{mIm8Vt(%bky$J=MHdjQ$c{mUyOF>5n>D|hGN5GIO(jEeMUNxe7! E3$Xk=cK`qY literal 0 HcmV?d00001 From 9571377d383a20fe9c64fb77ea6765c3cdbfc875 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Thu, 12 Nov 2020 09:12:33 +0000 Subject: [PATCH 11/20] update locales from crowdin [ci skip] --- config/locales/crowdin/tr.yml | 4 ++-- modules/boards/config/locales/crowdin/js-tr.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/crowdin/tr.yml b/config/locales/crowdin/tr.yml index 88446b9b6e..310b70b283 100644 --- a/config/locales/crowdin/tr.yml +++ b/config/locales/crowdin/tr.yml @@ -537,7 +537,7 @@ tr: invalid_url: 'geçerli bir adres değil.' invalid_url_scheme: 'bu protokol desteklenmiyor (izin: %{allowed_schemes}).' less_than_or_equal_to: "%{count} 'ten küçük veya bu değere eşit olmalıdır." - not_current_user: "is not the current user." + not_current_user: "mevcut kullanıcı değil." not_a_date: "geçerli bir tarih değil." not_a_datetime: "geçerli bir zaman değil." not_a_number: "bir sayı değil." @@ -617,7 +617,7 @@ tr: queries/filters/base: attributes: values: - inclusion: "filter has invalid values." + inclusion: "filtrede geçersiz değerler var." format: "%{message}" relation: typed_dag: diff --git a/modules/boards/config/locales/crowdin/js-tr.yml b/modules/boards/config/locales/crowdin/js-tr.yml index 8c4162d64f..468ad92491 100644 --- a/modules/boards/config/locales/crowdin/js-tr.yml +++ b/modules/boards/config/locales/crowdin/js-tr.yml @@ -50,7 +50,7 @@ tr: action_text_assignee: > Atanan kullanıcılara göre otomatik sütunlara sahip pano. İş paketlerini göndermek için ideal. action_text_version: > - Board with automated columns based on the version attribute. Ideal for planning product development. + Sürüm özelliğine göre otomatik sütunlara sahip pano. Ürün geliştirmeyi planlamak için idealdir. action_type: assignee: vekil status: durum From 0325b87d5799c68b324c5f48139fadaad7a64622 Mon Sep 17 00:00:00 2001 From: Cyril Rohr Date: Thu, 12 Nov 2020 17:08:45 +0100 Subject: [PATCH 12/20] Update docker-compose documentation (#8827) Requires #8798. cc @b12f --- .../installation/docker/README.md | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/installation-and-operations/installation/docker/README.md b/docs/installation-and-operations/installation/docker/README.md index cfaabdc747..cfa9bad07b 100644 --- a/docs/installation-and-operations/installation/docker/README.md +++ b/docs/installation-and-operations/installation/docker/README.md @@ -17,27 +17,40 @@ installed. OpenProject with Docker can be launched in two ways: 1. Multiple containers (recommended), each with a single process inside, using a Compose file. Allows to easily choose which services you want to run, and simplifies scaling and monitoring aspects. + 2. One container with all the processes inside. Easy but not recommended for production. This is the legacy behaviour. ## One container per process (recommended) ### Quick Start -First, you must clone the OpenProject repository: +First, you must clone the [openproject-deploy](https://github.com/opf/openproject-deploy/tree/stable/11/compose) repository: + +```bash +git clone https://github.com/opf/openproject-deploy --depth=1 --branch=stable/11 openproject +``` + +Then, go into the compose folder: + +```bash +cd openproject/compose +``` + +Make sure you are using the latest version of the Docker images: ```bash -git clone --depth=1 --branch=stable/11 https://github.com/opf/openproject +docker-compose pull ``` -Then, go into the OpenProject folder and you can launch all the services required by OpenProject with docker-compose: +Launch the containers: ```bash docker-compose up -d ``` -After some time, you will be able to access OpenProject on http://localhost:8080. The default username and password is login: `admin`, and password: `admin`. +After a while, OpenProject should be up and running on . The default username and password is login: `admin`, and password: `admin`. -Note that the official `docker-compose.yml` file present in the repository can be adjusted to your convenience. For instance you could mount specific configuration files, override environment variables, or switch off services you don't need. Please refer to the official docker-compose documentation for more details. +Note that the `docker-compose.yml` file present in the repository can be adjusted to your convenience. For instance you could mount specific configuration files, override environment variables, or switch off services you don't need. Please refer to the official [Docker Compose documentation](https://docs.docker.com/compose/extends/) for more details. You can stop the Compose stack by running: From b0863f93d0bc7fbe804193a99b260b994eabcee5 Mon Sep 17 00:00:00 2001 From: ML-OpenP <70652047+ML-OpenP@users.noreply.github.com> Date: Thu, 12 Nov 2020 17:49:52 +0100 Subject: [PATCH 13/20] docs: changes in description for feature request and bug report (#8842) * docs: changes in description for feature request and bug report * Adding information to search bar on top Co-authored-by: birthe --- docs/development/report-a-bug/README.md | 13 +++++++------ docs/development/submit-feature-idea/README.md | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/development/report-a-bug/README.md b/docs/development/report-a-bug/README.md index 667cabe368..f10425d71b 100644 --- a/docs/development/report-a-bug/README.md +++ b/docs/development/report-a-bug/README.md @@ -2,12 +2,13 @@ If you find a bug please create a bug report. -1. Login to the [OpenProject developer platform](https://community.openproject.com/login). -2. Open the [bug form](https://community.openproject.com/projects/openproject/work_packages/new?type=1). -3. Add a precise subject. -3. Add a detailed description. -4. Attach a file (optional). -5. Press Create. +1. Login to or register at the [OpenProject community platform](https://community.openproject.com/login). It's fast and free. +2. Look for an existing bug report using the search bar in the header navigation on top. If there's one, please leave a comment or add additional information. Otherwise: +3. Open the [bug form](https://community.openproject.com/projects/openproject/work_packages/new?type=1). +4. Add a precise subject. +5. Add a detailed description. +6. Attach a file (optional). +7. Press Create. # Information you should add to the bug description diff --git a/docs/development/submit-feature-idea/README.md b/docs/development/submit-feature-idea/README.md index 65d74cd87a..a729a812f0 100644 --- a/docs/development/submit-feature-idea/README.md +++ b/docs/development/submit-feature-idea/README.md @@ -2,12 +2,13 @@ ## How to submit a feature idea? -1. Login to the [OpenProject community platform](https://community.openproject.com/login). -2. Open the [feature create form](https://community.openproject.com/projects/openproject/work_packages/create_new?type=6). -3. Add a subject and detailed description. -4. Attach a file (optional). -5. Set version to "Wish List". -6. Press Create. +1. Login to or register at the [OpenProject community platform](https://community.openproject.com/login). It's fast and free. +2. Use the search bar in the header navigation on top to look for similar feature requests. If there's one, please leave a comment or add additional information. Otherwise: +3. Open the [feature create form](https://community.openproject.com/projects/openproject/work_packages/create_new?type=6). +4. Add a subject and detailed description. +5. Attach a file (optional). +6. Set version to "Wish List". +7. Press Create. ## Feature idea guideline From fbca03bb5f4966dd3c31b0e35484af4a39614593 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Fri, 13 Nov 2020 09:41:24 +0000 Subject: [PATCH 14/20] update locales from crowdin [ci skip] --- config/locales/crowdin/ru.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/crowdin/ru.yml b/config/locales/crowdin/ru.yml index 910f945f08..885d5ec261 100644 --- a/config/locales/crowdin/ru.yml +++ b/config/locales/crowdin/ru.yml @@ -538,7 +538,7 @@ ru: invalid_url: 'не является допустимым URL-адресом.' invalid_url_scheme: 'не является поддерживаемым протоколом (разрешены следующие: %{allowed_schemes}).' less_than_or_equal_to: "должно быть меньше или равно %{count}." - not_current_user: "is not the current user." + not_current_user: "не является текущим пользователем." not_a_date: "не является допустимой датой." not_a_datetime: "дата и время не являются допустимыми." not_a_number: "не является числом." From d7892a09fbb961365c880dda1d2dac021c8c19c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20B=C3=A4dorf?= Date: Fri, 13 Nov 2020 14:35:02 +0100 Subject: [PATCH 15/20] Fixed Bulk edit custom long-text field (#8829) This field was being cut off during bulk edit of work packages. This is a small CSS change to fix that. --- frontend/src/global_styles/content/_forms.sass | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/global_styles/content/_forms.sass b/frontend/src/global_styles/content/_forms.sass index e231620259..c6abd6aa97 100644 --- a/frontend/src/global_styles/content/_forms.sass +++ b/frontend/src/global_styles/content/_forms.sass @@ -498,6 +498,7 @@ fieldset.form--fieldset %form--field-element-container display: block flex: 1 1 + max-width: 100% &:nth-last-of-type(n+2) padding-right: $block-padding From 542d56d777a93eb5d3b93fe3abd6677807f0bca0 Mon Sep 17 00:00:00 2001 From: ML-OpenP Date: Fri, 13 Nov 2020 15:51:16 +0100 Subject: [PATCH 16/20] docs - embedded videos for project templates and Ubuntu 20.04 installation [ci skip] --- .../installation/packaged/README.md | 2 ++ docs/user-guide/projects/README.md | 3 +++ 2 files changed, 5 insertions(+) diff --git a/docs/installation-and-operations/installation/packaged/README.md b/docs/installation-and-operations/installation/packaged/README.md index bd9f6a2438..a29f5d9e77 100644 --- a/docs/installation-and-operations/installation/packaged/README.md +++ b/docs/installation-and-operations/installation/packaged/README.md @@ -75,6 +75,8 @@ sudo apt-get install openproject Then finish the installation by reading the [*Initial configuration*][initial-config] section. + + ### Ubuntu 18.04 Import the PGP key used to sign our packages: diff --git a/docs/user-guide/projects/README.md b/docs/user-guide/projects/README.md index d3cc6d1f2c..93ac77fb3b 100644 --- a/docs/user-guide/projects/README.md +++ b/docs/user-guide/projects/README.md @@ -149,6 +149,9 @@ Navigate to the [project settings](project-settings) and click **Set as template You can create a new project by using an existing template. This causes the properties of the project template to be copied to the new project. Find out in our Getting started guide how to [create a new project](../../getting-started/projects/#create-a-new-project) in OpenProject. Another way for using a template project would be to [copy it](#copy-a-project). + + + ### Copy a project From 593cc7ad05a383af8b954295705db641119934f7 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Fri, 13 Nov 2020 17:18:49 +0000 Subject: [PATCH 17/20] fixed unintended user deletion during group removal of synchronized ldap groups (#8843) --- .../app/models/ldap_groups/membership.rb | 2 + .../models/ldap_groups/synchronized_group.rb | 50 +++++++--- .../ldap_groups/synchronization.rb | 14 +-- .../factories/synchronized_group_factory.rb | 1 - .../spec/models/synchronized_group_spec.rb | 93 ++++++++++++++++++- 5 files changed, 134 insertions(+), 26 deletions(-) diff --git a/modules/ldap_groups/app/models/ldap_groups/membership.rb b/modules/ldap_groups/app/models/ldap_groups/membership.rb index 4a4793d874..c95f8e23c2 100644 --- a/modules/ldap_groups/app/models/ldap_groups/membership.rb +++ b/modules/ldap_groups/app/models/ldap_groups/membership.rb @@ -5,5 +5,7 @@ module LdapGroups class_name: '::LdapGroups::SynchronizedGroup', foreign_key: 'group_id', counter_cache: :users_count + + validates_uniqueness_of :user_id, scope: :group_id end end diff --git a/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb b/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb index fc3c28d7e2..5720516c16 100644 --- a/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb +++ b/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb @@ -23,31 +23,59 @@ module LdapGroups before_destroy :remove_all_members ## - # Add a set of new members to the internal group + # Add a set of new members to the synchronized group as well as the internal group. + # + # @param new_users [Array | Array] Users (or User IDs) to add to the group. def add_members!(new_users) + return if new_users.empty? + self.class.transaction do - users << new_users.map { |u| Membership.new group: self, user: u } - group.add_members!(new_users) + # create synchronized group memberships + memberships = new_users.map { |user| { group_id: self.id, user_id: user_id(user) } } + # Bulk insert the memberships to improve performance + ::LdapGroups::Membership.insert_all memberships + + # add users to users collection of internal group + group.add_members! new_users end end ## - # Remove a set of users from the internal group + # Remove a set of users from the synchronized group as well as the internal group. + # + # @param users_to_remove [Array | Array] Users (or User IDs) to remove from the group. def remove_members!(users_to_remove) - self.class.transaction do - user_ids = users_to_remove.pluck(:user_id) + return if users_to_remove.empty? - # We don't have access to the join table - # so we need to ensure we delete the users that are still present in the group - # since users MAY want to remove users manually - group.users.where(id: user_ids).destroy_all + self.class.transaction do + # 1) Delete synchronized group MEMBERSHIPS from collection. + # 2) Remove users from users collection of internal group. + if users_to_remove.first.is_a? User + users.delete users.where(user: users_to_remove).select(:id) + group.users.delete users_to_remove + elsif users_to_remove.first.is_a? Integer + users.delete users.where(user_id: users_to_remove).select(:id) + group.users.delete group.users.where(id: users_to_remove).select(:id) + else + raise ArgumentError, "Expected collection of Users or User IDs, got collection of #{users_to_remove.map(&:class).map(&:name).uniq.join(", ")}" + end end end private + def user_id(user) + if user.is_a? Integer + user + elsif user.is_a? User + user.id + else + raise ArgumentError, "Expected User or User ID (Integer) but got #{user}" + end + end + def remove_all_members - remove_members!(users) + remove_members! User.find(users.pluck(:user_id)) end end end diff --git a/modules/ldap_groups/lib/open_project/ldap_groups/synchronization.rb b/modules/ldap_groups/lib/open_project/ldap_groups/synchronization.rb index 8201545e3c..9d14954e87 100644 --- a/modules/ldap_groups/lib/open_project/ldap_groups/synchronization.rb +++ b/modules/ldap_groups/lib/open_project/ldap_groups/synchronization.rb @@ -100,15 +100,7 @@ module OpenProject::LdapGroups Rails.logger.info { "[LDAP groups] Adding #{new_member_ids.length} users to #{sync.dn}" } - # Bulk insert the memberships - memberships = new_member_ids.map do |user_id| - { - group_id: sync.id, - user_id: user_id - } - end - ::LdapGroups::Membership.insert_all memberships - sync.group.add_members! new_member_ids + sync.add_members! new_member_ids end ## @@ -120,8 +112,8 @@ module OpenProject::LdapGroups end Rails.logger.info "[LDAP groups] Removing users #{memberships.pluck(:user_id)} from #{sync.dn}" - sync.remove_members!(memberships) - memberships.delete_all + + sync.remove_members! memberships.pluck(:user_id) end end end diff --git a/modules/ldap_groups/spec/factories/synchronized_group_factory.rb b/modules/ldap_groups/spec/factories/synchronized_group_factory.rb index 16d8de8793..9cf745b0a1 100644 --- a/modules/ldap_groups/spec/factories/synchronized_group_factory.rb +++ b/modules/ldap_groups/spec/factories/synchronized_group_factory.rb @@ -5,4 +5,3 @@ FactoryBot.define do auth_source factory: :ldap_auth_source end end - diff --git a/modules/ldap_groups/spec/models/synchronized_group_spec.rb b/modules/ldap_groups/spec/models/synchronized_group_spec.rb index 49d7602b4a..e66c2c2199 100644 --- a/modules/ldap_groups/spec/models/synchronized_group_spec.rb +++ b/modules/ldap_groups/spec/models/synchronized_group_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe LdapGroups::SynchronizedGroup, type: :model do - subject { FactoryBot.build :ldap_synchronized_group } - describe 'validations' do + subject { FactoryBot.build :ldap_synchronized_group } + context 'correct attributes' do it 'saves the record' do expect(subject.save).to eq true @@ -20,4 +20,91 @@ describe LdapGroups::SynchronizedGroup, type: :model do end end end -end \ No newline at end of file + + describe 'manipulating members' do + let(:users) { [user_1, user_2] } + let(:user_1) { FactoryBot.create :user } + let(:user_2) { FactoryBot.create :user } + + describe '.add_members!' do + let(:synchronized_group) { FactoryBot.create :ldap_synchronized_group, group: group } + let(:group) { FactoryBot.create :group } + + shared_examples 'it adds users to the synchronized group and the internal one' do + let(:members) { raise "define me!" } + + before do + expect(synchronized_group.users).to be_empty + expect(group.users).to be_empty + + User.system.run_given do + synchronized_group.add_members! members + end + end + + it 'adds the user(s) to the internal group' do + expect(group.reload.users).to eq users + end + + it 'adds the user(s) to the synchronized group' do + expect(synchronized_group.reload.users.map(&:user)).to eq users + end + end + + context 'called with user records' do + it_behaves_like 'it adds users to the synchronized group and the internal one' do + let(:members) { users } + end + end + + context 'called just with user IDs' do + it_behaves_like 'it adds users to the synchronized group and the internal one' do + let(:members) { users.pluck(:id) } + end + end + end + + describe '.remove_members!' do + let(:synchronized_group) do + FactoryBot.create(:ldap_synchronized_group, group: group).tap do |sg| + group.users.each do |user| + sg.users.create user: user + end + end + end + let(:group) { FactoryBot.create :group, members: users } + + shared_examples 'it removes the users from the synchronized group and the internal one' do + let(:members) { raise "define me!" } + + before do + synchronized_group.remove_members! members + end + + it 'removes the user(s) from the internal group' do + expect(group.reload.users).to be_empty + end + + it 'removes the users(s) from the synchronized group' do + expect(synchronized_group.users).to be_empty + end + + it 'does not, however, delete the actual users!' do + expect(User.find(users.map(&:id))).to eq users + end + end + + context 'called with user records' do + it_behaves_like 'it removes the users from the synchronized group and the internal one' do + let(:members) { group.users } + end + end + + context 'called just with user IDs' do + it_behaves_like 'it removes the users from the synchronized group and the internal one' do + let(:members) { group.users.pluck(:id) } + end + end + end + end +end From 4b720c0abb66403933bdaf8463b146a263f03b00 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Mon, 16 Nov 2020 08:21:21 +0000 Subject: [PATCH 18/20] fixed URL xeokit tries to download attachments from with subdirectory (#8837) * fixed URL xeokit tries to download attachments from with subdirectory * DRYing up path to IFC model attachment files in XeokitServer Also finally typing XeokitServer in TypeScript. * Cleanup after review: - Remove unnecessary imports - Use string interpolation in PathHelper Co-authored-by: Wieland Lindenthal --- .../ifc-viewer/ifc-viewer.service.ts | 2 +- .../bim/ifc_models/xeokit/xeokit-server.d.ts | 1 - .../bim/ifc_models/xeokit/xeokit-server.js | 78 ---------------- .../bim/ifc_models/xeokit/xeokit-server.ts | 76 ++++++++++++++++ .../src/app/modules/common/gon/gon.service.ts | 2 + .../common/path-helper/path-helper.service.ts | 89 ++++++++++--------- 6 files changed, 125 insertions(+), 123 deletions(-) delete mode 100644 frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.d.ts delete mode 100644 frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.js create mode 100644 frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.ts diff --git a/frontend/src/app/modules/bim/ifc_models/ifc-viewer/ifc-viewer.service.ts b/frontend/src/app/modules/bim/ifc_models/ifc-viewer/ifc-viewer.service.ts index 20d0668943..0241a21fba 100644 --- a/frontend/src/app/modules/bim/ifc_models/ifc-viewer/ifc-viewer.service.ts +++ b/frontend/src/app/modules/bim/ifc_models/ifc-viewer/ifc-viewer.service.ts @@ -47,7 +47,7 @@ export class IFCViewerService extends ViewerBridgeService { public newViewer(elements:XeokitElements, projects:any[]) { import('@xeokit/xeokit-bim-viewer/dist/main').then((XeokitViewerModule:any) => { - let server = new XeokitServer(); + let server = new XeokitServer(this.pathHelper); let viewerUI = new XeokitViewerModule.BIMViewer(server, elements); viewerUI.on("queryPicked", (event:any) => { diff --git a/frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.d.ts b/frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.d.ts deleted file mode 100644 index b2fc7ba970..0000000000 --- a/frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.d.ts +++ /dev/null @@ -1 +0,0 @@ -export class XeokitServer {} \ No newline at end of file diff --git a/frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.js b/frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.js deleted file mode 100644 index 8bcc63f012..0000000000 --- a/frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.js +++ /dev/null @@ -1,78 +0,0 @@ -import {utils} from "@xeokit/xeokit-sdk/src/viewer/scene/utils"; -/** - * Default server client which loads content via HTTP from the file system. - */ -class XeokitServer { - - /** - * - * @param cfg - * @param.cfg.dataDir Base directory for content. - */ - constructor(cfg = {}) { - this._dataDir = cfg.dataDir || ""; - } - - /** - * Gets the manifest of all projects. - * @param done - * @param error - */ - getProjects(done, _error) { - done({ projects: window.gon.ifc_models.projects }); - } - - /** - * Gets a manifest for a project. - * @param projectId - * @param done - * @param error - */ - getProject(projectData, done, _error) { - var manifestData = { - id: projectData[0].id, - name: projectData[0].name, - models: window.gon.ifc_models.models, - viewerContent: { - modelsLoaded: window.gon.ifc_models.shown_models - }, - viewerConfigs: { - saoEnabled: true // Needs to be enabled by default if we want to use it selectively on the available models. - } - }; - - done(manifestData); - } - - /** - * Gets metadata for a model within a project. - * @param projectId - * @param modelId - * @param done - * @param error - */ - getMetadata(_projectId, modelId, done, error) { - const attachmentId = window.gon.ifc_models.metadata_attachment_ids[modelId]; - console.log(`Loading model metadata for: ${attachmentId}`); - utils.loadJSON(this.attachmentUrl(attachmentId), done, error); - } - - /** - * Gets geometry for a model within a project. - * @param projectId - * @param modelId - * @param done - * @param error - */ - getGeometry(projectId, modelId, done, error) { - const attachmentId = window.gon.ifc_models.xkt_attachment_ids[modelId]; - console.log(`Loading model geometry for: ${attachmentId}`); - utils.loadArraybuffer(this.attachmentUrl(attachmentId), done, error); - } - - attachmentUrl(attachmentId) { - return "/api/v3/attachments/" + attachmentId + "/content"; - } -} - -export {XeokitServer}; \ No newline at end of file diff --git a/frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.ts b/frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.ts new file mode 100644 index 0000000000..77b5066e78 --- /dev/null +++ b/frontend/src/app/modules/bim/ifc_models/xeokit/xeokit-server.ts @@ -0,0 +1,76 @@ +// @ts-ignore +import {utils} from "@xeokit/xeokit-sdk/src/viewer/scene/utils"; +import {PathHelperService} from "../../../common/path-helper/path-helper.service"; +import {IFCGonDefinition} from "../pages/viewer/ifc-models-data.service"; + +/** + * Default server client which loads content via HTTP from the file system. + */ +export class XeokitServer { + private ifcModels:IFCGonDefinition; + /** + * + * @param config + * @param.config.pathHelper instance of PathHelperService. + */ + constructor(private pathHelper:PathHelperService) { + this.ifcModels = window.gon.ifc_models; + } + + /** + * Gets the manifest of all projects. + * @param done + * @param error + */ + getProjects(done:Function, _error:Function) { + done({ projects: this.ifcModels.projects }); + } + + /** + * Gets a manifest for a project. + * @param projectId + * @param done + * @param error + */ + getProject(projectData:any, done:Function, _error:Function) { + var manifestData = { + id: projectData[0].id, + name: projectData[0].name, + models: this.ifcModels.models, + viewerContent: { + modelsLoaded: this.ifcModels.shown_models + }, + viewerConfigs: { + saoEnabled: true // Needs to be enabled by default if we want to use it selectively on the available models. + } + }; + + done(manifestData); + } + + /** + * Gets metadata for a model within a project. + * @param projectId + * @param modelId + * @param done + * @param error + */ + getMetadata(_projectId:string, modelId:number, done:Function, error:Function) { + const attachmentId = this.ifcModels.metadata_attachment_ids[modelId]; + console.log(`Loading model metadata for: ${attachmentId}`); + utils.loadJSON(this.pathHelper.attachmentContentPath(attachmentId), done, error); + } + + /** + * Gets geometry for a model within a project. + * @param projectId + * @param modelId + * @param done + * @param error + */ + getGeometry(projectId:string, modelId:number, done:Function, error:Function) { + const attachmentId = this.ifcModels.xkt_attachment_ids[modelId]; + console.log(`Loading model geometry for: ${attachmentId}`); + utils.loadArraybuffer(this.pathHelper.attachmentContentPath(attachmentId), done, error); + } +} diff --git a/frontend/src/app/modules/common/gon/gon.service.ts b/frontend/src/app/modules/common/gon/gon.service.ts index c2d02661c4..2c046150e7 100644 --- a/frontend/src/app/modules/common/gon/gon.service.ts +++ b/frontend/src/app/modules/common/gon/gon.service.ts @@ -27,6 +27,7 @@ // ++ import {Injectable} from "@angular/core"; +import {IFCGonDefinition} from "../../bim/ifc_models/pages/viewer/ifc-models-data.service"; declare global { interface Window { @@ -36,6 +37,7 @@ declare global { export interface GonType { [key:string]:unknown; + ifc_models:IFCGonDefinition; } @Injectable({ providedIn: 'root' }) diff --git a/frontend/src/app/modules/common/path-helper/path-helper.service.ts b/frontend/src/app/modules/common/path-helper/path-helper.service.ts index 10e2e553cf..d999b8cb3d 100644 --- a/frontend/src/app/modules/common/path-helper/path-helper.service.ts +++ b/frontend/src/app/modules/common/path-helper/path-helper.service.ts @@ -45,10 +45,10 @@ class Apiv3Paths { * @param context */ public previewMarkup(context:string) { - let base = this.apiV3Base + '/render/markdown'; + let base = `${this.apiV3Base}/render/markdown`; if (context) { - return base + `?context=${context}`; + return `${base}?context=${context}`; } else { return base; } @@ -85,7 +85,7 @@ class Apiv3Paths { @Injectable({ providedIn: 'root' }) export class PathHelperService { - public readonly appBasePath = window.appBasePath ? window.appBasePath : ''; + public readonly appBasePath = window.appBasePath || ''; public readonly api = { v3: new Apiv3Paths(this.appBasePath) }; @@ -95,21 +95,25 @@ export class PathHelperService { } public attachmentDownloadPath(attachmentIdentifier:string, slug:string|undefined) { - let path = this.staticBase + '/attachments/' + attachmentIdentifier; + let path = `${this.staticBase}/attachments/${attachmentIdentifier}`; if (slug) { - return path + "/" + slug; + return `${path}/${slug}`; } else { return path; } } + public attachmentContentPath(attachmentIdentifier:number|string) { + return `${this.staticBase}/attachments/${attachmentIdentifier}/content`; + } + public ifcModelsPath(projectIdentifier:string) { - return this.staticBase + `/projects/${projectIdentifier}/ifc_models`; + return `${this.staticBase}/projects/${projectIdentifier}/ifc_models`; } public bimDetailsPath(projectIdentifier:string, workPackageId:string, viewpoint:number|string|null = null) { - let path = this.projectPath(projectIdentifier) + `/bcf/split/details/${workPackageId}`; + let path = `${this.projectPath(projectIdentifier)}/bcf/split/details/${workPackageId}`; if (viewpoint !== null) { path += `?viewpoint=${viewpoint}`; @@ -119,95 +123,95 @@ export class PathHelperService { } public highlightingCssPath() { - return this.staticBase + '/highlighting/styles'; + return `${this.staticBase}/highlighting/styles`; } public forumPath(projectIdentifier:string, forumIdentifier:string) { - return this.projectForumPath(projectIdentifier) + '/' + forumIdentifier; + return `${this.projectForumPath(projectIdentifier)}/${forumIdentifier}`; } public keyboardShortcutsHelpPath() { - return this.staticBase + '/help/keyboard_shortcuts'; + return `${this.staticBase}/help/keyboard_shortcuts`; } public messagePath(messageIdentifier:string) { - return this.staticBase + '/topics/' + messageIdentifier; + return `${this.staticBase}/topics/${messageIdentifier}`; } public myPagePath() { - return this.staticBase + '/my/page'; + return `${this.staticBase}/my/page`; } public newsPath(newsId:string) { - return this.staticBase + '/news/' + newsId; + return `${this.staticBase}/news/${newsId}`; } public loginPath() { - return this.staticBase + '/login'; + return `${this.staticBase}/login`; } public projectsPath() { - return this.staticBase + '/projects'; + return `${this.staticBase}/projects`; } public projectPath(projectIdentifier:string) { - return this.projectsPath() + '/' + projectIdentifier; + return `${this.projectsPath()}/${projectIdentifier}`; } public projectActivityPath(projectIdentifier:string) { - return this.projectPath(projectIdentifier) + '/activity'; + return `${this.projectPath(projectIdentifier)}/activity`; } public projectForumPath(projectIdentifier:string) { - return this.projectPath(projectIdentifier) + '/forums'; + return `${this.projectPath(projectIdentifier)}/forums`; } public projectCalendarPath(projectId:string) { - return this.projectPath(projectId) + '/work_packages/calendar'; + return `${this.projectPath(projectId)}/work_packages/calendar`; } public projectMembershipsPath(projectId:string) { - return this.projectPath(projectId) + '/members'; + return `${this.projectPath(projectId)}/members`; } public projectNewsPath(projectId:string) { - return this.projectPath(projectId) + '/news'; + return `${this.projectPath(projectId)}/news`; } public projectTimeEntriesPath(projectIdentifier:string) { - return this.projectPath(projectIdentifier) + '/cost_reports'; + return `${this.projectPath(projectIdentifier)}/cost_reports`; } public projectWikiPath(projectId:string) { - return this.projectPath(projectId) + '/wiki'; + return `${this.projectPath(projectId)}/wiki`; } public projectWorkPackagePath(projectId:string, wpId:string|number) { - return this.projectWorkPackagesPath(projectId) + '/' + wpId; + return `${this.projectWorkPackagesPath(projectId)}/${wpId}`; } public projectWorkPackagesPath(projectId:string) { - return this.projectPath(projectId) + '/work_packages'; + return `${this.projectPath(projectId)}/work_packages`; } public projectWorkPackageNewPath(projectId:string) { - return this.projectWorkPackagesPath(projectId) + '/new'; + return `${this.projectWorkPackagesPath(projectId)}/new`; } public projectBoardsPath(projectIdentifier:string|null) { if (projectIdentifier) { - return this.projectPath(projectIdentifier) + '/boards'; + return `${this.projectPath(projectIdentifier)}/boards`; } else { - return this.staticBase + '/boards'; + return `${this.staticBase}/boards`; } } public projectDashboardsPath(projectIdentifier:string) { - return this.projectPath(projectIdentifier) + '/dashboards'; + return `${this.projectPath(projectIdentifier)}/dashboards`; } public timeEntriesPath(workPackageId:string|number) { - var suffix = '/time_entries'; + let suffix = '/time_entries'; if (workPackageId) { return this.workPackagePath(workPackageId) + suffix; @@ -217,51 +221,50 @@ export class PathHelperService { } public usersPath() { - return this.staticBase + '/users'; + return `${this.staticBase}/users`; } public userPath(id:string|number) { - return this.usersPath() + '/' + id; + return `${this.usersPath()}/${id}`; } public versionsPath() { - return this.staticBase + '/versions'; + return `${this.staticBase}/versions`; } public versionEditPath(id:string|number) { - return this.staticBase + '/versions/' + id + '/edit'; + return `${this.staticBase}/versions/${id}/edit`; } public versionShowPath(id:string|number) { - return this.staticBase + '/versions/' + id; + return `${this.staticBase}/versions/${id}`; } public workPackagesPath() { - return this.staticBase + '/work_packages'; + return `${this.staticBase}/work_packages`; } public workPackagePath(id:string|number) { - return this.staticBase + '/work_packages/' + id; + return `${this.staticBase}/work_packages/${id}`; } public workPackageCopyPath(workPackageId:string|number) { - return this.workPackagePath(workPackageId) + '/copy'; + return `${this.workPackagePath(workPackageId)}/copy`; } public workPackageDetailsCopyPath(projectIdentifier:string, workPackageId:string|number) { - return this.projectWorkPackagesPath(projectIdentifier) + '/details/' + workPackageId + '/copy'; + return `${this.projectWorkPackagesPath(projectIdentifier)}/details/${workPackageId}/copy`; } public workPackagesBulkDeletePath() { - return this.workPackagesPath() + '/bulk'; + return `${this.workPackagesPath()}/bulk`; } public projectLevelListPath() { - return this.projectsPath() + '/level_list.json'; + return `${this.projectsPath()}/level_list.json`; } public textFormattingHelp() { - return this.staticBase + '/help/text_formatting'; + return `${this.staticBase}/help/text_formatting`; } - } From 5c65ae2e1e490d04f29b2949bf47378c91f439e6 Mon Sep 17 00:00:00 2001 From: Wieland Lindenthal Date: Mon, 16 Nov 2020 09:28:18 +0100 Subject: [PATCH 19/20] Fix #35131: Cleanup migration for BIM themes (#8834) * Fix #35131: Addin a cleanup migration for BIM themes Elder BIM instances got "OpenProject" theme instead of the "OpenProject BIM" theme after migration as that became the default for the theme column. BIM instances need to get the theme set in a new CustomStyle entry AND its colors need to get written to DB. When digging around on Saas there were also BIM instances that had a theme set in a CustomStyle but did not have the colors written out to DB. * Refacotring: improve clearity of migration --- app/models/design_color.rb | 4 +- ...4091135_add_theme_name_to_custom_styles.rb | 5 +- .../custom_styles/color_themes.rb | 4 +- ...154216_seed_custom_style_with_bim_theme.rb | 101 ++++++++++++++++++ 4 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 modules/bim/db/migrate/20201105154216_seed_custom_style_with_bim_theme.rb diff --git a/app/models/design_color.rb b/app/models/design_color.rb index 315bc40dc5..3198b3849b 100644 --- a/app/models/design_color.rb +++ b/app/models/design_color.rb @@ -28,10 +28,10 @@ class DesignColor < ApplicationRecord after_commit -> do - # CustomStyle.current.updated_at determins the cache key for inline_css + # CustomStyle.current.updated_at determines the cache key for inline_css # in which the CSS color variables will be overwritten. That is why we need # to ensure that a CustomStyle.current exists and that the time stamps change - # whenever we chagen a color_variable. + # whenever we change a color_variable. if CustomStyle.current CustomStyle.current.touch else diff --git a/db/migrate/20200114091135_add_theme_name_to_custom_styles.rb b/db/migrate/20200114091135_add_theme_name_to_custom_styles.rb index 93187deffb..46f29ddf93 100644 --- a/db/migrate/20200114091135_add_theme_name_to_custom_styles.rb +++ b/db/migrate/20200114091135_add_theme_name_to_custom_styles.rb @@ -1,5 +1,8 @@ class AddThemeNameToCustomStyles < ActiveRecord::Migration[6.0] def change - add_column :custom_styles, :theme, :string, default: "OpenProject" + add_column :custom_styles, + :theme, + :string, + default: OpenProject::CustomStyles::ColorThemes::DEFAULT_THEME_NAME end end diff --git a/lib/open_project/custom_styles/color_themes.rb b/lib/open_project/custom_styles/color_themes.rb index 2454647013..03c448007d 100644 --- a/lib/open_project/custom_styles/color_themes.rb +++ b/lib/open_project/custom_styles/color_themes.rb @@ -29,9 +29,11 @@ module OpenProject::CustomStyles class ColorThemes + OpenProject::CustomStyles::ColorThemes::DEFAULT_THEME_NAME = 'OpenProject'.freeze + THEMES = [ { - theme: 'OpenProject', + theme: OpenProject::CustomStyles::ColorThemes::DEFAULT_THEME_NAME, colors: { 'primary-color' => "#1A67A3", 'primary-color-dark' => "#175A8E", diff --git a/modules/bim/db/migrate/20201105154216_seed_custom_style_with_bim_theme.rb b/modules/bim/db/migrate/20201105154216_seed_custom_style_with_bim_theme.rb new file mode 100644 index 0000000000..2f26f9a621 --- /dev/null +++ b/modules/bim/db/migrate/20201105154216_seed_custom_style_with_bim_theme.rb @@ -0,0 +1,101 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2020 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2017 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See docs/COPYRIGHT.rdoc for more details. +#++ + +# This migration cleans up messed up themes. Sometimes in the past +# the BIM theme was not set where it should have been set. +class SeedCustomStyleWithBimTheme < ActiveRecord::Migration[6.0] + + def up + # When + # migrating BIM instances + # that did not have any custom styles OR + # that do not have any design colors set and no custom logo/touch-icon/favicon + # (this basically means that no theme actually got applied) + # then + # add a custom style with the BIM theme set. This will write the theme's colors + # as DesignColor entries to the DB which is necessary for the theme to actually + # have an effect. + if OpenProject::Configuration.bim? && + (CustomStyle.current.nil? || + (DesignColor.count == 0 && + CustomStyle.current.favicon.nil? && + CustomStyle.current.logo.nil? && + CustomStyle.current.touch_icon.nil?)) + seed_bim_theme + end + end + + def down + # nop + end + + private + + def seed_bim_theme + CustomStyle.transaction do + set_custom_style + set_design_colors + end + end + + def set_design_colors + # There should not be any DesignColors present. However, we want to make sure. + DesignColor.delete_all + + theme[:colors].each do |param_variable, param_hexcode| + DesignColor.create variable: param_variable, hexcode: param_hexcode + end + end + + def set_custom_style + custom_style = (CustomStyle.current || CustomStyle.create!) + custom_style.attributes = { theme: theme[:theme], theme_logo: theme[:logo] } + custom_style.save! + custom_style + end + + def theme + { + theme: 'OpenProject BIM', + colors: { + 'primary-color' => "#3270DB", + 'primary-color-dark' => "#163473", + 'alternative-color' => "#349939", + 'header-bg-color' => "#05002C", + 'header-item-bg-hover-color' => "#163473", + 'content-link-color' => "#275BB5", + 'main-menu-bg-color' => "#0E2045", + 'main-menu-bg-selected-background' => "#3270DB", + 'main-menu-bg-hover-background' => "#163473" + }, + logo: 'bim/logo_openproject_bim_big.png' + } + end +end From fcec6f6681a4f11bf4403bc850f99231e193274b Mon Sep 17 00:00:00 2001 From: ulferts Date: Mon, 16 Nov 2020 09:36:33 +0100 Subject: [PATCH 20/20] Add release-notes file --- docs/release-notes/11-0-3/README.md | 22 ++++++++++++++++++++++ docs/release-notes/README.md | 7 +++++++ 2 files changed, 29 insertions(+) create mode 100644 docs/release-notes/11-0-3/README.md diff --git a/docs/release-notes/11-0-3/README.md b/docs/release-notes/11-0-3/README.md new file mode 100644 index 0000000000..ba5ab369c8 --- /dev/null +++ b/docs/release-notes/11-0-3/README.md @@ -0,0 +1,22 @@ +--- +title: OpenProject 11.0.3 +sidebar_navigation: + title: 11.0.3 +release_version: 11.0.3 +release_date: 2020-11-16 +--- + +# OpenProject 11.0.3 + +We released [OpenProject 11.0.3](https://community.openproject.com/versions/1456). +The release contains several bug fixes and we recommend updating to the newest version. + + +#### Bug fixes and changes + +- Fixed: Bulk edit: Custom field long text cut off \[[#34829](https://community.openproject.com/wp/34829)\] +- Fixed: "Estimates and time" not translated to German when not logged in on community.openproject.com \[[#35009](https://community.openproject.com/wp/35009)\] +- Fixed: IFC viewer can't load models when OP installed on subpath \[[#35129](https://community.openproject.com/wp/35129)\] +- Fixed: Elder BIM instances get "OpenProject" theme instead of the "OpenProject BIM" theme after migration. \[[#35131](https://community.openproject.com/wp/35131)\] +- Fixed: Transitive Relations embedded in work package representer -> poor performance \[[#35168](https://community.openproject.com/wp/35168)\] +- Fixed: LDAP Group sync deletes users when removed from group \[[#35265](https://community.openproject.com/wp/35265)\] diff --git a/docs/release-notes/README.md b/docs/release-notes/README.md index 5374bd505c..c2615d5450 100644 --- a/docs/release-notes/README.md +++ b/docs/release-notes/README.md @@ -12,6 +12,13 @@ Stay up to date and get an overview of the new features included in the releases +## 11.0.3 + +Release date: 2020-11-16 + +[Release Notes](11-0-3/) + + ## 11.0.2 Release date: 2020-11-06