diff --git a/saas/axops/src/ui/src/app/common/components.module.ts b/saas/axops/src/ui/src/app/common/components.module.ts index 603c4e51fce8..240a97b955ae 100644 --- a/saas/axops/src/ui/src/app/common/components.module.ts +++ b/saas/axops/src/ui/src/app/common/components.module.ts @@ -29,6 +29,7 @@ import { CommitPanelComponent } from './commit-panel/commit-panel.component'; import { CommitAuthorComponent } from './commit-author/commit-author.component'; import { CommitDescriptionComponent } from './commit-description/commit-description.component'; import { MultipleServiceLaunchPanelComponent } from './multiple-service-launch-panel/multiple-service-launch-panel.component'; +import { SetupJobNotificationsComponent } from './multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.component'; import { LaunchPanelService } from './multiple-service-launch-panel/launch-panel.service'; import { BranchesPanelComponent } from './branches-panel/branches-panel.component'; import { BranchSelectorPanelComponent } from './branch-selector-panel/branch-selector-panel.component'; @@ -87,6 +88,7 @@ let components: any[] = [ CommitAuthorComponent, CommitDescriptionComponent, MultipleServiceLaunchPanelComponent, + SetupJobNotificationsComponent, BranchesPanelComponent, BranchSelectorPanelComponent, CommitSelectorPanelComponent, diff --git a/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/multiple-service-launch-panel.component.ts b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/multiple-service-launch-panel.component.ts index 7348aba687be..ff53961832cc 100644 --- a/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/multiple-service-launch-panel.component.ts +++ b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/multiple-service-launch-panel.component.ts @@ -1,14 +1,15 @@ import * as _ from 'lodash'; -import { Component, Output, EventEmitter } from '@angular/core'; +import { Component, Output, EventEmitter, ViewChild } from '@angular/core'; import { Router } from '@angular/router'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { Subscription } from 'rxjs/Subscription'; import { Observable } from 'rxjs/Observable'; -import {Artifact, Commit, Template, Task, Project, ProjectAction, Branch } from '../../model'; +import { Artifact, Commit, Template, Task, Project, ProjectAction, Branch } from '../../model'; import { TemplateService, TaskService, CommitsService } from '../../services'; import { NotificationsService } from 'argo-ui-lib/src/components'; import { Session, HtmlForm, MULTIPLE_SERVICE_LAUNCH_PANEL_TABS } from './multiple-service-launch-panel.view-models'; +import { SetupJobNotificationsComponent } from './setup-job-notifications/setup-job-notifications.component'; @Component({ selector: 'ax-multiple-service-launch-panel', @@ -18,6 +19,9 @@ import { Session, HtmlForm, MULTIPLE_SERVICE_LAUNCH_PANEL_TABS } from './multipl export class MultipleServiceLaunchPanelComponent { @Output() submitted: EventEmitter = new EventEmitter(); + @ViewChild(SetupJobNotificationsComponent) + private setupJobNotifications: SetupJobNotificationsComponent; + public templates: Template[] = []; public templatesToSubmit: Template[] = []; public allSelected: boolean = false; @@ -25,7 +29,7 @@ export class MultipleServiceLaunchPanelComponent { public templateLoader: boolean = false; public commit: Commit = new Commit(); public isVisibleSelectServiceTemplatesPanel: boolean = false; - public selectingScreen: boolean = true; + public stepNumber: 1 | 2 | 3 = 1; public activeElementId: number = 0; public isSubmitClicked: boolean = false; public summaryErrorMessage: boolean = false; @@ -82,7 +86,7 @@ export class MultipleServiceLaunchPanelComponent { this.task = null; this.projectInfo = null; this.resubmit = resubmit; - this.selectingScreen = true; + this.stepNumber = 1; this.withCommitOnly = withCommitOnly; if (options) { @@ -95,11 +99,11 @@ export class MultipleServiceLaunchPanelComponent { this.isVisibleSelectServiceTemplatesPanel = true; this.next(); } - this.selectingScreen = false; + this.stepNumber = 2; } else { this.task = null; this.projectInfo = null; - this.selectingScreen = true; + this.stepNumber = 1; } if (commit) { @@ -133,7 +137,7 @@ export class MultipleServiceLaunchPanelComponent { this.session = new Session(); this.templates = []; this.templatesToSubmit = []; - this.selectingScreen = true; + this.stepNumber = 1; this.activeElementId = 0; this.allSelected = false; this.allForms.reset(); @@ -250,18 +254,23 @@ export class MultipleServiceLaunchPanelComponent { }) !== undefined; } + goToNextStep() { + this.stepNumber += 1; + this.next(); + } + next() { - this.selectingScreen = false; this.templatesToSubmit = this.templates.filter(item => item.selected); this.prepareForms(this.templatesToSubmit); } submit() { + let notifications = this.setupJobNotifications.getNotifications(); this.isSubmitClicked = true; this.summaryErrorMessage = this.allForms.invalid; - if (this.allForms.valid) { + if (this.allForms.valid && notifications) { if (this.resubmit) { this.resubmitTask(this.task, this.resubmit); } else { @@ -271,6 +280,7 @@ export class MultipleServiceLaunchPanelComponent { observableList.push(this.taskService.launchTask({ template_id: this.templatesToSubmit[index].id, arguments: this.listParameters(this.allForms.controls[index.toString()]['controls']), + notifications: notifications })); }); @@ -323,7 +333,6 @@ export class MultipleServiceLaunchPanelComponent { this.getTemplates(branch.repo); } - private prepareForms(templates: Template[], resubmitFailedParameters?: any) { templates.forEach((template, index) => { let newForm = new FormGroup({}); diff --git a/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/multiple-service-launch-panel.html b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/multiple-service-launch-panel.html index 8b7fd2ca3cf0..d5901535de13 100644 --- a/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/multiple-service-launch-panel.html +++ b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/multiple-service-launch-panel.html @@ -1,8 +1,10 @@ - - + + @@ -14,7 +16,7 @@ -
+
Select templates to create jobs @@ -105,7 +107,7 @@

Templates

-
+
Please enter the required parameters and submit again.
@@ -195,6 +197,9 @@

+
+ +
diff --git a/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.component.ts b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.component.ts new file mode 100644 index 000000000000..341e118f3322 --- /dev/null +++ b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.component.ts @@ -0,0 +1,229 @@ +import * as _ from 'lodash'; +import { Component, OnInit } from '@angular/core'; + +import { FilterMultiSelect } from 'argo-ui-lib/src/components'; + +import { PolicyNotification } from '../../../model'; +import { CustomRegex } from '../../customValidators/CustomRegex'; +import { AuthenticationService } from '../../../services'; + +interface NotificationObject { + jobEvents: FilterMultiSelect; + isArgoUsersAndGroupsVisible: boolean; + isSlackChannelsVisible: boolean; + isEmailVisible: boolean; + rules: PolicyNotification; + outsideUsers: string[]; + filteredOutsideUsers: string[]; + validationMessages: any; +} + +@Component({ + selector: 'ax-setup-job-notifications', + templateUrl: './setup-job-notifications.html', + styles: [ require('./setup-job-notifications.scss') ], +}) +export class SetupJobNotificationsComponent implements OnInit { + + public notification: NotificationObject = { + jobEvents: { + items: [ + {name: 'on_change', value: 'on_change', checked: false}, + {name: 'on_cron', value: 'on_cron', checked: false}, + {name: 'on_failure', value: 'on_failure', checked: false}, + {name: 'on_pull_request', value: 'on_pull_request', checked: false}, + {name: 'on_pull_request_merge', value: 'on_pull_request_merge', checked: false}, + {name: 'on_push', value: 'on_push', checked: false}, + {name: 'on_start', value: 'on_start', checked: false}, + {name: 'on_success', value: 'on_success', checked: false}, + ], + selectedItems: [], + messages: { + name: 'JOB EVENTS', + }, + isVisible: false, + isStaticList: true, + isDisplayedInline: true, + }, + + isArgoUsersAndGroupsVisible: false, + isSlackChannelsVisible: false, + isEmailVisible: false, + rules: { + whom: [], + when: [] + }, + outsideUsers: [], + filteredOutsideUsers: [], + validationMessages: { + jobEvents: { show: false, text: 'You have to choose at least one Job Event' }, + wrongFormatRecipients: { show: false, text: 'Recipients have to be an email format' }, + missingRecipients: { show: false, text: 'You have to choose at least one recipient from any of the groups' }, + } + }; + + public rules: PolicyNotification[] = []; + public notificationsList: any[] = []; + public isVisibleUserSelectorPanel: boolean = false; + public isVisibleSlackPanel: boolean = false; + public selectedId: number = 0; + + constructor(private authenticationService: AuthenticationService) { + } + + ngOnInit() { + if (!this.rules.length) { + this.addDefaultNotificationRule(); + } + } + + public onRuleChange(when: string[], index) { + this.notificationsList[index].rules.when = when; + this.notificationsList[index].validationMessages.jobEvents.show = false; + } + + public addNotificationRule() { + this.notificationsList.push(JSON.parse(JSON.stringify(this.notification))); + } + + public removeNotificationRule(index) { + this.notificationsList.splice(index, 1); + } + + public openUserSelectorPanel(index) { + this.isVisibleUserSelectorPanel = true; + this.selectedId = index; + this.notificationsList[index].validationMessages.missingRecipients.show = false; + } + + public closeUserSelectorPanel() { + this.isVisibleUserSelectorPanel = false; + } + + public openSlackChannelPanel(index) { + this.isVisibleSlackPanel = true; + this.selectedId = index; + this.notificationsList[index].validationMessages.missingRecipients.show = false; + } + + public closeSlackChannelPalen() { + this.isVisibleSlackPanel = false; + } + + public getOutsideUsers(index) { + this.notificationsList[index].filteredOutsideUsers = + this.notificationsList[index].rules.whom.recipients.filter(recipient => recipient.indexOf('@user') !== -1).sort(); + this.notificationsList[index].outsideUsers = this.notificationsList[index].filteredOutsideUsers.map(user => user.substring(0, user.indexOf('@user'))); + return this.notificationsList[index].rules.whom.filter(recipient => recipient.indexOf('@user') !== -1).sort(); + } + + public getOnlyUsersAndGroups(index) { + return this.notificationsList.length ? + this.notificationsList[index].rules.whom.filter(recipient => recipient.indexOf('@slack') === -1 && recipient.indexOf('@user') === -1).sort() : []; + } + + public getOnlySlackChannels(index) { + return this.notificationsList.length ? + this.notificationsList[index].rules.whom.filter(recipient => recipient.indexOf('@slack') !== -1).sort() : []; + } + + public updateOnlyUsersAndGroupsList(users: string[]) { + this.notificationsList[this.selectedId].rules.whom = + this.notificationsList[this.selectedId].rules.whom.filter(recipient => (recipient.indexOf('@slack') !== -1 || recipient.indexOf('@user') !== -1)).sort(); + this.updateNotificationWhomList(users); + } + + public updateSlackChannelsList(channels: string[]) { + this.notificationsList[this.selectedId].rules.whom = + this.notificationsList[this.selectedId].rules.whom.filter(recipient => (recipient.indexOf('@slack') === -1)).sort(); + let axSlackChannelsList = channels.map(channel => `${channel}@slack`); + this.updateNotificationWhomList(axSlackChannelsList); + } + + public updateNotificationWhomList(list: string[]) { + this.notificationsList[this.selectedId].rules.whom = + this.notificationsList[this.selectedId].rules.whom.concat(list).filter((value, index, self) => self.indexOf(value) === index ); + } + + public updateOutsideUsers(users: string, index) { + this.selectedId = index; + this.notificationsList[index].outsideUsers = users.split(','); + this.notificationsList[index].filteredOutsideUsers = + this.notificationsList[index].outsideUsers.filter(user => CustomRegex.emailPattern.test(user.trim())).map(user => `${user}@user`); + this.notificationsList[index].validationMessages.wrongFormatRecipients.show = false; + this.notificationsList[index].validationMessages.missingRecipients.show = false; + } + + public argoUsersAndGroupsCheckboxChange(notification, index) { + notification.isArgoUsersAndGroupsVisible = !notification.isArgoUsersAndGroupsVisible; + if (!notification.isArgoUsersAndGroupsVisible) { + notification.rules.whom = notification.rules.whom.filter(recipient => (recipient.indexOf('@slack') !== -1 || recipient.indexOf('@user') !== -1)).sort(); + } else { + this.openUserSelectorPanel(index); + } + } + + public emailCheckboxChange(notification) { + notification.isEmailVisible = !notification.isEmailVisible; + if (!notification.isEmailVisible) { + notification.outsideUsers = []; + notification.filteredOutsideUsers = []; + notification.rules.whom = notification.rules.whom.filter(recipient => (recipient.indexOf('@user') === -1)).sort(); + } + } + + public slackChannelsCheckboxChange(notification, index) { + notification.isSlackChannelsVisible = !notification.isSlackChannelsVisible; + if (!notification.isSlackChannelsVisible) { + notification.rules.whom = notification.rules.whom.filter(recipient => (recipient.indexOf('@slack') === -1)).sort(); + } else { + this.openSlackChannelPanel(index); + } + } + + public getNotifications(): PolicyNotification[] { + let isAnyError = false; + this.notificationsList.forEach(notification => { + if (!notification.rules.when.length) { + notification.validationMessages.jobEvents.show = true; + isAnyError = true; + } + + if (notification.outsideUsers.length !== notification.filteredOutsideUsers.length && notification.outsideUsers.toString().length) { + notification.validationMessages.wrongFormatRecipients.show = true; + isAnyError = true; + } else { + // remove all '@user' elements from rules.whom + notification.rules.whom = notification.rules.whom.filter(item => item.indexOf('@user') === -1); + this.updateNotificationWhomList(notification.filteredOutsideUsers); + } + + if (!notification.rules.whom.length) { + notification.validationMessages.missingRecipients.show = true; + isAnyError = true; + } + }); + + // if there is error in any notification rule, don't allow to submit + if (isAnyError) { + return; + } + + this.rules = this.notificationsList.map(notification => { + return notification.rules; + }); + + return _.uniqBy(this.rules, v => [v.whom, v.when].join()); + } + + private addDefaultNotificationRule() { + let notification = JSON.parse(JSON.stringify(this.notification)); + notification.rules = { + whom: [this.authenticationService.getUsername()], + when: ['on_failure', 'on_success'] + }; + notification.isArgoUsersAndGroupsVisible = true; + + this.notificationsList.push(notification); + } +} diff --git a/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.html b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.html new file mode 100644 index 000000000000..4dd8907e1d86 --- /dev/null +++ b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.html @@ -0,0 +1,130 @@ +
+
+ Set Up Job Notifications +
+
+ Set up notifications for job events. +
+
+
+ +
+
+ +
+
{{ 'Selected Job Events:' | uppercase }}
+
+ {{ notification.validationMessages.jobEvents.text }} + +
+ + +
+ +
{{ 'Select Recipients:' | uppercase }}
+
+ {{ notification.validationMessages.missingRecipients.text }} + +
+
+
+ + +
+ + +
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+ + +
+ + +
+
+
+ + + {{ notification.validationMessages.wrongFormatRecipients.text }} + +
+
+
+
+ +
+
+ + +
+ + +
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.scss b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.scss new file mode 100644 index 000000000000..4d4679190b56 --- /dev/null +++ b/saas/axops/src/ui/src/app/common/multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.scss @@ -0,0 +1,43 @@ +@import '../../../../assets/styles/config'; + +.notification-row { + & > h5 { + margin-top: 30px; + margin-bottom: 2px; + font-size: 14px; + font-weight: bold; + color: $ax-color-gray-6; + + &:first-child { + margin-top: 20px; + } + } + + & > hr { + margin-top: 0; + border-color: $ax-color-gray-4; + } + + &__plus-icon { + font-size: 25px; + vertical-align: middle; + font-weight: 300; + } + + &__events-selector { + width: 50%; + } + + &__input-adjustment { + margin-left: 30px; + margin-right: 60px; + } + + &__list-item { + margin-bottom: 15px; + + label { + font-size: 14px; + } + } +} \ No newline at end of file diff --git a/saas/axops/src/ui/src/app/common/users-selector-panel/users-selector-panel.html b/saas/axops/src/ui/src/app/common/users-selector-panel/users-selector-panel.html index 05e2870e3d34..e2adef874dca 100644 --- a/saas/axops/src/ui/src/app/common/users-selector-panel/users-selector-panel.html +++ b/saas/axops/src/ui/src/app/common/users-selector-panel/users-selector-panel.html @@ -43,7 +43,7 @@
- {{ user.name }} + {{ user.name }} {{ user.email }} diff --git a/saas/axops/src/ui/src/app/services/task.service.ts b/saas/axops/src/ui/src/app/services/task.service.ts index c29275c45e53..eb755ed12bd8 100644 --- a/saas/axops/src/ui/src/app/services/task.service.ts +++ b/saas/axops/src/ui/src/app/services/task.service.ts @@ -31,7 +31,9 @@ export class TaskService { } public launchTask(args: TaskCreationArgs, runPartial = false) { - args = Object.assign({}, args, { notifications: DEFAULT_NOTIFICATIONS }); + if (!args.hasOwnProperty('notifications') && !args.notifications) { + args = Object.assign({}, args, { notifications: DEFAULT_NOTIFICATIONS }); + } return this.http.post(`v1/services?run_partial=${runPartial}`, JSON.stringify(args)) .map(res => res.json()); } diff --git a/saas/axops/src/ui/src/app/views/+settings/notification-management/notification-creation-panel/notification-creation-panel.component.ts b/saas/axops/src/ui/src/app/views/+settings/notification-management/notification-creation-panel/notification-creation-panel.component.ts index 4f573fbd48e1..680a7fa62e54 100644 --- a/saas/axops/src/ui/src/app/views/+settings/notification-management/notification-creation-panel/notification-creation-panel.component.ts +++ b/saas/axops/src/ui/src/app/views/+settings/notification-management/notification-creation-panel/notification-creation-panel.component.ts @@ -87,19 +87,23 @@ export class NotificationCreationPanelComponent implements OnInit { messages: { name: 'Event Type', }, + selectedItems: [], isVisible: false, isStaticList: true, isDisplayedInline: true }; + private eventSeverity: FilterMultiSelect = { items: [], messages: { name: 'Event Severity', }, + selectedItems: [], isVisible: false, isStaticList: true, isDisplayedInline: true }; + private isNotificationCriteriaPanelVisible: boolean = false; constructor(private notificationService: NotificationService, diff --git a/saas/axops/src/ui/src/app/views/+settings/notification-management/notification-creation-panel/notification-creation-panel.scss b/saas/axops/src/ui/src/app/views/+settings/notification-management/notification-creation-panel/notification-creation-panel.scss index dc9927c44c4f..c7f3108ab966 100644 --- a/saas/axops/src/ui/src/app/views/+settings/notification-management/notification-creation-panel/notification-creation-panel.scss +++ b/saas/axops/src/ui/src/app/views/+settings/notification-management/notification-creation-panel/notification-creation-panel.scss @@ -13,34 +13,6 @@ } } -.shaded-box { - &__top { - color: $ax-color-gray-6; - height: 30px; - - & > span { - font-weight: bolder; - } - - &--right { - float: right; - - & > i { - cursor: pointer; - font-size: 30px; - color: $ax-color-teal-5; - } - } - } - - &__content { - border-radius: $border-radius; - border: 1px solid $ax-color-gray-4; - background-color: #F3F6F7; - padding: 15px 39px; - } -} - .criteria-row { display: block; margin-bottom: 5px; @@ -91,72 +63,3 @@ padding: 2px 10px; } } - -.labels-horizontal-list { - display: block; - color: $ax-color-gray-6; - - &__top { - display: block; - } - - &__title { - display: inline-block; - font-size: 14px; - margin: 8px 0; - } - - &__add { - float: right; - display: inline; - text-transform: uppercase; - font-weight: bolder; - font-size: 13px; - padding: 9px 40px; - - & > a > span { - font-size: 18px; - line-height: 20px; - vertical-align: middle; - } - } - - &__content { - & > textarea { - width: 100%; - max-width: 100%; - min-height: 70px; - border-radius: 5px; - box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.1); - background-color: #FFFFFF; - border: none; - padding: 5px 10px; - - &::placeholder { - color: $ax-color-gray-4; - } - - &:focus { - border: none; - outline: none; - } - } - } - - &__white-panel { - padding-bottom: 5px; - width: 100%; - min-height: 70px; - border-radius: $border-radius; - box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.1); - background-color: #FFFFFF; - - & > span { - display: inline-block; - background: $ax-color-gray-2; - margin: 5px 0 0 5px; - padding: 1px 10px; - border-radius: $border-radius; - } - } -} \ No newline at end of file diff --git a/saas/axops/src/ui/src/assets/styles/elements/_labels-horizontal-list.scss b/saas/axops/src/ui/src/assets/styles/elements/_labels-horizontal-list.scss new file mode 100644 index 000000000000..8725250c1228 --- /dev/null +++ b/saas/axops/src/ui/src/assets/styles/elements/_labels-horizontal-list.scss @@ -0,0 +1,80 @@ +.labels-horizontal-list { + display: block; + color: $ax-color-gray-6; + + &__top { + display: block; + } + + &__title { + display: inline-block; + font-size: 14px; + margin: 8px 0; + } + + &__add { + float: right; + display: inline; + text-transform: uppercase; + font-weight: bolder; + font-size: 13px; + padding: 9px 40px; + + & > a > span { + font-size: 18px; + line-height: 20px; + vertical-align: middle; + } + + &--no-padding { + padding: 0; + + i { + font-size: 38px; + } + } + } + + &__content { + & > textarea { + width: 100%; + max-width: 100%; + min-height: 70px; + border-radius: 5px; + box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.1); + background-color: #FFFFFF; + border: none; + padding: 5px 10px; + + &::placeholder { + color: $ax-color-gray-4; + } + + &:focus { + border: none; + outline: none; + } + } + } + + &__white-panel { + padding-bottom: 5px; + width: 100%; + min-height: 70px; + border-radius: $border-radius; + box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.1); + background-color: #FFFFFF; + + & > span { + display: inline-block; + background: $ax-color-gray-2; + margin: 5px 0 0 5px; + padding: 1px 10px; + border-radius: $border-radius; + } + + &--small { + min-height: 36px; + } + } +} \ No newline at end of file diff --git a/saas/axops/src/ui/src/assets/styles/elements/_shaded-box.scss b/saas/axops/src/ui/src/assets/styles/elements/_shaded-box.scss new file mode 100644 index 000000000000..35f1805656e4 --- /dev/null +++ b/saas/axops/src/ui/src/assets/styles/elements/_shaded-box.scss @@ -0,0 +1,27 @@ +.shaded-box { + &__top { + color: $ax-color-gray-6; + height: 30px; + + & > span { + font-weight: bolder; + } + + &--right { + float: right; + + & > i { + cursor: pointer; + font-size: 30px; + color: $ax-color-teal-5; + } + } + } + + &__content { + border-radius: $border-radius; + border: 1px solid $ax-color-gray-4; + background-color: #F3F6F7; + padding: 15px 39px; + } +} \ No newline at end of file