]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/shared/components/select/select.component.ts
3ff19fe04c238fb4debf1eba264ee8d9972d4de4
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / shared / components / select / select.component.ts
1 import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
2 import { FormControl, ValidatorFn } from '@angular/forms';
3
4 import _ from 'lodash';
5
6 import { Icons } from '~/app/shared/enum/icons.enum';
7 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
8 import { SelectMessages } from './select-messages.model';
9 import { SelectOption } from './select-option.model';
10
11 @Component({
12 selector: 'cd-select',
13 templateUrl: './select.component.html',
14 styleUrls: ['./select.component.scss']
15 })
16 export class SelectComponent implements OnInit, OnChanges {
17 @Input()
18 elemClass: string;
19 @Input()
20 data: Array<string> = [];
21 @Input()
22 options: Array<SelectOption> = [];
23 @Input()
24 messages = new SelectMessages({});
25 @Input()
26 selectionLimit: number;
27 @Input()
28 customBadges = false;
29 @Input()
30 customBadgeValidators: ValidatorFn[] = [];
31
32 @Output()
33 selection = new EventEmitter();
34
35 form: CdFormGroup;
36 filter: FormControl;
37 Object = Object;
38 filteredOptions: Array<SelectOption> = [];
39 icons = Icons;
40
41 ngOnInit() {
42 this.initFilter();
43 if (this.data.length > 0) {
44 this.initMissingOptions();
45 }
46 this.options = _.sortBy(this.options, ['name']);
47 this.updateOptions();
48 }
49
50 private initFilter() {
51 this.filter = new FormControl('', { validators: this.customBadgeValidators });
52 this.form = new CdFormGroup({ filter: this.filter });
53 this.filteredOptions = [...(this.options || [])];
54 }
55
56 private initMissingOptions() {
57 const options = this.options.map((option) => option.name);
58 const needToCreate = this.data.filter((option) => options.indexOf(option) === -1);
59 needToCreate.forEach((option) => this.addOption(option));
60 this.forceOptionsToReflectData();
61 }
62
63 private addOption(name: string) {
64 this.options.push(new SelectOption(false, name, ''));
65 this.options = _.sortBy(this.options, ['name']);
66 this.triggerSelection(this.options.find((option) => option.name === name));
67 }
68
69 triggerSelection(option: SelectOption) {
70 if (
71 !option ||
72 (this.selectionLimit && !option.selected && this.data.length >= this.selectionLimit)
73 ) {
74 return;
75 }
76 option.selected = !option.selected;
77 this.updateOptions();
78 this.selection.emit({ option: option });
79 }
80
81 private updateOptions() {
82 this.data.splice(0, this.data.length);
83 this.options.forEach((option: SelectOption) => {
84 if (option.selected) {
85 this.data.push(option.name);
86 }
87 });
88 this.updateFilter();
89 }
90
91 updateFilter() {
92 this.filteredOptions = this.options.filter((option) => option.name.includes(this.filter.value));
93 }
94
95 private forceOptionsToReflectData() {
96 this.options.forEach((option) => {
97 if (this.data.indexOf(option.name) !== -1) {
98 option.selected = true;
99 }
100 });
101 }
102
103 ngOnChanges() {
104 if (this.filter) {
105 this.updateFilter();
106 }
107 if (!this.options || !this.data || this.data.length === 0) {
108 return;
109 }
110 this.forceOptionsToReflectData();
111 }
112
113 selectOption() {
114 if (this.filteredOptions.length === 0) {
115 this.addCustomOption();
116 } else {
117 this.triggerSelection(this.filteredOptions[0]);
118 this.resetFilter();
119 }
120 }
121
122 addCustomOption() {
123 if (!this.isCreatable()) {
124 return;
125 }
126 this.addOption(this.filter.value);
127 this.resetFilter();
128 }
129
130 isCreatable() {
131 return (
132 this.customBadges &&
133 this.filter.valid &&
134 this.filter.value.length > 0 &&
135 this.filteredOptions.every((option) => option.name !== this.filter.value)
136 );
137 }
138
139 private resetFilter() {
140 this.filter.setValue('');
141 this.updateFilter();
142 }
143
144 removeItem(item: string) {
145 this.triggerSelection(
146 this.options.find((option: SelectOption) => option.name === item && option.selected)
147 );
148 }
149 }