summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_gfm.js4
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_metrics.js24
-rw-r--r--app/assets/javascripts/monitoring/components/charts/area.vue96
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue7
-rw-r--r--app/assets/javascripts/monitoring/components/embed.vue97
-rw-r--r--app/assets/javascripts/monitoring/constants.js2
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js12
-rw-r--r--app/assets/javascripts/monitoring/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/monitoring/stores/mutations.js3
-rw-r--r--app/assets/javascripts/monitoring/stores/state.js1
-rw-r--r--app/assets/stylesheets/pages/prometheus.scss5
-rw-r--r--app/controllers/projects/snippets_controller.rb3
-rw-r--r--app/controllers/projects/wikis_controller.rb3
-rw-r--r--app/controllers/projects_controller.rb8
-rw-r--r--app/controllers/registrations_controller.rb3
-rw-r--r--app/controllers/sessions_controller.rb7
-rw-r--r--app/controllers/snippets_controller.rb3
-rw-r--r--app/finders/autocomplete/move_to_project_finder.rb9
-rw-r--r--app/models/project.rb17
-rw-r--r--app/views/admin/groups/show.html.haml5
-rw-r--r--app/views/admin/projects/show.html.haml5
21 files changed, 232 insertions, 83 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js
index bfb073fdcdc..789a057caf8 100644
--- a/app/assets/javascripts/behaviors/markdown/render_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js
@@ -2,6 +2,7 @@ import $ from 'jquery';
import syntaxHighlight from '~/syntax_highlight';
import renderMath from './render_math';
import renderMermaid from './render_mermaid';
+import renderMetrics from './render_metrics';
import highlightCurrentUser from './highlight_current_user';
import initUserPopovers from '../../user_popovers';
import initMRPopovers from '../../mr_popover';
@@ -17,6 +18,9 @@ $.fn.renderGFM = function renderGFM() {
highlightCurrentUser(this.find('.gfm-project_member').get());
initUserPopovers(this.find('.gfm-project_member').get());
initMRPopovers(this.find('.gfm-merge_request').get());
+ if (gon.features && gon.features.gfmEmbeddedMetrics) {
+ renderMetrics(this.find('.js-render-metrics').get());
+ }
return this;
};
diff --git a/app/assets/javascripts/behaviors/markdown/render_metrics.js b/app/assets/javascripts/behaviors/markdown/render_metrics.js
new file mode 100644
index 00000000000..252b98610b6
--- /dev/null
+++ b/app/assets/javascripts/behaviors/markdown/render_metrics.js
@@ -0,0 +1,24 @@
+import Vue from 'vue';
+import Metrics from '~/monitoring/components/embed.vue';
+import { createStore } from '~/monitoring/stores';
+
+// TODO: Handle copy-pasting - https://gitlab.com/gitlab-org/gitlab-ce/issues/64369.
+export default function renderMetrics(elements) {
+ if (!elements.length) {
+ return;
+ }
+
+ elements.forEach(element => {
+ const { dashboardUrl } = element.dataset;
+ const MetricsComponent = Vue.extend(Metrics);
+
+ // eslint-disable-next-line no-new
+ new MetricsComponent({
+ el: element,
+ store: createStore(),
+ propsData: {
+ dashboardUrl,
+ },
+ });
+ });
+}
diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue
index 454ff4f284e..edf9423c74c 100644
--- a/app/assets/javascripts/monitoring/components/charts/area.vue
+++ b/app/assets/javascripts/monitoring/components/charts/area.vue
@@ -37,7 +37,13 @@ export default {
},
projectPath: {
type: String,
- required: true,
+ required: false,
+ default: () => '',
+ },
+ showBorder: {
+ type: Boolean,
+ required: false,
+ default: () => false,
},
thresholds: {
type: Array,
@@ -234,52 +240,54 @@ export default {
</script>
<template>
- <div class="prometheus-graph col-12 col-lg-6">
- <div class="prometheus-graph-header">
- <h5 ref="graphTitle" class="prometheus-graph-title">{{ graphData.title }}</h5>
- <div ref="graphWidgets" class="prometheus-graph-widgets"><slot></slot></div>
- </div>
- <gl-area-chart
- ref="areaChart"
- v-bind="$attrs"
- :data="chartData"
- :option="chartOptions"
- :format-tooltip-text="formatTooltipText"
- :thresholds="thresholds"
- :width="width"
- :height="height"
- @updated="onChartUpdated"
- >
- <template v-if="tooltip.isDeployment">
- <template slot="tooltipTitle">
- {{ __('Deployed') }}
- </template>
- <div slot="tooltipContent" class="d-flex align-items-center">
- <icon name="commit" class="mr-2" />
- <gl-link :href="tooltip.commitUrl">{{ tooltip.sha }}</gl-link>
- </div>
- </template>
- <template v-else>
- <template slot="tooltipTitle">
- <div class="text-nowrap">
- {{ tooltip.title }}
+ <div class="col-12 col-lg-6" :class="[showBorder ? 'p-2' : 'p-0']">
+ <div class="prometheus-graph" :class="{ 'prometheus-graph-embed w-100 p-3': showBorder }">
+ <div class="prometheus-graph-header">
+ <h5 ref="graphTitle" class="prometheus-graph-title">{{ graphData.title }}</h5>
+ <div ref="graphWidgets" class="prometheus-graph-widgets"><slot></slot></div>
+ </div>
+ <gl-area-chart
+ ref="areaChart"
+ v-bind="$attrs"
+ :data="chartData"
+ :option="chartOptions"
+ :format-tooltip-text="formatTooltipText"
+ :thresholds="thresholds"
+ :width="width"
+ :height="height"
+ @updated="onChartUpdated"
+ >
+ <template v-if="tooltip.isDeployment">
+ <template slot="tooltipTitle">
+ {{ __('Deployed') }}
+ </template>
+ <div slot="tooltipContent" class="d-flex align-items-center">
+ <icon name="commit" class="mr-2" />
+ <gl-link :href="tooltip.commitUrl">{{ tooltip.sha }}</gl-link>
</div>
</template>
- <template slot="tooltipContent">
- <div
- v-for="(content, key) in tooltip.content"
- :key="key"
- class="d-flex justify-content-between"
- >
- <gl-chart-series-label :color="isMultiSeries ? content.color : ''">
- {{ content.name }}
- </gl-chart-series-label>
- <div class="prepend-left-32">
- {{ content.value }}
+ <template v-else>
+ <template slot="tooltipTitle">
+ <div class="text-nowrap">
+ {{ tooltip.title }}
</div>
- </div>
+ </template>
+ <template slot="tooltipContent">
+ <div
+ v-for="(content, key) in tooltip.content"
+ :key="key"
+ class="d-flex justify-content-between"
+ >
+ <gl-chart-series-label :color="isMultiSeries ? content.color : ''">
+ {{ content.name }}
+ </gl-chart-series-label>
+ <div class="prepend-left-32">
+ {{ content.value }}
+ </div>
+ </div>
+ </template>
</template>
- </template>
- </gl-area-chart>
+ </gl-area-chart>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 6eaced0c108..c7c55880040 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -11,10 +11,9 @@ import MonitorSingleStatChart from './charts/single_stat.vue';
import PanelType from './panel_type.vue';
import GraphGroup from './graph_group.vue';
import EmptyState from './empty_state.vue';
-import { timeWindows, timeWindowsKeyNames } from '../constants';
+import { sidebarAnimationDuration, timeWindows, timeWindowsKeyNames } from '../constants';
import { getTimeDiff } from '../utils';
-const sidebarAnimationDuration = 150;
let sidebarMutationObserver;
export default {
@@ -370,8 +369,8 @@ export default {
</div>
<div v-if="!showEmptyState">
<graph-group
- v-for="(groupData, index) in groupsWithData"
- :key="index"
+ v-for="groupData in groupsWithData"
+ :key="`${groupData.group}.${groupData.priority}`"
:name="groupData.group"
:show-panels="showPanels"
>
diff --git a/app/assets/javascripts/monitoring/components/embed.vue b/app/assets/javascripts/monitoring/components/embed.vue
new file mode 100644
index 00000000000..e17f03de0fd
--- /dev/null
+++ b/app/assets/javascripts/monitoring/components/embed.vue
@@ -0,0 +1,97 @@
+<script>
+import { mapActions, mapState } from 'vuex';
+import GraphGroup from './graph_group.vue';
+import MonitorAreaChart from './charts/area.vue';
+import { sidebarAnimationDuration, timeWindowsKeyNames, timeWindows } from '../constants';
+import { getTimeDiff } from '../utils';
+
+let sidebarMutationObserver;
+
+export default {
+ components: {
+ GraphGroup,
+ MonitorAreaChart,
+ },
+ props: {
+ dashboardUrl: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ params: {
+ ...getTimeDiff(timeWindows[timeWindowsKeyNames.eightHours]),
+ },
+ elWidth: 0,
+ };
+ },
+ computed: {
+ ...mapState('monitoringDashboard', ['groups', 'metricsWithData']),
+ groupData() {
+ const groupsWithData = this.groups.filter(group => this.chartsWithData(group.metrics).length);
+ if (groupsWithData.length) {
+ return groupsWithData[0];
+ }
+ return null;
+ },
+ },
+ mounted() {
+ this.setInitialState();
+ this.fetchMetricsData(this.params);
+ sidebarMutationObserver = new MutationObserver(this.onSidebarMutation);
+ sidebarMutationObserver.observe(document.querySelector('.layout-page'), {
+ attributes: true,
+ childList: false,
+ subtree: false,
+ });
+ },
+ beforeDestroy() {
+ if (sidebarMutationObserver) {
+ sidebarMutationObserver.disconnect();
+ }
+ },
+ methods: {
+ ...mapActions('monitoringDashboard', [
+ 'fetchMetricsData',
+ 'setEndpoints',
+ 'setFeatureFlags',
+ 'setShowErrorBanner',
+ ]),
+ chartsWithData(charts) {
+ return charts.filter(chart =>
+ chart.metrics.some(metric => this.metricsWithData.includes(metric.metric_id)),
+ );
+ },
+ onSidebarMutation() {
+ setTimeout(() => {
+ this.elWidth = this.$el.clientWidth;
+ }, sidebarAnimationDuration);
+ },
+ setInitialState() {
+ this.setFeatureFlags({
+ prometheusEndpointEnabled: true,
+ });
+ this.setEndpoints({
+ dashboardEndpoint: this.dashboardUrl,
+ });
+ this.setShowErrorBanner(false);
+ },
+ },
+};
+</script>
+<template>
+ <div class="metrics-embed">
+ <div v-if="groupData" class="row w-100 m-n2 pb-4">
+ <monitor-area-chart
+ v-for="graphData in chartsWithData(groupData.metrics)"
+ :key="graphData.title"
+ :graph-data="graphData"
+ :container-width="elWidth"
+ group-id="monitor-area-chart"
+ :project-path="null"
+ :show-border="true"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js
index 26f1bf3f68d..605c95e6da5 100644
--- a/app/assets/javascripts/monitoring/constants.js
+++ b/app/assets/javascripts/monitoring/constants.js
@@ -1,5 +1,7 @@
import { __ } from '~/locale';
+export const sidebarAnimationDuration = 300; // milliseconds.
+
export const chartHeight = 300;
export const graphTypes = {
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index 5b3da51e9a6..245cc2eaca3 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -44,6 +44,10 @@ export const setFeatureFlags = (
commit(types.SET_ADDITIONAL_PANEL_TYPES_ENABLED, additionalPanelTypesEnabled);
};
+export const setShowErrorBanner = ({ commit }, enabled) => {
+ commit(types.SET_SHOW_ERROR_BANNER, enabled);
+};
+
export const requestMetricsDashboard = ({ commit }) => {
commit(types.REQUEST_METRICS_DATA);
};
@@ -99,7 +103,9 @@ export const fetchMetricsData = ({ state, dispatch }, params) => {
})
.catch(error => {
dispatch('receiveMetricsDataFailure', error);
- createFlash(s__('Metrics|There was an error while retrieving metrics'));
+ if (state.setShowErrorBanner) {
+ createFlash(s__('Metrics|There was an error while retrieving metrics'));
+ }
});
};
@@ -119,7 +125,9 @@ export const fetchDashboard = ({ state, dispatch }, params) => {
})
.catch(error => {
dispatch('receiveMetricsDashboardFailure', error);
- createFlash(s__('Metrics|There was an error while retrieving metrics'));
+ if (state.setShowErrorBanner) {
+ createFlash(s__('Metrics|There was an error while retrieving metrics'));
+ }
});
};
diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js
index c89daba3df7..4b1aadbcf05 100644
--- a/app/assets/javascripts/monitoring/stores/mutation_types.js
+++ b/app/assets/javascripts/monitoring/stores/mutation_types.js
@@ -16,3 +16,4 @@ export const SET_ALL_DASHBOARDS = 'SET_ALL_DASHBOARDS';
export const SET_ENDPOINTS = 'SET_ENDPOINTS';
export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE';
export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE';
+export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER';
diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js
index 0104dcb867d..b19520d6638 100644
--- a/app/assets/javascripts/monitoring/stores/mutations.js
+++ b/app/assets/javascripts/monitoring/stores/mutations.js
@@ -96,4 +96,7 @@ export default {
[types.SET_ADDITIONAL_PANEL_TYPES_ENABLED](state, enabled) {
state.additionalPanelTypesEnabled = enabled;
},
+ [types.SET_SHOW_ERROR_BANNER](state, enabled) {
+ state.showErrorBanner = enabled;
+ },
};
diff --git a/app/assets/javascripts/monitoring/stores/state.js b/app/assets/javascripts/monitoring/stores/state.js
index e54bb712695..440bdc951e0 100644
--- a/app/assets/javascripts/monitoring/stores/state.js
+++ b/app/assets/javascripts/monitoring/stores/state.js
@@ -12,6 +12,7 @@ export default () => ({
additionalPanelTypesEnabled: false,
emptyState: 'gettingStarted',
showEmptyState: true,
+ showErrorBanner: true,
groups: [],
deploymentData: [],
environments: [],
diff --git a/app/assets/stylesheets/pages/prometheus.scss b/app/assets/stylesheets/pages/prometheus.scss
index 2d600e3aef6..05a4cc168a8 100644
--- a/app/assets/stylesheets/pages/prometheus.scss
+++ b/app/assets/stylesheets/pages/prometheus.scss
@@ -29,6 +29,11 @@
padding: $gl-padding / 2;
}
+.prometheus-graph-embed {
+ border: 1px solid $border-color;
+ border-radius: $border-radius-default;
+}
+
.prometheus-graph-header {
display: flex;
align-items: center;
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 255f1f3569a..59f948959d6 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -7,7 +7,8 @@ class Projects::SnippetsController < Projects::ApplicationController
include SnippetsActions
include RendersBlob
- skip_before_action :verify_authenticity_token, only: [:show], if: :js_request?
+ skip_before_action :verify_authenticity_token,
+ if: -> { action_name == 'show' && js_request? }
before_action :check_snippets_available!
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index fa5bdbc7d49..b0998d7f3be 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -10,7 +10,8 @@ class Projects::WikisController < Projects::ApplicationController
before_action :authorize_admin_wiki!, only: :destroy
before_action :load_project_wiki
before_action :load_page, only: [:show, :edit, :update, :history, :destroy]
- before_action :valid_encoding?, only: [:show, :edit, :update], if: :load_page
+ before_action :valid_encoding?,
+ if: -> { %w[show edit update].include?(action_name) && load_page }
before_action only: [:edit, :update], unless: :valid_encoding? do
redirect_to(project_wiki_path(@project, @page))
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index feefc7f8137..37ffd28bf9e 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -18,9 +18,11 @@ class ProjectsController < Projects::ApplicationController
before_action :redirect_git_extension, only: [:show]
before_action :project, except: [:index, :new, :create, :resolve]
before_action :repository, except: [:index, :new, :create, :resolve]
- before_action :assign_ref_vars, only: [:show], if: :repo_exists?
- before_action :tree, only: [:show], if: [:repo_exists?, :project_view_files?]
- before_action :lfs_blob_ids, only: [:show], if: [:repo_exists?, :project_view_files?]
+ before_action :assign_ref_vars, if: -> { action_name == 'show' && repo_exists? }
+ before_action :tree,
+ if: -> { action_name == 'show' && repo_exists? && project_view_files? }
+ before_action :lfs_blob_ids,
+ if: -> { action_name == 'show' && repo_exists? && project_view_files? }
before_action :project_export_enabled, only: [:export, :download_export, :remove_export, :generate_new_export]
before_action :present_project, only: [:edit]
before_action :authorize_download_code!, only: [:refs]
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index b2b151bbcf0..638934694e0 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -8,8 +8,7 @@ class RegistrationsController < Devise::RegistrationsController
prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, only: [:destroy]
before_action :ensure_terms_accepted,
- if: -> { Gitlab::CurrentSettings.current_application_settings.enforce_terms? },
- only: [:create]
+ if: -> { action_name == 'create' && Gitlab::CurrentSettings.current_application_settings.enforce_terms? }
def new
redirect_to(new_user_session_path)
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index a841859621e..7604b31467a 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -13,18 +13,17 @@ class SessionsController < Devise::SessionsController
prepend_before_action :check_initial_setup, only: [:new]
prepend_before_action :authenticate_with_two_factor,
- if: :two_factor_enabled?, only: [:create]
+ if: -> { action_name == 'create' && two_factor_enabled? }
prepend_before_action :check_captcha, only: [:create]
prepend_before_action :store_redirect_uri, only: [:new]
prepend_before_action :ldap_servers, only: [:new, :create]
prepend_before_action :require_no_authentication_without_flash, only: [:new, :create]
- prepend_before_action :ensure_password_authentication_enabled!, if: :password_based_login?, only: [:create]
+ prepend_before_action :ensure_password_authentication_enabled!, if: -> { action_name == 'create' && password_based_login? }
before_action :auto_sign_in_with_provider, only: [:new]
before_action :load_recaptcha
- after_action :log_failed_login, only: [:new], if: :failed_login?
-
+ after_action :log_failed_login, if: -> { action_name == 'new' && failed_login? }
helper_method :captcha_enabled?
CAPTCHA_HEADER = 'X-GitLab-Show-Login-Captcha'.freeze
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index fad036b8df8..869655e9550 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -8,7 +8,8 @@ class SnippetsController < ApplicationController
include RendersBlob
include PreviewMarkdown
- skip_before_action :verify_authenticity_token, only: [:show], if: :js_request?
+ skip_before_action :verify_authenticity_token,
+ if: -> { action_name == 'show' && js_request? }
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
diff --git a/app/finders/autocomplete/move_to_project_finder.rb b/app/finders/autocomplete/move_to_project_finder.rb
index edaf74c5f92..491cce2232e 100644
--- a/app/finders/autocomplete/move_to_project_finder.rb
+++ b/app/finders/autocomplete/move_to_project_finder.rb
@@ -3,7 +3,9 @@
module Autocomplete
# Finder that retrieves a list of projects that an issue can be moved to.
class MoveToProjectFinder
- attr_reader :current_user, :search, :project_id, :offset_id
+ attr_reader :current_user, :search, :project_id
+
+ LIMIT = 20
# current_user - The User object of the user that wants to view the list of
# projects.
@@ -14,13 +16,10 @@ module Autocomplete
#
# * search: An optional search query to apply to the list of projects.
# * project_id: The ID of a project to exclude from the returned relation.
- # * offset_id: The ID of a project to use for pagination. When given, only
- # projects with a lower ID are included in the list.
def initialize(current_user, params = {})
@current_user = current_user
@search = params[:search]
@project_id = params[:project_id]
- @offset_id = params[:offset_id]
end
def execute
@@ -28,8 +27,8 @@ module Autocomplete
.projects_where_can_admin_issues
.optionally_search(search)
.excluding_project(project_id)
- .paginate_in_descending_order_using_id(before: offset_id)
.eager_load_namespace_and_owner
+ .sorted_by_name_asc_limited(LIMIT)
end
end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 8dfe2212282..ece7507e55c 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -357,6 +357,7 @@ class Project < ApplicationRecord
scope :sorted_by_activity, -> { reorder(Arel.sql("GREATEST(COALESCE(last_activity_at, '1970-01-01'), COALESCE(last_repository_updated_at, '1970-01-01')) DESC")) }
scope :sorted_by_stars_desc, -> { reorder(star_count: :desc) }
scope :sorted_by_stars_asc, -> { reorder(star_count: :asc) }
+ scope :sorted_by_name_asc_limited, ->(limit) { reorder(name: :asc).limit(limit) }
scope :in_namespace, ->(namespace_ids) { where(namespace_id: namespace_ids) }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
@@ -441,22 +442,6 @@ class Project < ApplicationRecord
without_deleted.find_by_id(id)
end
- # Paginates a collection using a `WHERE id < ?` condition.
- #
- # before - A project ID to use for filtering out projects with an equal or
- # greater ID. If no ID is given, all projects are included.
- #
- # limit - The maximum number of rows to include.
- def self.paginate_in_descending_order_using_id(
- before: nil,
- limit: Kaminari.config.default_per_page
- )
- relation = order_id_desc.limit(limit)
- relation = relation.where('projects.id < ?', before) if before
-
- relation
- end
-
def self.eager_load_namespace_and_owner
includes(namespace: :owner)
end
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 98230684d56..f9cc118a252 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -40,6 +40,11 @@
%strong
= @group.created_at.to_s(:medium)
+ %li
+ %span.light= _('ID:')
+ %strong
+ = @group.id
+
= render_if_exists 'admin/namespace_plan_info', namespace: @group
%li
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 0fae8060b32..3eff0a221d7 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -55,6 +55,11 @@
= @project.created_at.to_s(:medium)
%li
+ %span.light ID:
+ %strong
+ = @project.id
+
+ %li
%span.light http:
%strong
= link_to @project.http_url_to_repo, project_path(@project)