diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-12 15:09:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-12 15:09:02 +0300 |
commit | 49d26b2348f2eb9e345eb1f66214678f42f15dd3 (patch) | |
tree | e68c6c2e50aae17d37a4d5508613b3d93627a5e2 /app/assets | |
parent | 7f5e08060f261a63ebf5058a95419da66928173a (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
16 files changed, 432 insertions, 53 deletions
diff --git a/app/assets/javascripts/feature_highlight/constants.js b/app/assets/javascripts/feature_highlight/constants.js new file mode 100644 index 00000000000..3e4cd11f7d5 --- /dev/null +++ b/app/assets/javascripts/feature_highlight/constants.js @@ -0,0 +1 @@ +export const POPOVER_TARGET_ID = 'feature-highlight-trigger'; diff --git a/app/assets/javascripts/feature_highlight/feature_highlight_popover.vue b/app/assets/javascripts/feature_highlight/feature_highlight_popover.vue new file mode 100644 index 00000000000..879427eef96 --- /dev/null +++ b/app/assets/javascripts/feature_highlight/feature_highlight_popover.vue @@ -0,0 +1,101 @@ +<script> +import { + GlPopover, + GlSprintf, + GlLink, + GlButton, + GlSafeHtmlDirective as SafeHtml, +} from '@gitlab/ui'; +import clusterPopover from '@gitlab/svgs/dist/illustrations/cluster_popover.svg'; +import { __ } from '~/locale'; +import { dismiss } from './feature_highlight_helper'; +import { POPOVER_TARGET_ID } from './constants'; + +export default { + components: { + GlPopover, + GlSprintf, + GlLink, + GlButton, + }, + directives: { + SafeHtml, + }, + props: { + autoDevopsHelpPath: { + type: String, + required: true, + }, + highlightId: { + type: String, + required: true, + }, + dismissEndpoint: { + type: String, + required: true, + }, + }, + data() { + return { + dismissed: false, + triggerHidden: false, + }; + }, + methods: { + dismiss() { + dismiss(this.dismissEndpoint, this.highlightId); + this.$refs.popover.$emit('close'); + this.dismissed = true; + }, + hideTrigger() { + if (this.dismissed) { + this.triggerHidden = true; + } + }, + }, + clusterPopover, + targetId: POPOVER_TARGET_ID, + i18n: { + highlightMessage: __('Allows you to add and manage Kubernetes clusters.'), + autoDevopsProTipMessage: __( + 'Protip: %{linkStart}Auto DevOps%{linkEnd} uses Kubernetes clusters to deploy your code!', + ), + dismissButtonLabel: __('Got it!'), + }, +}; +</script> +<template> + <div class="gl-ml-3"> + <span v-if="!triggerHidden" :id="$options.targetId" class="feature-highlight"></span> + <gl-popover + ref="popover" + :target="$options.targetId" + :css-classes="['feature-highlight-popover']" + triggers="hover" + container="body" + placement="right" + boundary="viewport" + @hidden="hideTrigger" + > + <span + v-safe-html="$options.clusterPopover" + class="feature-highlight-illustration gl-display-flex gl-justify-content-center gl-py-4 gl-w-full" + ></span> + <div class="gl-px-4 gl-py-5"> + <p> + {{ $options.i18n.highlightMessage }} + </p> + <p> + <gl-sprintf :message="$options.i18n.autoDevopsProTipMessage"> + <template #link="{ content }"> + <gl-link class="gl-font-sm" :href="autoDevopsHelpPath">{{ content }}</gl-link> + </template> + </gl-sprintf> + </p> + <gl-button size="small" icon="thumb-up" variant="confirm" @click="dismiss"> + {{ $options.i18n.dismissButtonLabel }} + </gl-button> + </div> + </gl-popover> + </div> +</template> diff --git a/app/assets/javascripts/feature_highlight/index.js b/app/assets/javascripts/feature_highlight/index.js new file mode 100644 index 00000000000..3a8b211b3c5 --- /dev/null +++ b/app/assets/javascripts/feature_highlight/index.js @@ -0,0 +1,28 @@ +import Vue from 'vue'; + +const init = async () => { + const el = document.querySelector('.js-feature-highlight'); + + if (!el) { + return null; + } + + const { autoDevopsHelpPath, highlight: highlightId, dismissEndpoint } = el.dataset; + const { default: FeatureHighlight } = await import( + /* webpackChunkName: 'feature_highlight' */ './feature_highlight_popover.vue' + ); + + return new Vue({ + el, + render: (h) => + h(FeatureHighlight, { + props: { + autoDevopsHelpPath, + highlightId, + dismissEndpoint, + }, + }), + }); +}; + +export default init; diff --git a/app/assets/javascripts/issuable/components/issuable_by_email.vue b/app/assets/javascripts/issuable/components/issuable_by_email.vue new file mode 100644 index 00000000000..330118ce8a6 --- /dev/null +++ b/app/assets/javascripts/issuable/components/issuable_by_email.vue @@ -0,0 +1,169 @@ +<script> +import { + GlButton, + GlModal, + GlModalDirective, + GlTooltipDirective, + GlSprintf, + GlLink, + GlFormInputGroup, + GlIcon, +} from '@gitlab/ui'; +import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue'; +import { sprintf, __ } from '~/locale'; +import axios from '~/lib/utils/axios_utils'; + +export default { + name: 'IssuableByEmail', + components: { + GlButton, + GlModal, + GlSprintf, + GlLink, + GlFormInputGroup, + GlIcon, + ModalCopyButton, + }, + directives: { + GlModal: GlModalDirective, + GlTooltip: GlTooltipDirective, + }, + inject: { + initialEmail: { + default: null, + }, + issuableType: { + default: '', + }, + emailsHelpPagePath: { + default: '', + }, + quickActionsHelpPath: { + default: '', + }, + markdownHelpPath: { + default: '', + }, + resetPath: { + default: '', + }, + }, + data() { + return { + email: this.initialEmail, + // eslint-disable-next-line @gitlab/require-i18n-strings + issuableName: this.issuableType === 'issue' ? 'issue' : 'merge request', + }; + }, + computed: { + mailToLink() { + const subject = sprintf(__('Enter the %{name} title'), { + name: this.issuableName, + }); + const body = sprintf(__('Enter the %{name} description'), { + name: this.issuableName, + }); + // eslint-disable-next-line @gitlab/require-i18n-strings + return `mailto:${this.email}?subject=${subject}&body=${body}`; + }, + }, + methods: { + async resetIncomingEmailToken() { + try { + const { + data: { new_address: newAddress }, + } = await axios.put(this.resetPath); + this.email = newAddress; + } catch { + this.$toast.show(__('There was an error when reseting email token.'), { type: 'error' }); + } + }, + cancelHandler() { + this.$refs.modal.hide(); + }, + }, + modalId: 'issuable-email-modal', +}; +</script> + +<template> + <div> + <gl-button v-gl-modal="$options.modalId" variant="link" data-testid="issuable-email-modal-btn" + ><gl-sprintf :message="__('Email a new %{name} to this project')" + ><template #name>{{ issuableName }}</template></gl-sprintf + ></gl-button + > + <gl-modal ref="modal" :modal-id="$options.modalId"> + <template #modal-title> + <gl-sprintf :message="__('Create new %{name} by email')"> + <template #name>{{ issuableName }}</template> + </gl-sprintf> + </template> + <p> + <gl-sprintf + :message=" + __( + 'You can create a new %{name} inside this project by sending an email to the following email address:', + ) + " + > + <template #name>{{ issuableName }}</template> + </gl-sprintf> + </p> + <gl-form-input-group :value="email" readonly select-on-click class="gl-mb-4"> + <template #append> + <modal-copy-button :text="email" :title="__('Copy')" :modal-id="$options.modalId" /> + <gl-button + v-gl-tooltip.hover + :href="mailToLink" + :title="__('Send email')" + icon="mail" + data-testid="mail-to-btn" + /> + </template> + </gl-form-input-group> + <p> + <gl-sprintf + :message=" + __( + 'The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported.', + ) + " + > + <template #quickActionsLink="{ content }"> + <gl-link :href="quickActionsHelpPath" target="_blank">{{ content }}</gl-link> + </template> + <template #markdownLink="{ content }"> + <gl-link :href="markdownHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </p> + <p> + <gl-sprintf + :message=" + __( + 'This is a private email address %{helpIcon} generated just for you. Anyone who gets ahold of it can create issues or merge requests as if they were you. You should %{resetLinkStart}reset it%{resetLinkEnd} if that ever happens.', + ) + " + > + <template #helpIcon> + <gl-link :href="emailsHelpPagePath" target="_blank" + ><gl-icon class="gl-text-blue-600" name="question-o" + /></gl-link> + </template> + <template #resetLink="{ content }"> + <gl-button + variant="link" + data-testid="incoming-email-token-reset" + @click="resetIncomingEmailToken" + >{{ content }}</gl-button + > + </template> + </gl-sprintf> + </p> + <template #modal-footer> + <gl-button category="secondary" @click="cancelHandler">{{ s__('Cancel') }}</gl-button> + </template> + </gl-modal> + </div> +</template> diff --git a/app/assets/javascripts/issuable/init_issuable_by_email.js b/app/assets/javascripts/issuable/init_issuable_by_email.js new file mode 100644 index 00000000000..1fed55c3d8e --- /dev/null +++ b/app/assets/javascripts/issuable/init_issuable_by_email.js @@ -0,0 +1,35 @@ +import Vue from 'vue'; +import { GlToast } from '@gitlab/ui'; +import IssuableByEmail from './components/issuable_by_email.vue'; + +Vue.use(GlToast); + +export default () => { + const el = document.querySelector('.js-issueable-by-email'); + + if (!el) return null; + + const { + initialEmail, + issuableType, + emailsHelpPagePath, + quickActionsHelpPath, + markdownHelpPath, + resetPath, + } = el.dataset; + + return new Vue({ + el, + provide: { + initialEmail, + issuableType, + emailsHelpPagePath, + quickActionsHelpPath, + markdownHelpPath, + resetPath, + }, + render(h) { + return h(IssuableByEmail); + }, + }); +}; diff --git a/app/assets/javascripts/issuable_index.js b/app/assets/javascripts/issuable_index.js index 4f31d26ab5d..4856f9781ce 100644 --- a/app/assets/javascripts/issuable_index.js +++ b/app/assets/javascripts/issuable_index.js @@ -1,35 +1,7 @@ -import $ from 'jquery'; -import axios from './lib/utils/axios_utils'; -import { deprecatedCreateFlash as flash } from './flash'; -import { s__, __ } from './locale'; import issuableInitBulkUpdateSidebar from './issuable_init_bulk_update_sidebar'; export default class IssuableIndex { constructor(pagePrefix) { issuableInitBulkUpdateSidebar.init(pagePrefix); - IssuableIndex.resetIncomingEmailToken(); - } - - static resetIncomingEmailToken() { - const $resetToken = $('.incoming-email-token-reset'); - - $resetToken.on('click', (e) => { - e.preventDefault(); - - $resetToken.text(s__('EmailToken|resetting...')); - - axios - .put($resetToken.attr('href')) - .then(({ data }) => { - $('#issuable_email').val(data.new_address).focus(); - - $resetToken.text(s__('EmailToken|reset it')); - }) - .catch(() => { - flash(__('There was an error when reseting email token.')); - - $resetToken.text(s__('EmailToken|reset it')); - }); - }); } } diff --git a/app/assets/javascripts/pages/projects/issues/index/index.js b/app/assets/javascripts/pages/projects/issues/index/index.js index 5956933fd99..25790a27888 100644 --- a/app/assets/javascripts/pages/projects/issues/index/index.js +++ b/app/assets/javascripts/pages/projects/issues/index/index.js @@ -9,6 +9,7 @@ import { FILTERED_SEARCH } from '~/pages/constants'; import { ISSUABLE_INDEX } from '~/pages/projects/constants'; import initIssuablesList from '~/issues_list'; import initManualOrdering from '~/manual_ordering'; +import initIssuableByEmail from '~/issuable/init_issuable_by_email'; IssuableFilteredSearchTokenKeys.addExtraTokensForIssues(); @@ -24,3 +25,4 @@ new UsersSelect(); initManualOrdering(); initIssuablesList(); +initIssuableByEmail(); diff --git a/app/assets/javascripts/pages/projects/merge_requests/index/index.js b/app/assets/javascripts/pages/projects/merge_requests/index/index.js index 94a12cc2706..e9138d6ab4d 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js +++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js @@ -6,6 +6,7 @@ import initFilteredSearch from '~/pages/search/init_filtered_search'; import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; import { FILTERED_SEARCH } from '~/pages/constants'; import { ISSUABLE_INDEX } from '~/pages/projects/constants'; +import initIssuableByEmail from '~/issuable/init_issuable_by_email'; new IssuableIndex(ISSUABLE_INDEX.MERGE_REQUEST); // eslint-disable-line no-new @@ -19,3 +20,5 @@ initFilteredSearch({ new UsersSelect(); // eslint-disable-line no-new new ShortcutsNavigation(); // eslint-disable-line no-new + +initIssuableByEmail(); diff --git a/app/assets/javascripts/pages/projects/product_analytics/graphs/index.js b/app/assets/javascripts/pages/projects/product_analytics/graphs/index.js index 0539d318471..ba03fccdb03 100644 --- a/app/assets/javascripts/pages/projects/product_analytics/graphs/index.js +++ b/app/assets/javascripts/pages/projects/product_analytics/graphs/index.js @@ -1,3 +1,3 @@ import initActivityCharts from '~/analytics/product_analytics/activity_charts_bundle'; -document.addEventListener('DOMContentLoaded', () => initActivityCharts()); +initActivityCharts(); diff --git a/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue b/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue index 673c6f4a1eb..d1cfa84248c 100644 --- a/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue +++ b/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue @@ -83,6 +83,9 @@ export default { alertId: { default: '', }, + isThreatMonitoringPage: { + default: false, + }, projectId: { default: '', }, @@ -364,7 +367,11 @@ export default { </alert-summary-row> <alert-details-table :alert="alert" :loading="loading" /> </gl-tab> - <gl-tab :data-testid="$options.tabsConfig[1].id" :title="$options.tabsConfig[1].title"> + <gl-tab + v-if="isThreatMonitoringPage" + :data-testid="$options.tabsConfig[1].id" + :title="$options.tabsConfig[1].title" + > <alert-metrics :dashboard-url="alert.metricsDashboardUrl" /> </gl-tab> <gl-tab :data-testid="$options.tabsConfig[2].id" :title="$options.tabsConfig[2].title"> diff --git a/app/assets/javascripts/vue_shared/alert_details/components/alert_sidebar.vue b/app/assets/javascripts/vue_shared/alert_details/components/alert_sidebar.vue index 12c58b582c5..4584023380c 100644 --- a/app/assets/javascripts/vue_shared/alert_details/components/alert_sidebar.vue +++ b/app/assets/javascripts/vue_shared/alert_details/components/alert_sidebar.vue @@ -19,6 +19,10 @@ export default { projectId: { default: '', }, + // TODO remove this limitation in https://gitlab.com/gitlab-org/gitlab/-/issues/296717 + isThreatMonitoringPage: { + default: false, + }, }, props: { alert: { @@ -62,6 +66,7 @@ export default { @alert-error="$emit('alert-error', $event)" /> <sidebar-status + v-if="!isThreatMonitoringPage" :project-path="projectPath" :alert="alert" @toggle-sidebar="$emit('toggle-sidebar')" diff --git a/app/assets/javascripts/vue_shared/alert_details/constants.js b/app/assets/javascripts/vue_shared/alert_details/constants.js index 56f79410064..2ab5160534c 100644 --- a/app/assets/javascripts/vue_shared/alert_details/constants.js +++ b/app/assets/javascripts/vue_shared/alert_details/constants.js @@ -9,11 +9,10 @@ export const SEVERITY_LEVELS = { UNKNOWN: s__('severity|Unknown'), }; -export const DEFAULT_PAGE = 'OPERATIONS'; - /* eslint-disable @gitlab/require-i18n-strings */ export const PAGE_CONFIG = { OPERATIONS: { + TITLE: 'OPERATIONS', // Tracks snowplow event when user views alert details TRACK_ALERTS_DETAILS_VIEWS_OPTIONS: { category: 'Alert Management', @@ -26,4 +25,7 @@ export const PAGE_CONFIG = { label: 'Status', }, }, + THREAT_MONITORING: { + TITLE: 'THREAT_MONITORING', + }, }; diff --git a/app/assets/javascripts/vue_shared/alert_details/index.js b/app/assets/javascripts/vue_shared/alert_details/index.js index 643d6b3a3fe..eba8adf416a 100644 --- a/app/assets/javascripts/vue_shared/alert_details/index.js +++ b/app/assets/javascripts/vue_shared/alert_details/index.js @@ -6,13 +6,13 @@ import createDefaultClient from '~/lib/graphql'; import AlertDetails from './components/alert_details.vue'; import sidebarStatusQuery from './graphql/queries/alert_sidebar_status.query.graphql'; import createRouter from './router'; -import { DEFAULT_PAGE, PAGE_CONFIG } from './constants'; +import { PAGE_CONFIG } from './constants'; Vue.use(VueApollo); export default (selector) => { const domEl = document.querySelector(selector); - const { alertId, projectPath, projectIssuesPath, projectId, page = DEFAULT_PAGE } = domEl.dataset; + const { alertId, projectPath, projectIssuesPath, projectId, page } = domEl.dataset; const router = createRouter(); const resolvers = { @@ -52,16 +52,19 @@ export default (selector) => { const provide = { projectPath, alertId, + page, projectIssuesPath, projectId, }; - if (page === DEFAULT_PAGE) { + if (page === PAGE_CONFIG.OPERATIONS.TITLE) { const { TRACK_ALERTS_DETAILS_VIEWS_OPTIONS, TRACK_ALERT_STATUS_UPDATE_OPTIONS } = PAGE_CONFIG[ page ]; provide.trackAlertsDetailsViewsOptions = TRACK_ALERTS_DETAILS_VIEWS_OPTIONS; provide.trackAlertStatusUpdateOptions = TRACK_ALERT_STATUS_UPDATE_OPTIONS; + } else if (page === PAGE_CONFIG.THREAT_MONITORING.TITLE) { + provide.isThreatMonitoringPage = true; } // eslint-disable-next-line no-new diff --git a/app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss b/app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss index 093cba3560f..8d34f35502e 100644 --- a/app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss +++ b/app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss @@ -5,7 +5,7 @@ $bs-input-focus-border: #80bdff; $bs-input-focus-box-shadow: rgba(0, 123, 255, 0.25); - a:not(.btn):not(.gl-tab-nav-item), + a:not(.btn), .gl-button.btn-link, .gl-button.btn-link:hover, .gl-button.btn-link:focus, @@ -34,6 +34,7 @@ .ide-pipeline .top-bar .controllers .controllers-buttons, .controllers-buttons svg, .nav-links li a.active, + .gl-tabs-nav li a.gl-tab-nav-item-active, .md-area.is-focused { color: var(--ide-text-color, $gl-text-color); } @@ -44,13 +45,15 @@ } .nav-links:not(.quick-links) li:not(.md-header-toolbar) a, + .gl-tabs-nav li a, .dropdown-menu-inner-content, .file-row .file-row-icon svg, .file-row:hover .file-row-icon svg { color: var(--ide-text-color-secondary, $gl-text-color-secondary); } - .nav-links:not(.quick-links) li:not(.md-header-toolbar) { + .nav-links:not(.quick-links) li:not(.md-header-toolbar), + .gl-tabs-nav li { &:hover a, &.active a, a:hover, @@ -61,6 +64,10 @@ border-color: var(--ide-input-border, $gray-darkest); } } + + a.gl-tab-nav-item-active { + box-shadow: inset 0 -2px 0 0 var(--ide-input-border, $gray-darkest); + } } .drag-handle:hover { @@ -142,6 +149,7 @@ .md table:not(.code) tbody td, .md table:not(.code) tr th, .nav-links:not(.quick-links), + .gl-tabs-nav, .common-note-form .md-area.is-focused .nav-links { border-color: var(--ide-border-color-alt, $white-dark); } @@ -175,6 +183,10 @@ border-color: var(--ide-highlight-accent, $gl-text-color); } + .gl-tabs-nav li a.gl-tab-nav-item-active { + box-shadow: inset 0 -2px 0 0 var(--ide-highlight-accent, $gl-text-color); + } + // for other themes, suppress different avatar default colors for simplicity .avatar-container { &, @@ -304,6 +316,11 @@ border-color: var(--ide-dropdown-hover-background, $border-color); } + .gl-tabs-nav { + background-color: var(--ide-dropdown-hover-background, $white); + box-shadow: inset 0 -2px 0 0 var(--ide-dropdown-hover-background, $border-color); + } + .divider { background-color: var(--ide-dropdown-hover-background, $gray-100); border-color: var(--ide-dropdown-hover-background, $gray-100); diff --git a/app/assets/stylesheets/page_bundles/ide.scss b/app/assets/stylesheets/page_bundles/ide.scss index b5b34c0a64e..7c4d51ab677 100644 --- a/app/assets/stylesheets/page_bundles/ide.scss +++ b/app/assets/stylesheets/page_bundles/ide.scss @@ -97,7 +97,8 @@ $ide-commit-header-height: 48px; border-right: 1px solid var(--ide-border-color, $white-dark); border-bottom: 1px solid var(--ide-border-color, $white-dark); - &.active { + &.active, + .gl-tab-nav-item-active { background-color: var(--ide-highlight-background, $white); border-bottom-color: transparent; } @@ -114,6 +115,42 @@ $ide-commit-header-height: 48px; } } } + + .gl-tab-content { + padding: 0; + } + + .gl-tabs-nav { + border-width: 0; + + li { + padding: 0 !important; + background: transparent !important; + border: 0 !important; + + a { + display: flex; + align-items: center; + padding: $grid-size $gl-padding !important; + box-shadow: none !important; + font-weight: normal !important; + + background-color: var(--ide-background-hover, $gray-normal); + border-right: 1px solid var(--ide-border-color, $white-dark); + border-bottom: 1px solid var(--ide-border-color, $white-dark); + + &.gl-tab-nav-item-active { + background-color: var(--ide-highlight-background, $white); + border-color: var(--ide-border-color, $white-dark); + border-bottom-color: transparent; + } + + .multi-file-tab-close svg { + top: 0; + } + } + } + } } .multi-file-tab { @@ -634,7 +671,8 @@ $ide-commit-header-height: 48px; height: 100%; } - .nav-links { + .nav-links, + .gl-tabs-nav { height: 30px; } @@ -976,17 +1014,25 @@ $ide-commit-header-height: 48px; } .ide-nav-form { - .nav-links li { + .nav-links li, + .gl-tabs-nav li { width: 50%; padding-left: 0; padding-right: 0; a { text-align: center; + font-size: 14px; + line-height: 30px; - &:not(.active) { + &:not(.active), + &:not(.gl-tab-nav-item-active) { background-color: var(--ide-dropdown-background, $gray-light); } + + &.gl-tab-nav-item-active { + font-weight: bold; + } } } diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index fb483ade107..2a8a86615f6 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -108,18 +108,6 @@ ul.related-merge-requests > li { } } -.issuable-email-modal-btn { - padding: 0; - color: $blue-600; - background-color: transparent; - border: 0; - outline: 0; - - &:hover { - text-decoration: underline; - } -} - .email-modal-input-group { margin-bottom: 10px; |