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