Merge branch 'dev' into 45001-component-to-show-the-list-of-non-working-days-of-year

45001-component-to-show-the-list-of-non-working-days-of-year
bsatarnejad 2 years ago
commit e6e5028481
  1. 2
      Gemfile
  2. 14
      Gemfile.lock
  3. 8
      docs/system-admin-guide/authentication/saml/README.md
  4. 12
      frontend/package-lock.json
  5. 25
      frontend/src/app/features/work-packages/components/wp-form-group/wp-attribute-group.component.sass
  6. 48
      frontend/src/app/features/work-packages/components/wp-form-group/wp-attribute-group.component.ts
  7. 57
      frontend/src/app/features/work-packages/components/wp-form-group/wp-attribute-group.template.html
  8. 15
      frontend/src/app/features/work-packages/components/wp-single-view/wp-single-view.html
  9. 1
      frontend/src/app/shared/components/fields/edit/field/editable-attribute-field.component.ts
  10. 15
      frontend/src/global_styles/content/work_packages/single_view/_single_view.sass
  11. 24
      modules/two_factor_authentication/spec/lib/token_strategies/message_bird_spec.rb
  12. 6
      spec/features/work_packages/timeline/timeline_dates_spec.rb
  13. 11
      spec/support/multi_json_issue_workaround.rb

@ -174,8 +174,8 @@ gem 'sprockets', '~> 3.7.2' # lock sprockets below 4.0
gem 'sprockets-rails', '~> 3.4.2'
gem 'puma', '~> 5.6'
gem 'rack-timeout', '~> 0.6.3', require: "rack/timeout/base"
gem 'puma-plugin-statsd', '~> 2.0'
gem 'rack-timeout', '~> 0.6.3', require: "rack/timeout/base"
gem 'nokogiri', '~> 1.13.9'

