From dcfa0533ef026381dd18551bf14817ee6aabd406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Wed, 9 Jun 2021 08:06:59 +0200 Subject: [PATCH] Merge release/11.3 into dev --- config/locales/crowdin/js-ru.yml | 2 +- config/puma.rb | 2 +- .../endpoints/users/apiv3-users-paths.ts | 4 ++ .../core/current-user/current-user.service.ts | 4 +- .../invite-user-modal.module.ts | 2 +- .../principal/principal.component.html | 2 +- .../principal/principal.component.ts | 56 +++++++++---------- .../copy-project/copy-project.component.ts | 25 +++++---- .../new-project/new-project.component.ts | 2 +- .../projects/projects.component.html | 2 +- .../components/projects/projects.component.ts | 17 ++---- .../dynamic-form/dynamic-form.component.ts | 4 +- lib/open_project/logging/sentry_logger.rb | 2 +- 13 files changed, 61 insertions(+), 63 deletions(-) diff --git a/config/locales/crowdin/js-ru.yml b/config/locales/crowdin/js-ru.yml index 3e2a0b3324a..5b084f18b51 100644 --- a/config/locales/crowdin/js-ru.yml +++ b/config/locales/crowdin/js-ru.yml @@ -289,7 +289,7 @@ ru: bim: learn_about_link: https://www.openproject.org/openproject-11-3-release current_new_feature_html: > - The release contains various new features and improvements:
+ Релиз содержит различные новые функции и улучшения:
label_activate: "Активировать" label_add_column_after: "Добавить столбец после" label_add_column_before: "Добавить столбец перед" diff --git a/config/puma.rb b/config/puma.rb index 9ba804fbd1a..3c434920b5e 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -21,7 +21,7 @@ environment ENV.fetch("RAILS_ENV") { "development" } # Workers do not work on JRuby or Windows (both of which do not support # processes). # -workers ENV.fetch("OPENPROJECT_WEB_WORKERS") { 1 }.to_i +workers ENV.fetch("OPENPROJECT_WEB_WORKERS") { 0 }.to_i # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code diff --git a/frontend/src/app/core/apiv3/endpoints/users/apiv3-users-paths.ts b/frontend/src/app/core/apiv3/endpoints/users/apiv3-users-paths.ts index 6d9aed4a38a..d5926b8a6b7 100644 --- a/frontend/src/app/core/apiv3/endpoints/users/apiv3-users-paths.ts +++ b/frontend/src/app/core/apiv3/endpoints/users/apiv3-users-paths.ts @@ -31,6 +31,7 @@ import { APIv3UserPaths } from "core-app/core/apiv3/endpoints/users/apiv3-user-p import { Observable } from "rxjs"; import { UserResource } from "core-app/features/hal/resources/user-resource"; import { APIV3Service } from "core-app/core/apiv3/api-v3.service"; +import { APIv3FormResource } from "core-app/core/apiv3/forms/apiv3-form-resource"; export class Apiv3UsersPaths extends APIv3ResourceCollection { constructor(protected apiRoot:APIV3Service, @@ -43,6 +44,9 @@ export class Apiv3UsersPaths extends APIv3ResourceCollection actions.reduce( (acc, action) => { - return acc && !!capabilities.find(cap => cap.action.href === `/api/v3/actions/${action}`); + return acc && !!capabilities.find(cap => cap.action.href.endsWith(`/api/v3/actions/${action}`)); }, capabilities.length > 0, )), @@ -168,7 +168,7 @@ export class CurrentUserService { const actionsToFilter = _.castArray(actions); return this.capabilitiesForContext$(contextId).pipe( map((capabilities) => capabilities.reduce( - (acc, cap) => acc || !!actionsToFilter.find(action => cap.action.href === `/api/v3/actions/${action}`), + (acc, cap) => acc || !!actionsToFilter.find(action => cap.action.href.endsWith(`/api/v3/actions/${action}`)), false, )), distinctUntilChanged(), diff --git a/frontend/src/app/features/invite-user-modal/invite-user-modal.module.ts b/frontend/src/app/features/invite-user-modal/invite-user-modal.module.ts index cbf09245a52..162d5d71366 100644 --- a/frontend/src/app/features/invite-user-modal/invite-user-modal.module.ts +++ b/frontend/src/app/features/invite-user-modal/invite-user-modal.module.ts @@ -25,7 +25,7 @@ export function initializeServices(injector:Injector) { return function () { const inviteUserAugmentService = injector.get(OpInviteUserModalAugmentService); inviteUserAugmentService.setupListener(); - } + }; } @NgModule({ diff --git a/frontend/src/app/features/invite-user-modal/principal/principal.component.html b/frontend/src/app/features/invite-user-modal/principal/principal.component.html index af176122c74..4ea7f30d922 100644 --- a/frontend/src/app/features/invite-user-modal/principal/principal.component.html +++ b/frontend/src/app/features/invite-user-modal/principal/principal.component.html @@ -55,7 +55,7 @@ *ngIf="isNewPrincipal && type === PrincipalType.User && userDynamicFieldConfig.schema" [dynamicFormGroup]="dynamicFieldsControl" [settings]="userDynamicFieldConfig" - [resourcePath]="pathHelper.usersPath()" + [formUrl]="apiV3Service.users.form.path" [handleSubmit]="false" > diff --git a/frontend/src/app/features/invite-user-modal/principal/principal.component.ts b/frontend/src/app/features/invite-user-modal/principal/principal.component.ts index 8c216e78096..433381a808d 100644 --- a/frontend/src/app/features/invite-user-modal/principal/principal.component.ts +++ b/frontend/src/app/features/invite-user-modal/principal/principal.component.ts @@ -1,27 +1,17 @@ -import { - Component, - OnInit, - Input, - Output, - EventEmitter, - ViewChild, - ChangeDetectorRef, -} from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild, } from '@angular/core'; import { HttpClient } from "@angular/common/http"; -import { - FormGroup, - FormControl, - Validators, -} from '@angular/forms'; -import { PathHelperService } from "core-app/core/path-helper/path-helper.service"; +import { FormControl, FormGroup, Validators, } from '@angular/forms'; import { I18nService } from "core-app/core/i18n/i18n.service"; import { HalResource } from "core-app/features/hal/resources/hal-resource"; import { PrincipalData, PrincipalLike } from "core-app/shared/components/principal/principal-types"; import { ProjectResource } from "core-app/features/hal/resources/project-resource"; import { DynamicFormComponent } from "core-app/shared/components/dynamic-forms/components/dynamic-form/dynamic-form.component" import { PrincipalType } from '../invite-user.component'; +import { take } from 'rxjs/internal/operators/take'; +import { map } from 'rxjs/operators'; +import { APIV3Service } from "core-app/core/apiv3/api-v3.service"; -function extractCustomFieldsFromSchema(schema: IOPFormSettings['_embedded']['schema']) { +function extractCustomFieldsFromSchema(schema:IOPFormSettings['_embedded']['schema']) { return Object.keys(schema) .reduce((fields, name) => { if (name.startsWith('customField') && schema[name].required) { @@ -49,7 +39,7 @@ export class PrincipalComponent implements OnInit { @Output() save = new EventEmitter<{ principalData:PrincipalData, isAlreadyMember:boolean }>(); @Output() back = new EventEmitter(); - @ViewChild(DynamicFormComponent) dynamicForm: DynamicFormComponent; + @ViewChild(DynamicFormComponent) dynamicForm:DynamicFormComponent; public PrincipalType = PrincipalType; @@ -77,13 +67,13 @@ export class PrincipalComponent implements OnInit { }; public principalForm = new FormGroup({ - principal: new FormControl(null, [ Validators.required ]), + principal: new FormControl(null, [Validators.required]), userDynamicFields: new FormGroup({}), }); - public userDynamicFieldConfig: { - payload: IOPFormSettings['_embedded']['payload']|null, - schema: IOPFormSettings['_embedded']['schema']|null, + public userDynamicFieldConfig:{ + payload:IOPFormSettings['_embedded']['payload']|null, + schema:IOPFormSettings['_embedded']['schema']|null, } = { payload: null, schema: null, @@ -101,7 +91,7 @@ export class PrincipalComponent implements OnInit { return this.principalForm.get('userDynamicFields'); } - get customFields():{[key:string]:any} { + get customFields():{ [key:string]:any } { return this.dynamicFieldsControl?.value; } @@ -128,17 +118,27 @@ export class PrincipalComponent implements OnInit { constructor( readonly I18n:I18nService, readonly httpClient:HttpClient, - readonly pathHelper:PathHelperService, - readonly cdRef: ChangeDetectorRef, - ) {} + readonly apiV3Service:APIV3Service, + readonly cdRef:ChangeDetectorRef, + ) { + } ngOnInit() { this.principalControl?.setValue(this.principalData.principal); if (this.type === PrincipalType.User) { const payload = this.isNewPrincipal ? this.principalData.customFields : {}; - this.httpClient - .post('/api/v3/users/form', payload, { withCredentials: true, responseType: 'json' }) + this + .apiV3Service + .users + .form + .post(payload) + .pipe( + take(1), + // The subsequent code expects to not work with a HalResource but rather with the raw + // api response. + map(formResource => formResource.$source) + ) .subscribe((formConfig) => { this.userDynamicFieldConfig.schema = extractCustomFieldsFromSchema(formConfig._embedded?.schema); this.userDynamicFieldConfig.payload = formConfig._embedded?.payload; @@ -177,7 +177,7 @@ export class PrincipalComponent implements OnInit { _links: Object.keys(links).reduce((cfs, name) => ({ ...cfs, [name]: Array.isArray(links[name]) - ? links[name].map((opt: any) => opt._links ? opt._links.self : opt) + ? links[name].map((opt:any) => opt._links ? opt._links.self : opt) : (links[name]._links ? links[name]._links.self : links[name]) }), {}), }; diff --git a/frontend/src/app/features/projects/components/copy-project/copy-project.component.ts b/frontend/src/app/features/projects/components/copy-project/copy-project.component.ts index e386305c0fa..813fdf8fbc3 100644 --- a/frontend/src/app/features/projects/components/copy-project/copy-project.component.ts +++ b/frontend/src/app/features/projects/components/copy-project/copy-project.component.ts @@ -1,17 +1,18 @@ -import {Component, OnInit} from '@angular/core'; -import {StateService, UIRouterGlobals} from "@uirouter/core"; -import {UntilDestroyedMixin} from "core-app/shared/helpers/angular/until-destroyed.mixin"; -import {PathHelperService} from "core-app/core/path-helper/path-helper.service"; -import {HalSource} from "core-app/features/hal/resources/hal-resource"; +import { Component, OnInit } from '@angular/core'; +import { StateService } from "@uirouter/core"; +import { UntilDestroyedMixin } from "core-app/shared/helpers/angular/until-destroyed.mixin"; +import { PathHelperService } from "core-app/core/path-helper/path-helper.service"; +import { HalSource } from "core-app/features/hal/resources/hal-resource"; import { IDynamicFieldGroupConfig, IOPFormlyFieldSettings, IOPFormlyTemplateOptions, } from "core-app/shared/components/dynamic-forms/typings"; -import {I18nService} from "core-app/core/i18n/i18n.service"; -import {APIV3Service} from "core-app/core/apiv3/api-v3.service"; -import {JobStatusModal} from "core-app/features/job-status/job-status-modal/job-status.modal"; -import {OpModalService} from "core-app/shared/components/modal/modal.service"; +import { I18nService } from "core-app/core/i18n/i18n.service"; +import { APIV3Service } from "core-app/core/apiv3/api-v3.service"; +import { JobStatusModal } from "core-app/features/job-status/job-status-modal/job-status.modal"; +import { OpModalService } from "core-app/shared/components/modal/modal.service"; +import { CurrentProjectService } from "core-app/core/current-project/current-project.service"; @Component({ selector: 'op-copy-project', @@ -31,11 +32,11 @@ export class CopyProjectComponent extends UntilDestroyedMixin implements OnInit text = { advancedSettingsLabel: this.I18n.t("js.forms.advanced_settings"), copySettingsLabel: this.I18n.t("js.project.copy.copy_options"), - } + }; constructor( private apiV3Service:APIV3Service, - private uIRouterGlobals:UIRouterGlobals, + private currentProjectService:CurrentProjectService, private pathHelperService:PathHelperService, private modalService:OpModalService, private $state:StateService, @@ -45,7 +46,7 @@ export class CopyProjectComponent extends UntilDestroyedMixin implements OnInit } ngOnInit():void { - this.formUrl = this.apiV3Service.projects.id(this.uIRouterGlobals.params.projectPath).copy.form.path; + this.formUrl = this.apiV3Service.projects.id(this.currentProjectService.id!).copy.form.path; this.fieldGroups = [ { name: this.text.advancedSettingsLabel, diff --git a/frontend/src/app/features/projects/components/new-project/new-project.component.ts b/frontend/src/app/features/projects/components/new-project/new-project.component.ts index 2f1750863c5..e8486e3b04d 100644 --- a/frontend/src/app/features/projects/components/new-project/new-project.component.ts +++ b/frontend/src/app/features/projects/components/new-project/new-project.component.ts @@ -80,7 +80,7 @@ export class NewProjectComponent extends UntilDestroyedMixin implements OnInit { } ngOnInit():void { - this.resourcePath = this.pathHelperService.projectsPath(); + this.resourcePath = this.apiV3Service.projects.path; this.fieldGroups = [{ name: this.text.advancedSettingsLabel, fieldsFilter: (field) => !['name', 'parent'].includes(field.templateOptions?.property!) && diff --git a/frontend/src/app/features/projects/components/projects/projects.component.html b/frontend/src/app/features/projects/components/projects/projects.component.html index 298deb5b645..6943dfd1dff 100644 --- a/frontend/src/app/features/projects/components/projects/projects.component.html +++ b/frontend/src/app/features/projects/components/projects/projects.component.html @@ -1,6 +1,6 @@ \ No newline at end of file diff --git a/frontend/src/app/features/projects/components/projects/projects.component.ts b/frontend/src/app/features/projects/components/projects/projects.component.ts index 25b04efc430..dbf56e5d7e8 100644 --- a/frontend/src/app/features/projects/components/projects/projects.component.ts +++ b/frontend/src/app/features/projects/components/projects/projects.component.ts @@ -1,8 +1,9 @@ import { Component, OnInit } from '@angular/core'; -import { StateService, UIRouterGlobals } from "@uirouter/core"; +import { StateService } from "@uirouter/core"; import { UntilDestroyedMixin } from "core-app/shared/helpers/angular/until-destroyed.mixin"; import { PathHelperService } from "core-app/core/path-helper/path-helper.service"; import { IOPFormlyFieldSettings } from "core-app/shared/components/dynamic-forms/typings"; +import { CurrentProjectService } from "core-app/core/current-project/current-project.service"; @Component({ selector: 'app-projects', @@ -10,23 +11,22 @@ import { IOPFormlyFieldSettings } from "core-app/shared/components/dynamic-forms styleUrls: ['./projects.component.scss'] }) export class ProjectsComponent extends UntilDestroyedMixin implements OnInit { - resourceId:string; projectsPath:string; + formMethod = 'patch'; text:{ [key:string]:string }; dynamicFieldsSettingsPipe:(dynamicFieldsSettings:IOPFormlyFieldSettings[]) => IOPFormlyFieldSettings[]; hiddenFields = ['identifier', 'active']; constructor( - private _uIRouterGlobals:UIRouterGlobals, private _pathHelperService:PathHelperService, private _$state:StateService, + private _currentProjectService:CurrentProjectService, ) { super(); } ngOnInit():void { - this.projectsPath = this._pathHelperService.projectsPath(); - this.resourceId = this._uIRouterGlobals.params.projectPath; + this.projectsPath = this._currentProjectService.apiv3Path!; this.dynamicFieldsSettingsPipe = (dynamicFieldsSettings) => { return dynamicFieldsSettings .reduce((formattedDynamicFieldsSettings:IOPFormlyFieldSettings[], dynamicFormField) => { @@ -42,13 +42,6 @@ export class ProjectsComponent extends UntilDestroyedMixin implements OnInit { } } - onSubmitted(formResource:HalSource) { - // TODO: Filter out if this.resourceId === 'new'? - if (!this.resourceId) { - this._$state.go('.', { ...this._$state.params, projectPath: formResource.identifier }); - } - } - private isFieldHidden(name:string|undefined) { return this.hiddenFields.includes(name || ''); } diff --git a/frontend/src/app/shared/components/dynamic-forms/components/dynamic-form/dynamic-form.component.ts b/frontend/src/app/shared/components/dynamic-forms/components/dynamic-form/dynamic-form.component.ts index 9c2962a4526..38cc27d35df 100644 --- a/frontend/src/app/shared/components/dynamic-forms/components/dynamic-form/dynamic-form.component.ts +++ b/frontend/src/app/shared/components/dynamic-forms/components/dynamic-form/dynamic-form.component.ts @@ -295,7 +295,7 @@ export class DynamicFormComponent extends UntilDestroyedMixin implements OnChang } if (resourcePath) { - return `${this._pathHelperService.api.v3.apiV3Base}${resourcePath}`; + return resourcePath; } return; @@ -349,7 +349,7 @@ export class DynamicFormComponent extends UntilDestroyedMixin implements OnChang submit_message = `${title || ''} ${this.text.job_started}`; } else { - submit_message = this.resourceId ? this.text.successful_update : this.text.successful_create; + submit_message = this.formHttpMethod === 'patch' ? this.text.successful_update : this.text.successful_create; } this._notificationsService.addSuccess(submit_message); diff --git a/lib/open_project/logging/sentry_logger.rb b/lib/open_project/logging/sentry_logger.rb index 27af233a7c7..88d9511476d 100644 --- a/lib/open_project/logging/sentry_logger.rb +++ b/lib/open_project/logging/sentry_logger.rb @@ -6,7 +6,7 @@ module OpenProject # Capture a message to sentry def log(message, log_context = {}) Sentry.configure_scope do |sentry_scope| - build_sentry_context(sentry_scope, log_context) + build_sentry_context(sentry_scope, log_context.to_h) Sentry.capture_message(message, level: sentry_level(log_context[:level])) end end