mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
[38072] Disable already selected projects in notification settings
https://community.openproject.org/wp/38072
This commit is contained in:
+1
-1
@@ -433,7 +433,7 @@ ij_typescript_import_prefer_absolute_path = global
|
||||
ij_typescript_import_sort_members = true
|
||||
ij_typescript_import_sort_module_name = false
|
||||
ij_typescript_import_use_node_resolution = true
|
||||
ij_typescript_imports_wrap = on_every_item
|
||||
ij_typescript_imports_wrap = always
|
||||
ij_typescript_indent_case_from_switch = true
|
||||
ij_typescript_indent_chained_calls = true
|
||||
ij_typescript_indent_package_children = 0
|
||||
|
||||
@@ -582,6 +582,7 @@ en:
|
||||
watched: 'I am watching'
|
||||
all: 'All events'
|
||||
add: 'Add setting for project'
|
||||
already_selected: 'This project is already selected'
|
||||
remove_projects: 'Remove notifications for projects'
|
||||
title: "Notification settings"
|
||||
self_notify: "I want to be notified of changes that I make myself"
|
||||
|
||||
+16
@@ -14,10 +14,26 @@
|
||||
[placeholder]="text.please_select"
|
||||
(change)="selectProject($event)"
|
||||
(keydown.escape)="active = false"
|
||||
[fetchDataDirectly]="true"
|
||||
[filters]="autocompleterOptions.filters"
|
||||
[resource]="autocompleterOptions.resource"
|
||||
[getOptionsFn]="autocompleterOptions.getOptionsFn"
|
||||
appendTo="body"
|
||||
>
|
||||
<ng-template op-autocompleter-option-tmp let-item let-index="index" let-search="search">
|
||||
<div
|
||||
*ngIf="item"
|
||||
class="ng-option-label"
|
||||
>
|
||||
<!--Selectable option-->
|
||||
<div [ngOptionHighlight]="search">{{ item.name }}</div>
|
||||
|
||||
<!-- Project already selected -->
|
||||
<div
|
||||
*ngIf="item.disabled"
|
||||
class="ellipsis"
|
||||
>{{ text.already_selected }}</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</op-autocompleter>
|
||||
</div>
|
||||
+28
-14
@@ -1,12 +1,20 @@
|
||||
import {
|
||||
EventEmitter, Component, ChangeDetectionStrategy, Output, Input,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { I18nService } from 'core-app/core/i18n/i18n.service';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
map,
|
||||
withLatestFrom,
|
||||
} from 'rxjs/operators';
|
||||
import { APIV3Service } from 'core-app/core/apiv3/api-v3.service';
|
||||
import { ApiV3FilterBuilder } from 'core-app/shared/helpers/api-v3/api-v3-filter-builder';
|
||||
import { HalSourceLink } from 'core-app/features/hal/resources/hal-resource';
|
||||
import { UserPreferencesQuery } from 'core-app/features/user-preferences/state/user-preferences.query';
|
||||
|
||||
export interface NotificationSettingProjectOption {
|
||||
name:string;
|
||||
@@ -21,7 +29,7 @@ export interface NotificationSettingProjectOption {
|
||||
export class NotificationSettingInlineCreateComponent {
|
||||
@Input() userId:string;
|
||||
|
||||
@Output() onSelect = new EventEmitter<HalSourceLink>();
|
||||
@Output() selected = new EventEmitter<HalSourceLink>();
|
||||
|
||||
/** Active inline-create mode */
|
||||
active = false;
|
||||
@@ -29,41 +37,47 @@ export class NotificationSettingInlineCreateComponent {
|
||||
text = {
|
||||
add_setting: this.I18n.t('js.notifications.settings.add'),
|
||||
please_select: this.I18n.t('js.placeholders.selection'),
|
||||
already_selected: this.I18n.t('js.notifications.settings.already_selected'),
|
||||
};
|
||||
|
||||
public autocompleterOptions = {
|
||||
filters: [],
|
||||
resource: 'default',
|
||||
getOptionsFn: (query:string):Observable<any[]> => this.autocomplete(query),
|
||||
getOptionsFn: (query:string):Observable<unknown[]> => this.autocomplete(query),
|
||||
};
|
||||
|
||||
constructor(
|
||||
private I18n:I18nService,
|
||||
private apiV3Service:APIV3Service,
|
||||
private query:UserPreferencesQuery,
|
||||
) {
|
||||
}
|
||||
|
||||
selectProject($event:NotificationSettingProjectOption) {
|
||||
this.onSelect.emit({ title: $event.name, href: $event.href });
|
||||
selectProject($event:NotificationSettingProjectOption):void {
|
||||
this.selected.emit({ title: $event.name, href: $event.href });
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
private autocomplete(term:string):Observable<NotificationSettingProjectOption[]> {
|
||||
if (!term) {
|
||||
return of([]);
|
||||
}
|
||||
|
||||
private autocomplete(term:string|null):Observable<NotificationSettingProjectOption[]> {
|
||||
const filters = new ApiV3FilterBuilder()
|
||||
.add('name_and_identifier', '~', [term])
|
||||
.add('visible', '=', [this.userId]);
|
||||
|
||||
if (term) {
|
||||
filters.add('name_and_identifier', '~', [term]);
|
||||
}
|
||||
|
||||
return this
|
||||
.apiV3Service
|
||||
.projects
|
||||
.filtered(filters)
|
||||
.get()
|
||||
.pipe(
|
||||
map((collection) => collection.elements.map((project) => ({ href: project.href!, name: project.name }))),
|
||||
withLatestFrom(this.query.selectedProjects$),
|
||||
map(([collection, selected]) => collection.elements.map(
|
||||
(project) => (
|
||||
{ href: project.href || '', name: project.name, disabled: selected.has(project.href) }
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@
|
||||
<op-notification-setting-inline-create
|
||||
*ngIf="userId"
|
||||
[userId]="userId"
|
||||
(onSelect)="addRow($event)"
|
||||
(selected)="addRow($event)"
|
||||
data-qa-selector="notification-setting-inline-create"
|
||||
></op-notification-setting-inline-create>
|
||||
</div>
|
||||
|
||||
@@ -25,6 +25,15 @@ export class UserPreferencesQuery extends Query<UserPreferencesModel> {
|
||||
map((settings) => settings.filter((notification) => notification._links.project.href !== null)),
|
||||
);
|
||||
|
||||
/** Selected projects */
|
||||
selectedProjects$ = this
|
||||
.notificationSettings$
|
||||
.pipe(
|
||||
map((notifications) => (
|
||||
new Set(notifications.map((setting) => setting._links.project?.href))
|
||||
)),
|
||||
);
|
||||
|
||||
preferences$ = this.select();
|
||||
|
||||
constructor(protected store:UserPreferencesStore) {
|
||||
|
||||
@@ -59,6 +59,13 @@ shared_examples 'notification settings workflow' do
|
||||
expect(in_app.mentioned).to be_truthy
|
||||
expect(in_app.watched).to be_falsey
|
||||
expect(in_app.all).to be_truthy
|
||||
|
||||
# Trying to add the same project again will not be possible (Regression #38072)
|
||||
click_button 'Add setting for project'
|
||||
container = page.find('[data-qa-selector="notification-setting-inline-create"] ng-select')
|
||||
settings_page.search_autocomplete container, query: project.name, results_selector: 'body'
|
||||
expect(page).to have_text 'This project is already selected'
|
||||
expect(page).to have_selector('.ng-option-disabled', text: project.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user