@ -291,7 +291,7 @@ GEM
awesome_nested_set (3.5.0)
activerecord (>= 4.0.0, < 7.1)
aws-eventstream (1.2.0)
aws-partitions (1.665.0)
aws-partitions (1.666.0)
aws-sdk-core (3.168.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
@ -424,7 +424,7 @@ GEM
concurrent-ruby (~> 1.0)
zeitwerk (~> 2.6)
dry-inflector (1.0.0)
dry-logic (1.4.0)
dry-logic (1.5.0)
concurrent-ruby (~> 1.0)
dry-core (~> 1.0, < 2)
zeitwerk (~> 2.6)
@ -563,7 +563,7 @@ GEM
ice_cube (0.16.4)
interception (0.5)
iso8601 (0.13.0)
jmespath (1.6.1)
jmespath (1.6.2)
json (2.6.2)
json-jwt (1.15.3)
activesupport (>= 4.2)
@ -676,7 +676,7 @@ GEM
parallel (1.22.1)
parallel_tests (4.0.0)
parallel
parser (3.1.2.1)
parser (3.1.3.0)
ast (~> 2.4.1)
pdf-core (0.9.0)
pdf-inspector (1.3.0)
@ -729,7 +729,7 @@ GEM
multi_json
puma (5.6.5)
nio4r (~> 2.0)
puma-plugin-statsd (2.2.0)
puma-plugin-statsd (2.3.0)
puma (>= 5.0, < 6)
raabro (1.4.0)
racc (1.6.0)
@ -748,7 +748,7 @@ GEM
httpclient
json-jwt (>= 1.11.0)
rack (>= 2.1.0)
rack-protection (3.0.3)
rack-protection (3.0.4)
rack
rack-test (2.0.2)
rack (>= 1.3)
@ -924,7 +924,7 @@ GEM
activesupport (>= 5.2)
sprockets (>= 3.0.0)
ssrf_filter (1.1.1)
stackprof (0.2.22)
stackprof (0.2.23)
stringex (2.8.5)
stringio (3.0.2)
structured_warnings (0.4.0)

@ -229,8 +229,6 @@ default:
Be sure to choose the correct indentation and base key. The items below the `saml` key should be indented two spaces more than `saml` already is. And `saml` can will need to be placed in the `default` or `production` group so it will already be indented. You will get an YAML parsing error otherwise when trying to start OpenProject.
####
### 2. Configuration details
In this section, we detail some of the required and optional configuration options for SAML.
@ -493,11 +491,11 @@ In Keycloak, use the following steps to set up a SAML integration OpenProject:
You will be forwarded to the settings tab of the new client. Change these settings:
- Enable **Sign Documents**
- **Master SAML Processing URL**: Set to ``https://<Your OpenProject hostname>/auth/saml`
- **Master SAML Processing URL**: Set to `https://<Your OpenProject hostname>/auth/saml`
- **Name ID Format** Set to username
- Expand section "Fine Grain SAML Endpoint Configuration"
- **Assertion Consumer Service POST Binding URL**: Set to ``https://<Your OpenProject hostname>/auth/saml/callback`
- **Assertion Consumer Service Redirect Binding URL**: Set to ``https://<Your OpenProject hostname>/auth/saml/callback`
- **Assertion Consumer Service POST Binding URL**: Set to `https://<Your OpenProject hostname>/auth/saml/callback`
- **Assertion Consumer Service Redirect Binding URL**: Set to `https://<Your OpenProject hostname>/auth/saml/callback`
Go the "Mappers" tab and create the following mappers. Note that the "User attribute" values might differ depending on your LDAP or Keycloak configuration.

@ -45523,9 +45523,9 @@
}
},
"@angular/core": {
"version": "12.2.6",
"resolved": "https://registry.npmjs.org/@angular/core/-/core-12.2.6.tgz",
"integrity": "sha512-yM64SrhKbuw1/9uepz98C7H7yPK1yUc8ni0lsPmMf2JYD850xxya9+fTTc4b/FmotHHadOeRkX1H+Wd3Ylu1Gw==",
"version": "12.2.17",
"resolved": "https://registry.npmjs.org/@angular/core/-/core-12.2.17.tgz",
"integrity": "sha512-XUvTgU0D8XqNH5Y7UlTMk/XjUQaEGC0kZxhw/QSSQr65WrXtXmcD4d8Cg84TJ52uGXmf7IAruKvtbvu1Mbmvug==",
"requires": {
"tslib": "^2.2.0"
}
@ -45561,9 +45561,9 @@
}
},
"@angular/router": {
"version": "12.2.14",
"resolved": "https://registry.npmjs.org/@angular/router/-/router-12.2.14.tgz",
"integrity": "sha512-yP5grSnqBvc4vNhtYdcxDgDYIebUKs5f0xyFkUJM5030UnQ0CV45tBsSxHMkQbPZucIfOuxpRy8xy5+4GizuwQ==",
"version": "12.2.17",
"resolved": "https://registry.npmjs.org/@angular/router/-/router-12.2.17.tgz",
"integrity": "sha512-GKvEMUpLe157izpHLiS4bCZllqOj+MWhfWbhvR0DHFpE9FtkcDjBseTsWqQmyA1gqtRblO1Zn/1E33l9uaGMqw==",
"requires": {
"tslib": "^2.2.0"
}

@ -0,0 +1,25 @@
@import "src/assets/sass/helpers"
.wp-attribute-group
display: flex
flex-direction: row
flex-wrap: wrap
// We want a margin between items, but don't know if any one item is on the right,
// the left, or spanning both columns. The easy way to get a gutter is to give
// *all* elements margins on both sides, and then negating this margin on the parent.
// This also explains all of the + and - xrem calc() values below.
margin: 0 -1 * $spot-spacing-1_5
width: calc(100% + #{$spot-spacing-3})
&--attribute
flex-basis: calc(100% - #{$spot-spacing-3})
flex-grow: 0
flex-shrink: 0
margin: 0 $spot-spacing-1_5
@media screen and (min-width: 92rem), print
flex-basis: calc(50% - #{$spot-spacing-3})
&_span-all
flex-basis: calc(100% - #{$spot-spacing-3})

@ -27,14 +27,16 @@
//++
import {
Component, Injector, Input, AfterViewInit,
Component,
HostBinding,
Injector,
Input,
ViewEncapsulation,
} from '@angular/core';
import { I18nService } from 'core-app/core/i18n/i18n.service';
import { WorkPackageResource } from 'core-app/features/hal/resources/work-package-resource';
import { EditFormComponent } from 'core-app/shared/components/fields/edit/edit-form/edit-form.component';
import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import {
FieldDescriptor,
GroupDescriptor,
@ -43,8 +45,12 @@ import {
@Component({
selector: 'wp-attribute-group',
templateUrl: './wp-attribute-group.template.html',
styleUrls: ['./wp-attribute-group.component.sass'],
encapsulation: ViewEncapsulation.None,
})
export class WorkPackageFormAttributeGroupComponent extends UntilDestroyedMixin implements AfterViewInit {
export class WorkPackageFormAttributeGroupComponent extends UntilDestroyedMixin {
@HostBinding('class.wp-attribute-group') className = true;
@Input() public workPackage:WorkPackageResource;
@Input() public group:GroupDescriptor;
@ -55,20 +61,6 @@ export class WorkPackageFormAttributeGroupComponent extends UntilDestroyedMixin
super();
}
ngAfterViewInit() {
setTimeout(() => this.fixColumns());
// Listen to resize event and fix column start again
fromEvent(window, 'resize', { passive: true })
.pipe(
this.untilDestroyed(),
debounceTime(250),
)
.subscribe(() => {
this.fixColumns();
});
}
public trackByName(_index:number, elem:{ name:string }) {
return elem.name;
}
@ -88,24 +80,4 @@ export class WorkPackageFormAttributeGroupComponent extends UntilDestroyedMixin
}
return name;
}
/**
* Fix the top of the columns after view has been loaded
* to prevent columns from repositioning (e.g. when editing multi-select fields)
*/
private fixColumns() {
let lastOffset = 0;
// Find corresponding HTML of attribute fields for each group
const htmlAttributes = jQuery(`div.attributes-group:contains(${this.group.name})`).find('.attributes-key-value');
htmlAttributes.each(function () {
const offset = jQuery(this).position().top;
if (offset < lastOffset) {
// Fix position of the column start
jQuery(this).addClass('-column-start');
}
lastOffset = offset;
});
}
}

@ -1,27 +1,32 @@
<div class="-columns-2">
<div class="attributes-key-value"
[ngClass]="{'-span-all-columns': descriptor.spanAll }"
*ngFor="let descriptor of group.members; trackBy:trackByName">
<ng-template [ngIf]="!shouldHideField(descriptor)">
<div
class="attributes-key-value--key"
*ngIf="!descriptor.multiple && descriptor.field">
<wp-replacement-label [fieldName]="descriptor.name">
{{ descriptor.label }}
<span class="required"
*ngIf="descriptor.field!.required && descriptor.field!.writable"> *</span>
</wp-replacement-label>
<attribute-help-text [attribute]="descriptor.name" [attributeScope]="'WorkPackage'"></attribute-help-text>
</div>
<div *ngIf="!descriptor.multiple && descriptor.field"
class="attributes-key-value--value-container">
<op-editable-attribute-field [ngClass]="{'wp-edit-formattable-field': descriptor.field!.isFormattable }"
[resource]="workPackage"
[isDropTarget]="descriptor.field!.isFormattable"
[fieldName]="fieldName(descriptor.name)">
</op-editable-attribute-field>
</div>
</ng-template>
</div>
<div
class="wp-attribute-group--attribute attributes-key-value"
[ngClass]="{'wp-attribute-group--attribute_span-all': descriptor.spanAll }"
*ngFor="let descriptor of group.members; trackBy:trackByName"
>
<ng-template [ngIf]="!shouldHideField(descriptor)">
<div
class="attributes-key-value--key"
*ngIf="!descriptor.multiple && descriptor.field"
>
<wp-replacement-label [fieldName]="descriptor.name">
{{ descriptor.label }}
<span
class="required"
*ngIf="descriptor.field!.required && descriptor.field!.writable"
> *</span>
</wp-replacement-label>
<attribute-help-text [attribute]="descriptor.name" [attributeScope]="'WorkPackage'"></attribute-help-text>
</div>
<div
*ngIf="!descriptor.multiple && descriptor.field"
class="attributes-key-value--value-container"
>
<op-editable-attribute-field
[ngClass]="{'wp-edit-formattable-field': descriptor.field!.isFormattable }"
[resource]="workPackage"
[isDropTarget]="descriptor.field!.isFormattable"
[fieldName]="fieldName(descriptor.name)"
></op-editable-attribute-field>
</div>
</ng-template>
</div>

@ -93,13 +93,14 @@
</div>
</div>
<div *ngFor="let group of groupedFields; trackBy:trackByName"
[hidden]="shouldHideGroup(group)"
[attr.data-group-name]="group.name"
[ngClass]="'__overflowing_' + group.id"
[attr.data-overflowing-identifier]="'.__overflowing_' + group.id"
class="attributes-group __overflowing_element_container">
<div
*ngFor="let group of groupedFields; trackBy:trackByName"
[hidden]="shouldHideGroup(group)"
[attr.data-group-name]="group.name"
[ngClass]="'__overflowing_' + group.id"
[attr.data-overflowing-identifier]="'.__overflowing_' + group.id"
class="attributes-group __overflowing_element_container"
>
<ng-container wp-isolated-query-space *ngIf="group.isolated">
<ndc-dynamic [ndcDynamicComponent]="attributeGroupComponent(group)"
[ndcDynamicInputs]="{ workPackage: workPackage,

@ -194,6 +194,7 @@ export class EditableAttributeFieldComponent extends UntilDestroyedMixin impleme
public handleUserActivate(evt:MouseEvent|KeyboardEvent|null):boolean {
let positionOffset = 0;
// This can be both a direct click as well as a "click" via keyboard, e.g. the <Enter> key.
if (evt?.type === 'click') {
// Get the position where the user clicked.
positionOffset = getPosition(evt);

@ -80,21 +80,6 @@
textarea
resize: vertical
// Implement two column layout for WP full screen view
&_with-columns
@media screen and (min-width: 92rem), print
.-columns-2
@include two-column-layout
@supports (column-span: all)
// Remove the outline on focus since that breaks the column in chrome
// Chrome bug https://bugs.chromium.org/p/chromium/issues/detail?id=565116
body
.attributes-key-value--value-container
*:focus
outline: 1px solid $gray
.detail-panel-description
margin: 0
line-height: 18px

@ -1,11 +1,11 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require_relative '../../spec_helper'
require 'messagebird'
describe ::OpenProject::TwoFactorAuthentication::TokenStrategy::MessageBird do
let(:channel) { :sms }
let(:locale) { 'en' }
let(:user) { create :user, language: locale }
let(:device) { create :two_factor_authentication_device_sms, user:, channel: }
let(:user) { create(:user, language: locale) }
let(:device) { create(:two_factor_authentication_device_sms, user:, channel:) }
let(:strategy) { described_class.new user:, device:, channel: }
before do
@ -31,7 +31,7 @@ describe ::OpenProject::TwoFactorAuthentication::TokenStrategy::MessageBird do
end
end
context 'en' do
context 'with en' do
let(:locale) { 'en' }
it 'returns the correct language and message' do
@ -40,7 +40,7 @@ describe ::OpenProject::TwoFactorAuthentication::TokenStrategy::MessageBird do
end
end
context 'de' do
context 'with de' do
let(:locale) { 'de' }
it 'returns the correct language and message' do
@ -53,5 +53,19 @@ describe ::OpenProject::TwoFactorAuthentication::TokenStrategy::MessageBird do
expect(subject[:message]).to eql expected_message
end
end
context 'with unsupported locale ar (Arabic is not supported in message bird)' do
let(:locale) { 'ar' }
it 'falls back to english' do
expected_message = I18n.t("two_factor_authentication.text_otp_delivery_message_sms",
app_title: Setting.app_title,
locale: 'en',
token: '1234')
expect(subject[:language]).to eq :'en-us'
expect(subject[:message]).to eql expected_message
end
end
end
end

@ -148,7 +148,11 @@ RSpec.describe 'Work package timeline date formatting',
it 'shows english ISO dates' do
expect(page).to have_selector('.wp-timeline--header-element', text: '01')
expect(page).to have_selector('.wp-timeline--header-element', text: '02')
expect(page).to have_no_selector('.wp-timeline--header-element', text: '53')
# Most years do not have 53 weeks. Some do.
unless Date.current.beginning_of_year.saturday?
expect(page).not_to have_selector('.wp-timeline--header-element', text: '53')
end
# expect moment to return week 01 for start date and due date
expect_date_week work_package.start_date.iso8601, '01'

@ -0,0 +1,11 @@
# Multi_json issue #208 https://github.com/intridea/multi_json/issues/208
# produces a `NoMethodError` with some tests like
# modules/bim/spec/requests/api/bcf/v2_1/viewpoints_api_spec.rb:277 where grape
# is calling multi_json with a specific adapter. It will fail if it is the first
# test executed.
#
# Calling this will prevent the error from happening
MultiJson::OptionsCache.reset
# This file can be removed once the issue has been fixed and released in a new
# version of multi_json gem (issue exists in 1.15.0)
Loading…
Cancel
Save