20 changed files with 1217 additions and 323 deletions
@ -0,0 +1,56 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2019 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<form #ruleNodeLinkForm="ngForm" [formGroup]="ruleNodeLinkFormGroup" (ngSubmit)="add()" style="width: 900px;"> |
|||
<mat-toolbar fxLayout="row" color="primary"> |
|||
<h2 translate>rulenode.add-link</h2> |
|||
<span fxFlex></span> |
|||
<div [tb-help]="'ruleEngine'"></div> |
|||
<button mat-button mat-icon-button |
|||
(click)="cancel()" |
|||
type="button"> |
|||
<mat-icon class="material-icons">close</mat-icon> |
|||
</button> |
|||
</mat-toolbar> |
|||
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> |
|||
</mat-progress-bar> |
|||
<div mat-dialog-content> |
|||
<fieldset [disabled]="isLoading$ | async"> |
|||
<tb-rule-node-link |
|||
required |
|||
formControlName="link" |
|||
[allowedLabels]="labels" |
|||
[allowCustom]="allowCustomLabels"> |
|||
</tb-rule-node-link> |
|||
</fieldset> |
|||
</div> |
|||
<div mat-dialog-actions fxLayout="row"> |
|||
<span fxFlex></span> |
|||
<button mat-button mat-raised-button color="primary" |
|||
type="submit" |
|||
[disabled]="(isLoading$ | async) || ruleNodeLinkFormGroup.invalid || !ruleNodeLinkFormGroup.dirty"> |
|||
{{ 'action.add' | translate }} |
|||
</button> |
|||
<button mat-button color="primary" |
|||
style="margin-right: 20px;" |
|||
type="button" |
|||
[disabled]="(isLoading$ | async)" |
|||
(click)="cancel()" cdkFocusInitial> |
|||
{{ 'action.cancel' | translate }} |
|||
</button> |
|||
</div> |
|||
</form> |
|||
@ -0,0 +1,22 @@ |
|||
/** |
|||
* Copyright © 2016-2019 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
:host ::ng-deep { |
|||
tb-rule-node-link { |
|||
form { |
|||
overflow: hidden !important; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2019 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<mat-form-field [formGroup]="linksFormGroup" style="width: 100%;"> |
|||
<mat-label translate>rulenode.link-labels</mat-label> |
|||
<mat-chip-list #chipList> |
|||
<mat-chip |
|||
*ngFor="let label of labels" |
|||
[selectable]="!disabled" |
|||
[removable]="!disabled" |
|||
(removed)="remove(label)"> |
|||
{{label.name}} |
|||
<mat-icon matChipRemove *ngIf="!disabled">close</mat-icon> |
|||
</mat-chip> |
|||
<input matInput type="text" placeholder="{{ !disabled ? ('rulenode.link-label' | translate) : '' }}" |
|||
style="max-width: 200px;" |
|||
#labelInput |
|||
formControlName="label" |
|||
matAutocompleteOrigin |
|||
#origin="matAutocompleteOrigin" |
|||
[matAutocompleteConnectedTo]="origin" |
|||
[matAutocomplete]="labelAutocomplete" |
|||
[matChipInputFor]="chipList" |
|||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" |
|||
(matChipInputTokenEnd)="add($event)"> |
|||
</mat-chip-list> |
|||
<mat-autocomplete #labelAutocomplete="matAutocomplete" |
|||
class="tb-autocomplete" |
|||
(optionSelected)="selected($event)" |
|||
[displayWith]="displayLabelFn"> |
|||
<mat-option *ngFor="let label of filteredLabels | async" [value]="label"> |
|||
<span [innerHTML]="label.name | highlight:searchText"></span> |
|||
</mat-option> |
|||
<mat-option *ngIf="!(filteredLabels | async)?.length" [value]="null" class="tb-not-found"> |
|||
<div class="tb-not-found-content" (click)="$event.stopPropagation()"> |
|||
<div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty"> |
|||
<span translate>rulenode.no-link-labels-found</span> |
|||
</div> |
|||
<ng-template #searchNotEmpty> |
|||
<span> |
|||
{{ translate.get('rulenode.no-link-label-matching', |
|||
{label: truncate.transform(searchText, true, 6, '...')}) | async }} |
|||
</span> |
|||
</ng-template> |
|||
<span *ngIf="allowCustom"> |
|||
<a translate (click)="createLinkLabel($event, searchText)">rulenode.create-new-link-label</a> |
|||
</span> |
|||
</div> |
|||
</mat-option> |
|||
</mat-autocomplete> |
|||
</mat-form-field> |
|||
@ -0,0 +1,271 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { |
|||
AfterViewInit, |
|||
Component, ElementRef, |
|||
EventEmitter, forwardRef, |
|||
Input, |
|||
OnChanges, |
|||
OnInit, |
|||
Output, |
|||
SimpleChanges, |
|||
ViewChild |
|||
} from '@angular/core'; |
|||
import { PageComponent } from '@shared/components/page.component'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, NgForm, Validators } from '@angular/forms'; |
|||
import { FcRuleNode, FcRuleEdge } from './rulechain-page.models'; |
|||
import { RuleNodeType, LinkLabel } from '@shared/models/rule-node.models'; |
|||
import { EntityType } from '@shared/models/entity-type.models'; |
|||
import { Observable, of, Subscription } from 'rxjs'; |
|||
import { RuleChainService } from '@core/http/rule-chain.service'; |
|||
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
|||
import { deepClone } from '@core/utils'; |
|||
import { EntityAlias } from '@shared/models/alias.models'; |
|||
import { TruncatePipe } from '@shared/pipe/truncate.pipe'; |
|||
import { MatChipList, MatAutocomplete, MatChipInputEvent, MatAutocompleteSelectedEvent } from '@angular/material'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; |
|||
import { map, mergeMap, share, startWith } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-link-labels', |
|||
templateUrl: './link-labels.component.html', |
|||
styleUrls: [], |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => LinkLabelsComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChanges { |
|||
|
|||
@ViewChild('chipList', {static: false}) chipList: MatChipList; |
|||
@ViewChild('labelAutocomplete', {static: false}) matAutocomplete: MatAutocomplete; |
|||
@ViewChild('labelInput', {static: false}) labelInput: ElementRef<HTMLInputElement>; |
|||
|
|||
private requiredValue: boolean; |
|||
get required(): boolean { |
|||
return this.requiredValue; |
|||
} |
|||
@Input() |
|||
set required(value: boolean) { |
|||
this.requiredValue = coerceBooleanProperty(value); |
|||
} |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
private allowCustomValue: boolean; |
|||
get allowCustom(): boolean { |
|||
return this.allowCustomValue; |
|||
} |
|||
@Input() |
|||
set allowCustom(value: boolean) { |
|||
this.allowCustomValue = coerceBooleanProperty(value); |
|||
this.separatorKeysCodes = this.allowCustomValue ? [ENTER, COMMA, SEMICOLON] : []; |
|||
} |
|||
|
|||
@Input() |
|||
allowedLabels: {[label: string]: LinkLabel}; |
|||
|
|||
linksFormGroup: FormGroup; |
|||
|
|||
modelValue: Array<string>; |
|||
|
|||
private labelsList: Array<LinkLabel> = []; |
|||
|
|||
separatorKeysCodes: number[] = []; |
|||
|
|||
filteredLabels: Observable<Array<LinkLabel>>; |
|||
|
|||
private labels: Array<LinkLabel> = []; |
|||
|
|||
private searchText = ''; |
|||
|
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private fb: FormBuilder, |
|||
public truncate: TruncatePipe, |
|||
public translate: TranslateService) { |
|||
this.linksFormGroup = this.fb.group({ |
|||
label: [null] |
|||
}); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
|
|||
ngOnInit(): void { |
|||
this.filteredLabels = this.linksFormGroup.get('label').valueChanges |
|||
.pipe( |
|||
startWith(''), |
|||
map((value) => value ? value : ''), |
|||
mergeMap(name => this.fetchLabels(name) ), |
|||
share() |
|||
); |
|||
} |
|||
|
|||
ngOnChanges(changes: SimpleChanges): void { |
|||
let reloadLabels = false; |
|||
for (const propName of Object.keys(changes)) { |
|||
const change = changes[propName]; |
|||
if (change.currentValue !== change.previousValue) { |
|||
if (['allowCustom', 'allowedLabels'].includes(propName)) { |
|||
reloadLabels = true; |
|||
} |
|||
} |
|||
} |
|||
if (reloadLabels) { |
|||
this.linksFormGroup.get('label').patchValue('', {emitEvent: true}); |
|||
} |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (this.disabled) { |
|||
this.linksFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.linksFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: string[]): void { |
|||
this.searchText = ''; |
|||
this.labelsList.length = 0; |
|||
this.labels.length = 0; |
|||
this.modelValue = value; |
|||
for (const label of Object.keys(this.allowedLabels)) { |
|||
this.labelsList.push({name: this.allowedLabels[label].name, value: this.allowedLabels[label].value}); |
|||
} |
|||
if (value) { |
|||
value.forEach((label) => { |
|||
if (this.allowedLabels[label]) { |
|||
this.labels.push(deepClone(this.allowedLabels[label])); |
|||
} else { |
|||
this.labels.push({ |
|||
name: label, |
|||
value: label |
|||
}); |
|||
} |
|||
}); |
|||
} |
|||
if (this.chipList && this.required) { |
|||
this.chipList.errorState = this.labels.length ? false : true; |
|||
} |
|||
this.linksFormGroup.get('label').patchValue('', {emitEvent: true}); |
|||
} |
|||
|
|||
displayLabelFn(label?: LinkLabel): string | undefined { |
|||
return label ? label.name : undefined; |
|||
} |
|||
|
|||
textIsNotEmpty(text: string): boolean { |
|||
return (text && text != null && text.length > 0) ? true : false; |
|||
} |
|||
|
|||
createLinkLabel($event: Event, value: string) { |
|||
$event.preventDefault(); |
|||
this.transformLinkLabel(value); |
|||
} |
|||
|
|||
add(event: MatChipInputEvent): void { |
|||
if (!this.matAutocomplete.isOpen) { |
|||
this.transformLinkLabel(event.value); |
|||
} |
|||
} |
|||
|
|||
private fetchLabels(searchText?: string): Observable<Array<LinkLabel>> { |
|||
this.searchText = searchText; |
|||
if (this.searchText && this.searchText.length) { |
|||
const search = this.searchText.toUpperCase(); |
|||
return of(this.labelsList.filter(label => label.name.toUpperCase().includes(search))); |
|||
} else { |
|||
return of(this.labelsList); |
|||
} |
|||
} |
|||
|
|||
private transformLinkLabel(value: string) { |
|||
if ((value || '').trim()) { |
|||
let newLabel: LinkLabel = null; |
|||
const labelName = value.trim(); |
|||
const existingLabel = this.labelsList.find(label => label.name === labelName); |
|||
if (existingLabel) { |
|||
newLabel = deepClone(existingLabel); |
|||
} else if (this.allowCustom) { |
|||
newLabel = { |
|||
name: labelName, |
|||
value: labelName |
|||
}; |
|||
} |
|||
if (newLabel) { |
|||
this.addLabel(newLabel); |
|||
} |
|||
} |
|||
this.clear(''); |
|||
} |
|||
|
|||
remove(label: LinkLabel) { |
|||
const index = this.labels.indexOf(label); |
|||
if (index >= 0) { |
|||
this.labels.splice(index, 1); |
|||
if (!this.labels.length) { |
|||
if (this.required) { |
|||
this.chipList.errorState = true; |
|||
} |
|||
} |
|||
this.updateModel(); |
|||
} |
|||
} |
|||
|
|||
selected(event: MatAutocompleteSelectedEvent): void { |
|||
this.addLabel(event.option.value); |
|||
this.clear(''); |
|||
} |
|||
|
|||
addLabel(label: LinkLabel): void { |
|||
const index = this.labels.findIndex(existinglabel => existinglabel.value === label.value); |
|||
if (index === -1) { |
|||
this.labels.push(label); |
|||
if (this.required) { |
|||
this.chipList.errorState = false; |
|||
} |
|||
} |
|||
this.updateModel(); |
|||
} |
|||
|
|||
clear(value: string = '') { |
|||
this.labelInput.nativeElement.value = value; |
|||
this.linksFormGroup.get('label').patchValue(null, {emitEvent: true}); |
|||
setTimeout(() => { |
|||
this.labelInput.nativeElement.blur(); |
|||
this.labelInput.nativeElement.focus(); |
|||
}, 0); |
|||
} |
|||
|
|||
private updateModel() { |
|||
const labels = this.labels.map((label => label.value)); |
|||
this.propagateChange(labels); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,28 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2019 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<div class="mat-padding" fxLayout="column"> |
|||
<form #ruleNodeLinkForm="ngForm" [formGroup]="ruleNodeLinkFormGroup"> |
|||
<tb-link-labels |
|||
fxFlex |
|||
required |
|||
formControlName="labels" |
|||
[allowedLabels]="allowedLabels" |
|||
[allowCustom]="allowCustom" |
|||
></tb-link-labels> |
|||
</form> |
|||
</div> |
|||
@ -0,0 +1,135 @@ |
|||
///
|
|||
/// Copyright © 2016-2019 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { |
|||
AfterViewInit, |
|||
Component, ElementRef, |
|||
EventEmitter, forwardRef, |
|||
Input, |
|||
OnChanges, |
|||
OnInit, |
|||
Output, |
|||
SimpleChanges, |
|||
ViewChild |
|||
} from '@angular/core'; |
|||
import { PageComponent } from '@shared/components/page.component'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, NgForm, Validators } from '@angular/forms'; |
|||
import { FcRuleNode, FcRuleEdge } from './rulechain-page.models'; |
|||
import { RuleNodeType, LinkLabel } from '@shared/models/rule-node.models'; |
|||
import { EntityType } from '@shared/models/entity-type.models'; |
|||
import { Observable, of, Subscription } from 'rxjs'; |
|||
import { RuleChainService } from '@core/http/rule-chain.service'; |
|||
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
|||
import { deepClone } from '@core/utils'; |
|||
import { EntityAlias } from '@shared/models/alias.models'; |
|||
import { TruncatePipe } from '@shared/pipe/truncate.pipe'; |
|||
import { MatChipList, MatAutocomplete, MatChipInputEvent, MatAutocompleteSelectedEvent } from '@angular/material'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; |
|||
import { map, mergeMap, share } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-rule-node-link', |
|||
templateUrl: './rule-node-link.component.html', |
|||
styleUrls: [], |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => RuleNodeLinkComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class RuleNodeLinkComponent implements ControlValueAccessor, OnInit { |
|||
|
|||
@ViewChild('ruleNodeLinkForm', {static: true}) ruleNodeLinkForm: NgForm; |
|||
|
|||
private requiredValue: boolean; |
|||
get required(): boolean { |
|||
return this.requiredValue; |
|||
} |
|||
@Input() |
|||
set required(value: boolean) { |
|||
this.requiredValue = coerceBooleanProperty(value); |
|||
} |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
private allowCustomValue: boolean; |
|||
get allowCustom(): boolean { |
|||
return this.allowCustomValue; |
|||
} |
|||
@Input() |
|||
set allowCustom(value: boolean) { |
|||
this.allowCustomValue = coerceBooleanProperty(value); |
|||
} |
|||
|
|||
@Input() |
|||
allowedLabels: {[label: string]: LinkLabel}; |
|||
|
|||
ruleNodeLinkFormGroup: FormGroup; |
|||
|
|||
modelValue: FcRuleEdge; |
|||
|
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private fb: FormBuilder, |
|||
public truncate: TruncatePipe, |
|||
public translate: TranslateService) { |
|||
this.ruleNodeLinkFormGroup = this.fb.group({ |
|||
labels: [[], Validators.required] |
|||
}); |
|||
this.ruleNodeLinkFormGroup.get('labels').valueChanges.subscribe( |
|||
(labels: string[]) => this.updateModel(labels) |
|||
); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (this.disabled) { |
|||
this.ruleNodeLinkFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.ruleNodeLinkFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: FcRuleEdge): void { |
|||
this.modelValue = value; |
|||
const labels = this.modelValue && this.modelValue.labels ? this.modelValue.labels : []; |
|||
this.ruleNodeLinkFormGroup.get('labels').patchValue(labels, {emitEvent: false}); |
|||
} |
|||
|
|||
private updateModel(labels: string[]) { |
|||
if (labels && labels.length) { |
|||
this.modelValue.labels = labels; |
|||
this.modelValue.label = labels.join(' / '); |
|||
this.propagateChange(this.modelValue); |
|||
} else { |
|||
this.propagateChange(this.required ? null : this.modelValue); |
|||
} |
|||
} |
|||
} |
|||
@ -1,70 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2019 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
.tooltipster-base { |
|||
.tb-rule-node-tooltip, |
|||
.tb-rule-node-help { |
|||
color: #333; |
|||
} |
|||
|
|||
.tb-rule-node-tooltip { |
|||
max-width: 300px; |
|||
font-size: 14px; |
|||
|
|||
&.tb-lib-tooltip { |
|||
width: 300px; |
|||
} |
|||
} |
|||
|
|||
.tb-rule-node-help { |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.tb-rule-node-error-tooltip { |
|||
font-size: 16px; |
|||
color: #ea0d0d; |
|||
} |
|||
|
|||
.tb-rule-node-tooltip, |
|||
.tb-rule-node-error-tooltip, |
|||
.tb-rule-node-help { |
|||
#tb-node-content { |
|||
.tb-node-title { |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.tb-node-description { |
|||
font-style: italic; |
|||
color: #555; |
|||
} |
|||
|
|||
.tb-node-details { |
|||
padding-top: 10px; |
|||
padding-bottom: 10px; |
|||
} |
|||
|
|||
code { |
|||
padding: 0 3px 2px 3px; |
|||
margin: 1px; |
|||
font-size: 12px; |
|||
color: #ad1625; |
|||
white-space: nowrap; |
|||
background-color: #f7f7f9; |
|||
border: 1px solid #e1e1e8; |
|||
border-radius: 2px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue