Merge pull request #7124 from opf/feature/board-highlighting
Replace display-mode tab with highlighting tabpull/7134/head
commit
eb040ee2ea
@ -1 +1,3 @@ |
|||||||
export type HighlightingMode = 'status'|'priority'|'type'|'inline'|'none'; |
export type HighlightingMode = 'status'|'priority'|'type'|'inline'|'none'; |
||||||
|
|
||||||
|
export type CardHighlightingMode = 'status'|'priority'|'type'|'inline'|'none'|'entire-card'; |
||||||
|
@ -1,31 +0,0 @@ |
|||||||
<div> |
|
||||||
<form> |
|
||||||
<p [textContent]="text.choose_mode"></p> |
|
||||||
<div class="form--field -full-width"> |
|
||||||
<div class="form--field-container"> |
|
||||||
<label class="option-label"> |
|
||||||
<input type="radio" |
|
||||||
[(ngModel)]="displayMode" |
|
||||||
value="cards" |
|
||||||
name="display_mode_switch"> |
|
||||||
<op-icon icon-classes="icon-projects" [attr.icon-title]="text.card_mode"></op-icon> |
|
||||||
&ngsp; |
|
||||||
<span [textContent]="text.card_mode"></span> |
|
||||||
</label> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<div class="form--field -full-width"> |
|
||||||
<div class="form--field-container"> |
|
||||||
<label class="option-label"> |
|
||||||
<input type="radio" |
|
||||||
[(ngModel)]="displayMode" |
|
||||||
value="table" |
|
||||||
name="display_mode_switch"> |
|
||||||
<op-icon icon-classes="icon-view-list" [attr.icon-title]="text.table_mode"></op-icon> |
|
||||||
&ngsp; |
|
||||||
<span [textContent]="text.table_mode"></span> |
|
||||||
</label> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</form> |
|
||||||
</div> |
|
@ -1,39 +0,0 @@ |
|||||||
import {Component, Inject, Injector} from '@angular/core'; |
|
||||||
import {I18nService} from 'core-app/modules/common/i18n/i18n.service'; |
|
||||||
import {TabComponent} from 'core-components/wp-table/configuration-modal/tab-portal-outlet'; |
|
||||||
import {OpModalLocalsMap} from "core-components/op-modals/op-modal.types"; |
|
||||||
import {Board, BoardDisplayMode} from "core-app/modules/boards/board/board"; |
|
||||||
import {OpModalLocalsToken} from "core-components/op-modals/op-modal.service"; |
|
||||||
|
|
||||||
@Component({ |
|
||||||
templateUrl: './display-settings-tab.component.html' |
|
||||||
}) |
|
||||||
export class BoardConfigurationDisplaySettingsTab implements TabComponent { |
|
||||||
|
|
||||||
// Current board resource
|
|
||||||
public board:Board; |
|
||||||
|
|
||||||
// Display mode
|
|
||||||
public displayMode:BoardDisplayMode = 'cards'; |
|
||||||
|
|
||||||
public text = { |
|
||||||
choose_mode: this.I18n.t('js.work_packages.table_configuration.choose_display_mode'), |
|
||||||
card_mode: this.I18n.t('js.boards.configuration_modal.display_settings.card_mode'), |
|
||||||
table_mode: this.I18n.t('js.boards.configuration_modal.display_settings.table_mode'), |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
constructor(readonly injector:Injector, |
|
||||||
@Inject(OpModalLocalsToken) public locals:OpModalLocalsMap, |
|
||||||
readonly I18n:I18nService) { |
|
||||||
} |
|
||||||
|
|
||||||
public onSave() { |
|
||||||
this.board.displayMode = this.displayMode; |
|
||||||
} |
|
||||||
|
|
||||||
ngOnInit() { |
|
||||||
this.board = this.locals.board; |
|
||||||
this.displayMode = this.board.displayMode; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,60 @@ |
|||||||
|
<div> |
||||||
|
<form> |
||||||
|
<p [textContent]="text.highlighting_mode.description"></p> |
||||||
|
|
||||||
|
<div class="form--field -full-width"> |
||||||
|
<div class="form--field-container"> |
||||||
|
<label class="option-label"> |
||||||
|
<input type="radio" |
||||||
|
[(ngModel)]="highlightingMode" |
||||||
|
(change)="updateMode($event.target.value)" |
||||||
|
value="inline" |
||||||
|
name="highlighting_mode_switch"> |
||||||
|
{{ text.highlighting_mode.inline }} |
||||||
|
{{ text.highlighting_mode.type }} |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form--field -full-width"> |
||||||
|
<div class="form--field-container"> |
||||||
|
<label class="option-label"> |
||||||
|
<input type="radio" |
||||||
|
[(ngModel)]="entireCardMode" |
||||||
|
(change)="updateMode('entire-card')" |
||||||
|
[value]="true" |
||||||
|
name="entire_card_switch"> |
||||||
|
<span [textContent]="text.highlighting_mode.entire_card_by"></span> |
||||||
|
&ngsp; |
||||||
|
<select (change)="updateMode($event.target.value)" |
||||||
|
id="selected_attribute" |
||||||
|
name="selected_attribute" |
||||||
|
class="form--select form--inline-select"> |
||||||
|
<option [textContent]="text.highlighting_mode.status" |
||||||
|
[selected]="lastEntireCardAttribute === 'status'" |
||||||
|
value="status"></option> |
||||||
|
<option [textContent]="text.highlighting_mode.type" |
||||||
|
[selected]="lastEntireCardAttribute === 'type'" |
||||||
|
value="type"></option> |
||||||
|
<option [textContent]="text.highlighting_mode.priority" |
||||||
|
[selected]="lastEntireCardAttribute === 'priority'" |
||||||
|
value="priority"></option> |
||||||
|
</select> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form--field -full-width"> |
||||||
|
<div class="form--field-container"> |
||||||
|
<label class="option-label"> |
||||||
|
<input type="radio" |
||||||
|
[(ngModel)]="highlightingMode" |
||||||
|
(change)="updateMode($event.target.value)" |
||||||
|
value="none" |
||||||
|
name="highlighting_mode_switch"> |
||||||
|
<span [textContent]="text.highlighting_mode.none"></span> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
</form> |
||||||
|
</div> |
||||||
|
|
@ -0,0 +1,70 @@ |
|||||||
|
import {Component, Inject, Injector} from '@angular/core'; |
||||||
|
import {I18nService} from 'core-app/modules/common/i18n/i18n.service'; |
||||||
|
import {TabComponent} from 'core-components/wp-table/configuration-modal/tab-portal-outlet'; |
||||||
|
import {OpModalLocalsMap} from "core-components/op-modals/op-modal.types"; |
||||||
|
import {Board} from "core-app/modules/boards/board/board"; |
||||||
|
import {OpModalLocalsToken} from "core-components/op-modals/op-modal.service"; |
||||||
|
import { |
||||||
|
CardHighlightingMode, |
||||||
|
HighlightingMode |
||||||
|
} from "core-components/wp-fast-table/builders/highlighting/highlighting-mode.const"; |
||||||
|
import {WorkPackageTableHighlightingService} from "core-components/wp-fast-table/state/wp-table-highlighting.service"; |
||||||
|
import {HalResource} from "core-app/modules/hal/resources/hal-resource"; |
||||||
|
|
||||||
|
@Component({ |
||||||
|
templateUrl: './highlighting-tab.component.html' |
||||||
|
}) |
||||||
|
export class BoardHighlightingTabComponent implements TabComponent { |
||||||
|
|
||||||
|
// Highlighting mode
|
||||||
|
public highlightingMode:CardHighlightingMode = 'inline'; |
||||||
|
public entireCardMode:boolean = false; |
||||||
|
public lastEntireCardAttribute:CardHighlightingMode = 'status'; |
||||||
|
|
||||||
|
// Current board resource
|
||||||
|
public board:Board; |
||||||
|
|
||||||
|
public text = { |
||||||
|
highlighting_mode: { |
||||||
|
description: this.I18n.t('js.work_packages.table_configuration.highlighting_mode.description'), |
||||||
|
none: this.I18n.t('js.work_packages.table_configuration.highlighting_mode.none'), |
||||||
|
inline: this.I18n.t('js.card.highlighting.inline'), |
||||||
|
status: this.I18n.t('js.work_packages.table_configuration.highlighting_mode.status'), |
||||||
|
type: this.I18n.t('js.work_packages.properties.type'), |
||||||
|
priority: this.I18n.t('js.work_packages.table_configuration.highlighting_mode.priority'), |
||||||
|
entire_card_by: this.I18n.t('js.card.highlighting.entire_card_by'), |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
constructor(readonly injector:Injector, |
||||||
|
@Inject(OpModalLocalsToken) public locals:OpModalLocalsMap, |
||||||
|
readonly I18n:I18nService) { |
||||||
|
} |
||||||
|
|
||||||
|
public onSave() { |
||||||
|
this.updateMode(this.highlightingMode); |
||||||
|
this.board.highlightingMode = this.highlightingMode; |
||||||
|
} |
||||||
|
|
||||||
|
ngOnInit() { |
||||||
|
this.board = this.locals.board; |
||||||
|
this.highlightingMode = this.board.highlightingMode; |
||||||
|
this.updateMode(this.highlightingMode); |
||||||
|
} |
||||||
|
|
||||||
|
public updateMode(mode:CardHighlightingMode) { |
||||||
|
if (mode === 'entire-card') { |
||||||
|
this.highlightingMode = this.lastEntireCardAttribute; |
||||||
|
} else { |
||||||
|
this.highlightingMode = mode; |
||||||
|
} |
||||||
|
|
||||||
|
if (['status', 'priority', 'type'].indexOf(this.highlightingMode) !== -1) { |
||||||
|
this.lastEntireCardAttribute = this.highlightingMode; |
||||||
|
this.entireCardMode = true; |
||||||
|
} else { |
||||||
|
this.entireCardMode = false; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
#-- copyright |
||||||
|
# OpenProject is a project management system. |
||||||
|
# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) |
||||||
|
# |
||||||
|
# This program is free software; you can redistribute it and/or |
||||||
|
# modify it under the terms of the GNU General Public License version 3. |
||||||
|
# |
||||||
|
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||||
|
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||||
|
# Copyright (C) 2010-2013 the ChiliProject Team |
||||||
|
# |
||||||
|
# This program is free software; you can redistribute it and/or |
||||||
|
# modify it under the terms of the GNU General Public License |
||||||
|
# as published by the Free Software Foundation; either version 2 |
||||||
|
# of the License, or (at your option) any later version. |
||||||
|
# |
||||||
|
# This program is distributed in the hope that it will be useful, |
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
# GNU General Public License for more details. |
||||||
|
# |
||||||
|
# You should have received a copy of the GNU General Public License |
||||||
|
# along with this program; if not, write to the Free Software |
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
# |
||||||
|
# See docs/COPYRIGHT.rdoc for more details. |
||||||
|
#++ |
||||||
|
|
||||||
|
require 'spec_helper' |
||||||
|
require_relative './support/board_index_page' |
||||||
|
require_relative './support/board_page' |
||||||
|
|
||||||
|
describe 'Work Package boards spec', type: :feature, js: true do |
||||||
|
let(:user) do |
||||||
|
FactoryBot.create(:user, |
||||||
|
member_in_project: project, |
||||||
|
member_through_role: role) |
||||||
|
end |
||||||
|
let(:project) { FactoryBot.create(:project, enabled_module_names: %i[work_package_tracking board_view]) } |
||||||
|
let(:permissions) { %i[show_board_views manage_board_views add_work_packages view_work_packages manage_public_queries] } |
||||||
|
let(:role) { FactoryBot.create(:role, permissions: permissions) } |
||||||
|
|
||||||
|
let!(:wp) do |
||||||
|
FactoryBot.create(:work_package, |
||||||
|
project: project, |
||||||
|
type: type, |
||||||
|
priority: priority, |
||||||
|
status: open_status) |
||||||
|
end |
||||||
|
let!(:wp2) do |
||||||
|
FactoryBot.create(:work_package, |
||||||
|
project: project, |
||||||
|
type: type2, |
||||||
|
priority: priority2, |
||||||
|
status: open_status) |
||||||
|
end |
||||||
|
|
||||||
|
let!(:priority) { FactoryBot.create :priority, color: color } |
||||||
|
let!(:priority2) { FactoryBot.create :priority, color: color2 } |
||||||
|
let!(:type) { FactoryBot.create :type, color: color } |
||||||
|
let!(:type2) { FactoryBot.create :type, color: color2 } |
||||||
|
let!(:open_status) { FactoryBot.create :default_status, name: 'Open' } |
||||||
|
|
||||||
|
let(:board_index) { Pages::BoardIndex.new(project) } |
||||||
|
|
||||||
|
let(:color) { FactoryBot.create :color } |
||||||
|
let(:color2) { FactoryBot.create :color } |
||||||
|
|
||||||
|
before do |
||||||
|
project |
||||||
|
login_as(user) |
||||||
|
end |
||||||
|
|
||||||
|
it 'navigates from boards to the WP full view and back' do |
||||||
|
board_index.visit! |
||||||
|
|
||||||
|
board_page = board_index.create_board action: :Status |
||||||
|
|
||||||
|
# See the work packages |
||||||
|
board_page.expect_query 'Open', editable: true |
||||||
|
board_page.expect_card 'Open', wp.subject |
||||||
|
board_page.expect_card 'Open', wp2.subject |
||||||
|
|
||||||
|
# Highlight inline |
||||||
|
board_page.change_board_highlighting 'inline' |
||||||
|
expect(page).to have_selector('.__hl_dot_type_' + type.id.to_s) |
||||||
|
expect(page).to have_selector('.__hl_dot_type_' + type2.id.to_s) |
||||||
|
|
||||||
|
# Highlight whole card by type |
||||||
|
board_page.change_board_highlighting 'entire-card', 'Type' |
||||||
|
expect(page).to have_selector('.__hl_row_type_' + type.id.to_s) |
||||||
|
expect(page).to have_selector('.__hl_row_type_' + type2.id.to_s) |
||||||
|
|
||||||
|
# Highlight whole card by priority |
||||||
|
board_page.change_board_highlighting 'entire-card', 'Priority' |
||||||
|
expect(page).to have_selector('.__hl_row_priority_' + priority.id.to_s) |
||||||
|
expect(page).to have_selector('.__hl_row_priority_' + priority2.id.to_s) |
||||||
|
|
||||||
|
# Disable highlighting |
||||||
|
board_page.change_board_highlighting 'none' |
||||||
|
expect(page).not_to have_selector('.__hl_row_priority_' + priority.id.to_s) |
||||||
|
expect(page).not_to have_selector('.__hl_row_priority_' + priority2.id.to_s) |
||||||
|
end |
||||||
|
end |
Loading…
Reference in new issue