diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-08 21:15:10 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-08 21:15:10 +0000 |
commit | 7db94a9807df03ce7a4f210b513816a47f34e15b (patch) | |
tree | a20574d4297ba13e3340bfae217e3035e77d6423 /app/assets | |
parent | 3a563d7c1e15023f205d2a357e5d8a38a3b53ecc (diff) | |
download | gitlab-ce-7db94a9807df03ce7a4f210b513816a47f34e15b.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
16 files changed, 622 insertions, 50 deletions
diff --git a/app/assets/javascripts/analytics/cycle_analytics/components/base.vue b/app/assets/javascripts/analytics/cycle_analytics/components/base.vue index 52e36749351..39da3484dfe 100644 --- a/app/assets/javascripts/analytics/cycle_analytics/components/base.vue +++ b/app/assets/javascripts/analytics/cycle_analytics/components/base.vue @@ -9,7 +9,7 @@ import PathNavigation from '~/analytics/cycle_analytics/components/path_navigati import StageTable from '~/analytics/cycle_analytics/components/stage_table.vue'; import ValueStreamFilters from '~/analytics/cycle_analytics/components/value_stream_filters.vue'; import UrlSync from '~/vue_shared/components/url_sync.vue'; -import { __ } from '~/locale'; +import { __, s__ } from '~/locale'; import { SUMMARY_METRICS_REQUEST, METRICS_REQUESTS } from '../constants'; const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed'; @@ -79,7 +79,9 @@ export default { } return this.selectedStageError ? this.selectedStageError - : __("We don't have enough data to show this stage."); + : s__( + 'ValueStreamAnalyticsStage|There are 0 items to show in this stage, for these filters, within this time range.', + ); }, emptyStageText() { if (this.displayNoAccess) { diff --git a/app/assets/javascripts/analytics/cycle_analytics/constants.js b/app/assets/javascripts/analytics/cycle_analytics/constants.js index ebb2775b378..bea562fb18c 100644 --- a/app/assets/javascripts/analytics/cycle_analytics/constants.js +++ b/app/assets/javascripts/analytics/cycle_analytics/constants.js @@ -14,7 +14,7 @@ export const DEFAULT_VALUE_STREAM = { }; export const NOT_ENOUGH_DATA_ERROR = s__( - "ValueStreamAnalyticsStage|We don't have enough data to show this stage.", + 'ValueStreamAnalyticsStage|There are 0 items to show in this stage, for these filters, within this time range.', ); export const PAGINATION_TYPE = 'keyset'; diff --git a/app/assets/javascripts/analytics/shared/constants.js b/app/assets/javascripts/analytics/shared/constants.js index a07e2c3b799..3ac54900d37 100644 --- a/app/assets/javascripts/analytics/shared/constants.js +++ b/app/assets/javascripts/analytics/shared/constants.js @@ -38,6 +38,14 @@ const VSA_FLOW_METRICS_GROUP = { export const VSA_METRICS_GROUPS = [VSA_FLOW_METRICS_GROUP]; +export const VULNERABILITY_CRITICAL_TYPE = 'vulnerability_critical'; +export const VULNERABILITY_HIGH_TYPE = 'vulnerability_high'; + +export const VULNERABILITY_METRICS = { + CRITICAL: VULNERABILITY_CRITICAL_TYPE, + HIGH: VULNERABILITY_HIGH_TYPE, +}; + export const METRIC_TOOLTIPS = { [DORA_METRICS.DEPLOYMENT_FREQUENCY]: { description: s__( @@ -101,6 +109,18 @@ export const METRIC_TOOLTIPS = { projectLink: '-/analytics/merge_request_analytics', docsLink: helpPagePath('user/analytics/merge_request_analytics'), }, + [VULNERABILITY_METRICS.CRITICAL]: { + description: s__('ValueStreamAnalytics|Total Critical vulnerabilities.'), + groupLink: '-/security/vulnerabilities', + projectLink: '-/security/vulnerability_report', + docsLink: helpPagePath('user/application_security/vulnerability_report/index'), + }, + [VULNERABILITY_METRICS.HIGH]: { + description: s__('ValueStreamAnalytics|Total High vulnerabilities.'), + groupLink: '-/security/vulnerabilities', + projectLink: '-/security/vulnerability_report', + docsLink: helpPagePath('user/application_security/vulnerability_report/index'), + }, }; // TODO: Remove this once the migration to METRIC_TOOLTIPS is complete diff --git a/app/assets/javascripts/ci/artifacts/components/app.vue b/app/assets/javascripts/ci/artifacts/components/app.vue index 3a07be65341..c89df2610eb 100644 --- a/app/assets/javascripts/ci/artifacts/components/app.vue +++ b/app/assets/javascripts/ci/artifacts/components/app.vue @@ -18,12 +18,8 @@ export default { variables() { return { projectPath: this.projectPath }; }, - update({ - project: { - statistics: { buildArtifactsSize }, - }, - }) { - return buildArtifactsSize; + update({ project: { statistics } }) { + return statistics?.buildArtifactsSize ?? null; }, }, }, diff --git a/app/assets/javascripts/environments/components/kubernetes_overview.vue b/app/assets/javascripts/environments/components/kubernetes_overview.vue index 41abfcf6dc8..1f15c4daa2f 100644 --- a/app/assets/javascripts/environments/components/kubernetes_overview.vue +++ b/app/assets/javascripts/environments/components/kubernetes_overview.vue @@ -108,6 +108,7 @@ export default { @cluster-error="onClusterError" /> <kubernetes-tabs :configuration="k8sAccessConfiguration" + :namespace="namespace" class="gl-mb-5" @cluster-error="onClusterError" /></template> diff --git a/app/assets/javascripts/environments/components/kubernetes_summary.vue b/app/assets/javascripts/environments/components/kubernetes_summary.vue new file mode 100644 index 00000000000..85fc1c1a07d --- /dev/null +++ b/app/assets/javascripts/environments/components/kubernetes_summary.vue @@ -0,0 +1,180 @@ +<script> +import { GlTab, GlLoadingIcon, GlBadge } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import k8sWorkloadsQuery from '../graphql/queries/k8s_workloads.query.graphql'; +import { + getDeploymentsStatuses, + getDaemonSetStatuses, + getStatefulSetStatuses, + getReplicaSetStatuses, + getJobsStatuses, + getCronJobsStatuses, +} from '../helpers/k8s_integration_helper'; + +export default { + components: { + GlTab, + GlBadge, + GlLoadingIcon, + }, + apollo: { + k8sWorkloads: { + query: k8sWorkloadsQuery, + variables() { + return { + configuration: this.configuration, + namespace: this.namespace, + }; + }, + update(data) { + return data?.k8sWorkloads || {}; + }, + error(error) { + this.$emit('cluster-error', error); + }, + }, + }, + props: { + configuration: { + required: true, + type: Object, + }, + namespace: { + required: true, + type: String, + }, + }, + computed: { + summaryLoading() { + return this.$apollo.queries.k8sWorkloads.loading; + }, + summaryCount() { + return this.k8sWorkloads ? Object.values(this.k8sWorkloads).flat().length : 0; + }, + summaryObjects() { + return [ + this.deploymentsItems, + this.daemonSetsItems, + this.statefulSetItems, + this.replicaSetItems, + this.jobItems, + this.cronJobItems, + ].filter(Boolean); + }, + deploymentsItems() { + const items = this.k8sWorkloads?.DeploymentList; + if (!items?.length) { + return null; + } + + return { + name: this.$options.i18n.deployments, + items: getDeploymentsStatuses(items), + }; + }, + daemonSetsItems() { + const items = this.k8sWorkloads?.DaemonSetList; + if (!items?.length) { + return null; + } + + return { + name: this.$options.i18n.daemonSets, + items: getDaemonSetStatuses(items), + }; + }, + statefulSetItems() { + const items = this.k8sWorkloads?.StatefulSetList; + if (!items?.length) { + return null; + } + + return { + name: this.$options.i18n.statefulSets, + items: getStatefulSetStatuses(items), + }; + }, + replicaSetItems() { + const items = this.k8sWorkloads?.ReplicaSetList; + if (!items?.length) { + return null; + } + + return { + name: this.$options.i18n.replicaSets, + items: getReplicaSetStatuses(items), + }; + }, + jobItems() { + const items = this.k8sWorkloads?.JobList; + if (!items?.length) { + return null; + } + + return { + name: this.$options.i18n.jobs, + items: getJobsStatuses(items), + }; + }, + cronJobItems() { + const items = this.k8sWorkloads?.CronJobList; + if (!items?.length) { + return null; + } + + return { + name: this.$options.i18n.cronJobs, + items: getCronJobsStatuses(items), + }; + }, + }, + i18n: { + summaryTitle: s__('Environment|Summary'), + deployments: s__('Environment|Deployments'), + daemonSets: s__('Environment|DaemonSets'), + statefulSets: s__('Environment|StatefulSets'), + replicaSets: s__('Environment|ReplicaSets'), + jobs: s__('Environment|Jobs'), + cronJobs: s__('Environment|CronJobs'), + }, + badgeVariants: { + ready: 'success', + completed: 'success', + failed: 'danger', + suspended: 'neutral', + }, + icons: { + Active: { icon: 'status_success', class: 'gl-text-green-500' }, + }, +}; +</script> +<template> + <gl-tab> + <template #title> + {{ $options.i18n.summaryTitle }} + <gl-badge size="sm" class="gl-tab-counter-badge">{{ summaryCount }}</gl-badge> + </template> + + <gl-loading-icon v-if="summaryLoading" /> + + <ul v-else class="gl-mt-3 gl-list-style-none gl-bg-white gl-pl-0 gl-mb-0"> + <li + v-for="object in summaryObjects" + :key="object.name" + class="gl-display-flex gl-align-items-center gl-p-3 gl-border-t gl-text-gray-700" + data-testid="summary-list-item" + > + <div class="gl-flex-grow-1">{{ object.name }}</div> + + <gl-badge + v-for="(item, key) in object.items" + :key="key" + :variant="$options.badgeVariants[key]" + size="sm" + class="gl-ml-2" + >{{ item.length }} {{ key }}</gl-badge + > + </li> + </ul> + </gl-tab> +</template> diff --git a/app/assets/javascripts/environments/components/kubernetes_tabs.vue b/app/assets/javascripts/environments/components/kubernetes_tabs.vue index b1eb92a4049..b900c23b2b7 100644 --- a/app/assets/javascripts/environments/components/kubernetes_tabs.vue +++ b/app/assets/javascripts/environments/components/kubernetes_tabs.vue @@ -4,6 +4,7 @@ import { __, s__ } from '~/locale'; import k8sServicesQuery from '../graphql/queries/k8s_services.query.graphql'; import { generateServicePortsString, getServiceAge } from '../helpers/k8s_integration_helper'; import { SERVICES_LIMIT_PER_PAGE } from '../constants'; +import KubernetesSummary from './kubernetes_summary.vue'; const tableHeadingClasses = 'gl-bg-gray-50! gl-font-weight-bold gl-white-space-nowrap'; @@ -15,6 +16,7 @@ export default { GlTable, GlPagination, GlLoadingIcon, + KubernetesSummary, }, apollo: { k8sServices: { @@ -37,6 +39,10 @@ export default { required: true, type: Object, }, + namespace: { + required: true, + type: String, + }, }, data() { return { @@ -128,6 +134,8 @@ export default { </script> <template> <gl-tabs> + <kubernetes-summary :namespace="namespace" :configuration="configuration" /> + <gl-tab> <template #title> {{ $options.i18n.servicesTitle }} diff --git a/app/assets/javascripts/environments/graphql/client.js b/app/assets/javascripts/environments/graphql/client.js index b7754558b10..6d06cff06b9 100644 --- a/app/assets/javascripts/environments/graphql/client.js +++ b/app/assets/javascripts/environments/graphql/client.js @@ -7,6 +7,7 @@ import environmentToRollbackQuery from './queries/environment_to_rollback.query. import environmentToStopQuery from './queries/environment_to_stop.query.graphql'; import k8sPodsQuery from './queries/k8s_pods.query.graphql'; import k8sServicesQuery from './queries/k8s_services.query.graphql'; +import k8sWorkloadsQuery from './queries/k8s_workloads.query.graphql'; import { resolvers } from './resolvers'; import typeDefs from './typedefs.graphql'; @@ -109,6 +110,57 @@ export const apolloProvider = (endpoint) => { }, }, }); + cache.writeQuery({ + query: k8sWorkloadsQuery, + data: { + DeploymentList: { + status: { + conditions: [], + }, + }, + DaemonSetList: { + status: { + numberMisscheduled: 0, + numberReady: 0, + desiredNumberScheduled: 0, + }, + }, + StatefulSetList: { + status: { + readyReplicas: 0, + }, + spec: { + replicas: 0, + }, + }, + ReplicaSetList: { + status: { + readyReplicas: 0, + }, + spec: { + replicas: 0, + }, + }, + JobList: { + status: { + failed: 0, + succeeded: 0, + }, + spec: { + completions: 0, + }, + }, + CronJobList: { + status: { + active: 0, + lastScheduleTime: '', + }, + spec: { + suspend: false, + }, + }, + }, + }); return new VueApollo({ defaultClient, }); diff --git a/app/assets/javascripts/environments/graphql/queries/k8s_workloads.query.graphql b/app/assets/javascripts/environments/graphql/queries/k8s_workloads.query.graphql new file mode 100644 index 00000000000..27d39272734 --- /dev/null +++ b/app/assets/javascripts/environments/graphql/queries/k8s_workloads.query.graphql @@ -0,0 +1,50 @@ +query getK8sWorkloads($configuration: LocalConfiguration, $namespace: String) { + k8sWorkloads(configuration: $configuration, namespace: $namespace) @client { + DeploymentList { + status { + conditions + } + } + DaemonSetList { + status { + numberMisscheduled + numberReady + desiredNumberScheduled + } + } + StatefulSetList { + status { + readyReplicas + } + spec { + replicas + } + } + ReplicaSetList { + status { + readyReplicas + } + spec { + replicas + } + } + JobList { + status { + failed + succeeded + } + spec { + completions + } + } + CronJobList { + status { + active + lastScheduleTime + } + spec { + suspend + } + } + } +} diff --git a/app/assets/javascripts/environments/graphql/resolvers.js b/app/assets/javascripts/environments/graphql/resolvers.js index 8ebeeb92a53..044e7927606 100644 --- a/app/assets/javascripts/environments/graphql/resolvers.js +++ b/app/assets/javascripts/environments/graphql/resolvers.js @@ -1,4 +1,4 @@ -import { CoreV1Api, Configuration } from '@gitlab/cluster-client'; +import { CoreV1Api, Configuration, AppsV1Api, BatchV1Api } from '@gitlab/cluster-client'; import axios from '~/lib/utils/axios_utils'; import { s__ } from '~/locale'; import { @@ -29,6 +29,49 @@ const mapEnvironment = (env) => ({ __typename: 'LocalEnvironment', }); +const mapWorkloadItems = (items, kind) => { + return items.map((item) => { + const updatedItem = { + status: {}, + spec: {}, + }; + + switch (kind) { + case 'DeploymentList': + updatedItem.status.conditions = item.status.conditions || []; + break; + case 'DaemonSetList': + updatedItem.status = { + numberMisscheduled: item.status.numberMisscheduled || 0, + numberReady: item.status.numberReady || 0, + desiredNumberScheduled: item.status.desiredNumberScheduled || 0, + }; + break; + case 'StatefulSetList': + case 'ReplicaSetList': + updatedItem.status.readyReplicas = item.status.readyReplicas || 0; + updatedItem.spec.replicas = item.spec.replicas || 0; + break; + case 'JobList': + updatedItem.status.failed = item.status.failed || 0; + updatedItem.status.succeeded = item.status.succeeded || 0; + updatedItem.spec.completions = item.spec.completions || 0; + break; + case 'CronJobList': + updatedItem.status.active = item.status.active || 0; + updatedItem.status.lastScheduleTime = item.status.lastScheduleTime || ''; + updatedItem.spec.suspend = item.spec.suspend || 0; + break; + default: + updatedItem.status = item?.status; + updatedItem.spec = item?.spec; + break; + } + + return updatedItem; + }); +}; + export const resolvers = (endpoint) => ({ Query: { environmentApp(_context, { page, scope, search }, { cache }) { @@ -109,6 +152,60 @@ export const resolvers = (endpoint) => ({ throw error; }); }, + k8sWorkloads(_, { configuration, namespace }) { + const appsV1api = new AppsV1Api(configuration); + const batchV1api = new BatchV1Api(configuration); + + let promises; + + if (namespace) { + promises = [ + appsV1api.listAppsV1NamespacedDeployment(namespace), + appsV1api.listAppsV1NamespacedDaemonSet(namespace), + appsV1api.listAppsV1NamespacedStatefulSet(namespace), + appsV1api.listAppsV1NamespacedReplicaSet(namespace), + batchV1api.listBatchV1NamespacedJob(namespace), + batchV1api.listBatchV1NamespacedCronJob(namespace), + ]; + } else { + promises = [ + appsV1api.listAppsV1DeploymentForAllNamespaces(), + appsV1api.listAppsV1DaemonSetForAllNamespaces(), + appsV1api.listAppsV1StatefulSetForAllNamespaces(), + appsV1api.listAppsV1ReplicaSetForAllNamespaces(), + batchV1api.listBatchV1JobForAllNamespaces(), + batchV1api.listBatchV1CronJobForAllNamespaces(), + ]; + } + + const summaryList = { + DeploymentList: [], + DaemonSetList: [], + StatefulSetList: [], + ReplicaSetList: [], + JobList: [], + CronJobList: [], + }; + + return Promise.allSettled(promises).then((results) => { + if (results.every((res) => res.status === 'rejected')) { + const error = results[0].reason; + const errorMessage = error?.response?.data?.message ?? error; + throw new Error(errorMessage); + } + for (const promiseResult of results) { + if (promiseResult.status === 'fulfilled' && promiseResult?.value?.data) { + const { kind, items } = promiseResult.value.data; + + if (items?.length > 0) { + summaryList[kind] = mapWorkloadItems(items, kind); + } + } + } + + return summaryList; + }); + }, }, Mutation: { stopEnvironmentREST(_, { environment }, { client }) { diff --git a/app/assets/javascripts/environments/graphql/typedefs.graphql b/app/assets/javascripts/environments/graphql/typedefs.graphql index b85bf1e10d3..7e46385946f 100644 --- a/app/assets/javascripts/environments/graphql/typedefs.graphql +++ b/app/assets/javascripts/environments/graphql/typedefs.graphql @@ -93,6 +93,74 @@ type LocalK8sServices { spec: k8sServiceSpec } +type k8sDeploymentStatus { + conditions: JSON +} + +type localK8sDeployment { + status: k8sDeploymentStatus +} + +type k8sDaemonSetStatus { + IntMisscheduled: Int + IntReady: Int + desiredIntScheduled: Int +} + +type localK8sDaemonSet { + status: k8sDaemonSetStatus +} + +type k8sSetStatus { + readyReplicas: Int +} + +type k8sSetSpec { + replicas: Int +} + +type localK8sSet { + status: k8sSetStatus + spec: k8sSetSpec +} + +type k8sJobStatus { + failed: Int + succeeded: Int +} + +type k8sJobSpec { + completions: Int +} + +type localK8sJob { + status: k8sJobStatus + spec: k8sJobSpec +} + +type k8sCronJobStatus { + active: Int + lastScheduleTime: String +} + +type k8sCronJobSpec { + suspend: Boolean +} + +type localK8sCronJob { + status: k8sCronJobStatus + spec: k8sCronJobSpec +} + +type LocalK8sWorkloads { + DeploymentList: [localK8sDeployment] + DaemonSetList: [localK8sDaemonSet] + StatefulSetList: [localK8sSet] + ReplicaSetList: [localK8sSet] + JobList: [localK8sJob] + CronJobList: [localK8sCronJob] +} + extend type Query { environmentApp(page: Int, scope: String): LocalEnvironmentApp folder(environment: NestedLocalEnvironmentInput): LocalEnvironmentFolder @@ -104,6 +172,7 @@ extend type Query { isLastDeployment(environment: LocalEnvironmentInput): Boolean k8sPods(configuration: LocalConfiguration, namespace: String): [LocalK8sPods] k8sServices(configuration: LocalConfiguration): [LocalK8sServices] + k8sWorkloads(configuration: LocalConfiguration, namespace: String): LocalK8sWorkloads } extend type Mutation { diff --git a/app/assets/javascripts/environments/helpers/k8s_integration_helper.js b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js index 6a94ac31fa1..45c65c93a91 100644 --- a/app/assets/javascripts/environments/helpers/k8s_integration_helper.js +++ b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js @@ -34,3 +34,108 @@ export function getServiceAge(creationTimestamp) { return ageString; } + +export function getDeploymentsStatuses(items) { + const failed = []; + const ready = []; + + items.forEach((item) => { + const [available, progressing] = item.status?.conditions ?? []; + // eslint-disable-next-line @gitlab/require-i18n-strings + if (available.status === 'True') { + ready.push(item); + // eslint-disable-next-line @gitlab/require-i18n-strings + } else if (available.status !== 'True' && progressing.status !== 'True') { + failed.push(item); + } + }); + + return { + ...(failed.length && { failed }), + ...(ready.length && { ready }), + }; +} + +export function getDaemonSetStatuses(items) { + const failed = items.filter((item) => { + return ( + item.status?.numberMisscheduled > 0 || + item.status?.numberReady !== item.status?.desiredNumberScheduled + ); + }); + const ready = items.filter((item) => { + return ( + item.status?.numberReady === item.status?.desiredNumberScheduled && + !item.status?.numberMisscheduled + ); + }); + + return { + ...(failed.length && { failed }), + ...(ready.length && { ready }), + }; +} + +export function getStatefulSetStatuses(items) { + const failed = items.filter((item) => { + return item.status?.readyReplicas < item.spec?.replicas; + }); + const ready = items.filter((item) => { + return item.status?.readyReplicas === item.spec?.replicas; + }); + + return { + ...(failed.length && { failed }), + ...(ready.length && { ready }), + }; +} + +export function getReplicaSetStatuses(items) { + const failed = items.filter((item) => { + return item.status?.readyReplicas < item.spec?.replicas; + }); + const ready = items.filter((item) => { + return item.status?.readyReplicas === item.spec?.replicas; + }); + + return { + ...(failed.length && { failed }), + ...(ready.length && { ready }), + }; +} + +export function getJobsStatuses(items) { + const failed = items.filter((item) => { + return item.status.failed > 0 || item.status?.succeeded !== item.spec?.completions; + }); + const completed = items.filter((item) => { + return item.status?.succeeded === item.spec?.completions; + }); + + return { + ...(failed.length && { failed }), + ...(completed.length && { completed }), + }; +} + +export function getCronJobsStatuses(items) { + const failed = []; + const ready = []; + const suspended = []; + + items.forEach((item) => { + if (item.status?.active > 0 && !item.status?.lastScheduleTime) { + failed.push(item); + } else if (item.spec?.suspend) { + suspended.push(item); + } else if (item.status?.lastScheduleTime) { + ready.push(item); + } + }); + + return { + ...(failed.length && { failed }), + ...(suspended.length && { suspended }), + ...(ready.length && { ready }), + }; +} diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index aefac300839..15a31fbb3d9 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -451,3 +451,21 @@ color: $gl-text-color; } } + +@mixin omniauth-divider { + &::before, + &::after { + content: ''; + flex: 1; + border-bottom: 1px solid var(--gray-100, $gray-100); + margin: $gl-padding-24 0; + } + + &::before { + margin-right: $gl-padding; + } + + &::after { + margin-left: $gl-padding; + } +} diff --git a/app/assets/stylesheets/page_bundles/login.scss b/app/assets/stylesheets/page_bundles/login.scss index 495b7d58788..1ae7230772d 100644 --- a/app/assets/stylesheets/page_bundles/login.scss +++ b/app/assets/stylesheets/page_bundles/login.scss @@ -221,6 +221,10 @@ color: $red-700; } } + + .omniauth-divider { + @include omniauth-divider; + } } @include media-breakpoint-down(xs) { diff --git a/app/assets/stylesheets/page_bundles/signup.scss b/app/assets/stylesheets/page_bundles/signup.scss index 4fc671dace8..2bb3ff77132 100644 --- a/app/assets/stylesheets/page_bundles/signup.scss +++ b/app/assets/stylesheets/page_bundles/signup.scss @@ -9,21 +9,7 @@ } .omniauth-divider { - &::before, - &::after { - content: ''; - flex: 1; - border-bottom: 1px solid var(--gray-100, $gray-100); - margin: $gl-padding-24 0; - } - - &::before { - margin-right: $gl-padding; - } - - &::after { - margin-left: $gl-padding; - } + @include omniauth-divider; } .decline-page { diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss index cd768c3bbc0..f676782de2a 100644 --- a/app/assets/stylesheets/startup/startup-signin.scss +++ b/app/assets/stylesheets/startup/startup-signin.scss @@ -360,11 +360,6 @@ input.btn-block[type="button"] { align-items: center; justify-content: space-between; } -.clearfix::after { - display: block; - clear: both; - content: ""; -} .fixed-top { position: fixed; top: 0; @@ -783,11 +778,8 @@ svg { .gl-display-inline-block { display: inline-block; } -.gl-flex-wrap { - flex-wrap: wrap; -} -.gl-justify-content-center { - justify-content: center; +.gl-align-items-center { + align-items: center; } .gl-justify-content-space-between { justify-content: space-between; @@ -801,9 +793,6 @@ svg { .gl-w-half { width: 50%; } -.gl-w-90p { - width: 90%; -} .gl-w-full { width: 100%; } @@ -812,9 +801,6 @@ svg { width: 100%; } } -.gl-p-5 { - padding: 1rem; -} .gl-px-5 { padding-left: 1rem; padding-right: 1rem; @@ -822,6 +808,13 @@ svg { .gl-pt-5 { padding-top: 1rem; } +.gl-pb-5 { + padding-bottom: 1rem; +} +.gl-py-5 { + padding-top: 1rem; + padding-bottom: 1rem; +} .gl-mt-3 { margin-top: 0.5rem; } @@ -831,9 +824,6 @@ svg { .gl-mr-auto { margin-right: auto; } -.gl-mr-2 { - margin-right: 0.25rem; -} .gl-mb-1 { margin-bottom: 0.125rem; } @@ -846,9 +836,6 @@ svg { .gl-ml-auto { margin-left: auto; } -.gl-ml-2 { - margin-left: 0.25rem; -} @media (min-width: 576px) { .gl-sm-mt-0 { margin-top: 0; @@ -860,9 +847,6 @@ svg { .gl-font-size-h2 { font-size: 1.1875rem; } -.gl-font-weight-normal { - font-weight: 400; -} .gl-font-weight-bold { font-weight: 600; } |