mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
Merge remote-tracking branch 'origin/release/13.4' into dev
This commit is contained in:
@@ -77,7 +77,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
</label>
|
||||
<input type="submit" name="login" id="login-pulldown"
|
||||
value="<%=t(:button_login)%>" class="button -primary" tabindex="1" />
|
||||
value="<%=t(:button_login)%>" class="button -primary button_no-margin" tabindex="1" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -57,21 +57,24 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
<%= submit_tag t(:button_login),
|
||||
name: :login,
|
||||
class: 'button -primary',
|
||||
class: 'button -primary button_no-margin',
|
||||
data: { disable_with: t(:label_loading) } %>
|
||||
|
||||
<div class="login-options-container">
|
||||
<div class="login-links">
|
||||
<% if Setting.lost_password? %>
|
||||
<%= link_to t(:label_password_lost), { controller: '/account', action: 'lost_password' } %>
|
||||
<br>
|
||||
<% end %>
|
||||
<% if Setting::SelfRegistration.enabled? %>
|
||||
<%= link_to t(:label_register),
|
||||
'',
|
||||
title: t(:label_register),
|
||||
class: 'registration-modal--activation-link' %>
|
||||
<% end %>
|
||||
<div class="login-options-container">
|
||||
<div class="login-links">
|
||||
<% if Setting.lost_password? %>
|
||||
<%= link_to t(:label_password_lost),
|
||||
{ controller: '/account', action: 'lost_password' },
|
||||
class: 'login-form--footer-link' %>
|
||||
<br>
|
||||
<% end %>
|
||||
<% if Setting::SelfRegistration.enabled? %>
|
||||
<%= link_to t(:label_register),
|
||||
'',
|
||||
title: t(:label_register),
|
||||
class: 'login-form--footer-link registration-modal--activation-link' %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -384,17 +384,20 @@ en:
|
||||
learn_about: "Learn more about the new features"
|
||||
# Include the version to invalidate outdated translations in other locales.
|
||||
# Otherwise, e.g. chinese might still have the translations for 10.0 in the 12.0 release.
|
||||
"13_3":
|
||||
"13_4":
|
||||
standard:
|
||||
learn_about_link: https://www.openproject.org/blog/openproject-13-3-release/
|
||||
learn_about_link: https://www.openproject.org/blog/openproject-13-4-release/
|
||||
new_features_html: >
|
||||
The release contains various new features and improvements: <br>
|
||||
<ul class="%{list_styling_class}">
|
||||
<li>Filter and save custom project lists.</li>
|
||||
<li>Separate Gantt charts module with new default views.</li>
|
||||
<li>Automatically managed project folders for OneDrive/SharePoint integration.</li>
|
||||
<li>Show number of "Shared users" in the share button and display them in the work packages list.</li>
|
||||
<li>Improved calculations and updates for progress reporting for work package hierarchies.</li>
|
||||
<li>GitLab integration (originally developed by Community contributors)</li>
|
||||
<li>Advanced features for custom project lists</li>
|
||||
<li>Advanced features for the Meetings module</li>
|
||||
<li>Admins are nudged to go through OAuth flow when activating a storage</li>
|
||||
<li>Virus scanning functionality with ClamAV (Enterprise add-on)</li>
|
||||
<li>PDF Export: Lists in table cells are supported</li>
|
||||
<li>WebAuthn/FIDO/U2F is added as a second factor</li>
|
||||
<li>More languages added to the default available set</li>
|
||||
</ul>
|
||||
|
||||
ical_sharing_modal:
|
||||
|
||||
@@ -45,7 +45,7 @@ services:
|
||||
- "caddy_data:/data"
|
||||
|
||||
db:
|
||||
image: postgres:10
|
||||
image: postgres:13
|
||||
environment:
|
||||
POSTGRES_USER: app
|
||||
POSTGRES_PASSWORD: p4ssw0rd
|
||||
|
||||
@@ -26,11 +26,12 @@
|
||||
[searchFn]="customSearchFn"
|
||||
[virtualScroll]="false"
|
||||
(focus)="onFocus()"
|
||||
(blur)="onFocusOut()"
|
||||
(search)="search($event)"
|
||||
(close)="onClose()"
|
||||
(change)="followItem($event)"
|
||||
(keydown.enter)="onEnterBeforeResultsLoaded()"
|
||||
(keydown.escape)="blur()"
|
||||
(keydown.escape)="onFocusOut()"
|
||||
(clear)="clearSearch()"
|
||||
[filters]="autocompleterOptions.filters"
|
||||
[resource]="autocompleterOptions.resource"
|
||||
|
||||
@@ -251,6 +251,8 @@ export class GlobalSearchInputComponent implements AfterViewInit, OnDestroy {
|
||||
this.selectedItem = undefined;
|
||||
this.toggleTopMenuClass();
|
||||
}
|
||||
|
||||
(<HTMLInputElement>document.activeElement).blur();
|
||||
}
|
||||
|
||||
public onClose():void {
|
||||
@@ -467,11 +469,6 @@ export class GlobalSearchInputComponent implements AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
public blur():void {
|
||||
this.ngSelectComponent.ngSelectInstance.searchTerm = '';
|
||||
(<HTMLInputElement>document.activeElement).blur();
|
||||
}
|
||||
|
||||
private get currentScope():string {
|
||||
const serviceScope = this.globalSearchService.projectScope;
|
||||
return (serviceScope === '') ? 'current_project_and_all_descendants' : serviceScope;
|
||||
|
||||
@@ -35,10 +35,10 @@ import { imagePath } from 'core-app/shared/helpers/images/path-helper';
|
||||
export const homescreenNewFeaturesBlockSelector = 'homescreen-new-features-block';
|
||||
|
||||
// The key used in the I18n files to distinguish between versions.
|
||||
const OpVersionI18n = '13_3';
|
||||
const OpVersionI18n = '13_4';
|
||||
|
||||
/** Update the teaser image to the next version */
|
||||
const featureTeaserImage = '13_3_features.svg';
|
||||
const featureTeaserImage = '13_4_features.svg';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
|
||||
+2
-2
@@ -85,9 +85,9 @@ export class AddAssigneeComponent {
|
||||
.apiV3Service
|
||||
.principals
|
||||
.filtered(filters)
|
||||
.get()
|
||||
.getPaginatedResults()
|
||||
.pipe(
|
||||
map((collection) => collection.elements.filter(
|
||||
map((elements) => elements.filter(
|
||||
(user) => !this.alreadySelected.find((selected) => selected === user.id),
|
||||
)),
|
||||
);
|
||||
|
||||
+3
-1
@@ -82,6 +82,7 @@ import {
|
||||
import { HalResourceNotificationService } from 'core-app/features/hal/services/hal-resource-notification.service';
|
||||
import { SchemaCacheService } from 'core-app/core/schemas/schema-cache.service';
|
||||
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
|
||||
import { MAGIC_PAGE_NUMBER } from 'core-app/core/apiv3/helpers/get-paginated-results';
|
||||
import { CalendarDragDropService } from 'core-app/features/team-planner/team-planner/calendar-drag-drop.service';
|
||||
import { StatusResource } from 'core-app/features/hal/resources/status-resource';
|
||||
import { ResourceChangeset } from 'core-app/shared/components/fields/changeset/resource-changeset';
|
||||
@@ -223,7 +224,7 @@ export class TeamPlannerComponent extends UntilDestroyedMixin implements OnInit,
|
||||
|
||||
return this
|
||||
.capabilitiesResourceService
|
||||
.fetchCapabilities({ pageSize: -1, filters });
|
||||
.fetchCapabilities({ pageSize: MAGIC_PAGE_NUMBER, filters });
|
||||
}),
|
||||
map((result) => result
|
||||
._embedded
|
||||
@@ -250,6 +251,7 @@ export class TeamPlannerComponent extends UntilDestroyedMixin implements OnInit,
|
||||
filter((ids) => ids.length > 0),
|
||||
map((ids) => ({
|
||||
filters: [['id', '=', ids]],
|
||||
pageSize: MAGIC_PAGE_NUMBER,
|
||||
}) as ApiV3ListParameters),
|
||||
);
|
||||
|
||||
|
||||
+10
-1
@@ -8,4 +8,13 @@
|
||||
</widget-menu>
|
||||
</widget-header>
|
||||
|
||||
<op-wp-calendar [static]="true"></op-wp-calendar>
|
||||
<ng-container *ngIf="{hasCapability: hasCapability$ | async} as context">
|
||||
<div class="op-toast -error" *ngIf="context.hasCapability === false">
|
||||
<span [textContent]="text.missing_permission"></span>
|
||||
</div>
|
||||
|
||||
<op-wp-calendar
|
||||
*ngIf="context.hasCapability === true"
|
||||
[static]="true"
|
||||
></op-wp-calendar>
|
||||
</ng-container>
|
||||
|
||||
+13
-3
@@ -33,6 +33,7 @@ import { CurrentProjectService } from 'core-app/core/current-project/current-pro
|
||||
import {
|
||||
WorkPackageIsolatedQuerySpaceDirective,
|
||||
} from 'core-app/features/work-packages/directives/query-space/wp-isolated-query-space.directive';
|
||||
import { CurrentUserService } from 'core-app/core/current-user/current-user.service';
|
||||
|
||||
@Component({
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
@@ -40,10 +41,19 @@ import {
|
||||
hostDirectives: [WorkPackageIsolatedQuerySpaceDirective],
|
||||
})
|
||||
export class WidgetWpCalendarComponent extends AbstractWidgetComponent {
|
||||
constructor(protected readonly i18n:I18nService,
|
||||
text = {
|
||||
missing_permission: this.I18n.t('js.grid.widgets.missing_permission'),
|
||||
};
|
||||
|
||||
hasCapability$ = this.currentUser.hasCapabilities$('work_packages/read', this.currentProject.id);
|
||||
|
||||
constructor(
|
||||
protected readonly I18n:I18nService,
|
||||
protected readonly injector:Injector,
|
||||
protected readonly currentProject:CurrentProjectService) {
|
||||
super(i18n, injector);
|
||||
protected readonly currentProject:CurrentProjectService,
|
||||
protected readonly currentUser:CurrentUserService,
|
||||
) {
|
||||
super(I18n, injector);
|
||||
}
|
||||
|
||||
public get projectIdentifier() {
|
||||
|
||||
+12
-2
@@ -33,8 +33,10 @@ import {
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
|
||||
@@ -60,7 +62,7 @@ import SpotDropAlignmentOption from 'core-app/spot/drop-alignment-options';
|
||||
templateUrl: './file-link-list-item.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FileLinkListItemComponent implements OnInit, AfterViewInit {
|
||||
export class FileLinkListItemComponent implements OnInit, OnChanges, AfterViewInit {
|
||||
@Input() public fileLink:IFileLink;
|
||||
|
||||
@Input() public allowEditing = false;
|
||||
@@ -132,8 +134,16 @@ export class FileLinkListItemComponent implements OnInit, AfterViewInit {
|
||||
'js.storages.file_links.download',
|
||||
{ fileName: this.fileLink.originData.name },
|
||||
);
|
||||
}
|
||||
|
||||
this.floatingActions = this.getFloatingActions();
|
||||
// Before, the getFloatingActions() method was called in the ngOnInit() method.
|
||||
// The value of the allowEditing property can be calculated after the component is already initialized (in fact it is determined
|
||||
// asynchronously, by getting a value from the server in a separate request). Therefore, the available actions need
|
||||
// to be calculated whenever the value is set.
|
||||
ngOnChanges(changes:SimpleChanges):void {
|
||||
if (changes.allowEditing) {
|
||||
this.floatingActions = this.getFloatingActions();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit():void {
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 15 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 15 KiB |
@@ -28,16 +28,14 @@
|
||||
|
||||
#login-form
|
||||
margin: 50px auto 0
|
||||
padding-top: 20px
|
||||
padding: 20px
|
||||
width: 511px
|
||||
word-break: break-word
|
||||
|
||||
.login-options-container
|
||||
.login-form--footer
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
margin-bottom: 10px
|
||||
.login-links
|
||||
float: right
|
||||
text-align: right
|
||||
margin-top: -3rem
|
||||
|
||||
#content .login-auth-providers.wide
|
||||
width: auto
|
||||
@@ -63,13 +61,9 @@
|
||||
margin-top: 25px
|
||||
|
||||
h3
|
||||
border: none
|
||||
margin-top: 20px
|
||||
font-weight: normal
|
||||
font-size: 1rem
|
||||
text-decoration: none
|
||||
text-align: center
|
||||
|
||||
position: relative
|
||||
z-index: 1
|
||||
|
||||
@@ -101,24 +95,11 @@
|
||||
@include prevent-float-collapse
|
||||
margin-top: 1em
|
||||
|
||||
a.auth-provider
|
||||
float: left
|
||||
margin-left: 10px
|
||||
background-color: light-grey
|
||||
font-weight: normal
|
||||
color: var(--body-font-color)
|
||||
|
||||
&:hover
|
||||
text-decoration: none
|
||||
|
||||
.auth-provider-name
|
||||
line-height: normal
|
||||
white-space: normal
|
||||
a.auth-provider:hover
|
||||
text-decoration: none
|
||||
|
||||
#nav-login-content .login-auth-providers
|
||||
h3
|
||||
&:before
|
||||
width: 100%
|
||||
span
|
||||
background: var(--header-drop-down-bg-color)
|
||||
.login-auth-provider-list
|
||||
|
||||
@@ -32,31 +32,23 @@
|
||||
#nav-login-content .login-auth-providers
|
||||
width: 100%
|
||||
|
||||
#content .login-auth-providers
|
||||
margin-top: 114px
|
||||
|
||||
h3:before
|
||||
top: -14px
|
||||
|
||||
#login-form
|
||||
.form--field-container
|
||||
@include grid-content(12)
|
||||
padding: 0
|
||||
margin: 0
|
||||
|
||||
.login-options-container
|
||||
position: relative
|
||||
.login-form--footer
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
|
||||
.login-links
|
||||
float: none
|
||||
position: absolute
|
||||
text-align: center
|
||||
width: 100%
|
||||
margin-top: 0
|
||||
|
||||
a
|
||||
display: block
|
||||
.login-form--footer-link
|
||||
display: inline-block
|
||||
margin-top: 15px
|
||||
|
||||
.button
|
||||
margin-right: 0
|
||||
margin-left: 0
|
||||
width: 100%
|
||||
|
||||
#new_user
|
||||
|
||||
@@ -54,42 +54,14 @@
|
||||
.mobile-otp-new-device--body
|
||||
flex: 1
|
||||
|
||||
#login-form input[type=radio]
|
||||
float: left
|
||||
|
||||
#resend_otp_container
|
||||
margin-top: 30px
|
||||
|
||||
#resend_otp_container input[type=radio]
|
||||
margin-right: 8px
|
||||
|
||||
#resend_otp_container label
|
||||
margin-right: 10px
|
||||
|
||||
#resend_otp_container .resend-header
|
||||
font-size: 14px
|
||||
font-weight: var(--base-text-weight-bold)
|
||||
margin-bottom: 10px
|
||||
|
||||
#resend_otp_container .radios-wrapper
|
||||
padding-top: 7px
|
||||
float: left
|
||||
border: none
|
||||
overflow: hidden
|
||||
clear: none
|
||||
|
||||
|
||||
#resend_otp_container .radios-wrapper label
|
||||
float: left
|
||||
clear: none
|
||||
display: block
|
||||
padding: 2px 1em 0 0
|
||||
|
||||
|
||||
#resend_otp_container .radios-wrapper input[type=radio]
|
||||
float: left
|
||||
clear: none
|
||||
margin: 2px 0 15px 2px
|
||||
|
||||
// Add some paddings to action links
|
||||
.mobile-otp--two-factor-device-row td.buttons
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
//++
|
||||
|
||||
.op-table-baseline--old-field
|
||||
// Hide status bubbles in old values
|
||||
&[class^=__hl_inline_status]:before
|
||||
// Hide highlighting bubbles in old values
|
||||
&[class^=__hl_inline_]:before
|
||||
display: none
|
||||
|
||||
// Hide avatars in old values
|
||||
|
||||
@@ -4,3 +4,5 @@
|
||||
margin-top: 1rem
|
||||
width: 511px
|
||||
|
||||
@media screen and (max-width: $breakpoint-sm)
|
||||
width: 100%
|
||||
|
||||
@@ -8,6 +8,7 @@ en:
|
||||
text: "Some widgets, like the work package graph widget, are only available in the Enterprise edition."
|
||||
link: 'Enterprise edition.'
|
||||
widgets:
|
||||
missing_permission: "You don't have the necessary permissions to view this widget."
|
||||
custom_text:
|
||||
title: 'Custom text'
|
||||
documents:
|
||||
|
||||
@@ -129,7 +129,7 @@ RSpec.describe 'Managing file links in work package', :js, :webmock do
|
||||
end
|
||||
|
||||
it 'must enable the user to remove a file link' do
|
||||
within_test_selector('op-tab-content--tab-section', text: 'MY STORAGE', wait: 25) do
|
||||
within_test_selector('op-tab-content--tab-section', text: 'MY STORAGE') do
|
||||
within(:list_item, text: 'jingle.ogg') do
|
||||
page.find('span', text: 'jingle.ogg').hover
|
||||
page.click_on('Remove file link')
|
||||
|
||||
@@ -43,9 +43,7 @@ RSpec.describe 'Work package table context menu',
|
||||
team_planner.visit!
|
||||
loading_indicator_saveguard
|
||||
|
||||
retry_block do
|
||||
team_planner.add_assignee user
|
||||
end
|
||||
team_planner.add_assignee user
|
||||
|
||||
team_planner.within_lane(user) do
|
||||
team_planner.expect_event work_package
|
||||
|
||||
@@ -77,11 +77,7 @@ RSpec.describe 'Team planner create new work package', :js, with_ee: %i[team_pla
|
||||
|
||||
team_planner.expect_assignee(user, present: false)
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add user.name
|
||||
end
|
||||
team_planner.add_assignee user.name
|
||||
end
|
||||
|
||||
it_behaves_like 'can create a new work package'
|
||||
@@ -119,23 +115,9 @@ RSpec.describe 'Team planner create new work package', :js, with_ee: %i[team_pla
|
||||
team_planner.expect_assignee(other_user, present: false)
|
||||
team_planner.expect_assignee(third_user, present: false)
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add other_user.name
|
||||
end
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add third_user.name
|
||||
end
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add user.name
|
||||
end
|
||||
team_planner.add_assignee other_user.name
|
||||
team_planner.add_assignee third_user.name
|
||||
team_planner.add_assignee user.name
|
||||
end
|
||||
|
||||
it_behaves_like 'can create a new work package'
|
||||
|
||||
@@ -41,11 +41,7 @@ RSpec.describe 'Team planner working days', :js,
|
||||
team_planner.visit!
|
||||
|
||||
team_planner.expect_empty_state
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add user.name
|
||||
end
|
||||
team_planner.add_assignee user.name
|
||||
|
||||
# Initially, in the "Work week" view, non working days are hidden
|
||||
expect(page).to have_css('.fc-day-mon')
|
||||
|
||||
@@ -56,15 +56,11 @@ RSpec.describe 'Team planner project include', :js, with_ee: %i[team_planner_vie
|
||||
work_package_view.expect_assignee(other_user, present: false)
|
||||
|
||||
retry_block do
|
||||
work_package_view.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
work_package_view.select_user_to_add user.name
|
||||
work_package_view.add_assignee user.name
|
||||
end
|
||||
|
||||
retry_block do
|
||||
work_package_view.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
work_package_view.select_user_to_add other_user.name
|
||||
work_package_view.add_assignee other_user.name
|
||||
end
|
||||
|
||||
work_package_view.expect_assignee user
|
||||
|
||||
@@ -155,19 +155,11 @@ RSpec.describe 'Team planner',
|
||||
team_planner.expect_assignee(user, present: false)
|
||||
team_planner.expect_assignee(other_user, present: false)
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add user.name
|
||||
end
|
||||
team_planner.add_assignee user.name
|
||||
|
||||
team_planner.expect_empty_state(present: false)
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add other_user.name
|
||||
end
|
||||
team_planner.add_assignee other_user.name
|
||||
|
||||
team_planner.expect_assignee user
|
||||
team_planner.expect_assignee other_user
|
||||
@@ -249,21 +241,13 @@ RSpec.describe 'Team planner',
|
||||
team_planner.expect_assignee(user, present: false)
|
||||
team_planner.expect_assignee(other_user, present: false)
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add user.name
|
||||
end
|
||||
team_planner.add_assignee user.name
|
||||
|
||||
team_planner.expect_empty_state(present: false)
|
||||
team_planner.expect_assignee(user)
|
||||
team_planner.expect_assignee(other_user, present: false)
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add other_user.name
|
||||
end
|
||||
team_planner.add_assignee other_user.name
|
||||
|
||||
team_planner.expect_assignee(user)
|
||||
team_planner.expect_assignee(other_user)
|
||||
@@ -280,11 +264,7 @@ RSpec.describe 'Team planner',
|
||||
team_planner.expect_empty_state
|
||||
|
||||
# Try one more time to make sure deleting the full filter didn't kill the functionality
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add user.name
|
||||
end
|
||||
team_planner.add_assignee user.name
|
||||
|
||||
team_planner.expect_assignee(user)
|
||||
team_planner.expect_assignee(other_user, present: false)
|
||||
@@ -293,11 +273,7 @@ RSpec.describe 'Team planner',
|
||||
it 'filters possible assignees correctly' do
|
||||
team_planner.visit!
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.search_user_to_add user_outside_project.name
|
||||
end
|
||||
team_planner.search_assignee(user_outside_project.name)
|
||||
|
||||
expect(page).to have_css('.ng-option-disabled', text: "No items found")
|
||||
|
||||
@@ -307,14 +283,45 @@ RSpec.describe 'Team planner',
|
||||
|
||||
team_planner.expect_assignee(user)
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.search_user_to_add user.name
|
||||
end
|
||||
team_planner.search_assignee user.name
|
||||
|
||||
expect(page).to have_css('.ng-option-disabled', text: "No items found")
|
||||
end
|
||||
|
||||
context 'when the page size is smaller than the number of assignees' do
|
||||
before do
|
||||
allow(Setting)
|
||||
.to receive(:per_page_options_array)
|
||||
.and_return([1])
|
||||
end
|
||||
|
||||
it 'renders assignees and assignee dropdown correctly' do
|
||||
team_planner.visit!
|
||||
team_planner.wait_for_loaded
|
||||
|
||||
# Render all the available users in the select dropdown regardless of the page size
|
||||
team_planner.click_add_user
|
||||
|
||||
team_planner.expect_user_selectable user
|
||||
team_planner.expect_user_selectable other_user
|
||||
|
||||
team_planner.add_assignee user
|
||||
team_planner.add_assignee other_user
|
||||
|
||||
team_planner.save_as('TP1')
|
||||
page.refresh
|
||||
team_planner.wait_for_loaded
|
||||
|
||||
# Render all the available users in the team planner regardless of the page size
|
||||
team_planner.expect_assignee user
|
||||
team_planner.expect_assignee other_user
|
||||
|
||||
# Do not render any available users in the select
|
||||
team_planner.click_add_user
|
||||
team_planner.expect_user_selectable user, present: false
|
||||
team_planner.expect_user_selectable other_user, present: false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a readonly work package' do
|
||||
@@ -337,11 +344,7 @@ RSpec.describe 'Team planner',
|
||||
team_planner.expect_empty_state
|
||||
team_planner.expect_assignee(user, present: false)
|
||||
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add user.name
|
||||
end
|
||||
team_planner.add_assignee user.name
|
||||
|
||||
team_planner.expect_empty_state(present: false)
|
||||
team_planner.expect_assignee user
|
||||
|
||||
@@ -58,9 +58,7 @@ RSpec.describe 'Team planner constraints for a subproject',
|
||||
team_planner.visit!
|
||||
|
||||
team_planner.add_assignee user
|
||||
retry_block do
|
||||
team_planner.add_assignee other_user
|
||||
end
|
||||
team_planner.add_assignee other_user
|
||||
|
||||
# Include the subproject
|
||||
project_include.toggle!
|
||||
|
||||
@@ -79,9 +79,7 @@ RSpec.describe 'Team planner drag&dop and resizing',
|
||||
team_planner.visit!
|
||||
|
||||
team_planner.add_assignee user
|
||||
retry_block do
|
||||
team_planner.add_assignee other_user
|
||||
end
|
||||
team_planner.add_assignee other_user
|
||||
|
||||
team_planner.within_lane(user) do
|
||||
team_planner.expect_event first_wp, present: false
|
||||
@@ -247,9 +245,7 @@ RSpec.describe 'Team planner drag&dop and resizing',
|
||||
team_planner.visit!
|
||||
|
||||
team_planner.add_assignee user
|
||||
retry_block do
|
||||
team_planner.add_assignee other_user
|
||||
end
|
||||
team_planner.add_assignee other_user
|
||||
end
|
||||
|
||||
it 'allows neither dragging nor resizing any wp' do
|
||||
|
||||
@@ -36,11 +36,7 @@ RSpec.describe 'Team planner', :js, with_ee: %i[team_planner_view] do
|
||||
team_planner.visit!
|
||||
|
||||
team_planner.expect_empty_state
|
||||
retry_block do
|
||||
team_planner.click_add_user
|
||||
page.find("#{test_selector('tp-add-assignee')} input")
|
||||
team_planner.select_user_to_add user.name
|
||||
end
|
||||
team_planner.add_assignee user.name
|
||||
|
||||
team_planner.expect_view_mode 'Work week'
|
||||
expect(page).to have_css('.fc-timeline-slot-frame', count: 5)
|
||||
|
||||
@@ -225,9 +225,23 @@ module Pages
|
||||
end
|
||||
|
||||
def add_assignee(name)
|
||||
click_add_user
|
||||
page.find("#{page.test_selector('tp-add-assignee')} input")
|
||||
select_user_to_add name
|
||||
retry_block do
|
||||
return if page.has_selector?('.fc-resource', text: name, wait: 0)
|
||||
|
||||
click_add_user
|
||||
page.find("#{page.test_selector('tp-add-assignee')} input")
|
||||
select_user_to_add(name)
|
||||
end
|
||||
end
|
||||
|
||||
def search_assignee(name)
|
||||
retry_block do
|
||||
click_add_user
|
||||
page.find("#{page.test_selector('tp-add-assignee')} input")
|
||||
search_autocomplete page.find('[data-test-selector="tp-add-assignee"]'),
|
||||
query: name,
|
||||
results_selector: 'body'
|
||||
end
|
||||
end
|
||||
|
||||
def click_add_user
|
||||
@@ -243,10 +257,13 @@ module Pages
|
||||
results_selector: 'body'
|
||||
end
|
||||
|
||||
def search_user_to_add(name)
|
||||
search_autocomplete page.find('[data-test-selector="tp-add-assignee"]'),
|
||||
query: name,
|
||||
results_selector: 'body'
|
||||
def expect_user_selectable(user, present: true)
|
||||
name = user.is_a?(User) ? user.name : user.to_s
|
||||
|
||||
expect_ng_option page.find('[data-test-selector="tp-add-assignee"]'),
|
||||
name,
|
||||
results_selector: 'body',
|
||||
present:
|
||||
end
|
||||
|
||||
def change_wp_date_by_resizing(work_package, number_of_days:, is_start_date:)
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@
|
||||
<%= styled_text_field_tag 'backup_code', nil, required: true, autocomplete: 'off', size: 20, maxlength: 20, tabindex: 1, autofocus: true %>
|
||||
</div>
|
||||
</div>
|
||||
<input type="submit" name="login" value="<%=t(:button_submit)%>" class="button -primary" tabindex="2" />
|
||||
|
||||
<input type="submit" name="login" value="<%=t(:button_submit)%>" class="button -primary button_no-margin" tabindex="2" />
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+19
-10
@@ -43,7 +43,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<% end %>
|
||||
<input type="submit" name="login" value="<%= t(:button_login) %>" class="button -primary" tabindex="2"/>
|
||||
<input type="submit" name="login" value="<%= t(:button_login) %>" class="button -primary button_no-margin" tabindex="2"/>
|
||||
<% if resend_supported || has_other_devices || has_backup_codes %>
|
||||
<div class="login-options-container">
|
||||
<div class="login-links">
|
||||
@@ -68,15 +68,23 @@
|
||||
<%= hidden_field_tag 'use_device', @service.device.id %>
|
||||
<hr/>
|
||||
<div class="resend-header"><%= t(:text_send_otp_again) %></div>
|
||||
<div class="radios-wrapper">
|
||||
<% default_channel = @service.device.channel %>
|
||||
<% supported_channels = @used_device.class.supported_channels & @strategy.class.supported_channels %>
|
||||
<% supported_channels.each do |channel| %>
|
||||
|
||||
<% default_channel = @service.device.channel %>
|
||||
<% supported_channels = @used_device.class.supported_channels & @strategy.class.supported_channels %>
|
||||
<% supported_channels.each do |channel| %>
|
||||
<div class="form--field">
|
||||
<%= radio_button_tag 'use_channel', channel, default_channel == channel %>
|
||||
<label for="channel_<%= channel %>"><%= t("button_otp_by_#{channel}") %></label>
|
||||
<<<<<<< HEAD
|
||||
<% end %>
|
||||
</div>
|
||||
<input type="submit" value="<%= t(:button_resend_otp_form) %>" id="submit_resend_form" class="button -primary"/>
|
||||
=======
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<input type="submit" value="<%= t(:button_resend_otp_form) %>" id="submit_resend_form" class="button -highlight"/>
|
||||
>>>>>>> origin/release/13.4
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if has_other_devices %>
|
||||
@@ -95,12 +103,13 @@
|
||||
</ul>
|
||||
<% end %>
|
||||
<% if has_backup_codes %>
|
||||
<hr/>
|
||||
<div class="resend-header"><%= t('two_factor_authentication.login.enter_backup_code_title') %></div>
|
||||
<ul>
|
||||
<li>
|
||||
<%= link_to(t('two_factor_authentication.login.enter_backup_code_title'), { action: :enter_backup_code }) %>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -14,6 +14,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<input type="submit" name="login" value="<%= t 'button_continue' %>" class="button -primary" tabindex="2" />
|
||||
<input type="submit" name="login" value="<%= t 'button_continue' %>" class="button -primary button_no-margin" tabindex="2" />
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -45,9 +45,9 @@ module Components::Autocompleter
|
||||
end
|
||||
end
|
||||
|
||||
def expect_ng_option(element, option, results_selector: nil)
|
||||
def expect_ng_option(element, option, results_selector: nil, present: true)
|
||||
within(ng_find_dropdown(element, results_selector:)) do
|
||||
expect(page).to have_css('.ng-option', text: option)
|
||||
expect(page).to have_conditional_selector(present, '.ng-option', text: option)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user