UI: Minor change in notification

This commit is contained in:
Vladyslav_Prykhodko 2023-03-22 11:53:29 +02:00
parent d4547ade3d
commit fa1a5f086f
18 changed files with 193 additions and 187 deletions

View File

@ -186,7 +186,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS
NotificationTemplate ruleEngineComponentLifecycleFailureNotificationTemplate = createTemplate(tenantId, "Rule chain/node lifecycle failure notification", NotificationType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT,
"${componentType} '${componentName}' failed to ${action}",
"Rule chain '${ruleChainName}' - ${action} failure:<br/>${error}",
"warning", "Go to Rule chain", "/ruleChains/${ruleChainId}");
"warning", "Go to Rule chain", "/features/ruleChains/${ruleChainId}");
RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig ruleEngineComponentLifecycleEventRuleTriggerConfig = new RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig();
ruleEngineComponentLifecycleEventRuleTriggerConfig.setRuleChains(null);
ruleEngineComponentLifecycleEventRuleTriggerConfig.setRuleChainEvents(Set.of(ComponentLifecycleEvent.STARTED, ComponentLifecycleEvent.UPDATED, ComponentLifecycleEvent.STOPPED));

View File

@ -212,13 +212,6 @@ export class MenuService {
icon: 'mdi:message-badge',
isMdiIcon: true
},
{
id: guid(),
name: 'notification.notification',
type: 'link',
path: '/settings/notification',
icon: 'notifications'
},
{
id: guid(),
name: 'admin.queues',
@ -311,11 +304,6 @@ export class MenuService {
icon: 'sms',
path: '/settings/sms-provider'
},
{
name: 'notification.notification',
icon: 'notifications',
path: '/settings/notification'
},
{
name: 'admin.security-settings',
icon: 'security',
@ -585,13 +573,6 @@ export class MenuService {
path: '/settings/home',
icon: 'settings_applications'
},
{
id: guid(),
name: 'notification.notification',
type: 'link',
path: '/settings/notification',
icon: 'notifications'
},
{
id: guid(),
name: 'admin.repository',
@ -767,11 +748,6 @@ export class MenuService {
icon: 'settings_applications',
path: '/settings/home'
},
{
name: 'notification.notification',
icon: 'notifications',
path: '/settings/notification'
},
{
name: 'resource.resources-library',
icon: 'folder',

View File

@ -39,7 +39,6 @@ import { TwoFactorAuthSettingsComponent } from '@home/pages/admin/two-factor-aut
import { widgetsBundlesRoutes } from '@home/pages/widget/widget-library-routing.module';
import { RouterTabsComponent } from '@home/components/router-tabs.component';
import { auditLogsRoutes } from '@home/pages/audit-log/audit-log-routing.module';
import { NotificationSettingsComponent } from '@home/pages/admin/notification-settings.component';
@Injectable()
export class OAuth2LoginProcessingUrlResolver implements Resolve<string> {

View File

@ -32,7 +32,6 @@ import { QueueComponent } from '@home/pages/admin/queue/queue.component';
import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component';
import { AutoCommitAdminSettingsComponent } from '@home/pages/admin/auto-commit-admin-settings.component';
import { TwoFactorAuthSettingsComponent } from '@home/pages/admin/two-factor-auth-settings.component';
import { NotificationSettingsComponent } from '@home/pages/admin/notification-settings.component';
@NgModule({
declarations:
@ -48,8 +47,7 @@ import { NotificationSettingsComponent } from '@home/pages/admin/notification-se
QueueComponent,
RepositoryAdminSettingsComponent,
AutoCommitAdminSettingsComponent,
TwoFactorAuthSettingsComponent,
NotificationSettingsComponent
TwoFactorAuthSettingsComponent
],
imports: [
CommonModule,

View File

@ -1,49 +0,0 @@
<!--
Copyright © 2016-2023 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>
<mat-card appearance="outlined" class="settings-card">
<mat-card-header>
<mat-card-title>
<div fxLayout="row">
<span class="mat-headline-5" translate>admin.notification.notification-settings</span>
</div>
</mat-card-title>
</mat-card-header>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<mat-card-content style="padding-top: 16px;">
<form [formGroup]="notificationSettingsForm" (ngSubmit)="save()">
<fieldset [disabled]="isLoading$ | async" formGroupName="deliveryMethodsConfigs">
<fieldset class="fields-group" formGroupName="SLACK">
<legend class="group-title" translate>admin.notification.slack</legend>
<mat-form-field class="mat-block">
<mat-label translate>admin.notification.slack-api-token</mat-label>
<input matInput formControlName="botToken" />
</mat-form-field>
</fieldset>
<div fxLayout="row" fxLayoutAlign="end center" class="layout-wrap">
<button mat-button mat-raised-button color="primary" [disabled]="(isLoading$ | async) || notificationSettingsForm.invalid || !notificationSettingsForm.dirty"
type="submit">{{'action.save' | translate}}
</button>
</div>
</fieldset>
</form>
</mat-card-content>
</mat-card>
</div>

View File

@ -1,86 +0,0 @@
///
/// Copyright © 2016-2023 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 { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { PageComponent } from '@shared/components/page.component';
import { FormBuilder, FormGroup } from '@angular/forms';
import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard';
import { NotificationService } from '@core/http/notification.service';
import { NotificationSettings } from '@shared/models/notification.models';
import { deepTrim, isEmptyStr } from '@core/utils';
@Component({
selector: 'tb-notification-settings',
templateUrl: './notification-settings.component.html',
styleUrls: ['./settings-card.scss']
})
export class NotificationSettingsComponent extends PageComponent implements OnInit, HasConfirmForm {
notificationSettingsForm: FormGroup;
private notificationSettings: NotificationSettings;
constructor(protected store: Store<AppState>,
private notificationService: NotificationService,
public fb: FormBuilder) {
super(store);
}
ngOnInit() {
this.buildGeneralServerSettingsForm();
this.notificationService.getNotificationSettings().subscribe(
(settings) => {
this.notificationSettings = settings;
this.notificationSettingsForm.reset(this.notificationSettings);
}
);
}
buildGeneralServerSettingsForm() {
this.notificationSettingsForm = this.fb.group({
deliveryMethodsConfigs: this.fb.group({
SLACK: this.fb.group({
botToken: ['']
})
})
});
}
save(): void {
this.notificationSettings = deepTrim({
...this.notificationSettings,
...this.notificationSettingsForm.value
});
for (const method in this.notificationSettings.deliveryMethodsConfigs) {
const keys = Object.keys(this.notificationSettings.deliveryMethodsConfigs[method]);
if (keys.some(item => isEmptyStr(this.notificationSettings.deliveryMethodsConfigs[method][item]))) {
delete this.notificationSettings.deliveryMethodsConfigs[method];
} else {
this.notificationSettings.deliveryMethodsConfigs[method].method = method;
}
}
this.notificationService.saveNotificationSettings(this.notificationSettings).subscribe(setting => {
this.notificationSettings = setting;
this.notificationSettingsForm.reset(this.notificationSettings);
});
}
confirmForm(): FormGroup {
return this.notificationSettingsForm;
}
}

View File

@ -47,4 +47,34 @@
</form>
</mat-card-content>
</mat-card>
<mat-card appearance="outlined" class="settings-card">
<!-- <mat-card-header>-->
<!-- <mat-card-title>-->
<!-- <div fxLayout="row">-->
<!-- <span class="mat-headline-5" translate>admin.notifications-settings</span>-->
<!-- </div>-->
<!-- </mat-card-title>-->
<!-- </mat-card-header>-->
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<mat-card-content style="padding-top: 16px;">
<form [formGroup]="notificationSettingsForm" (ngSubmit)="saveNotification()">
<fieldset [disabled]="isLoading$ | async" formGroupName="deliveryMethodsConfigs">
<fieldset class="fields-group" formGroupName="SLACK">
<legend class="group-title" translate>admin.slack</legend>
<mat-form-field class="mat-block">
<mat-label translate>admin.slack-api-token</mat-label>
<input matInput formControlName="botToken" />
</mat-form-field>
</fieldset>
<div fxLayout="row" fxLayoutAlign="end center" class="layout-wrap">
<button mat-button mat-raised-button color="primary" [disabled]="(isLoading$ | async) || notificationSettingsForm.invalid || !notificationSettingsForm.dirty"
type="submit">{{'action.save' | translate}}
</button>
</div>
</fieldset>
</form>
</mat-card-content>
</mat-card>
</div>

View File

@ -19,12 +19,15 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { PageComponent } from '@shared/components/page.component';
import { Router } from '@angular/router';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { AdminSettings, SmsProviderConfiguration } from '@shared/models/settings.models';
import { AdminService } from '@core/http/admin.service';
import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard';
import { MatDialog } from '@angular/material/dialog';
import { SendTestSmsDialogComponent, SendTestSmsDialogData } from '@home/pages/admin/send-test-sms-dialog.component';
import { NotificationSettings } from '@shared/models/notification.models';
import { deepTrim, isEmptyStr } from '@core/utils';
import { NotificationService } from '@core/http/notification.service';
@Component({
selector: 'tb-sms-provider',
@ -33,35 +36,46 @@ import { SendTestSmsDialogComponent, SendTestSmsDialogData } from '@home/pages/a
})
export class SmsProviderComponent extends PageComponent implements OnInit, HasConfirmForm {
smsProvider: UntypedFormGroup;
smsProvider: FormGroup;
adminSettings: AdminSettings<SmsProviderConfiguration>;
notificationSettingsForm: FormGroup;
private notificationSettings: NotificationSettings;
constructor(protected store: Store<AppState>,
private router: Router,
private adminService: AdminService,
private notificationService: NotificationService,
private dialog: MatDialog,
public fb: UntypedFormBuilder) {
public fb: FormBuilder) {
super(store);
}
ngOnInit() {
this.buildSmsProviderForm();
this.adminService.getAdminSettings<SmsProviderConfiguration>('sms', {ignoreErrors: true}).subscribe(
(adminSettings) => {
this.buildGeneralServerSettingsForm();
this.notificationService.getNotificationSettings().subscribe(
(settings) => {
this.notificationSettings = settings;
this.notificationSettingsForm.reset(this.notificationSettings);
}
);
this.adminService.getAdminSettings<SmsProviderConfiguration>('sms', {ignoreErrors: true}).subscribe({
next: adminSettings => {
this.adminSettings = adminSettings;
this.smsProvider.reset({configuration: this.adminSettings.jsonValue});
},
() => {
error: () => {
this.adminSettings = {
key: 'sms',
jsonValue: null
};
this.smsProvider.reset({configuration: this.adminSettings.jsonValue});
}
);
});
}
buildSmsProviderForm() {
private buildSmsProviderForm() {
this.smsProvider = this.fb.group({
configuration: [null, [Validators.required]]
});
@ -88,8 +102,38 @@ export class SmsProviderComponent extends PageComponent implements OnInit, HasCo
);
}
confirmForm(): UntypedFormGroup {
return this.smsProvider;
confirmForm(): FormGroup {
return this.smsProvider.dirty ? this.smsProvider : this.notificationSettingsForm;
}
private buildGeneralServerSettingsForm() {
this.notificationSettingsForm = this.fb.group({
deliveryMethodsConfigs: this.fb.group({
SLACK: this.fb.group({
botToken: ['']
})
})
});
}
saveNotification(): void {
this.notificationSettings = deepTrim({
...this.notificationSettings,
...this.notificationSettingsForm.value
});
// eslint-disable-next-line guard-for-in
for (const method in this.notificationSettings.deliveryMethodsConfigs) {
const keys = Object.keys(this.notificationSettings.deliveryMethodsConfigs[method]);
if (keys.some(item => isEmptyStr(this.notificationSettings.deliveryMethodsConfigs[method][item]))) {
delete this.notificationSettings.deliveryMethodsConfigs[method];
} else {
this.notificationSettings.deliveryMethodsConfigs[method].method = method;
}
}
this.notificationService.saveNotificationSettings(this.notificationSettings).subscribe(setting => {
this.notificationSettings = setting;
this.notificationSettingsForm.reset(this.notificationSettings);
});
}
}

View File

@ -36,6 +36,7 @@ import { EscalationFormComponent } from '@home/pages/notification/rule/escalatio
import { EscalationsComponent } from '@home/pages/notification/rule/escalations.component';
import { RuleNotificationDialogComponent } from '@home/pages/notification/rule/rule-notification-dialog.component';
import { RuleTableHeaderComponent } from '@home/pages/notification/rule/rule-table-header.component';
import { SentTableHeaderComponent } from '@home/pages/notification/sent/sent-table-header.component';
@NgModule({
declarations: [
@ -51,7 +52,8 @@ import { RuleTableHeaderComponent } from '@home/pages/notification/rule/rule-tab
EscalationFormComponent,
EscalationsComponent,
RuleNotificationDialogComponent,
RuleTableHeaderComponent
RuleTableHeaderComponent,
SentTableHeaderComponent
],
imports: [
CommonModule,

View File

@ -16,6 +16,7 @@
import {
CellActionDescriptor,
DateEntityTableColumn,
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
@ -33,6 +34,7 @@ import { EntityAction } from '@home/models/entity/entity-component.models';
import { RecipientTableHeaderComponent } from '@home/pages/notification/recipient/recipient-table-header.component';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { Injectable } from '@angular/core';
import { DatePipe } from '@angular/common';
@Injectable()
export class RecipientTableConfigResolver implements Resolve<EntityTableConfig<NotificationTarget>> {
@ -41,7 +43,8 @@ export class RecipientTableConfigResolver implements Resolve<EntityTableConfig<N
constructor(private notificationService: NotificationService,
private translate: TranslateService,
private dialog: MatDialog) {
private dialog: MatDialog,
private datePipe: DatePipe) {
this.config.detailsPanelEnabled = false;
this.config.selectionEnabled = false;
@ -65,7 +68,7 @@ export class RecipientTableConfigResolver implements Resolve<EntityTableConfig<N
this.config.headerComponent = RecipientTableHeaderComponent;
this.config.onEntityAction = action => this.onTargetAction(action);
this.config.defaultSortOrder = {property: 'name', direction: Direction.ASC};
this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.config.handleRowClick = ($event, target) => {
this.editTarget($event, target);
@ -73,6 +76,7 @@ export class RecipientTableConfigResolver implements Resolve<EntityTableConfig<N
};
this.config.columns.push(
new DateEntityTableColumn<NotificationTarget>('createdTime', 'notification.created-time', this.datePipe, '170px'),
new EntityTableColumn<NotificationTarget>('name', 'notification.notification-target', '20%'),
new EntityTableColumn<NotificationTarget>('configuration.type', 'notification.type', '20%',
(target) => this.translate.instant(NotificationTargetTypeTranslationMap.get(target.configuration.type)),

View File

@ -16,6 +16,7 @@
import {
CellActionDescriptor,
DateEntityTableColumn,
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
@ -33,6 +34,7 @@ import {
} from '@home/pages/notification/rule/rule-notification-dialog.component';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { Injectable } from '@angular/core';
import { DatePipe } from '@angular/common';
@Injectable()
export class RuleTableConfigResolver implements Resolve<EntityTableConfig<NotificationRule>> {
@ -41,7 +43,8 @@ export class RuleTableConfigResolver implements Resolve<EntityTableConfig<Notifi
constructor(private notificationService: NotificationService,
private translate: TranslateService,
private dialog: MatDialog) {
private dialog: MatDialog,
private datePipe: DatePipe) {
this.config.detailsPanelEnabled = false;
this.config.selectionEnabled = false;
@ -64,7 +67,7 @@ export class RuleTableConfigResolver implements Resolve<EntityTableConfig<Notifi
this.config.headerComponent = RuleTableHeaderComponent;
this.config.onEntityAction = action => this.onTargetAction(action);
this.config.defaultSortOrder = {property: 'name', direction: Direction.ASC};
this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.config.handleRowClick = ($event, rule) => {
this.editRule($event, rule);
@ -72,6 +75,7 @@ export class RuleTableConfigResolver implements Resolve<EntityTableConfig<Notifi
};
this.config.columns.push(
new DateEntityTableColumn<NotificationRule>('createdTime', 'notification.created-time', this.datePipe, '170px'),
new EntityTableColumn<NotificationRule>('name', 'notification.rule-name', '30%'),
new EntityTableColumn<NotificationRule>('templateName', 'notification.template', '20%'),
new EntityTableColumn<NotificationRule>('triggerType', 'notification.trigger.trigger', '20%',

View File

@ -47,6 +47,7 @@ import {
} from '@home/pages/notification/sent/sent-error-dialog.component';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { Injectable } from '@angular/core';
import { SentTableHeaderComponent } from '@home/pages/notification/sent/sent-table-header.component';
@Injectable()
export class SentTableConfigResolver implements Resolve<EntityTableConfig<NotificationRequest, PageLink, NotificationRequestInfo>> {
@ -77,6 +78,7 @@ export class SentTableConfigResolver implements Resolve<EntityTableConfig<Notifi
this.config.cellActionDescriptors = this.configureCellActions();
this.config.headerComponent = SentTableHeaderComponent;
this.config.onEntityAction = action => this.onRequestAction(action);
this.config.handleRowClick = (event, entity) => {

View File

@ -0,0 +1,24 @@
<!--
Copyright © 2016-2023 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 fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
<button mat-flat-button color="primary" (click)="sendNotification($event)">
<div fxLayout="row" fxLayoutAlign="start center">
<mat-icon>send</mat-icon>{{ 'notification.send-notification' | translate }}
</div>
</button>
</div>

View File

@ -0,0 +1,18 @@
/**
* Copyright © 2016-2023 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{
width: 10000px;
}

View File

@ -0,0 +1,39 @@
///
/// Copyright © 2016-2023 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 { Component } from '@angular/core';
import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { NotificationRequest, NotificationRequestInfo } from '@shared/models/notification.models';
import { PageLink } from '@shared/models/page/page-link';
@Component({
selector: 'tb-sent-table-header',
templateUrl: './sent-table-header.component.html',
styleUrls: ['sent-table-header.component.scss']
})
export class SentTableHeaderComponent extends EntityTableHeaderComponent<NotificationRequest, PageLink, NotificationRequestInfo> {
constructor(protected store: Store<AppState>) {
super(store);
}
sendNotification($event: Event) {
this.entitiesTableConfig.onEntityAction({event: $event, action: 'add', entity: null});
}
}

View File

@ -16,6 +16,7 @@
import {
CellActionDescriptor,
DateEntityTableColumn,
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
@ -33,6 +34,7 @@ import { TranslateService } from '@ngx-translate/core';
import { TemplateTableHeaderComponent } from '@home/pages/notification/template/template-table-header.component';
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { DatePipe } from '@angular/common';
@Injectable()
export class TemplateTableConfigResolver implements Resolve<EntityTableConfig<NotificationTemplate>> {
@ -41,7 +43,8 @@ export class TemplateTableConfigResolver implements Resolve<EntityTableConfig<No
constructor(private notificationService: NotificationService,
private translate: TranslateService,
private dialog: MatDialog) {
private dialog: MatDialog,
private datePipe: DatePipe) {
this.config.detailsPanelEnabled = false;
this.config.selectionEnabled = false;
@ -65,7 +68,7 @@ export class TemplateTableConfigResolver implements Resolve<EntityTableConfig<No
this.config.headerComponent = TemplateTableHeaderComponent;
this.config.onEntityAction = action => this.onTemplateAction(action);
this.config.defaultSortOrder = {property: 'notificationType', direction: Direction.ASC};
this.config.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.config.handleRowClick = ($event, template) => {
this.editTemplate($event, template);
@ -73,6 +76,7 @@ export class TemplateTableConfigResolver implements Resolve<EntityTableConfig<No
};
this.config.columns.push(
new DateEntityTableColumn<NotificationTemplate>('createdTime', 'notification.created-time', this.datePipe, '170px'),
new EntityTableColumn<NotificationTemplate>('notificationType', 'notification.type', '15%',
(template) => this.translate.instant(NotificationTemplateTypeTranslateMap.get(template.notificationType).name)),
new EntityTableColumn<NotificationTemplate>('name', 'notification.template', '25%'),

View File

@ -29,6 +29,7 @@
.content {
letter-spacing: .25px;
word-break: break-word;
.title {
margin-bottom: 4px;
font-weight: 500;
@ -37,7 +38,6 @@
font-size: 14px;
line-height: 16px;
color: rgba(0, 0, 0, 0.76);
word-break: break-word;
}
.button {

View File

@ -415,11 +415,8 @@
"resources": "Resources",
"notifications": "Notifications",
"notifications-settings": "Notifications settings",
"notification": {
"notification-settings": "Notification settings",
"slack-api-token": "Slack api token",
"slack": "Slack"
}
},
"alarm": {
"alarm": "Alarm",