The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .vscode
    └── ltex.dictionary.en-US.txt
├── CHANGELOG.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── app
    ├── controllers
    │   ├── rdb_dashboard_controller.rb
    │   └── rdb_taskboard_controller.rb
    ├── helpers
    │   └── rdb_dashboard_helper.rb
    ├── models
    │   ├── rdb_assignee_filter.rb
    │   ├── rdb_category_filter.rb
    │   ├── rdb_column.rb
    │   ├── rdb_dashboard.rb
    │   ├── rdb_filter.rb
    │   ├── rdb_group.rb
    │   ├── rdb_taskboard.rb
    │   ├── rdb_tracker_filter.rb
    │   └── rdb_version_filter.rb
    └── views
    │   └── rdb_dashboard
    │       ├── _footer.html.slim
    │       ├── _taskboard.html.slim
    │       ├── configure.html.slim
    │       ├── error.js.erb
    │       ├── index.html.slim
    │       ├── index.js.erb
    │       ├── issues
    │           ├── _card.html.slim
    │           ├── _compact.html.slim
    │           ├── _issue.html.slim
    │           ├── _issue_menu.html.slim
    │           ├── _issue_properties.html.slim
    │           └── _parent.html.slim
    │       └── taskboard
    │           ├── _column.html.slim
    │           ├── _column_dialog.html.slim
    │           ├── _column_names.html.slim
    │           ├── _columns.html.slim
    │           ├── _group.html.slim
    │           ├── _groups.html.slim
    │           ├── _header.html.slim
    │           ├── _overall_progress.html.slim
    │           └── column_dialog.js.erb
├── assets
    ├── javascripts
    │   ├── dashboard.js
    │   ├── dashboard.taskboard.js
    │   ├── dashboard.ui.js
    │   ├── jquery.autoellipsis.js
    │   └── jquery.total-storage.js
    └── stylesheets
    │   ├── dashboard.css
    │   ├── dashboard.issues.css
    │   ├── dashboard.taskboard.css
    │   ├── dashboard.ui.css
    │   └── img
    │       ├── brick.png
    │       ├── cog.png
    │       ├── disabled_true.png
    │       ├── menu.gif
    │       ├── package.png
    │       ├── ticket.png
    │       ├── time.png
    │       └── user.png
├── config
    ├── default.yml
    ├── locales
    │   ├── bg.yml
    │   ├── ca.yml
    │   ├── cs.yml
    │   ├── de.yml
    │   ├── en.yml
    │   ├── es.yml
    │   ├── fr.yml
    │   ├── it.yml
    │   ├── ja.yml
    │   ├── ko.yml
    │   ├── mn.yml
    │   ├── nl.yml
    │   ├── pl.yml
    │   ├── pt-BR.yml
    │   ├── ru.yml
    │   ├── tr.yml
    │   ├── uk.yml
    │   ├── zh-TW.yml
    │   └── zh.yml
    └── routes.rb
└── init.rb


/.vscode/ltex.dictionary.en-US.txt:
--------------------------------------------------------------------------------
1 | Redmine
2 | redmine
3 | 


--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
  1 | # CHANGELOG
  2 | 
  3 | All notable changes to this project will be documented in this file.
  4 | This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a Changelog](http://keepachangelog.com/).
  5 | 
  6 | <!-- markdownlint-disable MD024 -->
  7 | 
  8 | ## Unreleased
  9 | 
 10 | ---
 11 | 
 12 | ### New
 13 | 
 14 | ### Changes
 15 | 
 16 | ### Fixes
 17 | 
 18 | ### Breaks
 19 | 
 20 | ## 2.16.0 - (2025-01-17)
 21 | 
 22 | ---
 23 | 
 24 | ### New
 25 | 
 26 | - Support for Redmine 6.0 by @jgraichen
 27 | - Support for Redmine 5.2 by @jgraichen
 28 | 
 29 | ### Changes
 30 | 
 31 | - Replaced deprecated functions in new Redmine versions by @jgraichen
 32 | 
 33 | ### Breaks
 34 | 
 35 | - Require Ruby 3.0+ by @jgraichen
 36 | - Require Redmine 5.0+ by @jgraichen
 37 | 
 38 | ## 2.15.0 - (2023-10-31)
 39 | 
 40 | ---
 41 | 
 42 | ### New
 43 | 
 44 | - Support for Redmine 5.1 by @jgraichen
 45 | 
 46 | ### Fixes
 47 | 
 48 | - Workaround a change in Redmine 5.1 to ignore roles with only the `:edit_own_issues` permission by @jgraichen
 49 | 
 50 | ## 2.14.0 - (2023-03-26)
 51 | 
 52 | ---
 53 | 
 54 | ### New
 55 | 
 56 | - Add Ukrainian locale by @serhiyraskoley
 57 | 
 58 | ## 2.13.0 - (2023-03-19)
 59 | 
 60 | ---
 61 | 
 62 | ### New
 63 | 
 64 | - Support `:edit_own_issues` permissions on dashboards by @jgraichen
 65 | 
 66 | ### Changes
 67 | 
 68 | - Wrap issue move into transaction to ensure atomic changes by @jgraichen
 69 | 
 70 | ### Fixes
 71 | 
 72 | - Error message when moving issue failed by @jgraichen
 73 | - Do not show draggable issues when allowed by workflow but not permissions by @jgraichen
 74 | 
 75 | ## 2.12.4 - (2023-02-10)
 76 | 
 77 | ---
 78 | 
 79 | ### Changes
 80 | 
 81 | - Improve Gemfile for broken docker container environments by @jgraichen
 82 | 
 83 | ## 2.12.3 - (2022-11-20)
 84 | 
 85 | ---
 86 | 
 87 | ### Fixes
 88 | 
 89 | - I18n.t requires keyword arguments (#285) by @jgraichen
 90 | 
 91 | ## 2.12.2 - (2022-07-09)
 92 | 
 93 | ---
 94 | 
 95 | ### Changes
 96 | 
 97 | - Call issue edit hooks before save hook (#260) by @salmanmp
 98 | 
 99 | ### Fixes
100 | 
101 | - Fix missing pluralization keys (#233)
102 | - Fix wrong count placeholder in pt-BR locale (#262)
103 | 
104 | ## 2.12.1 - (2022-05-03)
105 | 
106 | ---
107 | 
108 | ### Fixes
109 | 
110 | - Zeitwerk loading issue with Redmine 5.0
111 | 
112 | ## 2.12.0 - (2022-03-29)
113 | 
114 | ---
115 | 
116 | ### New
117 | 
118 | - Support for Ruby 3.0 and 3.1 with Redmine 5.0
119 | - Support for Redmine 5.0
120 | - Show or hide spend time and estimation based on the viewers permissions (#90)
121 | 
122 | ### Fixes
123 | 
124 | - Locale code file mapping for pt-BR and zh-TW
125 | - Spacing and padding issues with compact card properties
126 | 
127 | ## 2.11.0 - (2021-08-22)
128 | 
129 | ### New
130 | 
131 | - Use CSS native grid for dynamic columns and card width
132 | - Show status name as done column title if only a single closed status is shown
133 | - Include shared versions into filter (#79)
134 | - Only show issue statuses for trackers selected in filter (#108)
135 | - Limit shown statuses to the one available in the project (#121, #127, #130)
136 | - Store dashboard settings in user preferences (#39)
137 | 
138 | ### Changes
139 | 
140 | - Sort versions in filter (#78)
141 | 
142 | ### Fixes
143 | 
144 | - Fixed invisible subject in compact card layout
145 | - Duplicated filter items when including subprojects
146 | - Fix possible session cookie overflow as dashboard settings are no longer store in the session (#144)
147 | 
148 | ## 2.10.0 — (2021-07-10)
149 | 
150 | ### New
151 | 
152 | - Sort groups similar to nested project when grouping by projects (#122)
153 | 
154 | ### Changes
155 | 
156 | - Diverse performance improvements when querying issues and rendering the dashboard
157 | 
158 | ### Fixes
159 | 
160 | - Internal server error when grouping by priority (#133)
161 | - Ajax Error: Internal Server Error when grouping by parent issue (#142)
162 | 
163 | ## 2.9.0
164 | 
165 | ### Changes
166 | 
167 | - New Catalan and Dutch locale
168 | - Updated Turkish locale
169 | - Dropped old Redmine (< 4.0) and Ruby (< 2.5) versions from automated testing
170 | 
171 | ## 2.8.0
172 | 
173 | ### Changes
174 | 
175 | - Test with Redmine 4.0 and 4.1
176 | - Add new locales bg and pt_BR
177 | - Add support for Redmine 4.0 (experimental)
178 | - Drop old Ruby (< 2.3) and Redmine (< 3.4) versions from automated testing
179 | 
180 | ## 2.7.1
181 | 
182 | ### Changes
183 | 
184 | - Update locale files (new: ko)
185 | 
186 | ## 2.7.0
187 | 
188 | ### Changes
189 | 
190 | - Add Mongolian locale
191 | - Update Russian locale
192 | - Add Turkish locale (#102)
193 | - Fix issue with version filter on parent projects (#103, #96)
194 | - Fix/Add overdue handling and styling (#104)
195 | - Small fix for group by parent issue
196 | 
197 | ## 2.6.0
198 | 
199 | ### Changes
200 | 
201 | - Update for Redmine 3.0
202 | 
203 | ## 2.5.0
204 | 
205 | ### Changes
206 | 
207 | - Czech translations
208 | - Global YAML configuration file for default view options
209 | 
210 | ## 2.4.0
211 | 
212 | ### Changes
213 | 
214 | - Integration with ISSUE-ID plugin (#64)
215 | - Update locales (including new Polish translation)
216 | 
217 | ## 2.3.3
218 | 
219 | ### Changes
220 | 
221 | - Fix error with pluralization patch (#53)
222 | - Update locales
223 | - Bundle transifex utility as gem instead of git repo
224 | 
225 | ## 2.3.2
226 | 
227 | ### Changes
228 | 
229 | - Fix error with missing pluralization keys (#50):
230 |   Redmine I18n backend does not include a CLDR pluralization rule aware
231 |   pluralize method. Rdb now patches the backend to include
232 |   I18n::Backend::Pluralization as well as Redmines lazy locale load to
233 |   load the pluralization rules.
234 | - Update locales
235 | 
236 | ## 2.3.1
237 | 
238 | ### Changes
239 | 
240 | - Fix version number
241 | 
242 | ## 2.3.0
243 | 
244 | ### Changes
245 | 
246 | - New translations
247 | 
248 | ## 2.2.0
249 | 
250 | ### Changes
251 | 
252 | - Add support for subprojects
253 | 
254 | ## 2.1.0
255 | 
256 | ### Changes
257 | 
258 | - Include groups to assignee filter (#9)
259 | - Add swimlane for each team member instead of "others" (#18)
260 | - Several bug fixes
261 | 
262 | ## 2.0 (2.0.dev)
263 | 
264 | ### Changes
265 | 
266 | - New release for Redmine 2.1+
267 | - Improve grouping, swimlanes, filters
268 | - New drop-down menus
269 | - Quick issue editing (progress & assignee only)
270 | - Workflow based column drag'n'drop
271 | 
272 | ## 1.4
273 | 
274 | ### Changes
275 | 
276 | - Initial release for Redmine 1.4
277 | - Simple task board
278 | - Simple filter and grouping options
279 | 


--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | source 'https://rubygems.org'
 4 | # Gems required by redmine_dashboard
 5 | 
 6 | send :ruby, RUBY_VERSION if ENV['CI']
 7 | 
 8 | gem 'rake'
 9 | gem 'slim-rails'
10 | 
11 | group :test do
12 |   gem 'database_cleaner-active_record', '~> 2.0'
13 | 
14 |   gem 'rspec', '~> 3.10'
15 |   gem 'rspec-rails'
16 | 
17 |   # Redmine already defines capybara and puma, which required to run
18 |   # browser tests.
19 | end
20 | 
21 | # If rubocop is already defined, the Gemfile is loaded through Redmine's
22 | # own Gemfile as a plugin. In that case our local development gems are
23 | # not needed (and actually conflicting), therefore we skip them.
24 | if @dependencies.none? {|d| d.name == 'rubocop' }
25 |   group :development do
26 |     gem 'rubocop', '~> 1.81.0'
27 |     gem 'rubocop-performance', '~> 1.26.0'
28 |     gem 'rubocop-rails', '~> 2.33.0'
29 |     gem 'slim_lint', '~> 0.33.0'
30 |   end
31 | end
32 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
  1 |                                  Apache License
  2 |                            Version 2.0, January 2004
  3 |                         http://www.apache.org/licenses/
  4 | 
  5 |    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
  6 | 
  7 |    1. Definitions.
  8 | 
  9 |       "License" shall mean the terms and conditions for use, reproduction,
 10 |       and distribution as defined by Sections 1 through 9 of this document.
 11 | 
 12 |       "Licensor" shall mean the copyright owner or entity authorized by
 13 |       the copyright owner that is granting the License.
 14 | 
 15 |       "Legal Entity" shall mean the union of the acting entity and all
 16 |       other entities that control, are controlled by, or are under common
 17 |       control with that entity. For the purposes of this definition,
 18 |       "control" means (i) the power, direct or indirect, to cause the
 19 |       direction or management of such entity, whether by contract or
 20 |       otherwise, or (ii) ownership of fifty percent (50%) or more of the
 21 |       outstanding shares, or (iii) beneficial ownership of such entity.
 22 | 
 23 |       "You" (or "Your") shall mean an individual or Legal Entity
 24 |       exercising permissions granted by this License.
 25 | 
 26 |       "Source" form shall mean the preferred form for making modifications,
 27 |       including but not limited to software source code, documentation
 28 |       source, and configuration files.
 29 | 
 30 |       "Object" form shall mean any form resulting from mechanical
 31 |       transformation or translation of a Source form, including but
 32 |       not limited to compiled object code, generated documentation,
 33 |       and conversions to other media types.
 34 | 
 35 |       "Work" shall mean the work of authorship, whether in Source or
 36 |       Object form, made available under the License, as indicated by a
 37 |       copyright notice that is included in or attached to the work
 38 |       (an example is provided in the Appendix below).
 39 | 
 40 |       "Derivative Works" shall mean any work, whether in Source or Object
 41 |       form, that is based on (or derived from) the Work and for which the
 42 |       editorial revisions, annotations, elaborations, or other modifications
 43 |       represent, as a whole, an original work of authorship. For the purposes
 44 |       of this License, Derivative Works shall not include works that remain
 45 |       separable from, or merely link (or bind by name) to the interfaces of,
 46 |       the Work and Derivative Works thereof.
 47 | 
 48 |       "Contribution" shall mean any work of authorship, including
 49 |       the original version of the Work and any modifications or additions
 50 |       to that Work or Derivative Works thereof, that is intentionally
 51 |       submitted to Licensor for inclusion in the Work by the copyright owner
 52 |       or by an individual or Legal Entity authorized to submit on behalf of
 53 |       the copyright owner. For the purposes of this definition, "submitted"
 54 |       means any form of electronic, verbal, or written communication sent
 55 |       to the Licensor or its representatives, including but not limited to
 56 |       communication on electronic mailing lists, source code control systems,
 57 |       and issue tracking systems that are managed by, or on behalf of, the
 58 |       Licensor for the purpose of discussing and improving the Work, but
 59 |       excluding communication that is conspicuously marked or otherwise
 60 |       designated in writing by the copyright owner as "Not a Contribution."
 61 | 
 62 |       "Contributor" shall mean Licensor and any individual or Legal Entity
 63 |       on behalf of whom a Contribution has been received by Licensor and
 64 |       subsequently incorporated within the Work.
 65 | 
 66 |    2. Grant of Copyright License. Subject to the terms and conditions of
 67 |       this License, each Contributor hereby grants to You a perpetual,
 68 |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 69 |       copyright license to reproduce, prepare Derivative Works of,
 70 |       publicly display, publicly perform, sublicense, and distribute the
 71 |       Work and such Derivative Works in Source or Object form.
 72 | 
 73 |    3. Grant of Patent License. Subject to the terms and conditions of
 74 |       this License, each Contributor hereby grants to You a perpetual,
 75 |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 76 |       (except as stated in this section) patent license to make, have made,
 77 |       use, offer to sell, sell, import, and otherwise transfer the Work,
 78 |       where such license applies only to those patent claims licensable
 79 |       by such Contributor that are necessarily infringed by their
 80 |       Contribution(s) alone or by combination of their Contribution(s)
 81 |       with the Work to which such Contribution(s) was submitted. If You
 82 |       institute patent litigation against any entity (including a
 83 |       cross-claim or counterclaim in a lawsuit) alleging that the Work
 84 |       or a Contribution incorporated within the Work constitutes direct
 85 |       or contributory patent infringement, then any patent licenses
 86 |       granted to You under this License for that Work shall terminate
 87 |       as of the date such litigation is filed.
 88 | 
 89 |    4. Redistribution. You may reproduce and distribute copies of the
 90 |       Work or Derivative Works thereof in any medium, with or without
 91 |       modifications, and in Source or Object form, provided that You
 92 |       meet the following conditions:
 93 | 
 94 |       (a) You must give any other recipients of the Work or
 95 |           Derivative Works a copy of this License; and
 96 | 
 97 |       (b) You must cause any modified files to carry prominent notices
 98 |           stating that You changed the files; and
 99 | 
100 |       (c) You must retain, in the Source form of any Derivative Works
101 |           that You distribute, all copyright, patent, trademark, and
102 |           attribution notices from the Source form of the Work,
103 |           excluding those notices that do not pertain to any part of
104 |           the Derivative Works; and
105 | 
106 |       (d) If the Work includes a "NOTICE" text file as part of its
107 |           distribution, then any Derivative Works that You distribute must
108 |           include a readable copy of the attribution notices contained
109 |           within such NOTICE file, excluding those notices that do not
110 |           pertain to any part of the Derivative Works, in at least one
111 |           of the following places: within a NOTICE text file distributed
112 |           as part of the Derivative Works; within the Source form or
113 |           documentation, if provided along with the Derivative Works; or,
114 |           within a display generated by the Derivative Works, if and
115 |           wherever such third-party notices normally appear. The contents
116 |           of the NOTICE file are for informational purposes only and
117 |           do not modify the License. You may add Your own attribution
118 |           notices within Derivative Works that You distribute, alongside
119 |           or as an addendum to the NOTICE text from the Work, provided
120 |           that such additional attribution notices cannot be construed
121 |           as modifying the License.
122 | 
123 |       You may add Your own copyright statement to Your modifications and
124 |       may provide additional or different license terms and conditions
125 |       for use, reproduction, or distribution of Your modifications, or
126 |       for any such Derivative Works as a whole, provided Your use,
127 |       reproduction, and distribution of the Work otherwise complies with
128 |       the conditions stated in this License.
129 | 
130 |    5. Submission of Contributions. Unless You explicitly state otherwise,
131 |       any Contribution intentionally submitted for inclusion in the Work
132 |       by You to the Licensor shall be under the terms and conditions of
133 |       this License, without any additional terms or conditions.
134 |       Notwithstanding the above, nothing herein shall supersede or modify
135 |       the terms of any separate license agreement you may have executed
136 |       with Licensor regarding such Contributions.
137 | 
138 |    6. Trademarks. This License does not grant permission to use the trade
139 |       names, trademarks, service marks, or product names of the Licensor,
140 |       except as required for reasonable and customary use in describing the
141 |       origin of the Work and reproducing the content of the NOTICE file.
142 | 
143 |    7. Disclaimer of Warranty. Unless required by applicable law or
144 |       agreed to in writing, Licensor provides the Work (and each
145 |       Contributor provides its Contributions) on an "AS IS" BASIS,
146 |       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 |       implied, including, without limitation, any warranties or conditions
148 |       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 |       PARTICULAR PURPOSE. You are solely responsible for determining the
150 |       appropriateness of using or redistributing the Work and assume any
151 |       risks associated with Your exercise of permissions under this License.
152 | 
153 |    8. Limitation of Liability. In no event and under no legal theory,
154 |       whether in tort (including negligence), contract, or otherwise,
155 |       unless required by applicable law (such as deliberate and grossly
156 |       negligent acts) or agreed to in writing, shall any Contributor be
157 |       liable to You for damages, including any direct, indirect, special,
158 |       incidental, or consequential damages of any character arising as a
159 |       result of this License or out of the use or inability to use the
160 |       Work (including but not limited to damages for loss of goodwill,
161 |       work stoppage, computer failure or malfunction, or any and all
162 |       other commercial damages or losses), even if such Contributor
163 |       has been advised of the possibility of such damages.
164 | 
165 |    9. Accepting Warranty or Additional Liability. While redistributing
166 |       the Work or Derivative Works thereof, You may choose to offer,
167 |       and charge a fee for, acceptance of support, warranty, indemnity,
168 |       or other liability obligations and/or rights consistent with this
169 |       License. However, in accepting such obligations, You may act only
170 |       on Your own behalf and on Your sole responsibility, not on behalf
171 |       of any other Contributor, and only if You agree to indemnify,
172 |       defend, and hold each Contributor harmless for any liability
173 |       incurred by, or claims asserted against, such Contributor by reason
174 |       of your accepting any such warranty or additional liability.
175 | 
176 |    END OF TERMS AND CONDITIONS
177 | 
178 |    APPENDIX: How to apply the Apache License to your work.
179 | 
180 |       To apply the Apache License to your work, attach the following
181 |       boilerplate notice, with the fields enclosed by brackets "[]"
182 |       replaced with your own identifying information. (Don't include
183 |       the brackets!)  The text should be enclosed in the appropriate
184 |       comment syntax for the file format. We also recommend that a
185 |       file or class name and description of purpose be included on the
186 |       same "printed page" as the copyright notice for easier
187 |       identification within third-party archives.
188 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | # Redmine Dashboard 2
 2 | 
 3 | [![Last release](https://img.shields.io/github/v/release/jgraichen/redmine_dashboard?label=latest%20release&logo=github&style=flat-square)](https://github.com/jgraichen/redmine_dashboard/releases/latest)
 4 | [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/jgraichen/redmine_dashboard/test.yml?branch=main&logo=github&style=flat-square)](https://github.com/jgraichen/redmine_dashboard/actions)
 5 | [![Rate at redmine.org](http://img.shields.io/badge/rate%20at-redmine.org-blue.svg?style=flat-square)](http://www.redmine.org/plugins/redmine-dashboard)
 6 | [![Follow at Twitter](http://img.shields.io/badge/follow%20at-twitter-blue.svg?style=flat-square)](https://twitter.com/RmDashboard)
 7 | 
 8 | This [Redmine](http://redmine.org) plugin adds an issue dashboard that supports drag and drop for issues and various filters.
 9 | 
10 | **Redmine Dashboard 2** is compatible and tested with Redmine 6.0, 5.1, 5.0, and Ruby 3.3, 3.2, 3.1, and 3.0.
11 | 
12 | ![Redmine Dashboard v2.x Screenshot](docs/rdb_2-1.png)
13 | 
14 | ## Features List
15 | 
16 | * Drag-n-drop of issues
17 | * Configurable columns
18 | * Grouping & Filtering
19 | * Group folding
20 | * Hierarchical parent issue view
21 | * Include subproject issues
22 | * Quick edit of assignee and progress
23 | 
24 | Rate plugin at [redmine.org](http://www.redmine.org/plugins/redmine-dashboard).
25 | 
26 | ## Questions? Stories?
27 | 
28 | Please ask your questions, or tell us your stories or experience on [GitHub Discussions](https://github.com/jgraichen/redmine_dashboard/discussions).
29 | 
30 | ## Install
31 | 
32 | 1. Download the [latest release](https://github.com/jgraichen/redmine_dashboard/releases).
33 | 2. Extract archive to `<redmine>/plugins`. Make **sure** the plugin directory is called `<redmine>/plugins/redmine_dashboard/` ([#11](https://github.com/jgraichen/redmine_dashboard/issues/11)).
34 | 3. Install required dependencies by running `bundle install --without development test` in your Redmine directory. **Note**: Bitnami and other appliance are not officially supported and may need additional option e.g. `--path vendor/bundle` ([#58](https://github.com/jgraichen/redmine_dashboard/issues/58)).
35 | 4. A database migration is not needed. Restart Redmine.
36 | 
37 | ### Configure Redmine
38 | 
39 | 1. Add the dashboard module to your project (`Settings > Modules`).
40 | 2. Configure dashboard permissions to your user roles (`Administration > Roles and permissions`). Users won't see a Dashboard tab without having the `View Dashboard` permission.
41 | 
42 | ### Upgrade
43 | 
44 | 1. Remove old plugin directory.
45 | 2. Follow installation steps for new release.
46 | 
47 | ## Contribute
48 | 
49 | I appreciate any help and like Pull Requests. The `main` branch is the current stable branch for v2. The next version, Redmine Dashboard 3, a complete rewrite had been under development on the `develop` branch. Due to limited available time the project is in maintenance only mode but open to new contributors.
50 | 
51 | I gladly accept new translations or language additions for any version of Redmine Dashboard. I would prefer new translations via [Transifex](https://www.transifex.com/projects/p/redmine-dashboard/), but you can also send a Pull Request. Feel free to request new languages or to join the team directly on Transifex.
52 | 
53 | ## License
54 | 
55 | Redmine dashboard is licensed under the Apache License, Version 2.0.
56 | See LICENSE for more information.
57 | 


--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | require 'pathname'
 4 | require 'yaml'
 5 | 
 6 | require 'rspec/core/rake_task'
 7 | 
 8 | task default: [:spec]
 9 | 
10 | RSpec::Core::RakeTask.new(:spec) do |t|
11 |   t.pattern    = ENV.fetch('SPEC', 'spec/**/*_spec.rb')
12 |   t.ruby_opts  = '-Ispec'
13 |   t.rspec_opts = '--color --backtrace'
14 |   t.rspec_opts << " --seed #{ENV['SEED']}" if ENV['SEED']
15 | end
16 | 
17 | namespace :i18n do
18 |   desc 'Fix locale files after tx pull'
19 |   task :fix do
20 |     Pathname.glob('config/locales/*.yml').each do |file|
21 |       data = YAML.safe_load(file.read)
22 | 
23 |       # Transifex exports data inside the YAML using underscored
24 |       # identifiers (e.g. pt_BR), but Redmine needs dashed identifiers
25 |       # (pt-bR). We need convert each top-level key to use dashes.
26 |       #
27 |       # We cannot modify a hash while iterating using `#each_key`.
28 |       # Therefore, we must us `keys.each` here.
29 |       data.keys.each do |key|
30 |         if key.include?('_')
31 |           data[key.tr('_', '-')] = data.delete(key)
32 |         end
33 |       end
34 | 
35 |       fix_pluralizations = lambda do |locale_data|
36 |         # Redmine does not contain pluralization rules, but many
37 |         # languages only need an `other` key according to Unicode. Tools
38 |         # like transifex expect proper pluralization rules and do not
39 |         # export a `one` key when only an `other` key is needed, such as
40 |         # for Japanese.
41 |         #
42 |         # This method searches the locale data for any nested dictionary
43 |         # that looks like a pluralized section (contains only `one`,
44 |         # `few`, `other` `many`, `zero` keys). If found, an `one` key
45 |         # will be added with the `other` value.
46 |         locale_data.each_value do |value|
47 |           next unless value.is_a?(Hash)
48 | 
49 |           if (value.keys - %w[one few other many zero]).empty?
50 |             value['one'] ||= value['other'] if value.key?('other')
51 |           else
52 |             fix_pluralizations.call(value)
53 |           end
54 |         end
55 |       end
56 | 
57 |       fix_pluralizations.call(data)
58 | 
59 |       file.write(YAML.dump(data, line_width: -1))
60 |     end
61 |   end
62 | end
63 | 


--------------------------------------------------------------------------------
/app/controllers/rdb_dashboard_controller.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | class RdbDashboardController < ApplicationController
 4 |   menu_item :dashboard
 5 |   before_action :find_project, :authorize
 6 |   before_action :setup_board, except: :index
 7 |   before_action :find_issue, only: %i[move update]
 8 |   before_action :authorize_edit, only: %i[move update]
 9 |   after_action :save_board_options
10 | 
11 |   def index
12 |     return redirect_to rdb_taskboard_url if params[:controller] == 'rdb_dashboard'
13 | 
14 |     setup_board
15 |   end
16 | 
17 |   def filter
18 |     render action: 'index'
19 |   end
20 | 
21 |   def update
22 |     render_404
23 |   end
24 | 
25 |   def move
26 |     render_404
27 |   end
28 | 
29 |   private
30 | 
31 |   def board_type
32 |     nil
33 |   end
34 | 
35 |   def board
36 |     board_type.new(@project, options_for(board_type.name), params)
37 |   end
38 | 
39 |   def setup_board
40 |     return render_404 unless (@board = board)
41 | 
42 |     @board.setup(params)
43 |     @board.update(params)
44 |     @board.build
45 |     @board
46 |   end
47 | 
48 |   def save_board_options
49 |     save_options_for(@board.options, board_type.name) if @board
50 |   end
51 | 
52 |   def authorize_edit
53 |     return true if @issue&.attributes_editable?
54 | 
55 |     raise Unauthorized
56 |   end
57 | 
58 |   def find_project
59 |     @project = Project.find params[:id]
60 |   end
61 | 
62 |   def find_issue
63 |     flash_error :rdb_flash_missing_lock_version and return false unless params[:lock_version]
64 | 
65 |     @issue = Issue.find params[:issue]
66 | 
67 |     if @issue.lock_version != params[:lock_version].to_i
68 |       flash_error :rdb_flash_stale_object, update: true, issue: @issue.subject
69 |       return false
70 |     end
71 | 
72 |     @issue.lock_version = params[:lock_version].to_i
73 |     @issue
74 |   end
75 | 
76 |   def flash_error(sym, **options)
77 |     flash.now[:rdb_error] = I18n.t(sym, **options).html_safe
78 |     Rails.logger.info "Render Rdb flash error: #{sym}"
79 |     if options[:update]
80 |       render('index', formats: :js)
81 |     else
82 |       render('error', formats: :js)
83 |     end
84 |   end
85 | 
86 |   def options_for(board)
87 |     User.current.pref["rdb_#{@project.id}_#{board}"] ||
88 |       session["dashboard_#{@project.id}_#{User.current.id}_#{board}"] || {}
89 |   end
90 | 
91 |   def save_options_for(options, board)
92 |     User.current.pref["rdb_#{@project.id}_#{board}"] = options
93 |     User.current.pref.save
94 |   end
95 | end
96 | 


--------------------------------------------------------------------------------
/app/controllers/rdb_taskboard_controller.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | class RdbTaskboardController < RdbDashboardController
 4 |   menu_item :dashboard
 5 | 
 6 |   def board_type
 7 |     RdbTaskboard
 8 |   end
 9 | 
10 |   def move
11 |     return flash_error(:rdb_flash_invalid_request) unless (column = @board.columns[params[:column].to_s])
12 | 
13 |     # Get all status the user is allowed to assign and that are in the target column
14 |     @statuses = @issue.new_statuses_allowed_to(User.current) & column.statuses
15 | 
16 |     if @statuses.empty?
17 |       return flash_error :rdb_flash_illegal_workflow_action,
18 |         issue: @issue.subject, source: @issue.status.name, target: column.title
19 |     end
20 | 
21 |     # Show dialog if more than one status are available
22 |     return render 'rdb_dashboard/taskboard/column_dialog' if @statuses.many?
23 | 
24 |     params[:status] = @statuses.first.id
25 |     update
26 |   end
27 | 
28 |   def update
29 |     @issue.init_journal(User.current, params[:notes] || nil)
30 | 
31 |     @issue.done_ratio = params[:done_ratio].to_i if params[:done_ratio]
32 |     @issue.assigned_to_id = nil if params[:unassigne_me] && @issue.assigned_to_id == User.current.id
33 |     @issue.assigned_to_id = User.current.id if params[:assigne_me]
34 | 
35 |     if params[:status]
36 |       status = IssueStatus.find params[:status].to_i
37 |       if @issue.new_statuses_allowed_to(User.current).include?(status)
38 |         @issue.status         = status
39 |         @issue.assigned_to_id = User.current.id if @board.options[:change_assignee]
40 |       else
41 |         return flash_error :rdb_flash_illegal_workflow_action,
42 |           issue: @issue.subject, source: @issue.status.name, target: @status.name
43 |       end
44 |     end
45 | 
46 |     Issue.transaction do
47 |       call_hook(
48 |         :controller_issues_edit_before_save,
49 |         {
50 |           params: {},
51 |           issue: @issue,
52 |           journal: @issue.current_journal
53 |         },
54 |       )
55 | 
56 |       if @issue.save
57 |         call_hook(
58 |           :controller_issues_edit_after_save,
59 |           {
60 |             params: {},
61 |             issue: @issue,
62 |             journal: @issue.current_journal
63 |           },
64 |         )
65 |       else
66 |         raise ActiveRecord::Rollback
67 |       end
68 |     end
69 | 
70 |     render 'index'
71 |   end
72 | end
73 | 


--------------------------------------------------------------------------------
/app/helpers/rdb_dashboard_helper.rb:
--------------------------------------------------------------------------------
  1 | # frozen_string_literal: true
  2 | 
  3 | module RdbDashboardHelper
  4 |   def render_rdb_menu(id, title, options = {}, &container)
  5 |     options[:class] ||= ''
  6 |     options[:class] += ' rdb-menu-right' if options[:right]
  7 |     options[:class] += ' rdb-small' if options[:small]
  8 | 
  9 |     slim_tag :div, class: "rdb-menu rdb-menu-#{id} #{options[:class]}" do
 10 |       if options[:anchor]
 11 |         link = options[:anchor].call.to_s.html_safe
 12 |       else
 13 |         link = link_to(title, '#', class: 'rdb-menu-link')
 14 |       end
 15 | 
 16 |       if options[:header] && %i[h1 h2 h3 h4 h5].include?(options[:header].to_sym)
 17 |         slim_tag(options[:header], link)
 18 |       else
 19 |         concat link
 20 |       end
 21 | 
 22 |       slim_tag :div, class: "rdb-container #{'rdb-container-right' if options[:right]}" do
 23 |         slim_tag :div, class: "rdb-container-wrapper #{'rdb-icons' if options[:icons]}" do
 24 |           if options[:inlet]
 25 |             slim_tag(:div, class: 'rdb-container-inlet', &container)
 26 |           else
 27 |             yield
 28 |           end
 29 |         end
 30 |       end
 31 |     end
 32 |   end
 33 | 
 34 |   def render_rdb_menu_list(items = nil, options = {})
 35 |     if items.is_a?(Hash)
 36 |       options = items
 37 |       items = nil
 38 |     end
 39 | 
 40 |     slim_tag :div, class: "rdb-list #{'rdb-async' if options[:async]} #{options[:class]}" do
 41 |       slim_tag :h3, options[:title] if options[:title]
 42 |       slim_tag options[:list_tag] || :ul, class: options[:list_class] do
 43 |         if items
 44 |           items.each do |item|
 45 |             slim_tag :li do
 46 |               yield item
 47 |             end
 48 |           end
 49 |         else
 50 |           yield
 51 |         end
 52 |       end
 53 |     end
 54 |   end
 55 | 
 56 |   def render_rdb_menu_list_item(options = {}, &block)
 57 |     slim_tag(:li, class: options[:async] ? 'rdb-async' : '', &block)
 58 |   end
 59 | 
 60 |   def rdb_checkbox_link_to(*args)
 61 |     options = args.extract_options!
 62 |     options[:class] ||= ''
 63 |     options[:class] += ' rdb-checkbox-link'
 64 |     options[:class] += ' rdb-checkbox-link-enabled' if options[:enabled]
 65 |     options[:class] += ' rdb-checkbox-link-disabled' if !options[:enabled] && options[:show_disabled]
 66 |     options[:class].strip!
 67 | 
 68 |     options.delete :enabled
 69 |     options.delete :show_disabled
 70 | 
 71 |     args << options
 72 | 
 73 |     link_to(*args)
 74 |   end
 75 | 
 76 |   def rdb_update_path(issue, options = {})
 77 |     send(:"rdb_#{@board.id}_update_path", {
 78 |       issue: issue.id,
 79 |       lock_version: issue.lock_version
 80 |     }.merge(options),)
 81 |   end
 82 | 
 83 |   def rdb_move_path(issue, options = {})
 84 |     send(:"rdb_#{@board.id}_move_path", {
 85 |       issue: issue.id,
 86 |       lock_version: issue.lock_version
 87 |     }.merge(options),)
 88 |   end
 89 | 
 90 |   def rdb_filter_path(options = {})
 91 |     send(:"rdb_#{@board.id}_filter_path", options)
 92 |   end
 93 | 
 94 |   def rdb_board_path(options = {})
 95 |     send(:"rdb_#{@board.id}_path", options)
 96 |   end
 97 | 
 98 |   private
 99 | 
100 |   def slim_tag(name, content = nil, **attrs)
101 |     concat tag(name, attrs, true, true)
102 |     concat(content) if content.present?
103 |     yield if block_given?
104 |     concat "</#{name}>".html_safe
105 |   end
106 | end
107 | 


--------------------------------------------------------------------------------
/app/models/rdb_assignee_filter.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | class RdbAssigneeFilter < RdbFilter
 4 |   def initialize
 5 |     super(:assignee)
 6 |   end
 7 | 
 8 |   def scope(scope)
 9 |     case value
10 |       when :me   then scope.where(assigned_to_id: User.current.id)
11 |       when :none then scope.where(assigned_to_id: nil)
12 |       when :all  then scope
13 |       else scope.where(assigned_to_id: value)
14 |     end
15 |   end
16 | 
17 |   def apply_to_child_issues?
18 |     true
19 |   end
20 | 
21 |   def default_values
22 |     [RdbDashboard.defaults[:assignee] || :me]
23 |   end
24 | 
25 |   def update(params)
26 |     return unless (assignee = params[:assignee])
27 | 
28 |     Rails.logger.warn "CHANGE ASSIGNE: #{assignee}"
29 | 
30 |     if (assignee == 'all') || (assignee == 'me') || (assignee == 'none')
31 |       self.value = assignee.to_sym
32 |     elsif board.assignees.where(id: assignee.to_i).any?
33 |       self.value = assignee.to_i
34 |     end
35 | 
36 |     Rails.logger.warn "CHANGE ASSIGNE: #{assignee} => #{values.inspect}"
37 |   end
38 | 
39 |   def title
40 |     case value
41 |       when :all then I18n.t(:rdb_filter_assignee_all)
42 |       when :me then I18n.t(:rdb_filter_assignee_me)
43 |       when :none then I18n.t(:rdb_filter_assignee_none)
44 |       else
45 |         values.map {|id| board.assignees.find(id) }.map(&:name).join(', ')
46 |     end
47 |   end
48 | end
49 | 


--------------------------------------------------------------------------------
/app/models/rdb_category_filter.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | class RdbCategoryFilter < RdbFilter
 4 |   def initialize
 5 |     super(:category)
 6 |   end
 7 | 
 8 |   def scope(scope)
 9 |     return scope if all?
10 | 
11 |     scope.where category_id: values
12 |   end
13 | 
14 |   def all?
15 |     values.count >= board.issue_categories.count or board.issue_categories.empty?
16 |   end
17 | 
18 |   def default_values
19 |     board.issue_categories.pluck(:id)
20 |   end
21 | 
22 |   def valid_value?(value)
23 |     default_values.include? value.to_i
24 |   end
25 | 
26 |   def update(params)
27 |     return unless (category = params[:category])
28 | 
29 |     if category == 'all'
30 |       self.values = board.issue_categories.pluck(:id)
31 |     else
32 |       id = category.to_i
33 | 
34 |       if params[:only]
35 |         self.value = id
36 |       elsif values.include?(id) && values.count > 2
37 |         values.delete id
38 |       elsif valid_value?(id)
39 |         values << id
40 |       end
41 |     end
42 |   end
43 | 
44 |   def title
45 |     return I18n.t(:rdb_filter_category_all) if all?
46 |     return I18n.t(:rdb_filter_category_multiple) if values.many?
47 | 
48 |     board.issue_categories.find_by(id: value).try(:name)
49 |   end
50 | 
51 |   def enabled?(id)
52 |     return true if value == :all
53 | 
54 |     values.include? id
55 |   end
56 | end
57 | 


--------------------------------------------------------------------------------
/app/models/rdb_column.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | class RdbColumn
 4 |   attr_accessor :board
 5 |   attr_reader :name, :options, :id, :statuses
 6 | 
 7 |   def initialize(id, name, statuses, options = {})
 8 |     @id       = id.to_s
 9 |     @name     = name
10 |     @statuses = statuses.is_a?(Array) ? statuses : [statuses]
11 |     @options  = options
12 |   end
13 | 
14 |   def scope(issue_scope)
15 |     issue_scope.where status_id: statuses.map(&:id)
16 |   end
17 | 
18 |   def issues
19 |     @issues ||= board.issues_for(self)
20 |   end
21 | 
22 |   def percentage
23 |     all_issue_count = board.issues.count
24 |     all_issue_count > 0 ? ((issues.count.to_f / all_issue_count) * 100).round(4) : 0
25 |   end
26 | 
27 |   def title
28 |     name.is_a?(Symbol) ? I18n.t(name) : name.to_s
29 |   end
30 | 
31 |   def compact?
32 |     !!options[:compact]
33 |   end
34 | 
35 |   def visible?
36 |     !options[:hide]
37 |   end
38 | end
39 | 


--------------------------------------------------------------------------------
/app/models/rdb_dashboard.rb:
--------------------------------------------------------------------------------
  1 | # frozen_string_literal: true
  2 | 
  3 | class RdbDashboard
  4 |   attr_reader :project, :options
  5 | 
  6 |   VIEW_MODES = %i[card compact].freeze
  7 | 
  8 |   def initialize(project, opts, params = nil)
  9 |     @project = project
 10 |     @options = {filters: {}}
 11 | 
 12 |     options.merge! self.class.defaults
 13 |     options.merge! opts
 14 | 
 15 |     if params[:include_subprojects]
 16 |       options[:include_subprojects] = (params[:include_subprojects] == 'true')
 17 |     end
 18 | 
 19 |     # Init board in sub class
 20 |     init if respond_to? :init
 21 | 
 22 |     filters.each_value do |filter|
 23 |       filter.values = options[:filters][filter.id] if options[:filters][filter.id]
 24 |     end
 25 |   end
 26 | 
 27 |   def setup(params)
 28 |     # Update issue view mode
 29 |     options[:view] = params[:view].to_sym if params[:view] && RdbDashboard::VIEW_MODES.include?(params[:view].to_sym)
 30 |   end
 31 | 
 32 |   def update(params)
 33 |     if params[:reset]
 34 |       filters.each_value do |filter|
 35 |         filter.values = filter.default_values
 36 |       end
 37 |       options[:filters] = {}
 38 |     else
 39 |       filters.each_value do |filter|
 40 |         filter.update params if params
 41 |         options[:filters][filter.id] = filter.values
 42 |       end
 43 |     end
 44 |   end
 45 | 
 46 |   def issue_view
 47 |     options[:view]
 48 |   end
 49 | 
 50 |   def projects
 51 |     @projects ||= Project.where(
 52 |         project.project_condition(options[:include_subprojects]),
 53 |       )
 54 |   end
 55 | 
 56 |   def project_ids
 57 |     @project_ids ||= projects.pluck(:id)
 58 |   end
 59 | 
 60 |   def issues
 61 |     filter Issue
 62 |       .where(project_id: project_ids)
 63 |       .includes(:assigned_to, :time_entries, :tracker, :status, :priority, :fixed_version)
 64 |   end
 65 | 
 66 |   def versions
 67 |     @versions ||= begin
 68 |       version_ids = project.shared_versions.pluck(:id)
 69 | 
 70 |       if options[:include_subprojects]
 71 |         version_ids += project.rolled_up_versions.pluck(:id)
 72 |       end
 73 | 
 74 |       Version.where(id: version_ids.uniq).sorted
 75 |     end
 76 |   end
 77 | 
 78 |   def issue_categories
 79 |     @issue_categories ||= IssueCategory.where(project_id: project_ids).distinct
 80 |   end
 81 | 
 82 |   def trackers
 83 |     @trackers ||= Tracker.where(
 84 |       id: Tracker.joins(:projects).where(projects: {id: project_ids}).distinct,
 85 |     ).sorted
 86 |   end
 87 | 
 88 |   def assignees
 89 |     @assignees ||= Principal.where(
 90 |       id: Principal.active.joins(:memberships).where(members: {project_id: project_ids}).distinct,
 91 |     ).sorted
 92 |   end
 93 | 
 94 |   def filter(issues)
 95 |     issues = filters.inject(issues) {|issues, filter| filter[1].scope issues }
 96 |     filters.inject(issues) {|issues, filter| filter[1].filter issues }
 97 |   end
 98 | 
 99 |   def abbreviation(project_id)
100 |     project_id ||= project.id
101 | 
102 |     @abbreviations ||= []
103 |     @abbreviations[project_id] ||= begin
104 |       abbreviation = '#'
105 |       Project.find(project_id).custom_field_values.each do |f|
106 |         if f.to_s.blank? && f.custom_field.read_attribute(:name).casecmp('abbreviation').zero?
107 |           abbreviation = "#{f}-"
108 |         end
109 |       end
110 |       abbreviation
111 |     end
112 |   end
113 | 
114 |   def issue_id(issue)
115 |     if issue.respond_to?(:issue_id)
116 |       issue.issue_id
117 |     else
118 |       abbreviation(issue.project_id) + issue.id.to_s
119 |     end
120 |   end
121 | 
122 |   def id
123 |     self.class.board_type
124 |   end
125 | 
126 |   def name
127 |     I18n.t :"rdb_#{id}"
128 |   end
129 | 
130 |   def add_filter(filter)
131 |     filter.board = self
132 |     filters[filter.id.to_s] = filter
133 |   end
134 | 
135 |   def add_group(group)
136 |     group.board = self
137 |     group_list << group
138 |     groups[group.id.to_s] = group
139 |   end
140 | 
141 |   def editable?(str = nil)
142 |     @editable ||= !User.current.allowed_to?(:edit_issues, project).nil?
143 |     if str
144 |       @editable ? str : false
145 |     else
146 |       @editable
147 |     end
148 |   end
149 | 
150 |   def filters
151 |     @filters ||= ActiveSupport::HashWithIndifferentAccess.new
152 |   end
153 | 
154 |   def groups
155 |     @groups ||= ActiveSupport::HashWithIndifferentAccess.new
156 |   end
157 | 
158 |   def group_list
159 |     @group_list ||= []
160 |   end
161 | 
162 |   class << self
163 |     def board_type
164 |       @board_type ||= name.downcase.to_s.gsub(/^rdb/, '').to_sym
165 |     end
166 | 
167 |     def defaults
168 |       @defaults ||= load_defaults
169 |     end
170 | 
171 |     def load_defaults
172 |       config = YAML.load_file File.expand_path('../../config/default.yml', __dir__)
173 | 
174 |       {
175 |         view: check_opts(config, 'view', :card, :compact),
176 |         include_subprojects: check_opts(config, 'include_subprojects', false, true),
177 |         assignee: check_opts(config, 'assignee', :me, :all),
178 |         version: check_opts(config, 'version', :latest, :all),
179 |         hide_done: check_opts(config, 'hide_done', false, true),
180 |         change_assignee: check_opts(config, 'change_assignee', false, true)
181 |       }
182 |     end
183 | 
184 |     def check_opts(options, name, *values)
185 |       value = options.fetch(name) { return values.first }
186 |       values.each do |val|
187 |         return val if val == value || val.to_s == value
188 |       end
189 | 
190 |       values.first
191 |     end
192 |   end
193 | end
194 | 


--------------------------------------------------------------------------------
/app/models/rdb_filter.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | class RdbFilter
 4 |   attr_accessor :board
 5 |   attr_reader :id
 6 | 
 7 |   def initialize(id)
 8 |     @id = id.to_sym
 9 |   end
10 | 
11 |   def default_options
12 |     {}
13 |   end
14 | 
15 |   def values
16 |     @values ||= default_values
17 |   end
18 | 
19 |   def default_values
20 |     []
21 |   end
22 | 
23 |   def value
24 |     values.first
25 |   end
26 | 
27 |   def value=(value)
28 |     self.values = value ? [value] : []
29 |   end
30 | 
31 |   def values=(values)
32 |     values = [values] unless values.is_a?(Array)
33 |     @values = values.select {|value| valid_value? value }
34 |     @values = default_values if @values.empty? && !allow_no_values?
35 |   end
36 | 
37 |   def valid_value?(_value)
38 |     true
39 |   end
40 | 
41 |   def allow_no_values?
42 |     false
43 |   end
44 | 
45 |   def title
46 |     values.join
47 |   end
48 | 
49 |   def to_options
50 |     []
51 |   end
52 | 
53 |   def scope(scope)
54 |     scope
55 |   end
56 | 
57 |   def filter(issues)
58 |     issues
59 |   end
60 | 
61 |   def apply_to_child_issues?
62 |     false
63 |   end
64 | 
65 |   def update(params); end
66 | end
67 | 


--------------------------------------------------------------------------------
/app/models/rdb_group.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | class RdbGroup
 4 |   attr_accessor :board
 5 |   attr_reader :name, :options, :id
 6 | 
 7 |   def initialize(id, name, options = {})
 8 |     @id    = id.to_s
 9 |     @name  = name
10 | 
11 |     @options = default_options
12 |     @options[:accept] = options[:accept] if options[:accept].respond_to? :call
13 |   end
14 | 
15 |   def default_options
16 |     {}
17 |   end
18 | 
19 |   def accept?(issue)
20 |     return true if options[:accept].nil?
21 | 
22 |     options[:accept].call(issue)
23 |   end
24 | 
25 |   def title
26 |     name.is_a?(Symbol) ? I18n.t(name) : name.to_s
27 |   end
28 | 
29 |   def accepted_issues(source = nil)
30 |     @accepted_issues ||= filter((source || board).issues)
31 |   end
32 | 
33 |   def accepted_issue_ids
34 |     @accepted_issue_ids ||= accepted_issues.map(&:id)
35 |   end
36 | 
37 |   def filter(issues)
38 |     issues.select {|i| accept? i }
39 |   end
40 | 
41 |   def visible?
42 |     @visible ||= catch(:visible) do
43 |       board.columns.each_value do |column|
44 |         next if !column.visible? || column.compact?
45 | 
46 |         throw :visible, true if filter(column.issues).any?
47 |       end
48 |       false
49 |     end
50 |   end
51 | 
52 |   def issue_count
53 |     filter(@board.issues).count.to_i
54 |   end
55 | end
56 | 


--------------------------------------------------------------------------------
/app/models/rdb_taskboard.rb:
--------------------------------------------------------------------------------
  1 | # frozen_string_literal: true
  2 | 
  3 | class RdbTaskboard < RdbDashboard
  4 |   def init
  5 |     # Init filters
  6 |     add_filter RdbAssigneeFilter.new
  7 |     add_filter RdbVersionFilter.new if versions.any?
  8 |     add_filter RdbTrackerFilter.new
  9 |     add_filter RdbCategoryFilter.new if issue_categories.any?
 10 |   end
 11 | 
 12 |   def setup(params)
 13 |     super
 14 | 
 15 |     if %w[tracker priority assignee category version parent none project].include? params[:group]
 16 |       options[:group] = params[:group].to_sym
 17 |     end
 18 | 
 19 |     if params[:hide_done]
 20 |       options[:hide_done] = (params[:hide_done] == 'true')
 21 |     end
 22 | 
 23 |     if params[:change_assignee]
 24 |       options[:change_assignee] = (params[:change_assignee] == 'true')
 25 |     end
 26 | 
 27 |     if (id = params[:hide_column])
 28 |       options[:hide_columns] ||= []
 29 |       options[:hide_columns].include?(id) ? options[:hide_columns].delete(id) : (options[:hide_columns] << id)
 30 |     end
 31 |   end
 32 | 
 33 |   def statuses
 34 |     ids = WorkflowTransition
 35 |       .where(tracker_id: filters[:tracker].values)
 36 |       .distinct
 37 |       .pluck(:old_status_id, :new_status_id)
 38 |       .flatten
 39 |       .uniq
 40 | 
 41 |     IssueStatus.where(id: ids).sorted
 42 |   end
 43 | 
 44 |   def build
 45 |     # Init columns
 46 |     options[:hide_columns] ||= []
 47 | 
 48 |     done_statuses = statuses.select do |status|
 49 |       next true if status.is_closed?
 50 | 
 51 |       add_column RdbColumn.new(
 52 |         "s#{status.id}",
 53 |         status.name,
 54 |         status,
 55 |         hide: options[:hide_columns].include?("s#{status.id}"),
 56 |       )
 57 | 
 58 |       false
 59 |     end
 60 | 
 61 |     if done_statuses.one?
 62 |       status = done_statuses.first
 63 |       add_column RdbColumn.new(
 64 |         "s#{status.id}",
 65 |         status.name,
 66 |         status,
 67 |         compact: options[:hide_done],
 68 |         hide: options[:hide_columns].include?("s#{status.id}"),
 69 |       )
 70 |     elsif done_statuses.any?
 71 |       add_column RdbColumn.new(
 72 |         'sX',
 73 |         :rdb_column_done,
 74 |         done_statuses,
 75 |         compact: options[:hide_done],
 76 |         hide: options[:hide_columns].include?('sX'),
 77 |       )
 78 |     end
 79 | 
 80 |     # Init groups
 81 |     case options[:group]
 82 |       when :tracker
 83 |         trackers.each do |tracker|
 84 |           add_group RdbGroup.new(
 85 |             "tracker-#{tracker.id}",
 86 |             tracker.name,
 87 |             accept: proc {|issue| issue.tracker == tracker },
 88 |           )
 89 |         end
 90 | 
 91 |       when :priority
 92 |         IssuePriority.reorder(position: :desc).each do |p|
 93 |           add_group RdbGroup.new(
 94 |             "priority-#{p.position}",
 95 |             p.name,
 96 |             accept: proc {|issue| issue.priority_id == p.id },
 97 |           )
 98 |         end
 99 | 
100 |       when :assignee
101 |         add_group RdbGroup.new(
102 |           :assigne_me,
103 |           :rdb_filter_assignee_me,
104 |           accept: proc {|issue| issue.assigned_to_id == User.current.id },
105 |         )
106 |         add_group RdbGroup.new(
107 |           :assigne_none,
108 |           :rdb_filter_assignee_none,
109 |           accept: proc {|issue| issue.assigned_to_id.nil? },
110 |         )
111 |         assignees.sort_by(&:name).each do |principal|
112 |           next if principal.id == User.current.id
113 | 
114 |           add_group RdbGroup.new(
115 |             "assignee-#{id}",
116 |             principal.name,
117 |             accept: proc {|issue| !issue.assigned_to_id.nil? && issue.assigned_to_id == principal.id },
118 |           )
119 |         end
120 | 
121 |       when :category
122 |         issue_categories.each do |category|
123 |           add_group RdbGroup.new(
124 |             "category-#{category.id}",
125 |             category.name,
126 |             accept: proc {|issue| issue.category_id == category.id },
127 |           )
128 |         end
129 |         add_group RdbGroup.new(
130 |           :category_none,
131 |           :rdb_unassigned,
132 |           accept: proc {|issue| issue.category.nil? },
133 |         )
134 | 
135 |       when :version
136 |         versions.each do |version|
137 |           add_group RdbGroup.new(
138 |             "version-#{version.id}",
139 |             version.name,
140 |             accept: proc {|issue| issue.fixed_version_id == version.id },
141 |           )
142 |         end
143 |         add_group RdbGroup.new(
144 |           :version_none,
145 |           :rdb_unassigned,
146 |           accept: proc {|issue| issue.fixed_version.nil? },
147 |         )
148 | 
149 |       when :project
150 |         projects.each do |project|
151 |           add_group RdbGroup.new(
152 |             "project-#{project.id}",
153 |             project.name,
154 |             accept: proc {|issue| issue.project_id == project.id },
155 |           )
156 |         end
157 | 
158 |       when :parent
159 |         issues.where(id: issues.pluck(:parent_id).uniq).uniq.each do |issue|
160 |           add_group RdbGroup.new(
161 |             "issue-#{issue.id}",
162 |             issue.subject,
163 |             accept: proc {|sub_issue| sub_issue.parent_id == issue.id },
164 |           )
165 |         end
166 |         add_group RdbGroup.new(
167 |           'issue-others',
168 |           :rdb_no_parent,
169 |           accept: proc {|issue| issue.parent.nil? },
170 |         )
171 |     end
172 | 
173 |     add_group RdbGroup.new(:all, :rdb_all_issues) if groups.empty?
174 |   end
175 | 
176 |   # -------------------------------------------------------
177 |   # Helpers
178 | 
179 |   def issues_for(column)
180 |     filter column.scope(issues)
181 |   end
182 | 
183 |   def columns
184 |     @columns ||= ActiveSupport::HashWithIndifferentAccess.new
185 |   end
186 | 
187 |   def column_list
188 |     @column_list ||= []
189 |   end
190 | 
191 |   def add_column(column)
192 |     column.board = self
193 |     column_list << column
194 |     columns[column.id.to_s] = column
195 |   end
196 | 
197 |   def visible_columns
198 |     column_list.select(&:visible?)
199 |   end
200 | 
201 |   def drop_on(issue)
202 |     if User.current.admin?
203 |       return column_list.reject {|c| c.statuses.include? issue.status }.map(&:id).join(' ')
204 |     end
205 | 
206 |     return false unless issue&.attributes_editable?(User.current)
207 | 
208 |     statuses = issue.new_statuses_allowed_to(User.current)
209 |     statuses.delete issue.status
210 |     column_list.select do |c|
211 |       (statuses & c.statuses).any?
212 |     end.reject {|c| c.statuses.include? issue.status }.map(&:id).uniq.join(' ')
213 |   end
214 | end
215 | 


--------------------------------------------------------------------------------
/app/models/rdb_tracker_filter.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | class RdbTrackerFilter < RdbFilter
 4 |   def initialize
 5 |     super(:tracker)
 6 |   end
 7 | 
 8 |   def scope(scope)
 9 |     return scope if all?
10 | 
11 |     scope.where tracker_id: values
12 |   end
13 | 
14 |   def all?
15 |     values.count == board.trackers.count
16 |   end
17 | 
18 |   def apply_to_child_issues?
19 |     true
20 |   end
21 | 
22 |   def default_values
23 |     board.trackers.pluck(:id)
24 |   end
25 | 
26 |   def update(params)
27 |     return unless (tracker = params[:tracker])
28 | 
29 |     if tracker == 'all'
30 |       self.values = board.trackers.pluck(:id)
31 |       return
32 |     end
33 | 
34 |     id = tracker.to_i
35 |     return if board.trackers.where(id: id).empty?
36 | 
37 |     if params[:only]
38 |       self.value = id
39 |     elsif values.include? id
40 |       values.delete id if values.count > 2
41 |     else
42 |       values << id
43 |     end
44 |   end
45 | 
46 |   def title
47 |     return I18n.t(:rdb_filter_tracker_all) if all?
48 |     return I18n.t(:rdb_filter_tracker_multiple) if values.many?
49 | 
50 |     board.trackers.find(value).name
51 |   end
52 | 
53 |   def enabled?(id)
54 |     return true if value == :all
55 | 
56 |     values.include? id
57 |   end
58 | end
59 | 


--------------------------------------------------------------------------------
/app/models/rdb_version_filter.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | class RdbVersionFilter < RdbFilter
 4 |   def initialize
 5 |     super(:version)
 6 |   end
 7 | 
 8 |   def scope(issues)
 9 |     case value
10 |       when :all then issues
11 |       when :unassigned then issues.where fixed_version_id: nil
12 |       else issues.where fixed_version_id: value
13 |     end
14 |   end
15 | 
16 |   def valid_value?(value)
17 |     return true if (value == :all) || value.nil?
18 |     return false unless value.respond_to?(:to_i)
19 | 
20 |     board.versions.where(id: value.to_i).any?
21 |   end
22 | 
23 |   def default_values
24 |     if RdbDashboard.defaults[:version] == :latest
25 |       version = board.versions
26 |         .where(status: %i[open locked])
27 |         .where.not(effective_date: nil)
28 |         .order('effective_date ASC')
29 |         .first
30 |       return [version.id] unless version.nil?
31 | 
32 |       version = board.versions
33 |         .where(status: %i[open locked])
34 |         .order('name ASC')
35 |         .first
36 |       return [version.id] unless version.nil?
37 |     end
38 | 
39 |     [:all]
40 |   end
41 | 
42 |   def update(params)
43 |     return unless (version = params[:version])
44 | 
45 |     case version
46 |       when 'all'
47 |         self.value = :all
48 |       when 'unassigned'
49 |         self.values = [nil]
50 |       else
51 |         self.value = version.to_i
52 |     end
53 |   end
54 | 
55 |   def title
56 |     if value == :all
57 |       I18n.t(:rdb_filter_version_all)
58 |     elsif value.nil?
59 |       I18n.t(:rdb_filter_version_unassigned)
60 |     else
61 |       values.map {|id| board.versions.find(id) }.map(&:name).join(', ')
62 |     end
63 |   end
64 | 
65 |   def versions
66 |     board.versions.where(status: %i[open locked])
67 |   end
68 | 
69 |   def done_versions
70 |     board.versions.where(status: :closed)
71 |   end
72 | end
73 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/_footer.html.slim:
--------------------------------------------------------------------------------
 1 | #rdb-footer
 2 |   #rdb-copyright
 3 |     a href="https://github.com/jgraichen/redmine_dashboard"
 4 |       | Redmine Dashboard 2
 5 |     = " - v#{Redmine::Plugin.find(:redmine_dashboard).version}"
 6 | 
 7 |   #rdb-legend
 8 |     div
 9 |       p = t :rdb_legend_priorities
10 |       - IssuePriority.all.sort_by(&:position).each do |priority|
11 |         span class="rdb-priority rdb-priority-#{priority.position}"
12 |           = priority
13 | 
14 |     div
15 |       p = t :rdb_legend_warnings
16 |       span.rdb-overdue
17 |         span &nbsp;
18 |       = t :rdb_issue_overdue
19 |   .rdb-clear
20 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/_taskboard.html.slim:
--------------------------------------------------------------------------------
 1 | #rdb-taskboard
 2 |   header#rdb-header
 3 |     = render partial: 'rdb_dashboard/taskboard/header'
 4 |     .rdb-clear
 5 | 
 6 |   #rdb-board
 7 |     #rdb-board-container
 8 |       = render partial: 'rdb_dashboard/taskboard/column_names'
 9 |       = render partial: 'rdb_dashboard/taskboard/overall_progress'
10 |       = render partial: 'rdb_dashboard/taskboard/groups'
11 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/configure.html.slim:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/app/views/rdb_dashboard/configure.html.slim


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/error.js.erb:
--------------------------------------------------------------------------------
1 | <% if flash[:rdb_error] %>
2 | 	Rdb.rdbError("<%= escape_javascript(flash[:rdb_error]) %>");
3 | <% end %>
4 | Rdb.rdbDADShowIssue();
5 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/index.html.slim:
--------------------------------------------------------------------------------
 1 | - content_for :header_tags do
 2 |   = stylesheet_link_tag 'dashboard.css', plugin: :redmine_dashboard
 3 |   = stylesheet_link_tag 'dashboard.ui.css', plugin: :redmine_dashboard
 4 |   = stylesheet_link_tag 'dashboard.issues.css', plugin: :redmine_dashboard
 5 |   = stylesheet_link_tag 'dashboard.taskboard.css', plugin: :redmine_dashboard
 6 |   = javascript_include_tag 'jquery.autoellipsis.js', plugin: :redmine_dashboard
 7 |   = javascript_include_tag 'jquery.total-storage.js', plugin: :redmine_dashboard
 8 |   = javascript_include_tag 'dashboard.js', plugin: :redmine_dashboard
 9 |   = javascript_include_tag 'dashboard.ui.js', plugin: :redmine_dashboard
10 |   = javascript_include_tag 'dashboard.taskboard.js', plugin: :redmine_dashboard
11 | 
12 | #rdb data={'rdb-base': rdb_board_path}
13 |   #rdb-wrapper
14 |     #rdb-header
15 |     #rdb-board
16 |       #rdb-loading
17 | 
18 |   #rdb-errors
19 |   #rdb-dialogs
20 |   = render partial: 'footer'
21 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/index.js.erb:
--------------------------------------------------------------------------------
1 | $('#rdb-wrapper').html("<%= escape_javascript(render partial: @board.id.to_s) %>");
2 | Rdb.rdbInit();
3 | <% if flash[:rdb_error] %>
4 | 	Rdb.rdbError("<%= escape_javascript(flash[:rdb_error]) %>");
5 | <% end %>
6 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/issues/_card.html.slim:
--------------------------------------------------------------------------------
 1 | / ISSUE CARD
 2 | .rdb-card
 3 |   div class="rdb-priority rdb-priority-#{issue.priority.position}"
 4 |     header.rdb-card-header
 5 |       .rdb-card-title
 6 |         = render partial: 'rdb_dashboard/issues/issue_menu', locals: {issue: issue}
 7 |       div
 8 | 
 9 |     .rdb-card-progress
10 |       .rdb-card-progress-bar style="width: #{issue.done_ratio}%"
11 | 
12 |     .rdb-card-content
13 |       .rdb-card-subject.rdb-property-subject = issue.subject
14 |       = render partial: 'rdb_dashboard/issues/issue_properties', locals: {issue: issue}
15 | / ISSUE CARD END
16 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/issues/_compact.html.slim:
--------------------------------------------------------------------------------
 1 | / ISSUE COMPACT
 2 | .rdb-compact
 3 |   .rdb-priority class="rdb-priority-#{issue.priority.position}"
 4 | 
 5 |     .rdb-compact-progress
 6 |       .rdb-compact-progress-bar style="width: #{issue.done_ratio}%"
 7 |     header.rdb-compact-header
 8 |       .rdb-compact-title
 9 |         = render partial: 'rdb_dashboard/issues/issue_menu', locals: {issue: issue}
10 |       .rdb-compact-header-data
11 |         = render partial: 'rdb_dashboard/issues/issue_properties', locals: {issue: issue}
12 | 
13 |     .rdb-compact-content
14 |       .rdb-compact-subject.rdb-property-subject = issue.subject
15 | / ISSUE COMPACT END
16 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/issues/_issue.html.slim:
--------------------------------------------------------------------------------
1 | .rdb-issue(
2 |   class="rdb-issue-#{@board.issue_view} #{@board.editable?('rdb-issue-drag')} #{issue.overdue? ? 'rdb-overdue' : ''}"
3 |   data={'rdb-drop-on': @board.drop_on(issue), 'rdb-drop-group': group.id, 'rdb-issue-id': issue.id, 'rdb-lock-version': issue.lock_version}
4 | )
5 |   = render partial: "rdb_dashboard/issues/#{@board.issue_view}", locals: {issue: issue}
6 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/issues/_issue_menu.html.slim:
--------------------------------------------------------------------------------
 1 | - render_rdb_menu :issue, @board.issue_id(issue), small: true do
 2 |   - render_rdb_menu_list title: t(:rdb_issue_menu_redmine_issue) do
 3 |     - render_rdb_menu_list_item do
 4 |       = link_to t(:rdb_issue_menu_show), issue_path(issue)
 5 |     - if @board.editable?
 6 |       - render_rdb_menu_list_item do
 7 |         = link_to t(:rdb_issue_menu_edit), edit_issue_path(issue)
 8 |       - if issue.assigned_to_id == User.current.id
 9 |         - render_rdb_menu_list_item async: true do
10 |           = link_to t(:rdb_issue_menu_unassign_me), rdb_update_path(issue, unassigne_me: true)
11 |       - else
12 |         - render_rdb_menu_list_item async: true do
13 |           = link_to t(:rdb_issue_menu_assign_me), rdb_update_path(issue, assigne_me: true)
14 | 
15 |   - if @board.editable? && (issue.assigned_to_id == User.current.id || User.current.admin?)
16 |     - render_rdb_menu_list title: t(:rdb_issue_menu_progress_title), async: true, list_tag: :div do
17 |       ul.rdb-issue-menu-progress
18 |         - [0, 20, 40].each do |value|
19 |           li = link_to t(:rdb_issue_menu_progress, count: value), rdb_update_path(issue, done_ratio: value)
20 |       ul.rdb-issue-menu-progress
21 |         - [60, 80, 100].each do |value|
22 |           li = link_to t(:rdb_issue_menu_progress, count: value), rdb_update_path(issue, done_ratio: value)
23 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/issues/_issue_properties.html.slim:
--------------------------------------------------------------------------------
 1 | .rdb-property.rdb-property-tracker = issue.tracker
 2 | - if @board.versions.any?
 3 |   - if issue.fixed_version
 4 |     .rdb-property.rdb-property-version = issue.fixed_version.name
 5 |   - else
 6 |     .rdb-property.rdb-property-version.rdb-disabled = t(:rdb_filter_version_unassigned)
 7 | - if issue.assigned_to
 8 |   .rdb-property.rdb-property-assignee = issue.assigned_to.name
 9 | - else
10 |   .rdb-property.rdb-property-assignee.rdb-disabled = t(:rdb_unassigned)
11 | - if @board.issue_categories.any?
12 |   - if issue.category
13 |     .rdb-property.rdb-property-category = issue.category.name
14 |   - else
15 |     .rdb-property.rdb-property-category.rdb-disabled = t(:rdb_unassigned)
16 | - if User.current.allowed_to?(:view_time_entries, @project)
17 |   .rdb-property.rdb-property-time class=(issue.estimated_hours.nil? && issue.time_entries.empty? ? 'rdb-disabled' : '')
18 |     = t(:rdb_property_time, estimated: issue.estimated_hours.to_f.round(2), actual: issue.time_entries.map(&:hours).reduce(&:+).to_f.round(2)).html_safe
19 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/issues/_parent.html.slim:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/app/views/rdb_dashboard/issues/_parent.html.slim


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/taskboard/_column.html.slim:
--------------------------------------------------------------------------------
 1 | - if issues.any? && @board.groups.count > 1
 2 |   .rdb-column-head = t(:rdb_x_issues, count: issues.count)
 3 | div class="rdb-grid-#{@board.issue_view}"
 4 |   - grouped_issues = issues.group_by {|i| i.priority.position }
 5 |   - grouped_issues.keys.sort.reverse.each do |priority|
 6 |     - grouped_issues[priority].sort_by(&:id).each do |issue|
 7 |       = render partial: 'rdb_dashboard/issues/issue', locals: {issue: issue, group: group}
 8 | 
 9 |   / Render multple empty diff to fill-up the "grid" if
10 |   / very few issues are present in a column. Otherwise
11 |   / the column will not add CSS grid columns in the group
12 |   / if the overall column gets wide enought.
13 |   - 5.times do
14 |     div
15 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/taskboard/_column_dialog.html.slim:
--------------------------------------------------------------------------------
 1 | div
 2 |   .rdb-card.rdb-card-dialog
 3 |     .rdb-priority class="rdb-priority-#{@issue.priority.position}"
 4 |       header.rdb-card-header
 5 |         span.rdb-card-title
 6 |           = link_to "#{@board.abbreviation(@issue.project_id)}#{@issue.id}", @issue
 7 | 
 8 |       .rdb-card-progress
 9 |         .rdb-card-progress-bar style="width: #{@issue.done_ratio}%"
10 | 
11 |       .rdb-card-content
12 |         .rdb-card-subject.rdb-property-subject = @issue.subject
13 | 
14 |       .rdb-card-dialog-box.rdb-async
15 |         label = t(:rdb_dialog_update_issue_status)
16 |         ul
17 |           - @statuses.each do |status|
18 |             li = link_to status.name, rdb_update_path(@issue, status: status.id)
19 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/taskboard/_column_names.html.slim:
--------------------------------------------------------------------------------
1 | ul.rdb-headers
2 |   - @board.column_list.each do |column|
3 |     - if column.visible?
4 |       li.rdb-column class=(column.compact? ? 'rdb-column-compact' : '')
5 |         h3 = column.title
6 |         - if column.issues.count > 0
7 |           span = t :rdb_x_issues, count: column.issues.count
8 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/taskboard/_columns.html.slim:
--------------------------------------------------------------------------------
1 | ul.rdb-columns
2 |   - @board.visible_columns.each do |column|
3 |     li.rdb-column class=(column.compact? ? 'rdb-column-compact' : '') data={'rdb-column-id': column.id, 'rdb-drop-group': group.id}
4 |       - unless column.compact?
5 |         = render partial: 'rdb_dashboard/taskboard/column', locals: {column: column, issues: group.filter(column.issues), group: group}
6 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/taskboard/_group.html.slim:
--------------------------------------------------------------------------------
1 | .rdb-group data-rdb-group-id=group.id
2 |   .rdb-group-header
3 |     a.rdb-evt-group-toggle
4 |       h4 = group.title
5 |       span = t(:rdb_x_issues, count: group.issue_count)
6 |   = render partial: 'rdb_dashboard/taskboard/columns', locals: {group: group}
7 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/taskboard/_groups.html.slim:
--------------------------------------------------------------------------------
 1 | .rdb-groups
 2 |   - if @board.groups.count == 1
 3 |     .rdb-group data-rdb-group-id=@board.group_list.first.id
 4 |       = render partial: 'rdb_dashboard/taskboard/columns', locals: {group: @board.group_list.first}
 5 |   - else
 6 |     - show_all = @board.group_list.select(&:visible?).none?
 7 |     - @board.group_list.each do |group|
 8 |       - if show_all || group.visible?
 9 |         = render partial: 'rdb_dashboard/taskboard/group', locals: {group: group}
10 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/taskboard/_header.html.slim:
--------------------------------------------------------------------------------
 1 | .rdb-board
 2 |   = link_to '', rdb_board_path, class: 'rdb-async', id: 'rdb-refresh'
 3 | 
 4 |   - render_rdb_menu :board, @board.name, header: :h2 do
 5 |     - render_rdb_menu_list [:taskboard] do |val|
 6 |       = link_to t("rdb_#{val}"), rdb_path(board: val)
 7 | 
 8 | - if @board.versions.any?
 9 |   .rdb-filter.rdb-async
10 |     - render_rdb_menu :versions, @board.filters[:version].title do
11 |       - render_rdb_menu_list [:all, :unassigned] do |val|
12 |         = link_to t("rdb_filter_version_#{val}"), rdb_filter_path(version: val)
13 |       - render_rdb_menu_list @board.filters[:version].versions do |val|
14 |         = link_to val.name, rdb_filter_path(version: val.id)
15 | 
16 | .rdb-filter.rdb-async
17 |   - render_rdb_menu :tracker, @board.filters[:tracker].title, icons: true do
18 |     - render_rdb_menu_list [:all] do |val|
19 |       = link_to t("rdb_filter_tracker_#{val}"), rdb_filter_path(tracker: val)
20 |     - render_rdb_menu_list @board.trackers do |val|
21 |       span.rdb-multicheck
22 |         = rdb_checkbox_link_to '', rdb_filter_path(tracker: val.id), enabled: @board.filters[:tracker].enabled?(val.id), show_disabled: true
23 |         = link_to val.name, rdb_filter_path(tracker: val.id, only: true)
24 | 
25 | - if @board.issue_categories.any?
26 |   .rdb-filter.rdb-async
27 |     - render_rdb_menu :categories, @board.filters[:category].title, icons: true do
28 |       - render_rdb_menu_list [:all] do |val|
29 |         = link_to t("rdb_filter_category_#{val}"), rdb_filter_path(category: val)
30 |       - render_rdb_menu_list @board.issue_categories do |val|
31 |         span.rdb-multicheck
32 |           = rdb_checkbox_link_to '', rdb_filter_path(category: val.id), enabled: @board.filters[:category].enabled?(val.id), show_disabled: true
33 |           = link_to val.name, rdb_filter_path(category: val.id, only: true)
34 | 
35 | .rdb-filter.rdb-async
36 |   - render_rdb_menu :assignee, @board.filters[:assignee].title do
37 |     - render_rdb_menu_list [:all, :me, :none] do |val|
38 |       = link_to t("rdb_filter_assignee_#{val}"), rdb_filter_path(assignee: val)
39 |     - render_rdb_menu_list @board.assignees do |val|
40 |       - if User === val
41 |         = link_to val.name, rdb_filter_path(assignee: val.id)
42 |     - render_rdb_menu_list @board.assignees do |val|
43 |       - if Group === val
44 |         = link_to val.name, rdb_filter_path(assignee: val.id)
45 | 
46 | .rdb-option.rdb-async
47 |   - render_rdb_menu :options, t(:rdb_options), right: true, icons: true do
48 |     - render_rdb_menu_list do
49 |       - render_rdb_menu_list_item do
50 |         = rdb_checkbox_link_to t(:rdb_options_change_assignee), rdb_board_path(change_assignee: !@board.options[:change_assignee]),
51 |             enabled: @board.options[:change_assignee], title: t(:rdb_options_change_assignee_info)
52 |         = rdb_checkbox_link_to t(:rdb_options_hide_done), rdb_board_path(hide_done: !@board.options[:hide_done]),
53 |             enabled: @board.options[:hide_done], title: t(:rdb_options_hide_done_info)
54 |         = rdb_checkbox_link_to t(:rdb_options_include_subprojects), rdb_board_path(include_subprojects: (@board.project_ids.size > 1) ? 'false' : 'true'),
55 |             enabled: (@board.project_ids.size > 1)
56 |     - render_rdb_menu_list @board.column_list, title: t(:rdb_options_columns) do |column|
57 |       = rdb_checkbox_link_to column.title, rdb_board_path(hide_column: column.id), enabled: @board.columns[column.id].visible?
58 |     - render_rdb_menu_list do
59 |       - render_rdb_menu_list_item do
60 |         = link_to t(:rdb_options_fullscreen), 'javascript:Rdb.rdbToggleFullscreen();', id: "rdb-option-fullscreen"
61 |       - render_rdb_menu_list_item do
62 |         = link_to t(:rdb_options_reset), rdb_filter_path(reset: 1), id: "rdb-reset", title: t(:rdb_options_reset_info)
63 | 
64 | .rdb-option.rdb-async
65 |   - render_rdb_menu :view, t(:rdb_options_view), right: true do
66 |     - render_rdb_menu_list RdbDashboard::VIEW_MODES, title: t(:rdb_options_issue_view) do |view|
67 |       = rdb_checkbox_link_to t(:"rdb_options_issue_view_#{view}"), rdb_board_path(view: view), enabled: @board.options[:view] == view
68 |     - render_rdb_menu_list [:none, :tracker, :category, :priority, :assignee, :version, :parent, :project], title: t(:rdb_options_group) do |group|
69 |       = rdb_checkbox_link_to t(:"rdb_group_#{group}"), rdb_board_path(group: group), enabled: @board.options[:group] == group
70 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/taskboard/_overall_progress.html.slim:
--------------------------------------------------------------------------------
1 | div.rdb-overall-progress
2 |   - @board.column_list[0..-2].each do |column|
3 |     a.rdb-overall-progress class="rdb-column-#{column.id}" style="width: #{column.percentage}%"
4 | 


--------------------------------------------------------------------------------
/app/views/rdb_dashboard/taskboard/column_dialog.js.erb:
--------------------------------------------------------------------------------
1 | $().rdbDialog("<%= escape_javascript t(:rdb_dialog_update_issue_title) %>", "<%= escape_javascript(render :partial => 'rdb_dashboard/taskboard/column_dialog') %>");
2 | 


--------------------------------------------------------------------------------
/assets/javascripts/dashboard.js:
--------------------------------------------------------------------------------
  1 | (function(global, $) {
  2 | 
  3 | 	global.Rdb = {};
  4 | 	var rdbInits = [];
  5 | 
  6 | 	/* extend */
  7 | 	String.prototype.startsWith = function (string) {
  8 | 	    return(this.indexOf(string) === 0);
  9 | 	};
 10 | 
 11 | 	$.fn.rdbAny = function(selector) {
 12 | 		return $(this).length > 0;
 13 | 	};
 14 | 
 15 | 	$.fn.rdbEmpty = function(selector) {
 16 | 		return $(this).length == 0;
 17 | 	};
 18 | 
 19 | 	$.fn.rdbFindUp = function(selector) {
 20 | 		var el = $(this);
 21 | 		if(el.is(selector))
 22 | 			return $(this);
 23 | 		return el.parents(selector);
 24 | 	};
 25 | 
 26 | 	Rdb.rdbInit = function(fn) {
 27 | 		$.fn.rdbInit.call(Rdb.rdbBase(), fn);
 28 | 	}
 29 | 
 30 | 	$.fn.rdbInit = function(fn) {
 31 | 		if(fn) {
 32 | 			rdbInits.push(fn);
 33 | 		} else {
 34 | 			for(var i in rdbInits) {
 35 | 				rdbInits[i].call(this);
 36 | 			}
 37 | 		}
 38 | 	};
 39 | 
 40 | 	$.fn.rdbIssue = function() {
 41 | 		return $(this).rdbFindUp('[data-rdb-issue-id]');
 42 | 	};
 43 | 
 44 | 	$.fn.rdbIssueId = function() {
 45 | 		return $(this).rdbIssue().data('rdb-issue-id');
 46 | 	};
 47 | 
 48 | 	$.fn.rdbIssueLockVersion = function() {
 49 | 		return $(this).rdbIssue().data('rdb-lock-version');
 50 | 	};
 51 | 
 52 | 	Rdb.rdbError = function(message) {
 53 | 		var box = $('#rdb-errors');
 54 | 		var msg = $('<div class="rdb-error" />').html(message).hide();
 55 | 
 56 | 		msg.append('<a class="close">❌</a>')
 57 | 
 58 | 		msg.find('a.close').click(function(e) {
 59 | 			e.preventDefault();
 60 | 			msg.fadeOut(function() {
 61 | 				msg.remove();
 62 | 			});
 63 | 		});
 64 | 
 65 | 		msg.appendTo(box).fadeIn(function() {
 66 | 			setTimeout(function() {
 67 | 				msg.fadeOut(function() {
 68 | 					msg.remove();
 69 | 				});
 70 | 			}, 12000);
 71 | 		});
 72 | 	};
 73 | 
 74 | 	$.fn.rdbVisible = function() {
 75 | 		var el = $(this);
 76 | 		var docTop = $(window).scrollTop();
 77 | 		var docBottom = docTop + $(window).height();
 78 | 
 79 | 		var top = $(el).offset().top;
 80 | 		var bottom = top + $(el).height();
 81 | 
 82 | 		return ((bottom <= docBottom) && (top >= docTop));
 83 | 	};
 84 | 
 85 | 	Rdb.rdbStorageAdd = function(id, value) {
 86 | 		var storage = $.totalStorage('rdb-' + id);
 87 | 		if(!storage) storage = new Array;
 88 | 		storage.push(value);
 89 | 		$.totalStorage('rdb-' + id, storage);
 90 | 		return true;
 91 | 	};
 92 | 
 93 | 	Rdb.rdbStorageRemove = function(id, value) {
 94 | 		var storage = $.totalStorage('rdb-' + id);
 95 | 		if(!storage) return false;
 96 | 		var i = -1;
 97 | 		while((i = storage.indexOf(value)) >= 0) {
 98 | 			storage.splice(i, 1)
 99 | 		}
100 | 		$.totalStorage('rdb-' + id, storage);
101 | 		return true;
102 | 	};
103 | 
104 | 	Rdb.rdbStorageHas = function(id, value) {
105 | 		var storage = $.totalStorage('rdb-' + id);
106 | 		if(!storage) return false;
107 | 		for(var i in storage) {
108 | 			if(storage[i] == value) {
109 | 				return true;
110 | 			}
111 | 		}
112 | 		return false;
113 | 	};
114 | 
115 | 	Rdb.rdbBase = function() {
116 | 		return $('#rdb');
117 | 	};
118 | 
119 | 	Rdb.rdbBaseURL = function() {
120 | 		return Rdb.rdbBase().data('rdb-base');
121 | 	};
122 | 
123 | 	/*
124 | 	 * Ajax Filter / Options
125 | 	 */
126 | 	$(document).click(function(e) {
127 | 		var link = $(e.target).rdbFindUp('a').first();
128 | 		if(link.rdbFindUp('.rdb-async').rdbAny() && link.attr('href') != '#' && !link.is('.rdb-sync') && !link.attr('href').startsWith('javascript:')) {
129 | 			Rdb.rdbMenuClose();
130 | 			Rdb.rdbCloseDialog();
131 | 			e.preventDefault();
132 | 			$.getScript(
133 | 				link.attr('href')
134 | 			).fail(function(jqxhr, settings, exception) {
135 | 				Rdb.rdbError('<b>Ajax Error</b>: ' + exception);
136 | 			});
137 | 		}
138 | 	});
139 | 
140 | 	/* Issue subject text ellipsis */
141 | 	$(document).ready(function () {
142 | 		var resizeActions = function() {
143 | 			$('.rdb-property-subject').ellipsis();
144 | 
145 | 			var box = $('#rdb-errors');
146 | 			var board = $('#rdb-board');
147 | 			if($('#rdb-footer').rdbVisible()) {
148 | 				box.css({ 'position': 'absolute', 'bottom': '30px' });
149 | 			} else {
150 | 				box.css({ 'position': 'fixed', 'bottom': '30px' });
151 | 			}
152 | 		};
153 | 
154 | 		Rdb.rdbInit(resizeActions);
155 | 		$(window).resize(resizeActions);
156 | 	});
157 | 
158 | 	/* load board on startup */
159 | 	$(document).ready(function () {
160 | 		$.getScript('?');
161 | 	});
162 | 
163 | })(window, jQuery);
164 | 


--------------------------------------------------------------------------------
/assets/javascripts/dashboard.taskboard.js:
--------------------------------------------------------------------------------
  1 | (function($) {
  2 | 
  3 | 	$.fn.rdbColumn = function() {
  4 | 		return $(this).rdbFindUp('[data-rdb-column-id]');
  5 | 	};
  6 | 
  7 | 	$.fn.rdbColumnId = function() {
  8 | 		return $(this).rdbColumn().data('rdb-column-id');
  9 | 	};
 10 | 
 11 | 	$.fn.rdbGroup = function() {
 12 | 		return $(this).rdbFindUp('[data-rdb-group-id]');
 13 | 	};
 14 | 
 15 | 	$.fn.rdbGroupId = function() {
 16 | 		return $(this).rdbGroup().data('rdb-group-id');
 17 | 	};
 18 | 
 19 | 	/* ====================================================
 20 | 	** Drag and drop
 21 | 	*/
 22 | 
 23 | 	var currentIssue;
 24 | 
 25 | 	Rdb.rdbDADShowIssue = function() {
 26 | 		if(currentIssue) currentIssue.css({ visibility: 'visible', opacity: 1 });
 27 | 	};
 28 | 
 29 | 	Rdb.rdbInitDAD = function () {
 30 | 		var el = Rdb.rdbBase();
 31 | 		var baseURL = Rdb.rdbBaseURL();
 32 | 
 33 | 		el.find(".rdb-issue-drag").each(function() {
 34 | 			var issue = $(this);
 35 | 
 36 | 			issue.draggable({
 37 | 				scroll: false,
 38 | 				revert: true,
 39 | 				// containment: '#rdb-board',
 40 | 				distance: 20,
 41 | 				cancel: 'a,.rdb-menu',
 42 | 				start: function() {
 43 | 					Rdb.rdbMenuClose();
 44 | 					issue.addClass('rdb-issue-dragged');
 45 | 				},
 46 | 				stop: function() {
 47 | 					issue.removeClass('rdb-issue-dragged');
 48 | 				}
 49 | 			});
 50 | 		});
 51 | 
 52 | 		el.find(".rdb-column").each(function() {
 53 | 			var column = $(this);
 54 | 			var coluid = column.rdbColumnId();
 55 | 			var cgroup = column.data('rdb-drop-group');
 56 | 			if(coluid) {
 57 | 				column.droppable({
 58 | 					accept: function(draggable) {
 59 | 						var issue = draggable.rdbIssue();
 60 | 						var dropon = issue.data('rdb-drop-on') || '';
 61 | 						return issue.data('rdb-drop-group') == cgroup && dropon.indexOf(coluid) >= 0;
 62 | 					}, //'[data-rdb-drop-on*="' + accept + '"]',
 63 | 					activeClass: "rdb-column-drop-active",
 64 | 					hoverClass: "rdb-column-drop-hover",
 65 | 					tolerance: "pointer",
 66 | 					drop: function(event, ui) {
 67 | 						var issue = $(ui.draggable).rdbIssue();
 68 | 						var lock  = issue.rdbIssueLockVersion();
 69 | 						var issueId = issue.rdbIssueId();
 70 | 						var groupId = issue.rdbGroupId();
 71 | 
 72 | 						if(issueId && issue.rdbColumnId() != coluid) {
 73 | 							currentIssue = issue;
 74 | 							currentIssue.css({ visibility: 'hidden', opacity: 0 });
 75 | 							$.getScript(
 76 | 								baseURL + '/move?issue=' + issueId + '&lock_version=' + lock + '&column=' + coluid + '&group=' + groupId)
 77 | 							.fail(function(jqxhr, settings, exception) {
 78 | 								Rdb.rdbDADShowIssue();
 79 | 								Rdb.rdbError('<b>Error</b>: ' + exception);
 80 | 							});
 81 | 						}
 82 | 					}
 83 | 				});
 84 | 			}
 85 | 		});
 86 | 	};
 87 | 
 88 | 	Rdb.rdbDestroyDAD = function () {
 89 | 		Rdb.rdbBase().find(".rdb-issue-drag").draggable('destroy');
 90 | 	};
 91 | 
 92 | 	Rdb.rdbInit(function() {
 93 | 		Rdb.rdbInitDAD();
 94 | 	});
 95 | 
 96 | 	/* ====================================================
 97 | 	** Collapse groups
 98 | 	*/
 99 | 
100 | 	$(document).click(function (e) {
101 | 		var link  = $(e.target).rdbFindUp('a').first();
102 | 		var group = link.rdbGroup();
103 | 		if(link.rdbAny() && group.rdbAny() && link.parents().is('.rdb-group-header')) {
104 | 			e.preventDefault();
105 | 			if(group.hasClass('rdb-collapsed')) {
106 | 				Rdb.rdbStorageRemove('collapsed-groups', group.rdbGroupId());
107 | 				group.removeClass('rdb-collapsed');
108 | 			} else {
109 | 				Rdb.rdbStorageAdd('collapsed-groups', group.rdbGroupId());
110 | 				group.addClass('rdb-collapsed');
111 | 			}
112 | 		}
113 | 	});
114 | 
115 | 	Rdb.rdbInit(function() {
116 | 		$('.rdb-group').each(function() {
117 | 			var group = $(this);
118 | 			if(Rdb.rdbStorageHas('collapsed-groups', group.rdbGroupId())) {
119 | 				group.addClass('rdb-collapsed');
120 | 			}
121 | 		});
122 | 	});
123 | 
124 | })(jQuery);;
125 | 


--------------------------------------------------------------------------------
/assets/javascripts/dashboard.ui.js:
--------------------------------------------------------------------------------
  1 | (function($) {
  2 | 
  3 | 	$.fn.rdbMenu = function() {
  4 | 		$(this).rdbFindUp('.rdb-menu');
  5 | 	}
  6 | 
  7 | 	$.fn.rdbMenuShow = function() {
  8 | 		$(this).addClass('rdb-menu-active');
  9 | 	}
 10 | 
 11 | 	$.fn.rdbMenuHide = function() {
 12 | 		$(this).removeClass('rdb-menu-active');
 13 | 	}
 14 | 
 15 | 	/* =====================================================
 16 | 	** Dashboard Drop-Down Menus
 17 | 	*/
 18 | 	var lastMenu;
 19 | 
 20 | 	Rdb.rdbMenuClose = function() {
 21 | 		if(lastMenu != null) {
 22 | 			lastMenu.rdbMenuHide();
 23 | 			lastMenu = null;
 24 | 		}
 25 | 	}
 26 | 
 27 | 	$(document).click(function(e) {
 28 | 		var link = $(e.target).rdbFindUp('a.rdb-menu-link');
 29 | 		if(link.rdbAny() && link.parents('.rdb-menu-container').rdbEmpty() ) {
 30 | 			e.preventDefault();
 31 | 			var menu = link.parents('.rdb-menu').first();
 32 | 			if(menu.rdbAny()) {
 33 | 				if(menu.is(lastMenu)) {
 34 | 					lastMenu.rdbMenuHide();
 35 | 					lastMenu = null;
 36 | 				} else {
 37 | 					if(lastMenu) lastMenu.rdbMenuHide();
 38 | 					lastMenu = menu;
 39 | 					lastMenu.rdbMenuShow();
 40 | 				}
 41 | 			}
 42 | 		}
 43 | 
 44 | 		if(lastMenu != null && $(e.target).rdbFindUp('.rdb-menu').length == 0) {
 45 | 			lastMenu.rdbMenuHide();
 46 | 			lastMenu = null;
 47 | 		}
 48 | 	});
 49 | 
 50 | 	/* =====================================================
 51 | 	** Dashboard Dialog
 52 | 	*/
 53 | 
 54 | 	$.fn.rdbDialog = function(title, html) {
 55 | 		var dialog = $('<div class="rdb-dialog" />').html(html).dialog({
 56 | 			title: title,
 57 | 			modal: true,
 58 | 			draggable: false,
 59 | 			resizable: false,
 60 | 			dialogClass: 'alert',
 61 | 			close: function() { Rdb.rdbDADShowIssue(); }
 62 | 		});
 63 | 	};
 64 | 
 65 | 	Rdb.rdbCloseDialog = function() {
 66 | 		$('.rdb-dialog').remove();
 67 | 	};
 68 | 
 69 | 	/* =====================================================
 70 | 	** Dashboard Fullscreen
 71 | 	*/
 72 | 
 73 | 	Rdb.rdbIsFullscreen = function() {
 74 | 		return Rdb.rdbStorageHas('fullscreen', 'fullscreen');
 75 | 	};
 76 | 
 77 | 	Rdb.rdbLoadFullscreen = function() {
 78 | 		if(Rdb.rdbIsFullscreen()) {
 79 | 			Rdb.rdbShowFullscreen();
 80 | 		} else {
 81 | 			Rdb.rdbHideFullscreen();
 82 | 		}
 83 | 	};
 84 | 
 85 | 	Rdb.rdbToggleFullscreen = function() {
 86 | 		Rdb.rdbMenuClose();
 87 | 		if(Rdb.rdbIsFullscreen()) {
 88 | 			Rdb.rdbHideFullscreen();
 89 | 		} else {
 90 | 			Rdb.rdbShowFullscreen();
 91 | 		}
 92 | 	};
 93 | 
 94 | 	Rdb.rdbShowFullscreen = function() {
 95 | 		Rdb.rdbStorageAdd('fullscreen', 'fullscreen');
 96 | 		Rdb.rdbBase().addClass('rdb-fullscreen');
 97 | 	};
 98 | 
 99 | 	Rdb.rdbHideFullscreen = function() {
100 | 		Rdb.rdbStorageRemove('fullscreen', 'fullscreen');
101 | 		Rdb.rdbBase().removeClass('rdb-fullscreen');
102 | 	};
103 | 
104 | 	Rdb.rdbInit(Rdb.rdbLoadFullscreen);
105 | 
106 | })(jQuery);
107 | 


--------------------------------------------------------------------------------
/assets/javascripts/jquery.autoellipsis.js:
--------------------------------------------------------------------------------
  1 | /*!
  2 | 
  3 |     Copyright (c) 2011 Peter van der Spek
  4 | 
  5 |     Permission is hereby granted, free of charge, to any person obtaining a copy
  6 |     of this software and associated documentation files (the "Software"), to deal
  7 |     in the Software without restriction, including without limitation the rights
  8 |     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9 |     copies of the Software, and to permit persons to whom the Software is
 10 |     furnished to do so, subject to the following conditions:
 11 | 
 12 |     The above copyright notice and this permission notice shall be included in
 13 |     all copies or substantial portions of the Software.
 14 | 
 15 |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 |     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18 |     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 |     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20 |     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21 |     THE SOFTWARE.
 22 | 
 23 |  */
 24 | 
 25 | 
 26 | (function($) {
 27 | 
 28 |     /**
 29 |      * Hash containing mapping of selectors to settings hashes for target selectors that should be live updated.
 30 |      *
 31 |      * @type {Object.<string, Object>}
 32 |      * @private
 33 |      */
 34 |     var liveUpdatingTargetSelectors = {};
 35 | 
 36 |     /**
 37 |      * Interval ID for live updater. Contains interval ID when the live updater interval is active, or is undefined
 38 |      * otherwise.
 39 |      *
 40 |      * @type {number}
 41 |      * @private
 42 |      */
 43 |     var liveUpdaterIntervalId;
 44 | 
 45 |     /**
 46 |      * Boolean indicating whether the live updater is running.
 47 |      *
 48 |      * @type {boolean}
 49 |      * @private
 50 |      */
 51 |     var liveUpdaterRunning = false;
 52 | 
 53 |     /**
 54 |      * Set of default settings.
 55 |      *
 56 |      * @type {Object.<string, string>}
 57 |      * @private
 58 |      */
 59 |     var defaultSettings = {
 60 |                 ellipsis: '…',
 61 |                 setTitle: 'never',
 62 |                 live: false
 63 |             };
 64 | 
 65 |     /**
 66 |      * Perform ellipsis on selected elements.
 67 |      *
 68 |      * @param {string} selector the inner selector of elements that ellipsis may work on. Inner elements not referred to by this
 69 |      *      selector are left untouched.
 70 |      * @param {Object.<string, string>=} options optional options to override default settings.
 71 |      * @return {jQuery} the current jQuery object for chaining purposes.
 72 |      * @this {jQuery} the current jQuery object.
 73 |      */
 74 |     $.fn.ellipsis = function(selector, options) {
 75 |         var subjectElements, settings;
 76 | 
 77 |         subjectElements = $(this);
 78 | 
 79 |         // Check for options argument only.
 80 |         if (typeof selector !== 'string') {
 81 |             options = selector;
 82 |             selector = undefined;
 83 |         }
 84 | 
 85 |         // Create the settings from the given options and the default settings.
 86 |         settings = $.extend({}, defaultSettings, options);
 87 | 
 88 |         // If selector is not set, work on immediate children (default behaviour).
 89 |         settings.selector = selector;
 90 | 
 91 |         // Do ellipsis on each subject element.
 92 |         subjectElements.each(function() {
 93 |             var elem = $(this);
 94 | 
 95 |             // Do ellipsis on subject element.
 96 |             ellipsisOnElement(elem, settings);
 97 |         });
 98 | 
 99 |         // If live option is enabled, add subject elements to live updater. Otherwise remove from live updater.
100 |         if (settings.live) {
101 |             addToLiveUpdater(subjectElements.selector, settings);
102 | 
103 |         } else {
104 |             removeFromLiveUpdater(subjectElements.selector);
105 |         }
106 | 
107 |         // Return jQuery object for chaining.
108 |         return this;
109 |     };
110 | 
111 | 
112 |     /**
113 |      * Perform ellipsis on the given container.
114 |      *
115 |      * @param {jQuery} containerElement jQuery object containing one DOM element to perform ellipsis on.
116 |      * @param {Object.<string, string>} settings the settings for this ellipsis operation.
117 |      * @private
118 |      */
119 |     function ellipsisOnElement(containerElement, settings) {
120 |         var containerData = containerElement.data('jqae');
121 |         if (!containerData) containerData = {};
122 | 
123 |         // Check if wrapper div was already created and bound to the container element.
124 |         var wrapperElement = containerData.wrapperElement;
125 | 
126 |         // If not, create wrapper element.
127 |         if (!wrapperElement) {
128 |             wrapperElement = containerElement.wrapInner('<div/>').find('>div');
129 | 
130 |             // Wrapper div should not add extra size.
131 |             wrapperElement.css({
132 |                 margin: 0,
133 |                 padding: 0,
134 |                 border: 0
135 |             });
136 |         }
137 | 
138 |         // Check if the original wrapper element content was already bound to the wrapper element.
139 |         var wrapperElementData = wrapperElement.data('jqae');
140 |         if (!wrapperElementData) wrapperElementData = {};
141 | 
142 |         var wrapperOriginalContent = wrapperElementData.originalContent;
143 | 
144 |         // If so, clone the original content, re-bind the original wrapper content to the clone, and replace the
145 |         // wrapper with the clone.
146 |         if (wrapperOriginalContent) {
147 |             wrapperElement = wrapperElementData.originalContent.clone(true)
148 |                     .data('jqae', {originalContent: wrapperOriginalContent}).replaceAll(wrapperElement);
149 | 
150 |         } else {
151 |             // Otherwise, clone the current wrapper element and bind it as original content to the wrapper element.
152 | 
153 |             wrapperElement.data('jqae', {originalContent: wrapperElement.clone(true)});
154 |         }
155 | 
156 |         // Bind the wrapper element and current container width and height to the container element. Current container
157 |         // width and height are stored to detect changes to the container size.
158 |         containerElement.data('jqae', {
159 |             wrapperElement: wrapperElement,
160 |             containerWidth: containerElement.width(),
161 |             containerHeight: containerElement.height()
162 |         });
163 | 
164 |         // Calculate with current container element height.
165 |         var containerElementHeight = containerElement.height();
166 | 
167 |         // Calculate wrapper offset.
168 |         var wrapperOffset = (parseInt(containerElement.css('padding-top'), 10) || 0) + (parseInt(containerElement.css('border-top-width'), 10) || 0) - (wrapperElement.offset().top - containerElement.offset().top);
169 | 
170 |         // Normally the ellipsis characters are applied to the last non-empty text-node in the selected element. If the
171 |         // selected element becomes empty during ellipsis iteration, the ellipsis characters cannot be applied to that
172 |         // selected element, and must be deferred to the previous selected element. This parameter keeps track of that.
173 |         var deferAppendEllipsis = false;
174 | 
175 |         // Loop through all selected elements in reverse order.
176 |         var selectedElements = wrapperElement;
177 |         if (settings.selector) selectedElements = $(wrapperElement.find(settings.selector).get().reverse());
178 | 
179 |         selectedElements.each(function() {
180 |             var selectedElement = $(this),
181 |                     originalText = selectedElement.text(),
182 |                     ellipsisApplied = false;
183 | 
184 |             // Check if we can safely remove the selected element. This saves a lot of unnecessary iterations.
185 |             if (wrapperElement.innerHeight() - selectedElement.innerHeight() > containerElementHeight + wrapperOffset) {
186 |                 selectedElement.remove();
187 | 
188 |             } else {
189 |                 // Reverse recursively remove empty elements, until the element that contains a non-empty text-node.
190 |                 removeLastEmptyElements(selectedElement);
191 | 
192 |                 // If the selected element has not become empty, start ellipsis iterations on the selected element.
193 |                 if (selectedElement.contents().length) {
194 | 
195 |                     // If a deffered ellipsis is still pending, apply it now to the last text-node.
196 |                     if (deferAppendEllipsis) {
197 |                         getLastTextNode(selectedElement).get(0).nodeValue += settings.ellipsis;
198 |                         deferAppendEllipsis = false;
199 |                     }
200 | 
201 |                     // Iterate until wrapper element height is less than or equal to the original container element
202 |                     // height plus possible wrapperOffset.
203 |                     while (wrapperElement.innerHeight() > containerElementHeight + wrapperOffset) {
204 |                         // Apply ellipsis on last text node, by removing one word.
205 |                         ellipsisApplied = ellipsisOnLastTextNode(selectedElement);
206 | 
207 |                         // If ellipsis was succesfully applied, remove any remaining empty last elements and append the
208 |                         // ellipsis characters.
209 |                         if (ellipsisApplied) {
210 |                             removeLastEmptyElements(selectedElement);
211 | 
212 |                             // If the selected element is not empty, append the ellipsis characters.
213 |                             if (selectedElement.contents().length) {
214 |                                 getLastTextNode(selectedElement).get(0).nodeValue += settings.ellipsis;
215 | 
216 |                             } else {
217 |                                 // If the selected element has become empty, defer the appending of the ellipsis characters
218 |                                 // to the previous selected element.
219 |                                 deferAppendEllipsis = true;
220 |                                 selectedElement.remove();
221 |                                 break;
222 |                             }
223 | 
224 |                         } else {
225 |                             // If ellipsis could not be applied, defer the appending of the ellipsis characters to the
226 |                             // previous selected element.
227 |                             deferAppendEllipsis = true;
228 |                             selectedElement.remove();
229 |                             break;
230 |                         }
231 |                     }
232 | 
233 |                     // If the "setTitle" property is set to "onEllipsis" and the ellipsis has been applied, or if the
234 |                     // property is set to "always", the add the "title" attribute with the original text. Else remove the
235 |                     // "title" attribute. When the "setTitle" property is set to "never" we do not touch the "title"
236 |                     // attribute.
237 |                     if (((settings.setTitle == 'onEllipsis') && ellipsisApplied) || (settings.setTitle == 'always')) {
238 |                         selectedElement.attr('title', originalText);
239 | 
240 |                     } else if (settings.setTitle != 'never') {
241 |                         selectedElement.removeAttr('title');
242 |                     }
243 |                 }
244 |             }
245 |         });
246 |     }
247 | 
248 |     /**
249 |      * Performs ellipsis on the last text node of the given element. Ellipsis is done by removing a full word.
250 |      *
251 |      * @param {jQuery} element jQuery object containing a single DOM element.
252 |      * @return {boolean} true when ellipsis has been done, false otherwise.
253 |      * @private
254 |      */
255 |     function ellipsisOnLastTextNode(element) {
256 |         var lastTextNode = getLastTextNode(element);
257 | 
258 |         // If the last text node is found, do ellipsis on that node.
259 |         if (lastTextNode.length) {
260 |             var text = lastTextNode.get(0).nodeValue;
261 | 
262 |             // Find last space character, and remove text from there. If no space is found the full remaining text is
263 |             // removed.
264 |             var pos = text.lastIndexOf(' ');
265 |             if (pos > -1) {
266 |                 text = $.trim(text.substring(0, pos));
267 |                 lastTextNode.get(0).nodeValue = text;
268 | 
269 |             } else {
270 |                 lastTextNode.get(0).nodeValue = '';
271 |             }
272 | 
273 |             return true;
274 |         }
275 | 
276 |         return false;
277 |     }
278 | 
279 |     /**
280 |      * Get last text node of the given element.
281 |      *
282 |      * @param {jQuery} element jQuery object containing a single element.
283 |      * @return {jQuery} jQuery object containing a single text node.
284 |      * @private
285 |      */
286 |     function getLastTextNode(element) {
287 |         if (element.contents().length) {
288 | 
289 |             // Get last child node.
290 |             var contents = element.contents();
291 |             var lastNode = contents.eq(contents.length - 1);
292 | 
293 |             // If last node is a text node, return it.
294 |             if (lastNode.filter(textNodeFilter).length) {
295 |                 return lastNode;
296 | 
297 |             } else {
298 |                 // Else it is an element node, and we recurse into it.
299 | 
300 |                 return getLastTextNode(lastNode);
301 |             }
302 | 
303 |         } else {
304 |             // If there is no last child node, we append an empty text node and return that. Normally this should not
305 |             // happen, as we test for emptiness before calling getLastTextNode.
306 | 
307 |             element.append('');
308 |             var contents = element.contents();
309 |             return contents.eq(contents.length - 1);
310 |         }
311 |     }
312 | 
313 |     /**
314 |      * Remove last empty elements. This is done recursively until the last element contains a non-empty text node.
315 |      *
316 |      * @param {jQuery} element jQuery object containing a single element.
317 |      * @return {boolean} true when elements have been removed, false otherwise.
318 |      * @private
319 |      */
320 |     function removeLastEmptyElements(element) {
321 |         if (element.contents().length) {
322 | 
323 |             // Get last child node.
324 |             var contents = element.contents();
325 |             var lastNode = contents.eq(contents.length - 1);
326 | 
327 |             // If last child node is a text node, check for emptiness.
328 |             if (lastNode.filter(textNodeFilter).length) {
329 |                 var text = lastNode.get(0).nodeValue;
330 |                 text = $.trim(text);
331 | 
332 |                 if (text == '') {
333 |                     // If empty, remove the text node.
334 |                     lastNode.remove();
335 | 
336 |                     return true;
337 | 
338 |                 } else {
339 |                     return false;
340 |                 }
341 | 
342 |             } else {
343 |                 // If the last child node is an element node, remove the last empty child nodes on that node.
344 |                 while (removeLastEmptyElements(lastNode)) {
345 |                 }
346 | 
347 |                 // If the last child node contains no more child nodes, remove the last child node.
348 |                 if (lastNode.contents().length) {
349 |                     return false;
350 | 
351 |                 } else {
352 |                     lastNode.remove();
353 | 
354 |                     return true;
355 |                 }
356 |             }
357 |         }
358 | 
359 |         return false;
360 |     }
361 | 
362 |     /**
363 |      * Filter for testing on text nodes.
364 |      *
365 |      * @return {boolean} true when this node is a text node, false otherwise.
366 |      * @this {Node}
367 |      * @private
368 |      */
369 |     function textNodeFilter() {
370 |         return this.nodeType === 3;
371 |     }
372 | 
373 |     /**
374 |      * Add target selector to hash of target selectors. If this is the first target selector added, start the live
375 |      * updater.
376 |      *
377 |      * @param {string} targetSelector the target selector to run the live updater for.
378 |      * @param {Object.<string, string>} settings the settings to apply on this target selector.
379 |      * @private
380 |      */
381 |     function addToLiveUpdater(targetSelector, settings) {
382 |         // Store target selector with its settings.
383 |         liveUpdatingTargetSelectors[targetSelector] = settings;
384 | 
385 |         // If the live updater has not yet been started, start it now.
386 |         if (!liveUpdaterIntervalId) {
387 |             liveUpdaterIntervalId = window.setInterval(function() {
388 |                 doLiveUpdater();
389 |             }, 200);
390 |         }
391 |     }
392 | 
393 |     /**
394 |      * Remove the target selector from the hash of target selectors. It this is the last remaining target selector
395 |      * being removed, stop the live updater.
396 |      *
397 |      * @param {string} targetSelector the target selector to stop running the live updater for.
398 |      * @private
399 |      */
400 |     function removeFromLiveUpdater(targetSelector) {
401 |         // If the hash contains the target selector, remove it.
402 |         if (liveUpdatingTargetSelectors[targetSelector]) {
403 |             delete liveUpdatingTargetSelectors[targetSelector];
404 | 
405 |             // If no more target selectors are in the hash, stop the live updater.
406 |             if (!liveUpdatingTargetSelectors.length) {
407 |                 if (liveUpdaterIntervalId) {
408 |                     window.clearInterval(liveUpdaterIntervalId);
409 |                     liveUpdaterIntervalId = undefined;
410 |                 }
411 |             }
412 |         }
413 |     };
414 | 
415 |     /**
416 |      * Run the live updater. The live updater is periodically run to check if its monitored target selectors require
417 |      * re-applying of the ellipsis.
418 |      *
419 |      * @private
420 |      */
421 |     function doLiveUpdater() {
422 |         // If the live updater is already running, skip this time. We only want one instance running at a time.
423 |         if (!liveUpdaterRunning) {
424 |             liveUpdaterRunning = true;
425 | 
426 |             // Loop through target selectors.
427 |             for (var targetSelector in liveUpdatingTargetSelectors) {
428 |                 $(targetSelector).each(function() {
429 |                     var containerElement, containerData;
430 | 
431 |                     containerElement = $(this);
432 |                     containerData = containerElement.data('jqae');
433 | 
434 |                     // If container element dimensions have changed, or the container element is new, run ellipsis on
435 |                     // that container element.
436 |                     if ((containerData.containerWidth != containerElement.width()) ||
437 |                             (containerData.containerHeight != containerElement.height())) {
438 |                         ellipsisOnElement(containerElement, liveUpdatingTargetSelectors[targetSelector]);
439 |                     }
440 |                 });
441 |             }
442 | 
443 |             liveUpdaterRunning = false;
444 |         }
445 |     };
446 | 
447 | })(jQuery);
448 | 


--------------------------------------------------------------------------------
/assets/javascripts/jquery.total-storage.js:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * TotalStorage
  3 |  *
  4 |  * Copyright (c) 2012 Jared Novack & Upstatement (upstatement.com)
  5 |  * Dual licensed under the MIT and GPL licenses:
  6 |  * http://www.opensource.org/licenses/mit-license.php
  7 |  * http://www.gnu.org/licenses/gpl.html
  8 |  *
  9 |  * Total Storage is the conceptual the love child of jStorage by Andris Reinman,
 10 |  * and Cookie by Klaus Hartl -- though this is not connected to either project.
 11 |  */
 12 | 
 13 | /**
 14 |  * Create a local storage parameter
 15 |  *
 16 |  == What makes it TOTAL Storage? ==
 17 | 
 18 |  * The browser doesn't support local storage it will fall-back to cookies! (Using the
 19 |    wonderful $.cookie plugin).
 20 |  * Send it strings, numbers even complex object arrays! TotalStorage does not care.
 21 |    Your efforts to defeat it will prove futile.
 22 |  * Simple as shit. jStorage and some other very well-written plugins provide a bevy of
 23 |    options for expiration, security and so forth. Frequently this is more power than you
 24 |    need and vulnerable to confusion if you're just want it to work (JWITW)
 25 | 
 26 |  * @desc Set the value of a key to a string
 27 |  * @example $.totalStorage('the_key', 'the_value');
 28 |  * @desc Set the value of a key to a number
 29 |  * @example $.totalStorage('the_key', 800.2);
 30 |  * @desc Set the value of a key to a complex Array
 31 |  * @example	var myArray = new Array();
 32 |  *			myArray.push({name:'Jared', company:'Upstatement', zip:63124});
 33 | 			myArray.push({name:'McGruff', company:'Police', zip:60652};
 34 | 			$.totalStorage('people', myArray);
 35 | 			//to return:
 36 | 			$.totalStorage('people');
 37 |  *
 38 |  * @name $.totalStorage
 39 |  * @cat Plugins/Cookie
 40 |  * @author Jared Novack/jared@upstatement.com
 41 |  * @version 1.1
 42 |  * @url http://upstatement.com/blog/2012/01/jquery-local-storage-done-right-and-easy/
 43 |  */
 44 | 
 45 | ;(function($){
 46 | 
 47 | 	/* Variables I'll need throghout */
 48 | 
 49 | 	var ls = window.localStorage;
 50 | 	var supported;
 51 | 	if (typeof ls == 'undefined' || typeof window.JSON == 'undefined'){
 52 | 		supported = false;
 53 | 	} else {
 54 | 		supported = true;
 55 | 	}
 56 | 	// supported = false;
 57 | 	// console.log('supported = ' + supported);
 58 | 	/* Make the methods public */
 59 | 
 60 | 	$.totalStorage = function(key, value, options){
 61 | 		return $.totalStorage.impl.init(key, value);
 62 | 	}
 63 | 
 64 | 	$.totalStorage.setItem = function(key, value){
 65 | 		return $.totalStorage.impl.setItem(key, value);
 66 | 	}
 67 | 
 68 | 	$.totalStorage.getItem = function(key){
 69 | 		return $.totalStorage.impl.getItem(key);
 70 | 	}
 71 | 
 72 | 	$.totalStorage.getAll = function(){
 73 | 		return $.totalStorage.impl.getAll();
 74 | 	}
 75 | 
 76 | 	/* Object to hold all methods: public and private */
 77 | 
 78 | 	$.totalStorage.impl = {
 79 | 
 80 | 		init: function(key, value){
 81 | 			if (typeof value != 'undefined') {
 82 | 				return this.setItem(key, value);
 83 | 			} else {
 84 | 				return this.getItem(key);
 85 | 			}
 86 | 		},
 87 | 
 88 | 		setItem: function(key, value){
 89 | 			if (!supported){
 90 | 				try {
 91 | 					$.cookie(key, value);
 92 | 					return value;
 93 | 				} catch(e){
 94 | 					console.log('Local Storage not supported by this browser. Install the cookie plugin on your site to take advantage of the same functionality');
 95 | 				}
 96 | 			}
 97 | 			var saver = JSON.stringify(value);
 98 | 			ls.setItem(key, saver);
 99 | 			return this.parseResult(saver);
100 | 		},
101 | 
102 | 		getItem: function(key){
103 | 			if (!supported){
104 | 				try {
105 | 					return this.parseResult($.cookie(key));
106 | 				} catch(e){
107 | 					return null;
108 | 				}
109 |  			}
110 | 			return this.parseResult(ls.getItem(key));
111 | 		},
112 | 
113 | 		getAll: function(){
114 | 			var items = new Array();
115 | 			if (!supported){
116 | 				try {
117 | 					var pairs = document.cookie.split(";");
118 | 					for (var i = 0; i<pairs.length; i++){
119 | 						var pair = pairs[i].split('=');
120 | 						var key = pair[0];
121 | 						items.push({key:key, value:this.parseResult($.cookie(key))});
122 | 					}
123 | 				} catch(e){
124 | 					return null;
125 | 				}
126 | 			} else {
127 | 				for (var i in ls){
128 | 					if (i.length){
129 | 						items.push({key:i, value:this.parseResult(ls.getItem(i))});
130 | 					}
131 | 				}
132 | 			}
133 | 			return items;
134 | 		},
135 | 
136 | 		parseResult: function(res){
137 | 			var ret;
138 | 			try {
139 | 				ret = JSON.parse(res);
140 | 				if (ret == 'true'){
141 | 					ret = true;
142 | 				}
143 | 				if (ret == 'false'){
144 | 					ret = false;
145 | 				}
146 | 				if (parseFloat(ret) == ret){
147 | 					ret = parseFloat(ret);
148 | 				}
149 | 			} catch(e){}
150 | 			return ret;
151 | 		}
152 | 	}
153 | 
154 | })(jQuery);
155 | 


--------------------------------------------------------------------------------
/assets/stylesheets/dashboard.css:
--------------------------------------------------------------------------------
  1 | /*
  2 | **  Redmine Dashboard
  3 | */
  4 | 
  5 | /* =========================================================
  6 | ** Dashboard Origin
  7 | */
  8 | 
  9 | /* override */
 10 | body,
 11 | html {
 12 |   height: 100%;
 13 | }
 14 | 
 15 | /* override */
 16 | html > body #content {
 17 |   padding: 0 !important;
 18 |   background-color: #eee;
 19 | }
 20 | 
 21 | #rdb {
 22 |   background-color: #eee;
 23 |   position: relative;
 24 | }
 25 | 
 26 | #rdb.rdb-fullscreen {
 27 |   position: absolute;
 28 |   top: 0;
 29 |   left: 0;
 30 |   right: 0;
 31 |   min-height: 100%;
 32 |   z-index: 9999999995;
 33 | }
 34 | 
 35 | #rdb.rdb-fullscreen #rdb-header {
 36 |   position: fixed;
 37 |   top: 0;
 38 |   left: 0;
 39 |   right: 0;
 40 |   z-index: 9999999999;
 41 | }
 42 | 
 43 | #rdb.rdb-fullscreen {
 44 |   padding-top: 45px;
 45 | }
 46 | 
 47 | #rdb-board {
 48 |   clear: both;
 49 | 
 50 |   margin: 10px 15px;
 51 |   padding: 8px 2px 2px;
 52 | 
 53 |   background-color: #fff;
 54 |   border: 1px solid #ccc;
 55 |   border-radius: 8px;
 56 | }
 57 | 
 58 | #rdb-board-container {
 59 |   /*	padding: 1px;
 60 | 	padding-bottom: 1px;
 61 | */
 62 | }
 63 | 
 64 | #rdb-loading {
 65 |   padding: 40px;
 66 |   text-align: center;
 67 |   min-height: 200px;
 68 | }
 69 | 
 70 | .rdb-clear {
 71 |   clear: both;
 72 | }
 73 | 
 74 | /* =========================================================
 75 | ** Dashboard Header
 76 | */
 77 | 
 78 | #rdb-header {
 79 |   padding: 7px 30px 7px 11px;
 80 |   background-color: #fff;
 81 |   border-bottom: 1px solid #ccc;
 82 | }
 83 | 
 84 | #rdb-header .rdb-board,
 85 | #rdb-header .rdb-filter,
 86 | #rdb-header .rdb-option {
 87 |   float: left;
 88 |   margin: 0 4px;
 89 | }
 90 | 
 91 | #rdb-header .rdb-menu-link {
 92 |   padding: 4px 18px 4px 6px;
 93 |   border-radius: 2px;
 94 | }
 95 | 
 96 | #rdb-header .rdb-filter,
 97 | #rdb-header .rdb-option {
 98 |   margin-top: 8px;
 99 | }
100 | 
101 | #rdb-header .rdb-option {
102 |   float: right;
103 | }
104 | 
105 | #rdb-header .rdb-board .rdb-container {
106 |   margin-top: 4px;
107 | }
108 | 
109 | #rdb-header .rdb-board h1,
110 | #rdb-header .rdb-board h2,
111 | #rdb-header .rdb-board h3,
112 | #rdb-header .rdb-board h4,
113 | #rdb-header .rdb-board h5 {
114 |   margin: 0;
115 |   padding: 0;
116 |   white-space: nowrap;
117 | }
118 | #rdb-header .rdb-board h2 {
119 |   font-size: 20px;
120 | }
121 | 
122 | a#rdb-refresh {
123 |   float: left;
124 |   padding: 4px;
125 |   margin-right: 5px;
126 |   display: block;
127 |   width: 30px;
128 |   height: 17px;
129 |   background-image: url(../../../images/reload.png);
130 |   background-repeat: no-repeat;
131 |   background-position: 50% 40%;
132 |   border-radius: 2px;
133 |   border: 1px solid #fff;
134 | }
135 | a#rdb-refresh:hover {
136 |   background-color: #eee;
137 |   border: 1px solid #ccc;
138 |   box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
139 | }
140 | a#rdb-refresh:active {
141 |   background-color: #eee;
142 |   border: 1px solid #aaa;
143 |   box-shadow: 0 0 4px rgba(0, 0, 0, 0.3) inset;
144 | }
145 | 
146 | a#rdb-reset {
147 |   background-image: url(../../../images/cancel.png);
148 |   background-repeat: no-repeat;
149 |   background-position: 6px 60%;
150 | }
151 | 
152 | /* =========================================================
153 | ** Error message
154 | */
155 | 
156 | #rdb-errors {
157 |   position: fixed;
158 |   bottom: 10%;
159 |   left: 35%;
160 |   right: 35%;
161 | }
162 | #rdb-errors .rdb-error {
163 |   margin: 5px 0;
164 |   padding: 10px 20px;
165 | 
166 |   position: relative;
167 |   overflow: hidden;
168 | 
169 |   color: #b94a48;
170 |   background-color: #f2dede;
171 |   border: 1px solid #c58080;
172 |   text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
173 |   border-radius: 2px;
174 |   box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
175 | }
176 | #rdb-errors .rdb-error a.close {
177 |   position: absolute;
178 |   top: 0;
179 |   right: 8px;
180 | 
181 |   font-size: 25px;
182 |   color: #aaa;
183 | }
184 | #rdb-errors .rdb-error a.close:hover {
185 |   color: #777;
186 |   text-decoration: none;
187 |   cursor: pointer;
188 | }
189 | 
190 | /* =========================================================
191 | ** Legend / Footer
192 | */
193 | 
194 | #rdb-legend {
195 |   float: left;
196 | }
197 | #rdb-legend div {
198 |   padding: 0 0 4px 0;
199 | }
200 | #rdb-legend p {
201 |   float: left;
202 |   min-width: 70px;
203 |   margin: 0;
204 |   padding: 0;
205 |   font-weight: bold;
206 |   /*text-align: right;*/
207 |   padding-right: 10px;
208 | }
209 | #rdb-legend span {
210 |   padding: 0 10px 0 3px;
211 | }
212 | #rdb-legend .rdb-overdue {
213 |   padding: 0;
214 | }
215 | #rdb-legend .rdb-overdue span {
216 |   border: 1px solid red;
217 |   padding: 0;
218 | }
219 | 
220 | #rdb-footer {
221 |   padding: 5px 30px 10px;
222 |   margin: 0;
223 |   font-size: 0.9em;
224 | }
225 | 
226 | #rdb-copyright {
227 |   float: right;
228 |   color: #999;
229 | }
230 | 


--------------------------------------------------------------------------------
/assets/stylesheets/dashboard.issues.css:
--------------------------------------------------------------------------------
  1 | /*
  2 | ** Redmine.rdb-issue - Issues
  3 | */
  4 | 
  5 | .rdb-grid-card {
  6 |   margin: 3px;
  7 | 
  8 |   display: grid;
  9 |   grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
 10 |   gap: 3px;
 11 | }
 12 | 
 13 | .rdb-issue-dragged {
 14 |   z-index: 10;
 15 |   opacity: 0.9;
 16 |   cursor: move;
 17 | }
 18 | 
 19 | /* ========================================================
 20 | ** Issue Priorities
 21 | */
 22 | 
 23 | .rdb-priority {
 24 |   border-left: 5px solid black;
 25 | }
 26 | 
 27 | .rdb-priority-1 {
 28 |   border-color: #aaa;
 29 | }
 30 | .rdb-priority-2 {
 31 |   border-color: #6b6;
 32 | }
 33 | .rdb-priority-3 {
 34 |   border-color: orange;
 35 | }
 36 | .rdb-priority-4 {
 37 |   border-color: red;
 38 | }
 39 | .rdb-priority-5 {
 40 |   border-color: black;
 41 | }
 42 | 
 43 | /* ========================================================
 44 | ** Issue Card View
 45 | */
 46 | 
 47 | .rdb-card {
 48 |   border: 1px solid #ccc;
 49 |   background: #ffffdd;
 50 |   border-radius: 2px;
 51 | 
 52 |   position: relative;
 53 | }
 54 | 
 55 | .rdb-overdue .rdb-card {
 56 |   border-color: red;
 57 | }
 58 | 
 59 | .rdb-card-title {
 60 |   float: left;
 61 | }
 62 | .rdb-card-header-data {
 63 |   padding-top: 2px;
 64 | }
 65 | 
 66 | .rdb-card-title > a {
 67 |   padding-right: 4px;
 68 | }
 69 | .rdb-card-title a.rdb-menu-link,
 70 | .rdb-card-title > a {
 71 |   display: inline-block;
 72 |   padding-top: 2px;
 73 |   padding-bottom: 2px;
 74 |   font-size: 1em;
 75 |   border-right: 1px solid #ddd;
 76 | }
 77 | .rdb-card-title a.rdb-menu-link:hover,
 78 | .rdb-card-title > a:hover {
 79 |   background-color: #eee;
 80 | }
 81 | 
 82 | .rdb-card-header a.rdb-menu-link,
 83 | .rdb-compact-header a.rdb-menu-link,
 84 | .rdb-card-title > a {
 85 |   padding-left: 16px;
 86 |   background-image: url("img/cog.png");
 87 |   background-repeat: no-repeat;
 88 |   background-position: 4px 50%;
 89 | }
 90 | 
 91 | .rdb-card-header .rdb-container,
 92 | .rdb-compact-header .rdb-container {
 93 |   margin-top: 4px;
 94 | }
 95 | 
 96 | .rdb-card-content {
 97 |   padding: 2px 4px 2px 5px;
 98 | }
 99 | 
100 | .rdb-card-subject {
101 |   display: block;
102 |   margin: 0 0 0.25em 0;
103 |   height: 4.6em;
104 | 
105 |   text-overflow: ellipsis;
106 |   overflow: hidden;
107 | }
108 | 
109 | .rdb-card-progress,
110 | .rdb-compact-progress {
111 |   background-color: #ddd;
112 |   margin: 0 0;
113 |   clear: both;
114 | }
115 | 
116 | .rdb-card-progress-bar,
117 | .rdb-compact-progress-bar {
118 |   background-color: green;
119 |   height: 2px;
120 | }
121 | 
122 | /* ========================================================
123 | ** Issue Properties
124 | */
125 | 
126 | .rdb-property {
127 |   display: block;
128 |   padding: 1px 0 0 14px;
129 |   background: transparent none no-repeat 0 70%;
130 |   font-size: 0.95em;
131 | }
132 | .rdb-property.rdb-disabled {
133 |   color: #aaa;
134 | }
135 | 
136 | .rdb-property-tracker {
137 |   background-image: url("img/ticket.png");
138 | }
139 | .rdb-property-assignee {
140 |   background-image: url("img/user.png");
141 | }
142 | .rdb-property-category {
143 |   background-image: url("img/brick.png");
144 | }
145 | .rdb-property-version {
146 |   background-image: url("img/package.png");
147 | }
148 | .rdb-property-time {
149 |   background-image: url("img/time.png");
150 |   font-size: 70%;
151 | }
152 | .rdb-property-time span {
153 |   font-size: 140%;
154 | }
155 | 
156 | /* ========================================================
157 | ** Issue Compact View
158 | */
159 | 
160 | .rdb-compact {
161 |   position: relative;
162 |   margin-bottom: 2px;
163 | 
164 |   border: 1px solid #ccc;
165 |   background: #ffffdd;
166 |   border-radius: 2px;
167 | }
168 | 
169 | .rdb-overdue .rdb-compact {
170 |   border-color: red;
171 | }
172 | 
173 | .rdb-compact-header {
174 |   padding: 0 2px 0 0;
175 |   font-size: 1em;
176 |   height: 1.5em;
177 | }
178 | 
179 | .rdb-compact-header .rdb-compact-title a.rdb-menu-link {
180 |   padding-top: 2px;
181 |   padding-bottom: 2px;
182 |   padding-left: 18px;
183 |   background-position: 4px 50%;
184 |   display: block;
185 |   border-bottom-right-radius: 8px;
186 | }
187 | 
188 | .rdb-card-header .rdb-card-header-data,
189 | .rdb-compact-header .rdb-compact-header-data {
190 |   height: 1.5em;
191 |   font-size: 0.8em;
192 |   overflow: hidden;
193 | }
194 | .rdb-compact-header .rdb-property {
195 |   display: inline;
196 |   color: #888;
197 |   margin: 0 6px 0 0;
198 | }
199 | .rdb-compact-header .rdb-property:last-child {
200 |   margin: 0;
201 | }
202 | .rdb-compact-header .rdb-property.rdb-disabled {
203 |   display: none;
204 | }
205 | 
206 | .rdb-compact-title {
207 |   display: block;
208 |   min-width: 60px;
209 |   float: left;
210 | }
211 | 
212 | .rdb-compact-content {
213 |   padding: 2px 4px 4px 5px;
214 |   font-size: 0.95em;
215 | }
216 | .rdb-compact-subject {
217 |   overflow: hidden;
218 |   text-overflow: ellipsis;
219 | 
220 |   display: -webkit-box;
221 |   -webkit-line-clamp: 1;
222 |   -webkit-box-orient: vertical;
223 | }
224 | .rdb-compact-property {
225 |   color: #999;
226 |   display: inline;
227 |   display: inline-block;
228 |   background-position: 2px 70%;
229 | }
230 | .rdb-compact-progress-bar {
231 |   height: 2px;
232 | }
233 | 
234 | /* ========================================================
235 | ** Issue Menu
236 | */
237 | 
238 | .rdb-issue-menu-progress {
239 |   margin: 0;
240 |   padding: 0;
241 |   width: 100%;
242 |   list-style: none;
243 |   display: table;
244 |   table-layout: fixed;
245 | }
246 | .rdb-issue-menu-progress:last-child {
247 |   padding-bottom: 3px;
248 | }
249 | .rdb-issue-menu-progress li {
250 |   display: table-cell;
251 |   text-align: center;
252 | }
253 | 
254 | .rdb-issue-menu-progress li a {
255 |   display: block;
256 |   padding: 4px 8px;
257 | }
258 | 
259 | .rdb-issue-menu-progress li a:hover {
260 |   background-color: #eee;
261 | }
262 | 


--------------------------------------------------------------------------------
/assets/stylesheets/dashboard.taskboard.css:
--------------------------------------------------------------------------------
  1 | /*
  2 |  *  Redmine Dashboard - Taskboard
  3 |  */
  4 | 
  5 | /* ========================================================
  6 |  * Taskboard Header
  7 |  */
  8 | 
  9 | .rdb-columns,
 10 | .rdb-headers {
 11 |   margin: 0;
 12 |   padding: 0;
 13 |   width: 100%;
 14 | 
 15 |   display: table;
 16 |   table-layout: fixed;
 17 | }
 18 | 
 19 | .rdb-columns .rdb-column,
 20 | .rdb-headers .rdb-column {
 21 |   display: table-cell;
 22 |   vertical-align: top;
 23 | }
 24 | 
 25 | .rdb-headers {
 26 |   margin-bottom: 1px;
 27 | }
 28 | 
 29 | .rdb-headers .rdb-column {
 30 |   border-bottom: 1px solid #aaa;
 31 |   padding: 0 0 4px;
 32 | }
 33 | 
 34 | .rdb-headers .rdb-column h3 {
 35 |   margin: 0;
 36 |   padding: 0 0 0 10px;
 37 |   display: inline;
 38 | }
 39 | 
 40 | .rdb-headers .rdb-column span {
 41 |   font-size: 0.8em;
 42 |   margin-left: 10px;
 43 |   color: #999;
 44 | }
 45 | 
 46 | .rdb-columns {
 47 |   margin: 0;
 48 | }
 49 | .rdb-columns:first-child .rdb-column {
 50 |   padding-top: 8px;
 51 | }
 52 | 
 53 | .rdb-columns .rdb-column {
 54 |   border-left: 2px solid #f5f5f5;
 55 |   padding: 0 3px 25px 1px;
 56 |   transition: all 0.3s ease-in-out;
 57 | }
 58 | 
 59 | .rdb-column-compact {
 60 |   width: 170px;
 61 | }
 62 | 
 63 | .rdb-columns .rdb-column:first-child {
 64 |   border-left: none;
 65 | }
 66 | 
 67 | .rdb-column-head {
 68 |   font-size: 0.7em;
 69 |   color: #999;
 70 |   padding: 3px 10px 0;
 71 | }
 72 | 
 73 | .rdb-column-drop-active {
 74 |   background-color: #e8f7ff;
 75 |   transition: all 0.3s ease-in-out;
 76 | }
 77 | 
 78 | .rdb-column-drop-hover {
 79 |   background-color: #ddfade;
 80 |   transition: all 0.3s ease-in-out;
 81 | }
 82 | 
 83 | /* ========================================================
 84 | ** Groups / Group Headers
 85 | */
 86 | 
 87 | .rdb-group:last-child .rdb-columns .rdb-column {
 88 |   padding-bottom: 70px;
 89 | }
 90 | 
 91 | .rdb-group-header {
 92 |   overflow: hidden;
 93 |   *zoom: 1;
 94 | 
 95 |   border: 1px solid #ccc;
 96 |   border-radius: 2px;
 97 |   margin: 0 -5px;
 98 |   background-color: #f9f9f9;
 99 | }
100 | .rdb-group:first-child .rdb-group-header {
101 |   margin-top: 10px;
102 | }
103 | 
104 | .rdb-group-header h4 {
105 |   display: inline;
106 |   border: none;
107 |   padding: 0;
108 |   margin: 0;
109 | }
110 | 
111 | .rdb-group-header a {
112 |   position: relative;
113 |   padding: 0 12px 0 20px;
114 |   cursor: pointer;
115 |   display: block;
116 | }
117 | .rdb-group-header a:hover {
118 |   text-decoration: none;
119 |   border: none;
120 |   background-color: #eee;
121 | }
122 | 
123 | .rdb-group-header a::before {
124 |   position: absolute;
125 |   top: 45%;
126 |   left: 6px;
127 |   display: inline-block;
128 |   border-right: 4px solid transparent;
129 |   border-left: 4px solid transparent;
130 |   border-top: 4px solid #888;
131 |   border-bottom: 4px solid transparent;
132 |   content: "";
133 | }
134 | .rdb-collapsed .rdb-group-header {
135 |   margin-bottom: 10px;
136 | }
137 | .rdb-collapsed:last-child .rdb-group-header {
138 |   margin-bottom: 40px;
139 | }
140 | .rdb-collapsed .rdb-group-header a::before {
141 |   margin-top: -3px;
142 |   left: 8px;
143 |   border-left-color: #888;
144 |   border-top-color: transparent;
145 | }
146 | .rdb-collapsed .rdb-columns {
147 |   visibility: none;
148 |   display: none;
149 | }
150 | 
151 | .rdb-group-header span {
152 |   margin-left: 5px;
153 |   font-size: 0.8em;
154 |   color: #999;
155 | }
156 | 
157 | /* ========================================================
158 | ** Overall progress
159 | */
160 | 
161 | .rdb-overall-progress {
162 |   height: 8px;
163 |   background-color: #599917;
164 |   overflow: hidden;
165 |   *zoom: 1;
166 | 
167 |   margin-bottom: 2px;
168 | }
169 | 
170 | .rdb-overall-progress a {
171 |   height: 8px;
172 | 
173 |   float: left;
174 |   display: block;
175 |   background-color: #f2da30;
176 | }
177 | 
178 | .rdb-overall-progress a:first-child {
179 |   background-color: #c00;
180 | }
181 | 
182 | /* ========================================================
183 | ** Taskboard Column Dialog
184 | */
185 | 
186 | .rdb-card-dialog {
187 |   width: 100%;
188 |   margin-top: 10px;
189 |   margin-bottom: 8px;
190 |   font-size: 12px;
191 | }
192 | 
193 | .rdb-card-dialog .rdb-card-subject {
194 |   height: auto;
195 |   min-height: 4em;
196 |   max-height: none;
197 |   margin-top: 2px;
198 | }
199 | 
200 | .rdb-card-dialog .rdb-priority {
201 |   height: auto;
202 |   padding-bottom: 1px;
203 | }
204 | 
205 | .rdb-card-dialog-box {
206 |   margin: 4px;
207 |   border: 1px solid #ccc;
208 |   background-color: #fff;
209 |   padding: 10px;
210 | }
211 | 
212 | .rdb-card-dialog-box ul {
213 |   list-style: none;
214 |   margin: 5px 0;
215 |   padding: 0;
216 | }
217 | 
218 | .rdb-card-dialog-box ul li a {
219 |   display: block;
220 |   padding: 5px 10px;
221 |   border-radius: 2px;
222 | }
223 | 
224 | .rdb-card-dialog-box ul li a:hover {
225 |   background-color: #eee;
226 | }
227 | 


--------------------------------------------------------------------------------
/assets/stylesheets/dashboard.ui.css:
--------------------------------------------------------------------------------
  1 | /*
  2 | **  Redmine Dashboard UI
  3 | */
  4 | 
  5 | /* =========================================================
  6 | ** Dashboard Drop-Down-Menus
  7 | */
  8 | 
  9 | /* menu item */
 10 | .rdb-menu {
 11 |   position: relative;
 12 |   display: inline-block;
 13 | }
 14 | 
 15 | .rdb-menu a.rdb-menu-link {
 16 |   padding-right: 18px;
 17 | }
 18 | 
 19 | .rdb-menu h1 a.rdb-menu-link,
 20 | .rdb-menu h2 a.rdb-menu-link,
 21 | .rdb-menu h3 a.rdb-menu-link,
 22 | .rdb-menu h4 a.rdb-menu-link,
 23 | .rdb-menu h5 a.rdb-menu-link {
 24 |   padding-top: 1px;
 25 |   padding-bottom: 1px;
 26 | }
 27 | 
 28 | .rdb-menu a.rdb-menu-link::before {
 29 |   position: absolute;
 30 |   top: 45%;
 31 |   right: 6px;
 32 |   display: inline-block;
 33 |   border-right: 4px solid transparent;
 34 |   border-left: 4px solid transparent;
 35 |   border-top: 4px solid #888;
 36 |   content: "";
 37 | }
 38 | 
 39 | .rdb-menu a.rdb-menu-link:hover,
 40 | .rdb-menu-active a.rdb-menu-link {
 41 |   background-color: #eee;
 42 | }
 43 | 
 44 | /* =========================================================
 45 | ** Dashboard UI Container
 46 | */
 47 | 
 48 | /* menu container */
 49 | .rdb-container {
 50 |   position: absolute;
 51 |   left: -99999px;
 52 | 
 53 |   z-index: 1000;
 54 |   display: none;
 55 |   visibility: hidden;
 56 | 
 57 |   margin: 7px 0 0 0;
 58 |   padding: 0;
 59 | 
 60 |   border: 1px solid #ccc;
 61 |   background-color: #fff;
 62 |   box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
 63 |   border-radius: 2px;
 64 | }
 65 | 
 66 | .rdb-container-wrapper {
 67 |   overflow: auto;
 68 | 
 69 |   min-width: 160px;
 70 |   max-height: 400px;
 71 |   padding: 0 1px;
 72 | }
 73 | .rdb-container-wrapper::-webkit-scrollbar {
 74 |   width: 5px;
 75 |   background-color: #eee;
 76 | }
 77 | .rdb-container-wrapper::-webkit-scrollbar-thumb {
 78 |   background-color: #bbb;
 79 | }
 80 | 
 81 | .rdb-container::before {
 82 |   position: absolute;
 83 |   top: -7px;
 84 |   left: 9px;
 85 |   display: inline-block;
 86 |   border-right: 7px solid transparent;
 87 |   border-bottom: 7px solid #ccc;
 88 |   border-left: 7px solid transparent;
 89 |   border-bottom-color: rgba(0, 0, 0, 0.2);
 90 |   content: "";
 91 | }
 92 | .rdb-container::after {
 93 |   position: absolute;
 94 |   top: -6px;
 95 |   left: 10px;
 96 |   display: inline-block;
 97 |   border-right: 6px solid transparent;
 98 |   border-bottom: 6px solid white;
 99 |   border-left: 6px solid transparent;
100 |   content: "";
101 | }
102 | 
103 | .rdb-container-right::before {
104 |   left: auto;
105 |   right: 6px;
106 | }
107 | .rdb-container-right::after {
108 |   left: auto;
109 |   right: 7px;
110 | }
111 | 
112 | .rdb-container-inlet {
113 |   padding: 4px 8px;
114 | }
115 | 
116 | .rdb-menu-active .rdb-container,
117 | .rdb-container.rdb-visible {
118 |   display: block;
119 |   visibility: visible;
120 |   left: -3px;
121 | }
122 | 
123 | .rdb-menu-active .rdb-container-right,
124 | .rdb-container-right.rdb-visible {
125 |   display: block;
126 |   visibility: visible;
127 |   left: auto;
128 |   right: -4px;
129 | }
130 | 
131 | .rdb-container h3 {
132 |   margin: 0;
133 |   padding: 1px 6px 1px;
134 |   font-size: 0.9em;
135 |   font-weight: normal;
136 | }
137 | 
138 | .rdb-container h3 ~ ul {
139 |   padding-top: 0;
140 | }
141 | 
142 | /* =========================================================
143 | ** Dashboard Container List
144 | */
145 | 
146 | .rdb-container .rdb-list {
147 |   border-bottom: 1px solid #ccc;
148 | }
149 | .rdb-container .rdb-list:last-child {
150 |   border-bottom: none;
151 | }
152 | 
153 | .rdb-small .rdb-list {
154 |   font-size: 0.9em;
155 | }
156 | 
157 | .rdb-list > ul {
158 |   list-style: none;
159 |   padding: 4px 0 2px;
160 |   margin: 0;
161 | }
162 | 
163 | .rdb-small .rdb-list > ul {
164 |   padding-top: 2px;
165 |   padding-bottom: 2px;
166 | }
167 | 
168 | .rdb-list > ul > li > a,
169 | .rdb-list .rdb-multicheck a {
170 |   display: block;
171 |   padding: 6px 10px 6px 10px;
172 |   margin: 0 0 1px 0;
173 | }
174 | 
175 | .rdb-small .rdb-list > ul > li > a,
176 | .rdb-small .rdb-multicheck a {
177 |   padding-top: 4px;
178 |   padding-bottom: 4px;
179 | }
180 | 
181 | .rdb-icons .rdb-list > ul > li > a {
182 |   padding-left: 28px;
183 | }
184 | 
185 | .rdb-list > ul > li > a:hover,
186 | .rdb-list .rdb-multicheck a:hover,
187 | .rdb-list .rdb-multicheck a.rdb-checkbox-link:hover ~ a {
188 |   background-color: #eee;
189 | }
190 | .rdb-list .rdb-multicheck {
191 |   display: table;
192 |   width: 100%;
193 | }
194 | .rdb-list .rdb-multicheck a {
195 |   padding-left: 5px;
196 |   padding-right: 5px;
197 |   display: table-cell;
198 | }
199 | 
200 | .rdb-list .rdb-multicheck a.rdb-checkbox-link {
201 |   padding-right: 0;
202 |   padding-left: 24px;
203 |   margin-right: 4px;
204 |   /*float: left;*/
205 |   width: 1px;
206 |   height: 1em;
207 |   background-position: 4px 50%;
208 | }
209 | 
210 | /* =========================================================
211 | ** Dashboard Checkbox Links
212 | */
213 | 
214 | .rdb-checkbox-link {
215 |   padding-left: 20px;
216 |   background-image: none;
217 |   background-repeat: no-repeat;
218 |   background-position: 2px 50%;
219 | }
220 | 
221 | .rdb-checkbox-link.rdb-checkbox-link-enabled {
222 |   background-image: url(../../../images/true.png);
223 | }
224 | 
225 | .rdb-checkbox-link.rdb-checkbox-link-disabled {
226 |   background-image: url(img/disabled_true.png);
227 | }
228 | 
229 | .rdb-list > ul > li > a.rdb-checkbox-link {
230 |   padding-left: 28px;
231 |   background-position: 6px 50%;
232 | }
233 | 


--------------------------------------------------------------------------------
/assets/stylesheets/img/brick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/assets/stylesheets/img/brick.png


--------------------------------------------------------------------------------
/assets/stylesheets/img/cog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/assets/stylesheets/img/cog.png


--------------------------------------------------------------------------------
/assets/stylesheets/img/disabled_true.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/assets/stylesheets/img/disabled_true.png


--------------------------------------------------------------------------------
/assets/stylesheets/img/menu.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/assets/stylesheets/img/menu.gif


--------------------------------------------------------------------------------
/assets/stylesheets/img/package.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/assets/stylesheets/img/package.png


--------------------------------------------------------------------------------
/assets/stylesheets/img/ticket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/assets/stylesheets/img/ticket.png


--------------------------------------------------------------------------------
/assets/stylesheets/img/time.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/assets/stylesheets/img/time.png


--------------------------------------------------------------------------------
/assets/stylesheets/img/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jgraichen/redmine_dashboard/5717094cf13a41288c50f2b81c2cf925174ece12/assets/stylesheets/img/user.png


--------------------------------------------------------------------------------
/config/default.yml:
--------------------------------------------------------------------------------
 1 | # Configure default settings for dashboards here. They
 2 | # apply to every dashboard on all projects.
 3 | #
 4 | # Remember to restart redmine to apply changed settings.
 5 | # Also logout and login again as dashboard options are
 6 | # also stored in the user session (cookie).
 7 | 
 8 | # Default view mode.
 9 | # Allowed values are: `card` or `compact`.
10 | view: card
11 | 
12 | # Should subproject be included by default.
13 | # Allowed values are: `false` or `true`.
14 | include_subprojects: false
15 | 
16 | # Default setting for assignee filter.
17 | # Allowed values are: `me` or `all`.
18 | assignee: me
19 | 
20 | # Default setting for version filter.
21 | # Allowed values are: `latest` or `all`.
22 | version: latest
23 | 
24 | # Should done issues be hidden by default
25 | # Allowed values are: `false` or `true`.
26 | hide_done: false
27 | 
28 | # Should "Change assignee" option be enabled by default
29 | # Allowed values are: `false` or `true`
30 | change_assignee: false
31 | 


--------------------------------------------------------------------------------
/config/locales/bg.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | bg:
 3 |   project_module_dashboard: Табло
 4 |   permission_view_dashboards: Преглед на таблата
 5 |   permission_configure_dashboards: Конфигурация на таблата
 6 |   menu_label_dashboard: Табло
 7 |   rdb_filter_version_all: Всички версии
 8 |   rdb_filter_assignee_none: Неназначен
 9 |   rdb_filter_assignee_others: Други
10 |   rdb_options: Настройки
11 |   rdb_options_hide_done: Скрий завършените задачи
12 |   rdb_options_reset: Премахни филтър
13 |   rdb_options_configure: Настройки
14 |   rdb_options_group: Групиране на задачи
15 |   rdb_group_category: Категория
16 |   rdb_group_assignee: Назначен на
17 |   rdb_group_tracker: Тракер
18 |   rdb_group_priority: Приоритет
19 |   rdb_group_version: Версия
20 |   rdb_group_parent: Родителска задача
21 |   rdb_group_project: Проект
22 |   rdb_options_fullscreen: Цял екран
23 |   rdb_legend_priorities: Приоритети
24 |   rdb_column_done: Готово
25 |   rdb_others: Други
26 |   rdb_all_issues: Всички задачи
27 |   rdb_no_parent: Без родителски задачи
28 |   rdb_issue_menu_redmine_issue: Redmine задача
29 |   rdb_issue_menu_edit: Редакция
30 |   rdb_flash_invalid_request: "<p>Невалидна заявка.</p>"
31 | 


--------------------------------------------------------------------------------
/config/locales/ca.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | ca:
 3 |   project_module_dashboard: Taulers
 4 |   permission_view_dashboards: Mostra els taulers
 5 |   permission_configure_dashboards: Configura els taulers
 6 |   menu_label_dashboard: Tauler
 7 |   rdb_taskboard: Assumptes
 8 |   rdb_planningboard: 'Planificació '
 9 |   rdb_filter_version_all: Totes les versions
10 |   rdb_filter_version_unassigned: Sense assignar
11 |   rdb_filter_tracker_all: Tots els rastrejadors
12 |   rdb_filter_tracker_multiple: Diversos rastrejadors
13 |   rdb_filter_category_all: Totes les categories
14 |   rdb_filter_category_multiple: Diverses categories
15 |   rdb_filter_assignee_all: Tots els assignats
16 |   rdb_filter_assignee_me: Els meus assumptes
17 |   rdb_filter_assignee_none: Sense assignar
18 |   rdb_filter_assignee_others: Altres
19 |   rdb_options: Opcions
20 |   rdb_options_change_assignee: 'Canvia l''assignació '
21 |   rdb_options_change_assignee_info: Canvia l'assignació a l'usuari actual quan l'assumpte es mou
22 |   rdb_options_hide_done: Amaga els assumptes tancats
23 |   rdb_options_hide_done_info: Amaga assumptes tancats i redueix la columna "fet"
24 |   rdb_options_reset: Restableix filtre
25 |   rdb_options_reset_info: Restableix tots els filtres
26 |   rdb_options_configure: Configura
27 |   rdb_options_include_subprojects: Inclou subprojects
28 |   rdb_options_view: Veure
29 |   rdb_options_issue_view: Vista d'assumpte
30 |   rdb_options_issue_view_card: Targeta
31 |   rdb_options_issue_view_compact: Compacte
32 |   rdb_options_group: Agrupació d'assumptes
33 |   rdb_group_none: Sense agrupar
34 |   rdb_group_category: Categoria
35 |   rdb_group_assignee: Assignat
36 |   rdb_group_tracker: Rastrejador
37 |   rdb_group_priority: Prioritat
38 |   rdb_group_version: 'Versió '
39 |   rdb_group_parent: Assumpte pare
40 |   rdb_group_project: Projecte
41 |   rdb_options_board_view: Vista del tauler
42 |   rdb_options_board_view_compact: 'Clàssic '
43 |   rdb_options_board_view_outline: Esquema
44 |   rdb_options_columns: Columnes del tauler
45 |   rdb_options_fullscreen: Pantalla sencera
46 |   rdb_legend_priorities: Prioritats
47 |   rdb_legend_warnings: Avisos
48 |   rdb_issue_overdue: Endarrerit
49 |   rdb_property_time: <span title="Spend time">%{actual}</span> / <span title="Estimated time">%{estimated}</span>
50 |   rdb_not_available: N/D
51 |   rdb_column_done: Fet
52 |   rdb_x_issues:
53 |     one: 1 Assumpte
54 |     other: "%{count} Assumptes"
55 |   rdb_dialog_update_issue_title: Actualitza l'assumpte
56 |   rdb_dialog_update_issue_status: 'Escull un nou estat per l''assumpte '
57 |   rdb_other_issues: Altres assumptes <span>(%{count})</span>
58 |   rdb_unassigned: Sense assignar
59 |   rdb_others: Altres
60 |   rdb_all_issues: Tots els assumptes
61 |   rdb_no_parent: Sense assumpte pare
62 |   rdb_issue_menu_progress_title: 'Posa al dia l''actualització '
63 |   rdb_issue_menu_progress: "%{count}%"
64 |   rdb_issue_menu_redmine_issue: Assumpte de Redmine
65 |   rdb_issue_menu_show: Veure
66 |   rdb_issue_menu_edit: Edita
67 |   rdb_issue_menu_assign_me: Assigna-m'ho
68 |   rdb_issue_menu_unassign_me: Desassigna-m'ho
69 |   rdb_flash_illegal_workflow_action: "<p>No tens permís per realitzar l'acció següent:</p><p>Moure<b>%{issue}</b> des de <b>%{source}</b> a <b>%{target}</b>.</p>"
70 |   rdb_flash_missing_lock_version: "<p><b>No s'ha trobat el bloqueig de la versió </b>:No es pot actualitzar l'assumpte sense el bloqueig de la versió. Torna-ho a provar"
71 |   rdb_flash_stale_object: "<p>S'ha intentat actualitzar un assumpte antic: <b>%{issue}</b>. Comprova el canvis i torna-ho a intentar."
72 |   rdb_flash_invalid_request: "<p> Sol·licitud no vàlida.</p>"
73 | 


--------------------------------------------------------------------------------
/config/locales/cs.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | cs:
 3 |   project_module_dashboard: Nástěnka
 4 |   permission_view_dashboards: Zobrazit nástěnky
 5 |   permission_configure_dashboards: Nastavit nástěnky
 6 |   menu_label_dashboard: Nástěnka
 7 |   rdb_taskboard: Nástěnka úkolů
 8 |   rdb_planningboard: Plánovací nástěnka
 9 |   rdb_filter_version_all: Všechny verze
10 |   rdb_filter_version_unassigned: Nepřiřazené
11 |   rdb_filter_tracker_all: Všechny fronty
12 |   rdb_filter_tracker_multiple: Více front
13 |   rdb_filter_category_all: Všechny kategorie
14 |   rdb_filter_category_multiple: Více kategorií
15 |   rdb_filter_assignee_all: Přiřazené všem
16 |   rdb_filter_assignee_me: Mé úkoly
17 |   rdb_filter_assignee_none: Nepřiřazené
18 |   rdb_filter_assignee_others: Ostatní
19 |   rdb_options: Možnosti
20 |   rdb_options_change_assignee: Změnit přiřazeného uživatele
21 |   rdb_options_change_assignee_info: Při přesunu úkolu jej přiřadit aktuálně přihlášenému uživateli.
22 |   rdb_options_hide_done: Skrýt uzavřené úkoly
23 |   rdb_options_hide_done_info: Skrýt uzavřené úkoly a zmenšit sloupec hotových úkolů.
24 |   rdb_options_reset: Zrušit filtry
25 |   rdb_options_reset_info: Obnoví všechny filtry do výchozího nastavení.
26 |   rdb_options_configure: Konfigurovat
27 |   rdb_options_include_subprojects: Zahrnout podprojekty
28 |   rdb_options_view: Zobrazení
29 |   rdb_options_issue_view: Zobrazení úkolů
30 |   rdb_options_issue_view_card: Karty
31 |   rdb_options_issue_view_compact: Kompaktní
32 |   rdb_options_group: Seskupit úkoly podle
33 |   rdb_group_none: Neseskupovat
34 |   rdb_group_category: Kategorie
35 |   rdb_group_assignee: Přiřazeno
36 |   rdb_group_tracker: Fronty
37 |   rdb_group_priority: Priority
38 |   rdb_group_version: Verze
39 |   rdb_group_parent: Rodičovského úkolu
40 |   rdb_group_project: Projektu
41 |   rdb_options_board_view: Zobrazení nástěnky
42 |   rdb_options_board_view_compact: Klasické
43 |   rdb_options_board_view_outline: Hrubý přehled
44 |   rdb_options_columns: Sloupce nástěnky
45 |   rdb_options_fullscreen: Celá obrazovka
46 |   rdb_legend_priorities: Priority
47 |   rdb_legend_warnings: Varování
48 |   rdb_issue_overdue: Zpožděné
49 |   rdb_property_time: <span title="Strávený čas">%{actual}</span> / <span title="Odhadovaný čas">%{estimated}</span>
50 |   rdb_not_available: Nedostupné
51 |   rdb_column_done: Hotové
52 |   rdb_x_issues:
53 |     one: 1 úkol
54 |     few: "%{count} úkoly"
55 |     many: "%{count} úkolů"
56 |     other: "%{count} úkolů"
57 |   rdb_dialog_update_issue_title: Upravit úkol
58 |   rdb_dialog_update_issue_status: Zvolte nový stav úkolu
59 |   rdb_other_issues: Ostatní úkoly <span>(%{count})</span>
60 |   rdb_unassigned: Nepřiřazeno
61 |   rdb_others: Ostatní
62 |   rdb_all_issues: Všechny úkoly
63 |   rdb_no_parent: Bez nadřazeného úkolu
64 |   rdb_issue_menu_progress_title: Aktualizovat % hotovo
65 |   rdb_issue_menu_progress: "%{count}%"
66 |   rdb_issue_menu_redmine_issue: Úkol
67 |   rdb_issue_menu_show: Zobrazit
68 |   rdb_issue_menu_edit: Upravit
69 |   rdb_issue_menu_assign_me: Přiřadit mně
70 |   rdb_issue_menu_unassign_me: Zrušit přiřazení mně
71 |   rdb_flash_illegal_workflow_action: "<p>Nemáte oprávnění provést následující akci v průběhu prací:</p><p>Přesunout <b>%{issue}</b> z <b>%{source}</b> na <b>%{target}</b>.</p>"
72 |   rdb_flash_missing_lock_version: "<p><b>Chybějící uzamčená verze</b>: Nelze aktualizovat úkol bez uzamčené verze. Opakujte akci."
73 |   rdb_flash_stale_object: "<p>Pokus o odeslání starých změn úkolu <b>%{issue}</b>. Úkol byl nejspíše upraven jiným uživatelem. Zkontrolujte změny a opakujte akci."
74 |   rdb_flash_invalid_request: "<p>Neplatný požadavek.</p>"
75 | 


--------------------------------------------------------------------------------
/config/locales/de.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | de:
 3 |   project_module_dashboard: Dashboard
 4 |   permission_view_dashboards: Dashboards anschauen
 5 |   permission_configure_dashboards: Dashboards konfigurieren
 6 |   menu_label_dashboard: Dashboard
 7 |   rdb_taskboard: Task Board
 8 |   rdb_planningboard: Planning Board
 9 |   rdb_filter_version_all: Alle Versionen
10 |   rdb_filter_version_unassigned: Keine Version
11 |   rdb_filter_tracker_all: Alle Trackers
12 |   rdb_filter_tracker_multiple: Mehrere Trackers
13 |   rdb_filter_category_all: Alle Kategorien
14 |   rdb_filter_category_multiple: Mehrere Kategorien
15 |   rdb_filter_assignee_all: Alle Tickets
16 |   rdb_filter_assignee_me: Meine Tickets
17 |   rdb_filter_assignee_none: Nicht zugewiesen
18 |   rdb_filter_assignee_others: Andere
19 |   rdb_options: Optionen
20 |   rdb_options_change_assignee: Ändere Verantwortlichen
21 |   rdb_options_change_assignee_info: Ändere Verantwortlichen auf aktuellen Benutzer wenn ein Ticket verschoben wird.
22 |   rdb_options_hide_done: Verberge fertige Tickets
23 |   rdb_options_hide_done_info: Verbirgt fertige Tickets und verkleinert Fertig-Spalte.
24 |   rdb_options_reset: Filter zurücksetzen
25 |   rdb_options_reset_info: Setzt alle Filter auf Standardeinstellungen zurück.
26 |   rdb_options_configure: Konfigurieren
27 |   rdb_options_include_subprojects: Unterprojekte einbeziehen
28 |   rdb_options_view: Ansicht
29 |   rdb_options_issue_view: Ticket-Ansicht
30 |   rdb_options_issue_view_card: Karte
31 |   rdb_options_issue_view_compact: Kompakt
32 |   rdb_options_group: Gruppierung
33 |   rdb_group_none: Keine Gruppierung
34 |   rdb_group_category: Kategorie
35 |   rdb_group_assignee: Verantwortlicher
36 |   rdb_group_tracker: Tracker
37 |   rdb_group_priority: Priorität
38 |   rdb_group_version: Version
39 |   rdb_group_parent: Übergeordnete Aufgabe
40 |   rdb_group_project: Projekt
41 |   rdb_options_board_view: Board Ansicht
42 |   rdb_options_board_view_compact: Klassisch (Kompakt)
43 |   rdb_options_board_view_outline: Outline
44 |   rdb_options_columns: Spalten
45 |   rdb_options_fullscreen: Vollbildschirm
46 |   rdb_legend_priorities: Prioritäten
47 |   rdb_legend_warnings: Warnungen
48 |   rdb_issue_overdue: Überfällig
49 |   rdb_property_time: <span title="Verbrauchte Zeit">%{actual}</span> / <span title="Geschätzte Zeit">%{estimated}</span>
50 |   rdb_not_available: N/A
51 |   rdb_column_done: Fertig
52 |   rdb_x_issues:
53 |     one: 1 Ticket
54 |     other: "%{count} Tickets"
55 |   rdb_dialog_update_issue_title: Ticket aktualisieren
56 |   rdb_dialog_update_issue_status: Wähle neuen Ticket-Status
57 |   rdb_other_issues: Andere Tickets <span>(%{count})</span>
58 |   rdb_unassigned: Nicht zugewiesen
59 |   rdb_others: Andere
60 |   rdb_all_issues: Alle Tickets
61 |   rdb_no_parent: Keine übergeordneten Aufgaben
62 |   rdb_issue_menu_progress_title: Fortschritt ändern
63 |   rdb_issue_menu_progress: "%{count}%"
64 |   rdb_issue_menu_redmine_issue: Redmine Ticket
65 |   rdb_issue_menu_show: Anzeigen
66 |   rdb_issue_menu_edit: Bearbeiten
67 |   rdb_issue_menu_assign_me: Mich zuweisen
68 |   rdb_issue_menu_unassign_me: Zuweisung entfernen
69 |   rdb_flash_illegal_workflow_action: "<p>Diese Änderung verstößt gegen den festgelegten Arbeitsfluss:</p><p><b>%{issue}</b> von <b>%{source}</b> nach <b>%{target}</b> ändern.</p>"
70 |   rdb_flash_missing_lock_version: "<p><b>Lock-Version fehlt</b>: Ticket kann nicht aktualisiert werden. Bitte nochmal probieren."
71 |   rdb_flash_stale_object: "<p>Ticket wurde verändert: <b>%{issue}</b>. Überprüfe die Änderungen und probiere es erneut."
72 |   rdb_flash_invalid_request: "<p>Ungültige Anfrage.</p>"
73 | 


--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | en:
 3 |   project_module_dashboard: Dashboard
 4 |   permission_view_dashboards: View Dashboards
 5 |   permission_configure_dashboards: Configure Dashboards
 6 |   menu_label_dashboard: Dashboard
 7 |   rdb_taskboard: Task Board
 8 |   rdb_planningboard: Planning Board
 9 |   rdb_filter_version_all: All Versions
10 |   rdb_filter_version_unassigned: Unassigned
11 |   rdb_filter_tracker_all: All Trackers
12 |   rdb_filter_tracker_multiple: Multiple Trackers
13 |   rdb_filter_category_all: All Categories
14 |   rdb_filter_category_multiple: Multiple Categories
15 |   rdb_filter_assignee_all: All Assignees
16 |   rdb_filter_assignee_me: My Issues
17 |   rdb_filter_assignee_none: Unassigned
18 |   rdb_filter_assignee_others: Others
19 |   rdb_options: Options
20 |   rdb_options_change_assignee: Change assignee
21 |   rdb_options_change_assignee_info: Change assignee to current user when issue is moved.
22 |   rdb_options_hide_done: Hide closed issues
23 |   rdb_options_hide_done_info: Hide closed issues and makes done column smaller.
24 |   rdb_options_reset: Reset filter
25 |   rdb_options_reset_info: Reset all filters back to default
26 |   rdb_options_configure: Configure
27 |   rdb_options_include_subprojects: Include subprojects
28 |   rdb_options_view: View
29 |   rdb_options_issue_view: Issue View
30 |   rdb_options_issue_view_card: Card
31 |   rdb_options_issue_view_compact: Compact
32 |   rdb_options_group: Issue Grouping
33 |   rdb_group_none: No Grouping
34 |   rdb_group_category: Category
35 |   rdb_group_assignee: Assignee
36 |   rdb_group_tracker: Tracker
37 |   rdb_group_priority: Priority
38 |   rdb_group_version: Version
39 |   rdb_group_parent: Parent Task
40 |   rdb_group_project: Project
41 |   rdb_options_board_view: Board View
42 |   rdb_options_board_view_compact: Classic
43 |   rdb_options_board_view_outline: Outline
44 |   rdb_options_columns: Board Columns
45 |   rdb_options_fullscreen: Full Screen
46 |   rdb_legend_priorities: Priorities
47 |   rdb_legend_warnings: Warnings
48 |   rdb_issue_overdue: Overdue
49 |   rdb_property_time: <span title="Spend time">%{actual}</span> / <span title="Estimated time">%{estimated}</span>
50 |   rdb_not_available: N/A
51 |   rdb_column_done: Done
52 |   rdb_x_issues:
53 |     one: 1 Issue
54 |     other: "%{count} Issues"
55 |   rdb_dialog_update_issue_title: Update Issue
56 |   rdb_dialog_update_issue_status: Choose new issue status
57 |   rdb_other_issues: Other Issues <span>(%{count})</span>
58 |   rdb_unassigned: Unassigned
59 |   rdb_others: Others
60 |   rdb_all_issues: All Issues
61 |   rdb_no_parent: No parent tasks
62 |   rdb_issue_menu_progress_title: Update progress
63 |   rdb_issue_menu_progress: "%{count}%"
64 |   rdb_issue_menu_redmine_issue: Redmine Issue
65 |   rdb_issue_menu_show: Show
66 |   rdb_issue_menu_edit: Edit
67 |   rdb_issue_menu_assign_me: Assign me
68 |   rdb_issue_menu_unassign_me: Unassign me
69 |   rdb_flash_illegal_workflow_action: "<p>You are not allowed to perform this workflow action:</p><p>Move <b>%{issue}</b> from <b>%{source}</b> to <b>%{target}</b>.</p>"
70 |   rdb_flash_missing_lock_version: "<p><b>Missing lock version</b>: Cannot update issue without lock version. Try again."
71 |   rdb_flash_stale_object: "<p>Attempted to update a stale issue: <b>%{issue}</b>. Check changes and try again."
72 |   rdb_flash_invalid_request: "<p>Invalid request.</p>"
73 | 


--------------------------------------------------------------------------------
/config/locales/es.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | es:
 3 |   project_module_dashboard: Tablero
 4 |   permission_view_dashboards: Ver tableros
 5 |   permission_configure_dashboards: Configurar tableros
 6 |   menu_label_dashboard: Tablero
 7 |   rdb_taskboard: Tareas
 8 |   rdb_planningboard: Planificación
 9 |   rdb_filter_version_all: Todas las versiones
10 |   rdb_filter_version_unassigned: Sin asignar
11 |   rdb_filter_tracker_all: Todos los rastreadores
12 |   rdb_filter_tracker_multiple: Varios rastreadores
13 |   rdb_filter_category_all: Todas las categorías
14 |   rdb_filter_category_multiple: Múltiples categorías
15 |   rdb_filter_assignee_all: Todas las asignadas
16 |   rdb_filter_assignee_me: Mis tareas
17 |   rdb_filter_assignee_none: Sin asignar
18 |   rdb_filter_assignee_others: Otros
19 |   rdb_options: Opciones
20 |   rdb_options_change_assignee: Cambiar asignación
21 |   rdb_options_change_assignee_info: Cambiar asignación al usuario actual cuando la tarea se mueva
22 |   rdb_options_hide_done: Ocultar tareas cerradas
23 |   rdb_options_hide_done_info: Oculta tareas cerradas y disminuye la columna "hecho"
24 |   rdb_options_reset: Restablecer filtro
25 |   rdb_options_reset_info: Restablecer todos los filtros
26 |   rdb_options_configure: Configurar
27 |   rdb_options_include_subprojects: Incluir proyectos hijo
28 |   rdb_options_view: Ver
29 |   rdb_options_issue_view: Vista de tarea
30 |   rdb_options_issue_view_card: Tarjeta
31 |   rdb_options_issue_view_compact: Compacta
32 |   rdb_options_group: Agrupación de tareas
33 |   rdb_group_none: Sin agrupar
34 |   rdb_group_category: Categoría
35 |   rdb_group_assignee: Asignación
36 |   rdb_group_tracker: Rastreador
37 |   rdb_group_priority: Prioridad
38 |   rdb_group_version: Versión
39 |   rdb_group_parent: Tarea padre
40 |   rdb_group_project: Proyecto
41 |   rdb_options_board_view: Vista de tablero
42 |   rdb_options_board_view_compact: Clásico
43 |   rdb_options_board_view_outline: Esquema
44 |   rdb_options_columns: Columnas de tablero
45 |   rdb_options_fullscreen: Pantalla completa
46 |   rdb_legend_priorities: Prioridades
47 |   rdb_legend_warnings: Advertencias
48 |   rdb_issue_overdue: Atrasado
49 |   rdb_property_time: <span title="Spend time">%{actual}</span> / <span title="Estimated time">%{estimated}</span>
50 |   rdb_not_available: N/D
51 |   rdb_column_done: Hecho
52 |   rdb_x_issues:
53 |     one: 1 Tarea
54 |     many: "%{count} Tareas"
55 |     other: "%{count} Tareas"
56 |   rdb_dialog_update_issue_title: Actualizar tarea
57 |   rdb_dialog_update_issue_status: Escoger nuevo estado de la tarea
58 |   rdb_other_issues: Otras tareas <span>(%{count})</span>
59 |   rdb_unassigned: Sin asignar
60 |   rdb_others: Otros
61 |   rdb_all_issues: Todas las tareas
62 |   rdb_no_parent: Sin tareas padre
63 |   rdb_issue_menu_progress_title: Progreso de actualización
64 |   rdb_issue_menu_progress: "%{count}%"
65 |   rdb_issue_menu_redmine_issue: Tarea de Redmine
66 |   rdb_issue_menu_show: Ver
67 |   rdb_issue_menu_edit: Editar
68 |   rdb_issue_menu_assign_me: Asignar a mi
69 |   rdb_issue_menu_unassign_me: Desasignar
70 |   rdb_flash_illegal_workflow_action: "<p>No tienes permiso para realizar la siguiente acción:</p><p>Mover <b>%{issue}</b> de <b>%{source}</b> a <b>%{target}</b>.</p>"
71 |   rdb_flash_missing_lock_version: "<p><b>Bloqueo de la versión no encontrado</b>: No puedes actualizar la tarea sin bloquear la versión. Inténtalo de nuevo"
72 |   rdb_flash_stale_object: "<p>Se ha intentado actualizar un tarea antigua: <b>%{issue}</b>. Comprueba los cambios e inténtalo de nuevo."
73 |   rdb_flash_invalid_request: "<p>Solicitud no válida.</p>"
74 | 


--------------------------------------------------------------------------------
/config/locales/fr.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | fr:
 3 |   project_module_dashboard: Tableau de bord
 4 |   permission_view_dashboards: Voir les tableaux de bord
 5 |   permission_configure_dashboards: Configurer les tableaux de bord
 6 |   menu_label_dashboard: Tableau de bord
 7 |   rdb_taskboard: Tableau des tâches
 8 |   rdb_planningboard: Tableau du planning
 9 |   rdb_filter_version_all: Toutes les versions
10 |   rdb_filter_version_unassigned: Non assigné
11 |   rdb_filter_tracker_all: Tous les trackers
12 |   rdb_filter_tracker_multiple: Trackers multiples
13 |   rdb_filter_category_all: Toutes les catégories
14 |   rdb_filter_category_multiple: Catégories multiples
15 |   rdb_filter_assignee_all: Tous les membres assignés
16 |   rdb_filter_assignee_me: Mes demandes
17 |   rdb_filter_assignee_none: Non assigné
18 |   rdb_filter_assignee_others: Autres
19 |   rdb_options: Options
20 |   rdb_options_change_assignee: Changer l'assignation
21 |   rdb_options_change_assignee_info: Assigner à l'utilisateur courant lorsque la demande est déplacée.
22 |   rdb_options_hide_done: Masquer les demandes fermées
23 |   rdb_options_hide_done_info: Masquer les demandes fermées et réduire la colonne Terminé
24 |   rdb_options_reset: Réinitialiser le filtre
25 |   rdb_options_reset_info: Réinitialiser tous les filtres
26 |   rdb_options_configure: Configurer
27 |   rdb_options_include_subprojects: Inclure les sous-projets
28 |   rdb_options_view: Affichage
29 |   rdb_options_issue_view: Affichage des demandes
30 |   rdb_options_issue_view_card: Carte
31 |   rdb_options_issue_view_compact: Compact
32 |   rdb_options_group: Regrouper par demande
33 |   rdb_group_none: Pas de regroupement
34 |   rdb_group_category: Catégorie
35 |   rdb_group_assignee: 'Assigné à '
36 |   rdb_group_tracker: Tracker
37 |   rdb_group_priority: Priorité
38 |   rdb_group_version: Version
39 |   rdb_group_parent: Tâche parente
40 |   rdb_group_project: Projet
41 |   rdb_options_board_view: Affichage du tableau
42 |   rdb_options_board_view_compact: Classique
43 |   rdb_options_board_view_outline: Contour
44 |   rdb_options_columns: Colonnes du tableau
45 |   rdb_options_fullscreen: Plein écran
46 |   rdb_legend_priorities: Priorités
47 |   rdb_legend_warnings: Avertissements
48 |   rdb_issue_overdue: En retard
49 |   rdb_property_time: <span title="Temps passé">%{actual}</span> / <span title="Temps estimé">%{estimated}</span>
50 |   rdb_not_available: N/A
51 |   rdb_column_done: Terminé
52 |   rdb_x_issues:
53 |     one: 1 demande
54 |     many: "%{count} demandes"
55 |     other: "%{count} demandes"
56 |   rdb_dialog_update_issue_title: Mettre à jour la demande
57 |   rdb_dialog_update_issue_status: Choisir le statut des nouvelles demandes
58 |   rdb_other_issues: Autres demandes <span>(%{count})</span>
59 |   rdb_unassigned: Non assignée
60 |   rdb_others: Autres
61 |   rdb_all_issues: Toutes les demandes
62 |   rdb_no_parent: Pas de tâche parente
63 |   rdb_issue_menu_progress_title: Mettre à jour la progression
64 |   rdb_issue_menu_progress: "%{count}%"
65 |   rdb_issue_menu_redmine_issue: Demande Redmine
66 |   rdb_issue_menu_show: Voir
67 |   rdb_issue_menu_edit: Editer
68 |   rdb_issue_menu_assign_me: Assigner à moi
69 |   rdb_issue_menu_unassign_me: Ne plus assigner à moi
70 |   rdb_flash_illegal_workflow_action: "<p>Vous n'êtes pas autorisé à effectuer cette action du workflow :</p><p>Déplacer <b>%{issue}</b> de <b>%{source}</b> à <b>%{target}</b>.</p>"
71 |   rdb_flash_missing_lock_version: "<p><b>Version de verrou manquante</b> : impossible de mettre à jour la demande sans version de verrou. Veuillez réessayer."
72 |   rdb_flash_stale_object: "<p>Tentative de mise à jour d'une demande dépassée : <b>%{issue}</b>. Vérifiez les changements puis réessayez."
73 |   rdb_flash_invalid_request: "<p>Requête non valide.</p>"
74 | 


--------------------------------------------------------------------------------
/config/locales/it.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | it:
 3 |   project_module_dashboard: Dashboard
 4 |   permission_view_dashboards: Visualizza Dashboards
 5 |   permission_configure_dashboards: Configura Dashboards
 6 |   menu_label_dashboard: Dashboard
 7 |   rdb_taskboard: Quadro attività
 8 |   rdb_planningboard: Quadro pianificazione
 9 |   rdb_filter_version_all: Tutte le versioni
10 |   rdb_filter_version_unassigned: Non assegnato
11 |   rdb_filter_tracker_all: Tutti i Trackers
12 |   rdb_filter_tracker_multiple: Trackers Multipli
13 |   rdb_filter_category_all: Tutte le Categorie
14 |   rdb_filter_category_multiple: Categorie Multiple
15 |   rdb_filter_assignee_all: Tutti gli Assegnatari
16 |   rdb_filter_assignee_me: Le mie Segnalazioni
17 |   rdb_filter_assignee_none: Non assegnato
18 |   rdb_filter_assignee_others: Altri
19 |   rdb_options: Opzioni
20 |   rdb_options_change_assignee: Cambio assegnatario
21 |   rdb_options_change_assignee_info: Cambia assegnatario in utente attuale allo spostamento della segnalazione.
22 |   rdb_options_hide_done: Nascondi le segnalazioni chiuse
23 |   rdb_options_hide_done_info: Nascondi le segnalazioni chiuse e riduci le colonne del completato.
24 |   rdb_options_reset: Reset filtro
25 |   rdb_options_reset_info: Reset di tutti i filtri ai valori di default
26 |   rdb_options_configure: Configura
27 |   rdb_options_include_subprojects: Includi i sottoprogetti
28 |   rdb_options_view: Vista
29 |   rdb_options_issue_view: Vista delle segnalazioni
30 |   rdb_options_issue_view_card: Card
31 |   rdb_options_issue_view_compact: Compatta
32 |   rdb_options_group: Raggruppamento segnalazioni
33 |   rdb_group_none: Nessun raggruppamento
34 |   rdb_group_category: Categoria
35 |   rdb_group_assignee: Assegnatario
36 |   rdb_group_tracker: Tracker
37 |   rdb_group_priority: Priorita'
38 |   rdb_group_version: Versione
39 |   rdb_group_parent: Task padre
40 |   rdb_group_project: Progetto
41 |   rdb_options_board_view: Board View
42 |   rdb_options_board_view_compact: Classic
43 |   rdb_options_board_view_outline: Outline
44 |   rdb_options_columns: Board Columns
45 |   rdb_options_fullscreen: Full Screen
46 |   rdb_legend_priorities: Priorita'
47 |   rdb_legend_warnings: Avvisi
48 |   rdb_issue_overdue: Superato
49 |   rdb_property_time: <span title="Tempo impiegato">%{actual}</span> / <span title="Tempo stimato">%{estimated}</span>
50 |   rdb_not_available: N/A
51 |   rdb_column_done: Fatto
52 |   rdb_x_issues:
53 |     one: 1 segnalazione
54 |     many: "%{count} segnalazioni"
55 |     other: "%{count} segnalazioni"
56 |   rdb_dialog_update_issue_title: Aggiorna la segnalazione
57 |   rdb_dialog_update_issue_status: Scegli lo stato della nuova segnalazione
58 |   rdb_other_issues: Altre segnalazioni <span>(%{count})</span>
59 |   rdb_unassigned: Non assegnata
60 |   rdb_others: Altri
61 |   rdb_all_issues: Tutte le segnalazioni
62 |   rdb_no_parent: Nessun task padre
63 |   rdb_issue_menu_progress_title: Aggiorna avanzamento
64 |   rdb_issue_menu_progress: "%{count}%"
65 |   rdb_issue_menu_redmine_issue: Segnalazione Redmine
66 |   rdb_issue_menu_show: Mostra
67 |   rdb_issue_menu_edit: Edita
68 |   rdb_issue_menu_assign_me: Assegnalo a me
69 |   rdb_issue_menu_unassign_me: Rimuovi l'assegnazione
70 |   rdb_flash_illegal_workflow_action: "<p>Non sei autorizzato a compiere quest'azione sul workflow:</p><p>Sposta <b>%{issue}</b> da <b>%{source}</b> a <b>%{target}</b>.</p>"
71 |   rdb_flash_missing_lock_version: "<p><b>Versione lock mancante</b>: Impossibile aggiornare la segnalazione senza il lock della versione. Riprova."
72 |   rdb_flash_stale_object: "<p>Tentativo di aggiornare una segnalazione scaduta: <b>%{issue}</b>. Controlla le modifiche e riprova."
73 |   rdb_flash_invalid_request: "<p>Richiesta non valida.</p>"
74 | 


--------------------------------------------------------------------------------
/config/locales/ja.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | ja:
 3 |   project_module_dashboard: ダッシュボード
 4 |   permission_view_dashboards: ダッシュボードを表示
 5 |   permission_configure_dashboards: ダッシュボードの設定
 6 |   menu_label_dashboard: ダッシュボード
 7 |   rdb_taskboard: タスクボード
 8 |   rdb_planningboard: 計画ボード
 9 |   rdb_filter_version_all: すべてのバージョン
10 |   rdb_filter_version_unassigned: 未割当
11 |   rdb_filter_tracker_all: すべてのトラッカー
12 |   rdb_filter_tracker_multiple: 複数のトラッカー
13 |   rdb_filter_category_all: すべてのカテゴリ
14 |   rdb_filter_category_multiple: 複数のカテゴリ
15 |   rdb_filter_assignee_all: すべての担当
16 |   rdb_filter_assignee_me: 自分
17 |   rdb_filter_assignee_none: 未割当
18 |   rdb_filter_assignee_others: 自分以外
19 |   rdb_options: オプション
20 |   rdb_options_change_assignee: 担当者を変更する
21 |   rdb_options_change_assignee_info: ステータスを移動する際に担当者が自分に変更されます
22 |   rdb_options_hide_done: 完了は表示しない
23 |   rdb_options_hide_done_info: ステータスが完了しているチケットは表示しません
24 |   rdb_options_reset: フィルタをリセット
25 |   rdb_options_reset_info: デフォルトのフィルタにリセットします
26 |   rdb_options_configure: 設定
27 |   rdb_options_include_subprojects: 子プロジェクトを含めます
28 |   rdb_options_view: 表示
29 |   rdb_options_issue_view: ボードの表示形式
30 |   rdb_options_issue_view_card: カード形式
31 |   rdb_options_issue_view_compact: 簡易
32 |   rdb_options_group: グルーピング
33 |   rdb_group_none: グルーピングなし
34 |   rdb_group_category: カテゴリ
35 |   rdb_group_assignee: 担当
36 |   rdb_group_tracker: トラッカー
37 |   rdb_group_priority: 優先度
38 |   rdb_group_version: バージョン
39 |   rdb_group_parent: 親チケット
40 |   rdb_group_project: プロジェクト
41 |   rdb_options_board_view: ボードビュー
42 |   rdb_options_board_view_compact: クラシック
43 |   rdb_options_board_view_outline: アウトライン
44 |   rdb_options_columns: ボードに表示するチケットのステータス
45 |   rdb_options_fullscreen: 全画面表示
46 |   rdb_legend_priorities: 優先度
47 |   rdb_legend_warnings: 警告
48 |   rdb_issue_overdue: 期日超過
49 |   rdb_not_available: 利用不可
50 |   rdb_column_done: 完了
51 |   rdb_x_issues:
52 |     other: "%{count} 件のチケット"
53 |     one: "%{count} 件のチケット"
54 |   rdb_dialog_update_issue_title: チケットの更新
55 |   rdb_dialog_update_issue_status: チケットのステータスを選んでください
56 |   rdb_other_issues: 他のチケット <span>(%{count})</span>
57 |   rdb_unassigned: 未割当
58 |   rdb_others: その他
59 |   rdb_all_issues: すべてのチケット
60 |   rdb_no_parent: 親のないチケット
61 |   rdb_issue_menu_progress_title: 進捗率の変更
62 |   rdb_issue_menu_progress: "%{count}%"
63 |   rdb_issue_menu_redmine_issue: チケット
64 |   rdb_issue_menu_show: チケットを表示
65 |   rdb_issue_menu_edit: チケットの編集
66 |   rdb_issue_menu_assign_me: 担当を自分にする
67 |   rdb_issue_menu_unassign_me: 担当を未割当にする
68 |   rdb_flash_illegal_workflow_action: "<p>このワークフローアクションを実行することはできません。</p><p><b>%{issue} </b><b>%{source}</b> から<b>%{target}</b>.</p>"
69 |   rdb_flash_missing_lock_version: "<p><b>ロックされたバージョンがありません</b>:もう一度やり直してください"
70 |   rdb_flash_stale_object: "<p>チケットはすでに更新されています: <b>%{issue}</b>. 変更を確認して再度更新してください"
71 |   rdb_flash_invalid_request: "<p>リクエストは無効です</p>"
72 | 


--------------------------------------------------------------------------------
/config/locales/ko.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | ko:
 3 |   project_module_dashboard: 현황판
 4 |   permission_view_dashboards: 현황판 보기
 5 |   permission_configure_dashboards: 현황판 설정
 6 |   menu_label_dashboard: 현황판
 7 |   rdb_taskboard: 작업판
 8 |   rdb_planningboard: 계획판
 9 |   rdb_filter_version_all: 모든 버전
10 |   rdb_filter_version_unassigned: 버전 없음
11 |   rdb_filter_tracker_all: 모든 유형
12 |   rdb_filter_tracker_multiple: 여러 유형
13 |   rdb_filter_category_all: 모든 범주
14 |   rdb_filter_category_multiple: 여러 범주
15 |   rdb_filter_assignee_all: 모든 담당자
16 |   rdb_filter_assignee_me: 내 일감
17 |   rdb_filter_assignee_none: 담당자 없음
18 |   rdb_filter_assignee_others: 다른 사람
19 |   rdb_options: 옵션
20 |   rdb_options_change_assignee: 담당자 변경
21 |   rdb_options_change_assignee_info: 일감을 옮기면서 담당자를 자신으로 변경
22 |   rdb_options_hide_done: 닫힌 일감 숨기기
23 |   rdb_options_hide_done_info: 닫힌 일감을 숨기고 종료됨 영역을 작게 표시
24 |   rdb_options_reset: 필터 재설정
25 |   rdb_options_reset_info: 모든 필터를 재설정하여 기본상대로 돌가감
26 |   rdb_options_configure: 설정
27 |   rdb_options_include_subprojects: 하위 프로젝트 포함
28 |   rdb_options_view: 보기
29 |   rdb_options_issue_view: 이슈 보기
30 |   rdb_options_issue_view_card: 카드
31 |   rdb_options_issue_view_compact: 작게 보기
32 |   rdb_options_group: 이슈 묶기
33 |   rdb_group_none: 묶음 없음
34 |   rdb_group_category: 범주
35 |   rdb_group_assignee: 담당자
36 |   rdb_group_tracker: 유형
37 |   rdb_group_priority: 우선순위
38 |   rdb_group_version: 버전
39 |   rdb_group_parent: 상위 일감
40 |   rdb_group_project: 프로젝트
41 |   rdb_options_board_view: 현황판 보기
42 |   rdb_options_board_view_compact: 클래식
43 |   rdb_options_board_view_outline: 개괄
44 |   rdb_options_columns: 현황판 열
45 |   rdb_options_fullscreen: 전체화면
46 |   rdb_legend_priorities: 우선순위
47 |   rdb_legend_warnings: 경고
48 |   rdb_issue_overdue: 기한 지남
49 |   rdb_not_available: N/A
50 |   rdb_column_done: 완료
51 |   rdb_x_issues:
52 |     other: "%{count} 일감"
53 |     one: "%{count} 일감"
54 |   rdb_dialog_update_issue_title: 일감 갱신
55 |   rdb_dialog_update_issue_status: 일감의 새 상태 선택
56 |   rdb_other_issues: 다른 일감들 <span>(%{count})</span>
57 |   rdb_unassigned: 지정되지 않음
58 |   rdb_others: 기타
59 |   rdb_all_issues: 모든 일감
60 |   rdb_no_parent: 상위 일감 없음
61 |   rdb_issue_menu_progress_title: 진척률 조정
62 |   rdb_issue_menu_progress: "%{count}%"
63 |   rdb_issue_menu_redmine_issue: 일감
64 |   rdb_issue_menu_show: 보기
65 |   rdb_issue_menu_edit: 편집
66 |   rdb_issue_menu_assign_me: 내가 맡기
67 |   rdb_issue_menu_unassign_me: 일감 놓기
68 |   rdb_flash_illegal_workflow_action: "<p>이 업무흐름이 허용되지 않습니다:</p><p><b>%{source}</b>에서 <b>%{target}</b>로 <b>%{issue}</b> 이동</p>"
69 |   rdb_flash_invalid_request: "<p>잘못된 요청.</p>"
70 | 


--------------------------------------------------------------------------------
/config/locales/mn.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | mn:
 3 |   project_module_dashboard: Хянах самбар
 4 |   permission_view_dashboards: Хянах самбар харах
 5 |   permission_configure_dashboards: Хянах самбар тохируулах
 6 |   menu_label_dashboard: Хянах самбар
 7 |   rdb_taskboard: Ажлын самбар
 8 |   rdb_planningboard: Төлөвлөгөөний самбар
 9 |   rdb_filter_version_all: Бүх хувилбар
10 |   rdb_filter_version_unassigned: Хуваарилагдаагүй
11 |   rdb_filter_tracker_all: Бүх трэкер
12 |   rdb_filter_tracker_multiple: Хэд хэдэн трэкер
13 |   rdb_filter_category_all: Бүх ангилал
14 |   rdb_filter_category_multiple: Хэд хэдэн ангилал
15 |   rdb_filter_assignee_all: Бүх хариуцагч
16 |   rdb_filter_assignee_me: Миний ажлууд
17 |   rdb_filter_assignee_none: Хуваарилагдаагүй
18 |   rdb_filter_assignee_others: Бусад
19 |   rdb_options: Нэмэлт тохируулга
20 |   rdb_options_change_assignee: Хариуцагчийг солих
21 |   rdb_options_change_assignee_info: Асуудлыг зөөхөд хариуцагчийг одоогийн хэрэглэгчээр солих
22 |   rdb_options_hide_done: Хаагдсан асуудлуудыг нуух
23 |   rdb_options_hide_done_info: Хаагдсан асуудлуудыг нууж гүйцэтгэлийн баганыг нарийсгах
24 |   rdb_options_reset: Шүүлтийг арилгах
25 |   rdb_options_reset_info: Бүх шүүлтийг анхны төлөвт оруулах
26 |   rdb_options_configure: Тохируулах
27 |   rdb_options_include_subprojects: Бүх дэд төслийг оруулах
28 |   rdb_options_view: Харах
29 |   rdb_options_issue_view: Асуудлыг харах
30 |   rdb_options_issue_view_card: Карт
31 |   rdb_options_issue_view_compact: Цомхон
32 |   rdb_options_group: Асуудлыг бүлэглэх
33 |   rdb_group_none: Бүлэглэхгүй
34 |   rdb_group_category: Ангилал
35 |   rdb_group_assignee: Хариуцагч
36 |   rdb_group_tracker: Трэкер
37 |   rdb_group_priority: Зэрэглэл
38 |   rdb_group_version: Хувилбар
39 |   rdb_group_parent: Эх ажил
40 |   rdb_group_project: Төсөл
41 |   rdb_options_board_view: Самбар харах
42 |   rdb_options_board_view_compact: Сонгодог
43 |   rdb_options_board_view_outline: Тойм
44 |   rdb_options_columns: Самбарын баганууд
45 |   rdb_options_fullscreen: Бүтэн дэлгэцээр
46 |   rdb_legend_priorities: Зэрэглэлүүд
47 |   rdb_legend_warnings: Анхааруулга
48 |   rdb_issue_overdue: Хугацаа хэтэрсэн
49 |   rdb_property_time: <span title="Зарцуулсан хугацаа">%{actual}</span> / <span title="Төлөвлөсөн хугацаа">%{estimated}</span>
50 |   rdb_not_available: Хамааралгүй
51 |   rdb_column_done: Гүйцэтгэл
52 |   rdb_x_issues:
53 |     one: 1 асуудал
54 |     other: "%{count} асуудал"
55 |   rdb_dialog_update_issue_title: Асуудлыг шинэчлэх
56 |   rdb_dialog_update_issue_status: Шинэ асуудлын төлөвийг сонго
57 |   rdb_other_issues: Бусад асуудлууд <span>(%{count})</span>
58 |   rdb_unassigned: Хуваарилагдаагүй
59 |   rdb_others: Бусад
60 |   rdb_all_issues: Бүх асуудлууд
61 |   rdb_no_parent: Эх ажил алга
62 |   rdb_issue_menu_progress_title: Явц шинэчлэх
63 |   rdb_issue_menu_progress: "%{count}%"
64 |   rdb_issue_menu_redmine_issue: Redmine Issue
65 |   rdb_issue_menu_show: Харуулах
66 |   rdb_issue_menu_edit: Засварлах
67 |   rdb_issue_menu_assign_me: Надад хариуцуул
68 |   rdb_issue_menu_unassign_me: Хариуцагчаас намайг хас
69 |   rdb_flash_illegal_workflow_action: "<p>Танд энэ үйлдлийг хийх эрх алга:</p><p><b>%{issue}</b>-г <b>%{source}</b>-с <b>%{target}</b> уруу зөөх.</p>"
70 |   rdb_flash_missing_lock_version: "<p><b>Түгжих хувилбар алга</b>: Түгжих хувилбаргүйгээр асуудлыг шинэчилж чадахгүй. Дахин оролд."
71 |   rdb_flash_stale_object: "<p>Хоосон асуудлыг шинэчлэх гэж оролдсон байна: <b>%{issue}</b>. Өөрчлөлтөө шалгаад дахин оролд."
72 |   rdb_flash_invalid_request: "<p>Хүсэлт буруу.</p>"
73 | 


--------------------------------------------------------------------------------
/config/locales/nl.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | nl:
 3 |   project_module_dashboard: Dashboard
 4 |   permission_view_dashboards: Dashboards bekijken
 5 |   permission_configure_dashboards: Dashboards instellen
 6 |   menu_label_dashboard: Dashboard
 7 |   rdb_taskboard: Takenlijst
 8 |   rdb_planningboard: Planningschema
 9 |   rdb_filter_version_all: Alle versies
10 |   rdb_filter_version_unassigned: Niet toegekend
11 |   rdb_filter_tracker_all: Alle trackers
12 |   rdb_filter_tracker_multiple: Meerdere trackers
13 |   rdb_filter_category_all: Alle Categorieën
14 |   rdb_filter_category_multiple: Meerdere Categorieën
15 |   rdb_filter_assignee_all: Alle toegewezen personen
16 |   rdb_filter_assignee_me: Mijn Issues
17 |   rdb_filter_assignee_none: Niet toegewezen
18 |   rdb_filter_assignee_others: Andere
19 |   rdb_options: Opties
20 |   rdb_options_change_assignee: Verander de aangewezen persoon
21 |   rdb_options_change_assignee_info: Verander de aangewezen persoon wanneer het issue verplaatst wordt.
22 |   rdb_options_hide_done: Verberg afgesloten issues
23 |   rdb_options_hide_done_info: Verberg afgesloten issues en maak de klaar kolom smaller
24 |   rdb_options_reset: Herstel filter
25 |   rdb_options_reset_info: Herstel alle filters naar hun standaardwaarde
26 |   rdb_options_configure: Instellen
27 |   rdb_options_include_subprojects: Neem ondergeschikte projecten mee
28 |   rdb_options_view: Bekijk
29 |   rdb_options_issue_view: Issue beeld
30 |   rdb_options_issue_view_card: Kaart
31 |   rdb_options_issue_view_compact: Bondig
32 |   rdb_options_group: Issue groepering
33 |   rdb_group_none: Gene groepering
34 |   rdb_group_category: Categorie
35 |   rdb_group_assignee: Toegewezen persoon
36 |   rdb_group_tracker: Tracker
37 |   rdb_group_priority: Prioriteit
38 |   rdb_group_version: Versie
39 |   rdb_group_parent: Bovenliggende taak
40 |   rdb_group_project: Project
41 |   rdb_options_board_view: Overzichtsbeeld
42 |   rdb_options_board_view_compact: Klassiek
43 |   rdb_options_board_view_outline: Overzicht
44 |   rdb_options_columns: Kolommen in het overzicht
45 |   rdb_options_fullscreen: Schermvullend
46 |   rdb_legend_priorities: Prioriteiten
47 |   rdb_legend_warnings: Waarschuwingen
48 |   rdb_issue_overdue: Te laat
49 |   rdb_property_time: <span title="Spend time">%{actual}</span> / <span title="Estimated time">%{estimated}</span>
50 |   rdb_not_available: Niet toepasbaar
51 |   rdb_column_done: Klaar
52 |   rdb_x_issues:
53 |     one: 1 Issue
54 |     other: "%{count} Issues"
55 |   rdb_dialog_update_issue_title: Issue bijwerken
56 |   rdb_dialog_update_issue_status: Kies een nieuwe Issue status
57 |   rdb_other_issues: Andere Issues <span>(%{count})</span>
58 |   rdb_unassigned: Niet toegewezen
59 |   rdb_others: Andere
60 |   rdb_all_issues: Alle Issues
61 |   rdb_no_parent: Geen bovenliggende taak
62 |   rdb_issue_menu_progress_title: De voortgang bewerken
63 |   rdb_issue_menu_progress: "%{count}%"
64 |   rdb_issue_menu_redmine_issue: Redmine Issue
65 |   rdb_issue_menu_show: Toon
66 |   rdb_issue_menu_edit: Bewerken
67 |   rdb_issue_menu_assign_me: Aan mezelf toewijzen
68 |   rdb_issue_menu_unassign_me: Niet meer aan mezelf toewijzen
69 |   rdb_flash_illegal_workflow_action: "<p>U hebt geen toegang om deze werkproces actie uit te voeren :</p><p>Verplaats <b>%{issue}</b> van <b>%{source}</b> naar <b>%{target}</b>.</p>"
70 |   rdb_flash_missing_lock_version: "<p><b>Ontbrekende lock versie</b>: Kan het issue niet bijwerken zonder lock versie. Probeer het opnieuw."
71 |   rdb_flash_stale_object: "<p>Geprobeerd om een vastgelopen issue bij te werken : <b>%{issue}</b>. Controleer de wijzigingen en probeer opnieuw."
72 |   rdb_flash_invalid_request: "<p>Ongeldige vraag.</p>"
73 | 


--------------------------------------------------------------------------------
/config/locales/pl.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | pl:
 3 |   project_module_dashboard: Tablica
 4 |   permission_view_dashboards: Przeglądanie tablic
 5 |   permission_configure_dashboards: Konfigurowanie tablic
 6 |   menu_label_dashboard: Tablica
 7 |   rdb_taskboard: Tablica zadań
 8 |   rdb_planningboard: Tablica planowania
 9 |   rdb_filter_version_all: Wszystkie wersje
10 |   rdb_filter_version_unassigned: Nieprzypisane
11 |   rdb_filter_tracker_all: Wszystkie typy zagadnień
12 |   rdb_filter_tracker_multiple: Wiele typów zagadnień
13 |   rdb_filter_category_all: Wszystkie kategorie
14 |   rdb_filter_category_multiple: Wiele kategorii
15 |   rdb_filter_assignee_all: Wszyscy użytkownicy przypisani do zagadnień
16 |   rdb_filter_assignee_me: Moje zagadnienia
17 |   rdb_filter_assignee_none: Nieprzypisane
18 |   rdb_filter_assignee_others: Inni
19 |   rdb_options: Opcje
20 |   rdb_options_change_assignee: Zmień przypisaną osobę
21 |   rdb_options_change_assignee_info: Zmienia przypisaną do zagadnienia osobę na aktualnego użytkownika gdy zagadnienie jest przesuwane
22 |   rdb_options_hide_done: Ukryj zamknięte zagadnienia
23 |   rdb_options_hide_done_info: Ukrywa zamknięte zagadnienia i zmniejsza kolumnę wykonane
24 |   rdb_options_reset: Resetuj filtr
25 |   rdb_options_reset_info: Resetuje wszystkie filtry do ustawień domyślnych
26 |   rdb_options_configure: Konfiguruj
27 |   rdb_options_include_subprojects: Uwzględnij podprojekty
28 |   rdb_options_view: Widok
29 |   rdb_options_issue_view: Widok zagadnień
30 |   rdb_options_issue_view_card: Karty
31 |   rdb_options_issue_view_compact: Kompaktowy
32 |   rdb_options_group: Grupowanie zagadnień
33 |   rdb_group_none: Bez grupowania
34 |   rdb_group_category: Kategoria
35 |   rdb_group_assignee: Osoba przypisana do zagadnienia
36 |   rdb_group_tracker: Typ zagadnienia
37 |   rdb_group_priority: Priorytet
38 |   rdb_group_version: Wersja
39 |   rdb_group_parent: Zagadnienie nadrzędne
40 |   rdb_group_project: Projekt
41 |   rdb_options_board_view: Widok tablicy
42 |   rdb_options_board_view_compact: Klasyczny
43 |   rdb_options_board_view_outline: Zarys
44 |   rdb_options_columns: Kolumny tablicy
45 |   rdb_options_fullscreen: Pełny ekran
46 |   rdb_legend_priorities: Priorytety
47 |   rdb_legend_warnings: Ostrzeżenia
48 |   rdb_issue_overdue: Opóźnienie
49 |   rdb_property_time: '''<span title="Spędzony czas">%{actual}</span> / <span title="Szacowany czas">%{estimated}</span>'''
50 |   rdb_not_available: N/A
51 |   rdb_column_done: Zrobione
52 |   rdb_x_issues:
53 |     one: 1 zagadnienie
54 |     few: "%{count} zagadnień"
55 |     many: "%{count} zagadnień"
56 |     other: "%{count} zagadnień"
57 |   rdb_dialog_update_issue_title: Aktualizacja zagadnienia
58 |   rdb_dialog_update_issue_status: Wybierz nowy status zagadnienia
59 |   rdb_other_issues: Inne zagadnienia <span>(%{count})</span>
60 |   rdb_unassigned: Nieprzypisane
61 |   rdb_others: Inni
62 |   rdb_all_issues: Wszystkie zagadnienia
63 |   rdb_no_parent: Brak zagadnień nadrzędnych
64 |   rdb_issue_menu_progress_title: Postęp aktualizacji
65 |   rdb_issue_menu_progress: "%{count}%"
66 |   rdb_issue_menu_redmine_issue: Zagadnienie Redmine
67 |   rdb_issue_menu_show: Pokaż
68 |   rdb_issue_menu_edit: Edycja
69 |   rdb_issue_menu_assign_me: Przypisz do mnie
70 |   rdb_issue_menu_unassign_me: Cofnij przypisanie do mnie
71 |   rdb_flash_illegal_workflow_action: "<p>Nie masz uprawnień do wykonania tej akcji przepływu pracy:</p><p>Przesuń <b>%{issue}</b> z <b>%{source}</b> do <b>%{target}</b>.</p>"
72 |   rdb_flash_missing_lock_version: "<p><b>Brak wersji docelowej</b>: Nie można zaktualizować zagadnienia bez wersji docelowej. Spróbuj ponownie."
73 |   rdb_flash_stale_object: "<p>Próba aktualizacji przestarzałego zagadnienia: <b>%{issue}</b>. Sprawdź zmiany i spróbuj ponownie."
74 |   rdb_flash_invalid_request: "<p>Niepoprawne żądanie.</p>"
75 | 


--------------------------------------------------------------------------------
/config/locales/pt-BR.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | pt-BR:
 3 |   project_module_dashboard: Dashboard
 4 |   permission_view_dashboards: Ver Dashboard
 5 |   permission_configure_dashboards: Configurar Dashboards
 6 |   menu_label_dashboard: Dashboard
 7 |   rdb_taskboard: Tarefas
 8 |   rdb_planningboard: Planejamento
 9 |   rdb_filter_version_all: Todas Versões
10 |   rdb_filter_version_unassigned: Não atribuído
11 |   rdb_filter_tracker_all: Todos Observadores
12 |   rdb_filter_tracker_multiple: Múltiplos Observadores
13 |   rdb_filter_category_all: Todas Categorias
14 |   rdb_filter_category_multiple: Múltiplas Categorias
15 |   rdb_filter_assignee_all: Todas Atribuições
16 |   rdb_filter_assignee_me: Minhas tarefas
17 |   rdb_filter_assignee_none: Não atribuído
18 |   rdb_filter_assignee_others: Outros
19 |   rdb_options: Opções
20 |   rdb_options_change_assignee: Mudar atribuição
21 |   rdb_options_change_assignee_info: Mudar atribuição para o usuário atual quando a tarefa for alterada
22 |   rdb_options_hide_done: Esconder tarefas fechadas
23 |   rdb_options_hide_done_info: Esconder tarefas fechadas e diminuir a coluna "feito"
24 |   rdb_options_reset: Resetar filtro
25 |   rdb_options_reset_info: Resetar todos filtros para o padrão
26 |   rdb_options_configure: Configurar
27 |   rdb_options_include_subprojects: Incluir sub-projetos
28 |   rdb_options_view: Visualização
29 |   rdb_options_issue_view: Visualização de tarefa
30 |   rdb_options_issue_view_card: Cartão
31 |   rdb_options_issue_view_compact: Compactar
32 |   rdb_options_group: Agrupamento de tarefas
33 |   rdb_group_none: Sem agrupamento
34 |   rdb_group_category: Categoria
35 |   rdb_group_assignee: Atribuído para
36 |   rdb_group_tracker: Observador
37 |   rdb_group_priority: Prioridade
38 |   rdb_group_version: Versão
39 |   rdb_group_parent: Tarefa pai
40 |   rdb_group_project: Projeto
41 |   rdb_options_board_view: Modo de visualização
42 |   rdb_options_board_view_compact: Classico
43 |   rdb_options_board_view_outline: Contorno
44 |   rdb_options_columns: Colunas
45 |   rdb_options_fullscreen: Tela cheia
46 |   rdb_legend_priorities: Prioridades
47 |   rdb_legend_warnings: Alertas
48 |   rdb_issue_overdue: Atrasado
49 |   rdb_property_time: <span title="Spend time">%{actual}</span> / <span title="Estimated time">%{estimated}</span>
50 |   rdb_not_available: N/A
51 |   rdb_column_done: Feito
52 |   rdb_x_issues:
53 |     one: 1 Tarefa
54 |     many: "%{count} Tarefas"
55 |     other: "%{count} Tarefas"
56 |   rdb_dialog_update_issue_title: Atualizar Tarefa
57 |   rdb_dialog_update_issue_status: Escolher status da tarefa
58 |   rdb_other_issues: Outras tarefas <span>(%{count})</span>
59 |   rdb_unassigned: Não atribuidas
60 |   rdb_others: Outras
61 |   rdb_all_issues: Todas Tarefas
62 |   rdb_no_parent: Sem tarefas pai
63 |   rdb_issue_menu_progress_title: Progresso de atualização
64 |   rdb_issue_menu_progress: "%{count}%"
65 |   rdb_issue_menu_redmine_issue: Tarefa Redmine
66 |   rdb_issue_menu_show: Mostrar
67 |   rdb_issue_menu_edit: Editar
68 |   rdb_issue_menu_assign_me: Atribuir para mim
69 |   rdb_issue_menu_unassign_me: Retirar atribuição
70 |   rdb_flash_illegal_workflow_action: "<p>Você não tem autorização para altera o fluxo:</p><p>Mover <b>%{issue}</b> de <b>%{source}</b> para <b>%{target}</b>.</p>"
71 |   rdb_flash_missing_lock_version: "<p><b>Falta versão bloqueada</b>: Não é possível atualizar uma tarefa sem uma versão bloqueada. Tente novamente."
72 |   rdb_flash_stale_object: "<p>Tentando atualizar uma tarefa antiga: <b>%{issue}</b>. Verifique as mudanças e tente novamente."
73 |   rdb_flash_invalid_request: "<p>Requisição inválida.</p>"
74 | 


--------------------------------------------------------------------------------
/config/locales/ru.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | ru:
 3 |   project_module_dashboard: Панель задач
 4 |   permission_view_dashboards: Просмотр Панели
 5 |   permission_configure_dashboards: Управление панелями
 6 |   menu_label_dashboard: Панель задач
 7 |   rdb_taskboard: Панель задач
 8 |   rdb_planningboard: Доска планирования
 9 |   rdb_filter_version_all: Все версии
10 |   rdb_filter_version_unassigned: Неназначенные
11 |   rdb_filter_tracker_all: Все трекеры
12 |   rdb_filter_tracker_multiple: Множественные трекеры
13 |   rdb_filter_category_all: Все категории
14 |   rdb_filter_category_multiple: Множественные категории
15 |   rdb_filter_assignee_all: Все ответственные
16 |   rdb_filter_assignee_me: Мои задачи
17 |   rdb_filter_assignee_none: Не назначены
18 |   rdb_filter_assignee_others: Другие
19 |   rdb_options: Настройки
20 |   rdb_options_change_assignee: Изменить назначение
21 |   rdb_options_change_assignee_info: Назначать задачу текущему пользователю при перемещении
22 |   rdb_options_hide_done: Скрыть закрытые задачи
23 |   rdb_options_hide_done_info: Скрыть закрытые задачи и сделать колонку 'Выполнено' меньше
24 |   rdb_options_reset: Очистить фильтр
25 |   rdb_options_reset_info: Сбросить все фильтры по-умолчанию
26 |   rdb_options_configure: Настроить
27 |   rdb_options_include_subprojects: Включить под-проекты
28 |   rdb_options_view: Вид
29 |   rdb_options_issue_view: Вид задач
30 |   rdb_options_issue_view_card: Карточки
31 |   rdb_options_issue_view_compact: Компактный
32 |   rdb_options_group: Группировка задач
33 |   rdb_group_none: Без группировки
34 |   rdb_group_category: Категория
35 |   rdb_group_assignee: Назначена
36 |   rdb_group_tracker: Трекер
37 |   rdb_group_priority: Приоритет
38 |   rdb_group_version: Версия
39 |   rdb_group_parent: Основная задача
40 |   rdb_group_project: Проект
41 |   rdb_options_board_view: Вид панели
42 |   rdb_options_board_view_compact: Классический
43 |   rdb_options_board_view_outline: Контур
44 |   rdb_options_columns: Колонки панели
45 |   rdb_options_fullscreen: Полный экран
46 |   rdb_legend_priorities: Приоритеты
47 |   rdb_legend_warnings: Предупреждения
48 |   rdb_issue_overdue: Изменить дату
49 |   rdb_property_time: <span title="Затраченное время">%{actual}</span> / <span title="Оценка времени">%{estimated}</span>
50 |   rdb_not_available: Нет
51 |   rdb_column_done: Выполнено
52 |   rdb_x_issues:
53 |     one: 1 задача
54 |     few: "%{count} задачи"
55 |     many: "%{count} задач"
56 |     other: "%{count} задач"
57 |   rdb_dialog_update_issue_title: Обновить задачу
58 |   rdb_dialog_update_issue_status: Выбрать новый статус задачи
59 |   rdb_other_issues: Другие задачи <span>(%{count})</span>
60 |   rdb_unassigned: Неназначенные
61 |   rdb_others: Другие
62 |   rdb_all_issues: Все задачи
63 |   rdb_no_parent: Нет основной задачи
64 |   rdb_issue_menu_progress_title: Обновить готовность
65 |   rdb_issue_menu_progress: "%{count}%"
66 |   rdb_issue_menu_redmine_issue: Задача
67 |   rdb_issue_menu_show: Просмотр
68 |   rdb_issue_menu_edit: Изменить
69 |   rdb_issue_menu_assign_me: Назначить мне
70 |   rdb_issue_menu_unassign_me: Снять назначение
71 |   rdb_flash_illegal_workflow_action: "<p>У вас не достаточно прав для выполенния действия:</p><p>Переместить <b>%{issue}</b> из <b>%{source}</b> в <b>%{target}</b>.</p>"
72 |   rdb_flash_missing_lock_version: "<p><b>Не задана версия</b>: Невозможно обновить задачу без определенной версии. Попробуйте позже."
73 |   rdb_flash_stale_object: "<p>Задача устарела: <b>%{issue}</b>. Проверьте изменения и попробуйте снова."
74 |   rdb_flash_invalid_request: "<p>Неверный запрос.</p>"
75 | 


--------------------------------------------------------------------------------
/config/locales/tr.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | tr:
 3 |   project_module_dashboard: Gösterge Paneli
 4 |   permission_view_dashboards: Gösterge Panelini Görüntüle
 5 |   permission_configure_dashboards: Gösterge Panelini Yapılandır
 6 |   menu_label_dashboard: Gösterge Paneli
 7 |   rdb_taskboard: Görev  Panosu
 8 |   rdb_planningboard: Planlama Panosu
 9 |   rdb_filter_version_all: Tüm Uyarlamalar
10 |   rdb_filter_version_unassigned: Atanmamış
11 |   rdb_filter_tracker_all: Tüm Takipçiler
12 |   rdb_filter_tracker_multiple: Çoklu Takipçiler
13 |   rdb_filter_category_all: Tüm Kategoriler
14 |   rdb_filter_category_multiple: Çoklu Kategoriler
15 |   rdb_filter_assignee_all: Tüm Atananlar
16 |   rdb_filter_assignee_me: Taleplerim
17 |   rdb_filter_assignee_none: Atanmamışlar
18 |   rdb_filter_assignee_others: Diğerleri
19 |   rdb_options: Seçenekler
20 |   rdb_options_change_assignee: Atananı Değiştir
21 |   rdb_options_change_assignee_info: Talep taşındığında atananı mevcut kullanıcıyla değiştirin.
22 |   rdb_options_hide_done: Kapalı talepleri gizle
23 |   rdb_options_hide_done_info: Kapalı talepleri gizler ve yapılan sütununu ufaltır.
24 |   rdb_options_reset: Süzgeçi sıfırla
25 |   rdb_options_reset_info: Tüm süzgeçleri geri varsayılana sıfırla
26 |   rdb_options_configure: Yapılandır
27 |   rdb_options_include_subprojects: Alt projeleri dahil et
28 |   rdb_options_view: Göster
29 |   rdb_options_issue_view: Talep Görünümü
30 |   rdb_options_issue_view_card: Kart
31 |   rdb_options_issue_view_compact: Derli toplu
32 |   rdb_options_group: Talep Gruplama
33 |   rdb_group_none: Gruplama Yok
34 |   rdb_group_category: Kategori
35 |   rdb_group_assignee: Atanan
36 |   rdb_group_tracker: Takipçi
37 |   rdb_group_priority: Öncelik
38 |   rdb_group_version: Uyarlama
39 |   rdb_group_parent: Üst Görev
40 |   rdb_group_project: Proje
41 |   rdb_options_board_view: Pano Görünüü
42 |   rdb_options_board_view_compact: Klasik
43 |   rdb_options_board_view_outline: Anahat
44 |   rdb_options_columns: Pano Sütunları
45 |   rdb_options_fullscreen: Tam Ekran
46 |   rdb_legend_priorities: Öncelikler
47 |   rdb_legend_warnings: Uyarılar
48 |   rdb_issue_overdue: Vadesi geçmiş
49 |   rdb_property_time: <span title="Gerçekleşen Zaman">%{actual}</span> / <span title="Tahmini zaman">%{estimated}</span>
50 |   rdb_not_available: N/A
51 |   rdb_column_done: Tamam
52 |   rdb_x_issues:
53 |     one: 1 İş
54 |     other: "%{count}Talepler"
55 |   rdb_dialog_update_issue_title: Talebi Güncelle
56 |   rdb_dialog_update_issue_status: Yeni talep durumunu seçin
57 |   rdb_other_issues: Diğer Talepler <span>(%{count})</span>
58 |   rdb_unassigned: Atanmamış
59 |   rdb_others: Diğerleri
60 |   rdb_all_issues: Tüm Talepler
61 |   rdb_no_parent: Üst görev yok
62 |   rdb_issue_menu_progress_title: İlerlemeleri güncelle
63 |   rdb_issue_menu_progress: "%{count}%"
64 |   rdb_issue_menu_redmine_issue: Redmine Talep
65 |   rdb_issue_menu_show: Göster
66 |   rdb_issue_menu_edit: Düzenle
67 |   rdb_issue_menu_assign_me: Bana Ata
68 |   rdb_issue_menu_unassign_me: Atamamı kaldır
69 |   rdb_flash_illegal_workflow_action: "<p>Bu İş akışı eylemini gerçekleştirme izniniz yok:</p><p>Taşı <b>%{issue}</b> durumundan <b>%{source}</b>  <b>%{target}</b> durumuna.</p>"
70 |   rdb_flash_missing_lock_version: "<p><b>Kilit uyarlaması eksik</b>: Kilit uyarlaması olmadan talep güncellenemez. Tekrar deneyin."
71 |   rdb_flash_stale_object: "<p>Bayat bir talebi güncelleme girişimi: <b>%{issue}</b>. Değişiklikleri denetleyin ve tekrar deneyin."
72 |   rdb_flash_invalid_request: "<p>Geçersiz istem.</p>"
73 | 


--------------------------------------------------------------------------------
/config/locales/uk.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | uk:
 3 |   project_module_dashboard: Дошка завдань
 4 |   permission_view_dashboards: Перегляд
 5 |   permission_configure_dashboards: Керування
 6 |   menu_label_dashboard: Дошка завдань
 7 |   rdb_taskboard: Дошка завдань
 8 |   rdb_planningboard: Дошка планування
 9 |   rdb_filter_version_all: Всі версії
10 |   rdb_filter_version_unassigned: Без версії
11 |   rdb_filter_tracker_all: Всі координатори
12 |   rdb_filter_tracker_multiple: Декілька координаторів
13 |   rdb_filter_category_all: Всі категорії
14 |   rdb_filter_category_multiple: Декілька категорій
15 |   rdb_filter_assignee_all: Всі відповідальні
16 |   rdb_filter_assignee_me: Мої завдання
17 |   rdb_filter_assignee_none: Без відповідального
18 |   rdb_filter_assignee_others: Інші
19 |   rdb_options: Налаштування
20 |   rdb_options_change_assignee: Змінити відповідального
21 |   rdb_options_change_assignee_info: При перетягуванні завдання доручити його мені
22 |   rdb_options_hide_done: Приховати виконанні завдання
23 |   rdb_options_hide_done_info: Приховати виконанні завдання і зменшити колонку "Done"
24 |   rdb_options_reset: Скинути фільтр
25 |   rdb_options_reset_info: Скинути фільтр за замовчуванням
26 |   rdb_options_configure: Налаштування
27 |   rdb_options_include_subprojects: Додати підпроекти
28 |   rdb_options_view: Вигляд
29 |   rdb_options_issue_view: Вигляд
30 |   rdb_options_issue_view_card: У формі картки
31 |   rdb_options_issue_view_compact: Компактний
32 |   rdb_options_group: Групувати за
33 |   rdb_group_none: Без групування
34 |   rdb_group_category: Категорією
35 |   rdb_group_assignee: Відповідальним
36 |   rdb_group_tracker: Координатором
37 |   rdb_group_priority: Пріоритетом
38 |   rdb_group_version: Версією
39 |   rdb_group_parent: Батьківським завданням
40 |   rdb_group_project: Проєктом
41 |   rdb_options_board_view: Вигляд дошки
42 |   rdb_options_board_view_compact: Класичний
43 |   rdb_options_board_view_outline: Контур
44 |   rdb_options_columns: Колонки дошки
45 |   rdb_options_fullscreen: На повний екран
46 |   rdb_legend_priorities: Пріоритети
47 |   rdb_legend_warnings: Попередження
48 |   rdb_issue_overdue: Протермінований
49 |   rdb_property_time: <span title="Затрачено часу">%{actual}</span> / <span title="Орієнтований час">%{estimated}</span>
50 |   rdb_not_available: Недоступно
51 |   rdb_column_done: Done
52 |   rdb_x_issues:
53 |     one: 1 Завдання
54 |     few: 1%{count} Завдання
55 |     many: 1%{count} Завдання
56 |     other: 1%{count} Завдання
57 |   rdb_dialog_update_issue_title: Оновити завдання
58 |   rdb_dialog_update_issue_status: Виберіть новий статус для завдання
59 |   rdb_other_issues: Інші завдання <span>(%{count})</span>
60 |   rdb_unassigned: Не призначений
61 |   rdb_others: Інші
62 |   rdb_all_issues: Всі завдання
63 |   rdb_no_parent: Без батьківського завдання
64 |   rdb_issue_menu_progress_title: Оновити прогрес
65 |   rdb_issue_menu_progress: "%{count}%"
66 |   rdb_issue_menu_redmine_issue: Завдання
67 |   rdb_issue_menu_show: Перейти
68 |   rdb_issue_menu_edit: Редагувати
69 |   rdb_issue_menu_assign_me: Доручити мені
70 |   rdb_issue_menu_unassign_me: Зняти з мене
71 |   rdb_flash_illegal_workflow_action: "<p>Ви не маєте права виконувати цю дію в робочому процесі:</p><p>Перетягнути  <b>%{issue}</b> з  <b>%{source}</b> у <b>%{target}</b>.</p>"
72 |   rdb_flash_missing_lock_version: "<p><b>Не вказана версія</b>: Не можливо оновити завдання не вказавши версію. Спробуйте ще раз."
73 |   rdb_flash_stale_object: "<p>Завдання застарілe: <b>%{issue}</b>. Перевірте зміни і спробуйте ще раз."
74 |   rdb_flash_invalid_request: "<p>Невірний запит.</p>"
75 | 


--------------------------------------------------------------------------------
/config/locales/zh-TW.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | zh-TW:
 3 |   project_module_dashboard: 儀表板
 4 |   permission_view_dashboards: 檢視儀表板
 5 |   permission_configure_dashboards: 設定儀表板
 6 |   menu_label_dashboard: 儀表板
 7 |   rdb_taskboard: 任務板
 8 |   rdb_planningboard: 計畫板
 9 |   rdb_filter_version_all: 所有版本
10 |   rdb_filter_version_unassigned: 未指派
11 |   rdb_filter_tracker_all: 所有標籤
12 |   rdb_filter_tracker_multiple: 多個標籤
13 |   rdb_filter_category_all: 所有分類
14 |   rdb_filter_category_multiple: 多個分類
15 |   rdb_filter_assignee_all: 所有指派
16 |   rdb_filter_assignee_me: 我的指派
17 |   rdb_filter_assignee_none: 未指派
18 |   rdb_filter_assignee_others: 其他指派
19 |   rdb_options: 選項
20 |   rdb_options_change_assignee: 更換指派
21 |   rdb_options_change_assignee_info: 更換指派給移動這個問題的人
22 |   rdb_options_hide_done: 隱藏已關閉的問題
23 |   rdb_options_hide_done_info: 隱藏已關閉的問題且縮小完成欄
24 |   rdb_options_reset: 重置篩選條件
25 |   rdb_options_reset_info: 重置篩選條件成預設
26 |   rdb_options_configure: 設定
27 |   rdb_options_include_subprojects: 包含子項目
28 |   rdb_options_view: 視圖
29 |   rdb_options_issue_view: 問題視圖
30 |   rdb_options_issue_view_card: 卡片
31 |   rdb_options_issue_view_compact: 簡潔
32 |   rdb_options_group: 問題分組
33 |   rdb_group_none: 沒有分組
34 |   rdb_group_category: 分類
35 |   rdb_group_assignee: 指派人
36 |   rdb_group_tracker: 標籤
37 |   rdb_group_priority: 優先
38 |   rdb_group_version: 版本
39 |   rdb_group_parent: 父項目
40 |   rdb_group_project: 項目
41 |   rdb_options_board_view: 黑板視圖
42 |   rdb_options_board_view_compact: 經典
43 |   rdb_options_board_view_outline: 大綱
44 |   rdb_options_columns: 黑板欄位
45 |   rdb_options_fullscreen: 全螢幕
46 |   rdb_legend_priorities: 優先權
47 |   rdb_legend_warnings: 警告
48 |   rdb_issue_overdue: 過期
49 |   rdb_property_time: <span title="花費時間">%{actual}</span> / <span title="預計時間">%{estimated}</span>
50 |   rdb_not_available: N/A
51 |   rdb_column_done: 完成
52 |   rdb_x_issues:
53 |     other: "%{count} 問題"
54 |     one: "%{count} 問題"
55 |   rdb_dialog_update_issue_title: 更新問題
56 |   rdb_dialog_update_issue_status: 選擇新問題的狀態
57 |   rdb_other_issues: 其他問題 <span>(%{count})</span>
58 |   rdb_unassigned: 未指派
59 |   rdb_others: 其他
60 |   rdb_all_issues: 所有問題
61 |   rdb_no_parent: 沒有父項目
62 |   rdb_issue_menu_progress_title: 更新進度
63 |   rdb_issue_menu_progress: "%{count}%"
64 |   rdb_issue_menu_redmine_issue: Redmine 問題
65 |   rdb_issue_menu_show: 顯示
66 |   rdb_issue_menu_edit: 編輯
67 |   rdb_issue_menu_assign_me: 指派給我
68 |   rdb_issue_menu_unassign_me: 解除我的指派
69 |   rdb_flash_illegal_workflow_action: "<p>你不被允許進行這樣的工作流程:</p><p>將 <b>%{issue}</b> 從 <b>%{source}</b> 移動到 <b>%{target}</b>.</p>"
70 |   rdb_flash_missing_lock_version: "<p><b>遺失的鎖定版本</b>: 無法更新問題,請重試。"
71 |   rdb_flash_stale_object: "<p>更改已穩定的問題: <b>%{issue}</b>請重試。"
72 |   rdb_flash_invalid_request: "<p>無效的請求</p>"
73 | 


--------------------------------------------------------------------------------
/config/locales/zh.yml:
--------------------------------------------------------------------------------
 1 | ---
 2 | zh:
 3 |   project_module_dashboard: 看板
 4 |   permission_view_dashboards: 浏览看板
 5 |   permission_configure_dashboards: 配置看板
 6 |   menu_label_dashboard: 看板
 7 |   rdb_taskboard: 任务看板
 8 |   rdb_planningboard: 计划看板
 9 |   rdb_filter_version_all: 所有版本
10 |   rdb_filter_version_unassigned: 未指派
11 |   rdb_filter_tracker_all: 所有跟踪
12 |   rdb_filter_tracker_multiple: 多个跟踪
13 |   rdb_filter_category_all: 所有类别
14 |   rdb_filter_category_multiple: 多个类别
15 |   rdb_filter_assignee_all: 所有指派
16 |   rdb_filter_assignee_me: 我的指派
17 |   rdb_filter_assignee_none: 未指派
18 |   rdb_filter_assignee_others: 其他指派
19 |   rdb_options: 选项
20 |   rdb_options_change_assignee: 更换指派
21 |   rdb_options_change_assignee_info: 更换指派给移动本问题的人
22 |   rdb_options_hide_done: 隐藏已关闭的问题
23 |   rdb_options_hide_done_info: 隐藏已关闭的问题并缩小栏位
24 |   rdb_options_reset: 重置过滤条件
25 |   rdb_options_reset_info: 重置过滤条件为预设
26 |   rdb_options_configure: 配置
27 |   rdb_options_include_subprojects: 包含子项目
28 |   rdb_options_view: 视图
29 |   rdb_options_issue_view: 问题视图
30 |   rdb_options_issue_view_card: 卡片
31 |   rdb_options_issue_view_compact: 精简
32 |   rdb_options_group: 问题分组
33 |   rdb_group_none: 沒有分组
34 |   rdb_group_category: 类别
35 |   rdb_group_assignee: 指派人
36 |   rdb_group_tracker: 跟踪
37 |   rdb_group_priority: 优先级
38 |   rdb_group_version: 版本
39 |   rdb_group_parent: 父项
40 |   rdb_group_project: 项目
41 |   rdb_options_board_view: 看板视图
42 |   rdb_options_board_view_compact: 精简
43 |   rdb_options_board_view_outline: 大纲
44 |   rdb_options_columns: 看板栏位
45 |   rdb_options_fullscreen: 全屏幕
46 |   rdb_legend_priorities: 优先级
47 |   rdb_legend_warnings: 警告
48 |   rdb_issue_overdue: 过期
49 |   rdb_property_time: <span title="花费时间">%{actual}</span> / <span title="预计时间">%{estimated}</span>
50 |   rdb_not_available: N/A
51 |   rdb_column_done: 完成
52 |   rdb_x_issues:
53 |     other: "%{count} 问题"
54 |     one: "%{count} 问题"
55 |   rdb_dialog_update_issue_title: 更新问题
56 |   rdb_dialog_update_issue_status: 选择新问题的状态
57 |   rdb_other_issues: 其他问题 <span>(%{count})</span>
58 |   rdb_unassigned: 未指派
59 |   rdb_others: 其他
60 |   rdb_all_issues: 所有问题
61 |   rdb_no_parent: 没有父项目
62 |   rdb_issue_menu_progress_title: 更新进度
63 |   rdb_issue_menu_progress: "%{count}%"
64 |   rdb_issue_menu_redmine_issue: Redmine 问题
65 |   rdb_issue_menu_show: 显示
66 |   rdb_issue_menu_edit: 编辑
67 |   rdb_issue_menu_assign_me: 指派给我
68 |   rdb_issue_menu_unassign_me: 未指派给我
69 |   rdb_flash_illegal_workflow_action: "<p>你未经许可进行以下操作步骤:</p><p>将 <b>%{issue}</b> 从 <b>%{source}</b> 移动到 <b>%{target}</b>.</p>"
70 |   rdb_flash_missing_lock_version: "<p><b>丢失的冻结版本</b>: 无法更新问题,请重试。"
71 |   rdb_flash_stale_object: "<p>试图更改已冻结的问题: <b>%{issue}</b>请重试。"
72 |   rdb_flash_invalid_request: "<p>无效的请求</p>"
73 | 


--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | # Plugin's routes
 4 | # See: http://guides.rubyonrails.org/routing.html
 5 | 
 6 | match 'projects/:id/rdb/taskboard'        => 'rdb_taskboard#index',  :as => :rdb_taskboard,        via: %i[get post]
 7 | match 'projects/:id/rdb/taskboard/move'   => 'rdb_taskboard#move',   :as => :rdb_taskboard_move,   via: %i[get post]
 8 | match 'projects/:id/rdb/taskboard/update' => 'rdb_taskboard#update', :as => :rdb_taskboard_update, via: %i[get post]
 9 | match 'projects/:id/rdb/taskboard/filter' => 'rdb_taskboard#filter', :as => :rdb_taskboard_filter, via: %i[get post]
10 | 
11 | match 'projects/:id/rdb(/:board)'  => 'rdb_dashboard#index', :as => :rdb, via: %i[get post]
12 | match 'projects/:id/dashboard'     => 'rdb_dashboard#index', via: %i[get post]
13 | 


--------------------------------------------------------------------------------
/init.rb:
--------------------------------------------------------------------------------
 1 | # frozen_string_literal: true
 2 | 
 3 | require 'redmine'
 4 | 
 5 | Redmine::Plugin.register :redmine_dashboard do
 6 |   name 'Redmine Dashboard plugin'
 7 |   author 'Jan Graichen'
 8 |   description 'Add a task board and a planning board to Redmine'
 9 |   version '2.16.0'
10 |   url 'https://github.com/jgraichen/redmine_dashboard'
11 |   author_url 'mailto:jgraichen@altimos.de'
12 | 
13 |   requires_redmine '5.0'
14 | 
15 |   project_module :dashboard do
16 |     permission :view_dashboards, {
17 |       rdb_dashboard: [:index],
18 |       rdb_taskboard: %i[index filter move update]
19 |     }
20 |     permission :configure_dashboards, {rdb_dashboard: [:configure]}
21 |   end
22 |   menu :project_menu, :dashboard, {controller: 'rdb_dashboard', action: 'index'},
23 |     caption: :menu_label_dashboard, after: :new_issue
24 | end
25 | 


--------------------------------------------------------------------------------