Merge pull request #9636 from opf/feature/38723-notification-settings-frontend
Feature/38723 notification settings frontendpull/9687/head
commit
6bf3475348
@ -0,0 +1,3 @@ |
||||
.op-autocompleter |
||||
display: block |
||||
max-width: 600px |
@ -1,16 +1,117 @@ |
||||
<op-notifications-settings-toolbar></op-notifications-settings-toolbar> |
||||
<op-notification-settings-table |
||||
<form |
||||
[formGroup]="form" |
||||
(ngSubmit)="saveChanges()" |
||||
class="op-form" |
||||
> |
||||
<h5>{{ text.notifyImmediately.title }}</h5> |
||||
<p>{{ text.notifyImmediately.description }}</p> |
||||
|
||||
<op-checkbox-field [label]="text.mentioned.title"> |
||||
<input |
||||
disabled |
||||
checked |
||||
type="checkbox" |
||||
slot="input" |
||||
/> |
||||
<p slot="description">{{ text.mentioned.description }}</p> |
||||
</op-checkbox-field> |
||||
|
||||
<op-checkbox-field |
||||
[label]="text.involved.title" |
||||
[control]="form.get('involved')" |
||||
> |
||||
<input |
||||
slot="input" |
||||
type="checkbox" |
||||
formControlName="involved" |
||||
data-qa-global-notification-type="involved" |
||||
/> |
||||
<p slot="description">{{ text.mentioned.title }}</p> |
||||
</op-checkbox-field> |
||||
|
||||
<h5>{{ text.alsoNotifyFor.title }}</h5> |
||||
<p>{{ text.alsoNotifyFor.description }}</p> |
||||
|
||||
<op-checkbox-field> |
||||
<input |
||||
disabled |
||||
checked |
||||
type="checkbox" |
||||
slot="input" |
||||
/> |
||||
<p slot="description">{{ text.watched }}</p> |
||||
</op-checkbox-field> |
||||
|
||||
<op-checkbox-field [control]="form.get('workPackageCreated')"> |
||||
<input |
||||
slot="input" |
||||
type="checkbox" |
||||
formControlName="workPackageCreated" |
||||
data-qa-global-notification-type="work_package_created" |
||||
/> |
||||
<p slot="description">{{ text.work_package_created }}</p> |
||||
</op-checkbox-field> |
||||
|
||||
<op-checkbox-field [control]="form.get('workPackageProcessed')"> |
||||
<input |
||||
slot="input" |
||||
type="checkbox" |
||||
formControlName="workPackageProcessed" |
||||
data-qa-global-notification-type="work_package_processed" |
||||
/> |
||||
<p slot="description">{{ text.work_package_processed }}</p> |
||||
</op-checkbox-field> |
||||
|
||||
<op-checkbox-field [control]="form.get('workPackageScheduled')"> |
||||
<input |
||||
slot="input" |
||||
type="checkbox" |
||||
formControlName="workPackageScheduled" |
||||
data-qa-global-notification-type="work_package_scheduled" |
||||
/> |
||||
<p slot="description">{{ text.work_package_scheduled }}</p> |
||||
</op-checkbox-field> |
||||
|
||||
<op-checkbox-field [control]="form.get('workPackagePrioritized')"> |
||||
<input |
||||
slot="input" |
||||
type="checkbox" |
||||
formControlName="workPackagePrioritized" |
||||
data-qa-global-notification-type="work_package_prioritized" |
||||
/> |
||||
<p slot="description">{{ text.work_package_prioritized }}</p> |
||||
</op-checkbox-field> |
||||
|
||||
<op-checkbox-field [control]="form.get('workPackageCommented')"> |
||||
<input |
||||
slot="input" |
||||
type="checkbox" |
||||
formControlName="workPackageCommented" |
||||
data-qa-global-notification-type="work_package_commented" |
||||
/> |
||||
<p slot="description">{{ text.work_package_commented }}</p> |
||||
</op-checkbox-field> |
||||
|
||||
<hr /> |
||||
|
||||
<h5>Project-specific notification settings</h5> |
||||
<p>These project-specific settings override default settings above</p> |
||||
|
||||
<op-notification-settings-table |
||||
*ngIf="userId" |
||||
[userId]="userId" |
||||
></op-notification-settings-table> |
||||
[settings]="form.controls.projectSettings" |
||||
formArrayName="projectSettings" |
||||
class="op-notification-settings-page--table" |
||||
></op-notification-settings-table> |
||||
|
||||
<div class="generic-table--action-buttons"> |
||||
<button |
||||
<div class="generic-table--action-buttons"> |
||||
<button |
||||
class="button -highlight" |
||||
[textContent]="text.save" |
||||
(click)="saveChanges()" |
||||
> |
||||
</button> |
||||
</div> |
||||
|
||||
type="submit" |
||||
></button> |
||||
</div> |
||||
</form> |
||||
|
||||
|
@ -1,116 +0,0 @@ |
||||
<td |
||||
*ngIf="first" |
||||
[attr.rowspan]="count" |
||||
> |
||||
<span |
||||
*ngIf="setting._links.project.href; else defaultTitle" |
||||
[textContent]="setting._links.project.title" |
||||
></span> |
||||
<ng-template #defaultTitle> |
||||
<em [textContent]="text.default_all_projects"></em> |
||||
</ng-template> |
||||
</td> |
||||
<td [textContent]="text.channel(setting.channel)"> |
||||
</td> |
||||
<td> |
||||
<input |
||||
type="checkbox" |
||||
[checked]="setting.involved || setting.all" |
||||
[disabled]="setting.all" |
||||
(change)="update({ involved: $event.target.checked })" |
||||
data-qa-notification-type="involved" |
||||
[attr.aria-label]="text.involved_header" |
||||
/> |
||||
</td> |
||||
<td> |
||||
<input |
||||
type="checkbox" |
||||
[checked]="setting.mentioned || setting.all" |
||||
[disabled]="setting.all" |
||||
(change)="update({ mentioned: $event.target.checked })" |
||||
data-qa-notification-type="mentioned" |
||||
[attr.aria-label]="text.mentioned_header" |
||||
/> |
||||
</td> |
||||
<td> |
||||
<input |
||||
type="checkbox" |
||||
[checked]="setting.watched || setting.all" |
||||
[disabled]="setting.all" |
||||
(change)="update({ watched: $event.target.checked })" |
||||
data-qa-notification-type="watched" |
||||
[attr.aria-label]="text.watched_header" |
||||
/> |
||||
</td> |
||||
<td> |
||||
<input |
||||
type="checkbox" |
||||
[checked]="setting.workPackageCreated || setting.all" |
||||
[disabled]="setting.all" |
||||
(change)="update({ workPackageCreated: $event.target.checked })" |
||||
data-qa-notification-type="work_package_created" |
||||
[attr.aria-label]="text.work_package_created_header" |
||||
/> |
||||
</td> |
||||
<td> |
||||
<input |
||||
type="checkbox" |
||||
[checked]="setting.workPackageCommented || setting.all" |
||||
[disabled]="setting.all" |
||||
(change)="update({ workPackageCommented: $event.target.checked })" |
||||
data-qa-notification-type="work_package_commented" |
||||
[attr.aria-label]="text.work_package_commented_header" |
||||
/> |
||||
</td> |
||||
<td> |
||||
<input |
||||
type="checkbox" |
||||
[checked]="setting.workPackageProcessed || setting.all" |
||||
[disabled]="setting.all" |
||||
(change)="update({ workPackageProcessed: $event.target.checked })" |
||||
data-qa-notification-type="work_package_processed" |
||||
[attr.aria-label]="text.work_package_processed_header" |
||||
/> |
||||
</td> |
||||
<td> |
||||
<input |
||||
type="checkbox" |
||||
[checked]="setting.workPackagePrioritized || setting.all" |
||||
[disabled]="setting.all" |
||||
(change)="update({ workPackagePrioritized: $event.target.checked })" |
||||
data-qa-notification-type="work_package_prioritized" |
||||
[attr.aria-label]="text.work_package_prioritized_header" |
||||
/> |
||||
</td> |
||||
<td> |
||||
<input |
||||
type="checkbox" |
||||
[checked]="setting.workPackageScheduled || setting.all" |
||||
[disabled]="setting.all" |
||||
(change)="update({ workPackageScheduled: $event.target.checked })" |
||||
data-qa-notification-type="work_package_scheduled" |
||||
[attr.aria-label]="text.work_package_scheduled_header" |
||||
/> |
||||
</td> |
||||
<td> |
||||
<input |
||||
type="checkbox" |
||||
[checked]="setting.all" |
||||
(change)="update({ all: $event.target.checked })" |
||||
data-qa-notification-type="all" |
||||
[attr.aria-label]="text.any_event_header" |
||||
/> |
||||
</td> |
||||
<td |
||||
*ngIf="first" |
||||
[attr.rowspan]="count" |
||||
class="buttons" |
||||
> |
||||
<button |
||||
*ngIf="!global" |
||||
class="op-link" |
||||
(click)="remove()" |
||||
> |
||||
<op-icon icon-classes="icon-remove icon-no-color"></op-icon> |
||||
</button> |
||||
</td> |
@ -1,80 +0,0 @@ |
||||
import { |
||||
ChangeDetectionStrategy, |
||||
Component, |
||||
Input, |
||||
OnInit, |
||||
} from '@angular/core'; |
||||
import { I18nService } from 'core-app/core/i18n/i18n.service'; |
||||
import { arrayUpdate } from '@datorama/akita'; |
||||
import { NotificationSetting } from 'core-app/features/user-preferences/state/notification-setting.model'; |
||||
import { UserPreferencesService } from 'core-app/features/user-preferences/state/user-preferences.service'; |
||||
|
||||
@Component({ |
||||
// eslint-disable-next-line @angular-eslint/component-selector
|
||||
selector: '[op-notification-setting-row]', |
||||
templateUrl: './notification-setting-row.component.html', |
||||
changeDetection: ChangeDetectionStrategy.OnPush, |
||||
}) |
||||
export class NotificationSettingRowComponent implements OnInit { |
||||
@Input() first = false; |
||||
|
||||
@Input() count:number; |
||||
|
||||
@Input() setting:NotificationSetting; |
||||
|
||||
/** Whether this setting is global */ |
||||
global = false; |
||||
|
||||
text = { |
||||
title: this.I18n.t('js.notifications.settings.title'), |
||||
save: this.I18n.t('js.button_save'), |
||||
email: this.I18n.t('js.notifications.email'), |
||||
inApp: this.I18n.t('js.notifications.in_app'), |
||||
remove_all: this.I18n.t('js.notifications.settings.remove_all'), |
||||
involved_header: this.I18n.t('js.notifications.settings.involved'), |
||||
mentioned_header: this.I18n.t('js.notifications.settings.mentioned'), |
||||
watched_header: this.I18n.t('js.notifications.settings.watched'), |
||||
work_package_commented_header: this.I18n.t('js.notifications.settings.work_package_commented'), |
||||
work_package_created_header: this.I18n.t('js.notifications.settings.work_package_created'), |
||||
work_package_processed_header: this.I18n.t('js.notifications.settings.work_package_processed'), |
||||
work_package_prioritized_header: this.I18n.t('js.notifications.settings.work_package_prioritized'), |
||||
work_package_scheduled_header: this.I18n.t('js.notifications.settings.work_package_scheduled'), |
||||
any_event_header: this.I18n.t('js.notifications.settings.all'), |
||||
default_all_projects: this.I18n.t('js.notifications.settings.default_all_projects'), |
||||
add_setting: this.I18n.t('js.notifications.settings.add'), |
||||
channel: (channel:string):string => this.I18n.t(`js.notifications.channels.${channel}`), |
||||
}; |
||||
|
||||
constructor( |
||||
private I18n:I18nService, |
||||
private storeService:UserPreferencesService, |
||||
) { |
||||
} |
||||
|
||||
ngOnInit() { |
||||
this.global = this.setting._links.project.href === null; |
||||
} |
||||
|
||||
remove():void { |
||||
this.storeService.store.update( |
||||
({ notifications }) => ({ |
||||
notifications: notifications.filter((notification) => notification._links.project.href !== this.setting._links.project.href), |
||||
}), |
||||
); |
||||
} |
||||
|
||||
update(delta:Partial<NotificationSetting>) { |
||||
this.storeService.store.update( |
||||
({ notifications }) => ({ |
||||
notifications: arrayUpdate( |
||||
notifications, this.matcherFn.bind(this), delta, |
||||
), |
||||
}), |
||||
); |
||||
} |
||||
|
||||
private matcherFn(notification:NotificationSetting) { |
||||
return notification._links.project.href === this.setting._links.project.href |
||||
&& notification.channel === this.setting.channel; |
||||
} |
||||
} |
@ -1,125 +1,142 @@ |
||||
<div class="generic-table--container form--section"> |
||||
<div class="generic-table--results-container"> |
||||
<table class="generic-table"> |
||||
<colgroup> |
||||
<col> |
||||
<col opHighlightCol> |
||||
<col opHighlightCol> |
||||
<col opHighlightCol> |
||||
<col opHighlightCol> |
||||
<col opHighlightCol> |
||||
<col opHighlightCol> |
||||
<col opHighlightCol> |
||||
<col opHighlightCol> |
||||
<col opHighlightCol> |
||||
<col opHighlightCol> |
||||
</colgroup> |
||||
<thead> |
||||
<div class="op-scrollable-table"> |
||||
<table |
||||
class="op-table" |
||||
*ngIf="settings.length > 0" |
||||
> |
||||
<thead> |
||||
<tr> |
||||
<th> |
||||
<div class="generic-table--empty-header"></div> |
||||
<th class="op-table--cell op-table--cell_heading"> |
||||
{{ text.notify_me }} |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.channel_header"></span> |
||||
</div> |
||||
</div> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.involved_header"></span> |
||||
</div> |
||||
</div> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.mentioned_header"></span> |
||||
</div> |
||||
</div> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.watched_header"></span> |
||||
</div> |
||||
</div> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.work_package_created_header"></span> |
||||
</div> |
||||
</div> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.work_package_commented_header"></span> |
||||
</div> |
||||
</div> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.work_package_processed_header"></span> |
||||
</div> |
||||
</div> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.work_package_prioritized_header"></span> |
||||
</div> |
||||
</div> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.work_package_scheduled_header"></span> |
||||
</div> |
||||
</div> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--sort-header-outer"> |
||||
<div class="generic-table--sort-header"> |
||||
<span [textContent]="text.any_event_header"></span> |
||||
</div> |
||||
</div> |
||||
<ng-container *ngFor="let item of settings.controls"> |
||||
<th class="op-table--cell op-table--cell_heading"> |
||||
<a |
||||
class="op-link" |
||||
[href]="projectLink(item.controls.project.value.href)" |
||||
>{{ item.controls.project.value.title }}</a> |
||||
</th> |
||||
</ng-container> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<tr> |
||||
<th class="op-table--cell op-table--cell_soft-heading"> |
||||
<h5>{{ text.mentioned_header.title }}</h5> |
||||
<p>{{ text.mentioned_header.description }}</p> |
||||
</th> |
||||
<th> |
||||
<div class="generic-table--empty-header"></div> |
||||
<ng-container *ngFor="let item of settings.controls"> |
||||
<td class="op-table--cell"><input type="checkbox" disabled checked /></td> |
||||
</ng-container> |
||||
</tr> |
||||
<tr> |
||||
<th class="op-table--cell op-table--cell_soft-heading"> |
||||
<h5>{{ text.involved_header.title }}</h5> |
||||
<p>{{ text.involved_header.description }}</p> |
||||
</th> |
||||
<ng-container *ngFor="let item of settings.controls"> |
||||
<td class="op-table--cell" [formGroup]="item"> |
||||
<input |
||||
type="checkbox" |
||||
formControlName="involved" |
||||
data-qa-project-notification-type="involved" |
||||
[attr.data-qa-project]="item.controls.project.value.title" |
||||
/> |
||||
</td> |
||||
</ng-container> |
||||
</tr> |
||||
<tr> |
||||
<th class="op-table--cell op-table--cell_soft-heading">{{ text.watched_header }}</th> |
||||
<ng-container *ngFor="let item of settings.controls"> |
||||
<td class="op-table--cell"><input type="checkbox" disabled checked /></td> |
||||
</ng-container> |
||||
</tr> |
||||
<tr> |
||||
<th class="op-table--cell op-table--cell_soft-heading">{{ text.work_package_created_header }}</th> |
||||
<ng-container *ngFor="let item of settings.controls"> |
||||
<td class="op-table--cell" [formGroup]="item"> |
||||
<input |
||||
type="checkbox" |
||||
formControlName="workPackageCreated" |
||||
data-qa-project-notification-type="work_package_created" |
||||
[attr.data-qa-project]="item.controls.project.value.title" |
||||
/> |
||||
</td> |
||||
</ng-container> |
||||
</tr> |
||||
<tr> |
||||
<th class="op-table--cell op-table--cell_soft-heading">{{ text.work_package_processed_header }}</th> |
||||
<ng-container *ngFor="let item of settings.controls"> |
||||
<td class="op-table--cell" [formGroup]="item"> |
||||
<input |
||||
type="checkbox" |
||||
formControlName="workPackageProcessed" |
||||
data-qa-project-notification-type="work_package_processed" |
||||
[attr.data-qa-project]="item.controls.project.value.title" |
||||
/> |
||||
</td> |
||||
</ng-container> |
||||
</tr> |
||||
<tr> |
||||
<th class="op-table--cell op-table--cell_soft-heading">{{ text.work_package_scheduled_header }}</th> |
||||
<ng-container *ngFor="let item of settings.controls"> |
||||
<td class="op-table--cell" [formGroup]="item"> |
||||
<input |
||||
type="checkbox" |
||||
formControlName="workPackageScheduled" |
||||
data-qa-project-notification-type="work_package_scheduled" |
||||
[attr.data-qa-project]="item.controls.project.value.title" |
||||
/> |
||||
</td> |
||||
</ng-container> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<ng-container *ngFor="let item of (groupedNotificationSettings$ | async) | keyvalue: projectOrder"> |
||||
<ng-container *ngFor="let setting of item.value; let first = first; let last = last"> |
||||
<tr |
||||
class="-no-highlighting" |
||||
op-notification-setting-row |
||||
[attr.data-qa-notification-project]="item.key" |
||||
[attr.data-qa-notification-channel]="setting.channel" |
||||
[count]="item.value.length" |
||||
[first]="first" |
||||
[setting]="setting" |
||||
> |
||||
</tr> |
||||
<tr *ngIf="last" |
||||
class="op-notifications-settings-table--spacer"> |
||||
<td colspan="7"></td> |
||||
</tr> |
||||
<tr> |
||||
<th class="op-table--cell op-table--cell_soft-heading">{{ text.work_package_prioritized_header }}</th> |
||||
<ng-container *ngFor="let item of settings.controls"> |
||||
<td class="op-table--cell" [formGroup]="item"> |
||||
<input |
||||
type="checkbox" |
||||
formControlName="workPackagePrioritized" |
||||
data-qa-project-notification-type="work_package_prioritized" |
||||
[attr.data-qa-project]="item.controls.project.value.title" |
||||
/> |
||||
</td> |
||||
</ng-container> |
||||
</tr> |
||||
<tr> |
||||
<th class="op-table--cell op-table--cell_soft-heading">{{ text.work_package_commented_header }}</th> |
||||
<ng-container *ngFor="let item of settings.controls"> |
||||
<td class="op-table--cell" [formGroup]="item"> |
||||
<input |
||||
type="checkbox" |
||||
formControlName="workPackageCommented" |
||||
data-qa-project-notification-type="work_package_commented" |
||||
[attr.data-qa-project]="item.controls.project.value.title" |
||||
/> |
||||
</td> |
||||
</ng-container> |
||||
</ng-container> |
||||
</tbody> |
||||
</table> |
||||
<op-notification-setting-inline-create |
||||
*ngIf="userId" |
||||
[userId]="userId" |
||||
(selected)="addRow($event)" |
||||
data-qa-selector="notification-setting-inline-create" |
||||
></op-notification-setting-inline-create> |
||||
</div> |
||||
</div> |
||||
</tr> |
||||
<tr> |
||||
<th class="op-table--cell op-table--cell_soft-heading"></th> |
||||
<ng-container *ngFor="let item of settings.controls; let index = index"> |
||||
<td class="op-table--cell"> |
||||
<button |
||||
type="button" |
||||
class="op-link" |
||||
(click)="removeProjectSettings(index)" |
||||
> |
||||
Remove Project Settings |
||||
</button> |
||||
</td> |
||||
</ng-container> |
||||
</tr> |
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
|
||||
<op-notification-setting-inline-create |
||||
*ngIf="userId" |
||||
[userId]="userId" |
||||
[settings]="settings" |
||||
(selected)="addProjectSettings($event)" |
||||
data-qa-selector="notification-setting-inline-create" |
||||
></op-notification-setting-inline-create> |
@ -1,6 +1,2 @@ |
||||
.op-notifications-settings-table |
||||
&--spacer |
||||
|
||||
// The default table styles are a mess |
||||
td |
||||
padding: 0 !important |
||||
.op-table |
||||
margin-bottom: 1rem |
@ -0,0 +1,45 @@ |
||||
<ng-container *ngIf="!hidden"> |
||||
<label class="op-form-field--label-wrap op-checkbox-field--label-wrap"> |
||||
<div |
||||
class="op-form-field--input op-checkbox-field--input" |
||||
[attr.aria-describedby]="describedByID" |
||||
> |
||||
<ng-content select="[slot=input]"></ng-content> |
||||
</div> |
||||
|
||||
<div |
||||
*ngIf="label" |
||||
class="op-form-field--label op-checkbox-field--label" |
||||
> |
||||
<span |
||||
*ngIf="showErrorMessage" |
||||
class="Hidden for sighted" |
||||
>Invalid</span> |
||||
{{ label }} |
||||
<span *ngIf="required" class="op-form-field--label-indicator">*</span> |
||||
<attribute-help-text |
||||
[attribute]="helpTextAttribute" |
||||
[attributeScope]="helpTextAttributeScope" |
||||
></attribute-help-text> |
||||
</div> |
||||
|
||||
<div |
||||
class="op-form-field--description op-checkbox-field--description" |
||||
[id]="descriptionID" |
||||
> |
||||
<ng-content select="[slot=description]"></ng-content> |
||||
</div> |
||||
</label> |
||||
|
||||
<div class="op-form-field--help-text"> |
||||
<ng-content select="[slot=help-text]"></ng-content> |
||||
</div> |
||||
|
||||
<div |
||||
class="op-form-field--errors" |
||||
*ngIf="showErrorMessage" |
||||
[id]="errorsID" |
||||
> |
||||
<ng-content select="[slot=errors]"></ng-content> |
||||
</div> |
||||
</ng-container> |
@ -0,0 +1,80 @@ |
||||
import { |
||||
Component, |
||||
ContentChild, |
||||
HostBinding, |
||||
Input, |
||||
Optional, |
||||
} from '@angular/core'; |
||||
import { |
||||
AbstractControl, |
||||
FormGroupDirective, |
||||
NgControl, |
||||
} from '@angular/forms'; |
||||
|
||||
@Component({ |
||||
selector: 'op-checkbox-field', |
||||
templateUrl: './checkbox-field.component.html', |
||||
}) |
||||
export class OpCheckboxFieldComponent { |
||||
@HostBinding('class.op-form-field') className = true; |
||||
|
||||
@HostBinding('class.op-checkbox-field') classNameCheckbox = true; |
||||
|
||||
@HostBinding('class.op-form-field_invalid') get errorClassName():boolean { |
||||
return this.showErrorMessage; |
||||
} |
||||
|
||||
@Input() label = ''; |
||||
|
||||
@Input() hidden = false; |
||||
|
||||
@Input() required = false; |
||||
|
||||
@Input() showValidationErrorOn:'change' | 'blur' | 'submit' | 'never' = 'submit'; |
||||
|
||||
@Input() control?:AbstractControl; |
||||
|
||||
@Input() helpTextAttribute?:string; |
||||
|
||||
@Input() helpTextAttributeScope?:string; |
||||
|
||||
@ContentChild(NgControl) ngControl:NgControl; |
||||
|
||||
internalID = `op-checkbox-field-${+new Date()}`; |
||||
|
||||
get errorsID():string { |
||||
return `${this.internalID}-errors`; |
||||
} |
||||
|
||||
get descriptionID():string { |
||||
return `${this.internalID}-description`; |
||||
} |
||||
|
||||
get describedByID():string { |
||||
return this.showErrorMessage ? this.errorsID : this.descriptionID; |
||||
} |
||||
|
||||
get formControl():AbstractControl|undefined|null { |
||||
return this.ngControl?.control || this.control; |
||||
} |
||||
|
||||
get showErrorMessage():boolean { |
||||
if (!this.formControl) { |
||||
return false; |
||||
} |
||||
|
||||
if (this.showValidationErrorOn === 'submit') { |
||||
return this.formControl.invalid && this.formGroupDirective?.submitted; |
||||
} if (this.showValidationErrorOn === 'blur') { |
||||
return this.formControl.invalid && this.formControl.touched; |
||||
} if (this.showValidationErrorOn === 'change') { |
||||
return this.formControl.invalid && this.formControl.dirty; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
constructor( |
||||
@Optional() private formGroupDirective:FormGroupDirective, |
||||
) {} |
||||
} |
@ -0,0 +1,34 @@ |
||||
.op-checkbox-field |
||||
&--label-wrap |
||||
display: grid |
||||
grid-template-columns: auto 1fr |
||||
grid-template-rows: auto auto |
||||
|
||||
&--input |
||||
grid-column-start: 1 |
||||
grid-column-end: 2 |
||||
grid-row-start: 1 |
||||
grid-row-end: 3 |
||||
align-self: center |
||||
padding-right: 1rem |
||||
margin-bottom: 0 |
||||
|
||||
&--label |
||||
grid-column-start: 2 |
||||
grid-column-end: 2 |
||||
grid-row-start: 1 |
||||
grid-row-end: 2 |
||||
margin-bottom: 0 |
||||
|
||||
&--description |
||||
grid-column-start: 2 |
||||
grid-column-end: 2 |
||||
grid-row-start: 2 |
||||
grid-row-end: 3 |
||||
margin-bottom: 0 |
||||
|
||||
&--label, |
||||
&--description |
||||
white-space: pre-line |
||||
word-break: break-word |
||||
word-wrap: break-word |
@ -1,4 +1,5 @@ |
||||
@import './form-field/form-field' |
||||
@import './checkbox-field/checkbox-field' |
||||
@import './form' |
||||
@import './fieldset' |
||||
@import './highlighted-input' |
||||
|
@ -0,0 +1,6 @@ |
||||
.op-scrollable-table |
||||
max-width: 100% |
||||
overflow-x: scroll |
||||
|
||||
.op-table |
||||
width: auto |
@ -0,0 +1,18 @@ |
||||
.op-table |
||||
border-collapse: collapse |
||||
width: 100% |
||||
|
||||
&--cell |
||||
padding: 12px 16px |
||||
border: 1px solid #cccccc |
||||
text-align: center |
||||
|
||||
&_heading |
||||
background-color: #f3f3f3 |
||||
font-weight: bold |
||||
text-align: left |
||||
|
||||
&_soft-heading |
||||
background-color: transparent |
||||
text-align: left |
||||
font-weight: normal |
Loading…
Reference in new issue