Commit 648fb0e8 authored by Robert Speicher's avatar Robert Speicher

Merge branch 'add-operations-environments-list-endpoint' into 'master'

Add operations/environments_list Endpoint

See merge request gitlab-org/gitlab-ee!14965
parents 82d3f692 d48d66ae
...@@ -26,6 +26,13 @@ class OperationsController < ApplicationController ...@@ -26,6 +26,13 @@ class OperationsController < ApplicationController
render json: { projects: serialize_as_json(projects) } render json: { projects: serialize_as_json(projects) }
end end
def environments_list
Gitlab::PollingInterval.set_header(response, interval: POLLING_INTERVAL)
projects = load_environments_projects(current_user)
render json: { projects: serialize_as_json_for_environments(projects) }
end
def create def create
project_ids = params['project_ids'] project_ids = params['project_ids']
...@@ -58,6 +65,10 @@ class OperationsController < ApplicationController ...@@ -58,6 +65,10 @@ class OperationsController < ApplicationController
Dashboard::Operations::ListService.new(current_user).execute Dashboard::Operations::ListService.new(current_user).execute
end end
def load_environments_projects(current_user)
Dashboard::Environments::ListService.new(current_user).execute
end
def add_projects(current_user, project_ids) def add_projects(current_user, project_ids)
UsersOpsDashboardProjects::CreateService.new(current_user).execute(project_ids) UsersOpsDashboardProjects::CreateService.new(current_user).execute(project_ids)
end end
...@@ -69,4 +80,8 @@ class OperationsController < ApplicationController ...@@ -69,4 +80,8 @@ class OperationsController < ApplicationController
def serialize_as_json(projects) def serialize_as_json(projects)
DashboardOperationsSerializer.new(current_user: current_user).represent(projects).as_json DashboardOperationsSerializer.new(current_user: current_user).represent(projects).as_json
end end
def serialize_as_json_for_environments(projects)
DashboardEnvironmentsSerializer.new.represent(projects).as_json
end
end end
...@@ -9,4 +9,13 @@ module OperationsHelper ...@@ -9,4 +9,13 @@ module OperationsHelper
'empty-dashboard-help-path' => help_page_path('user/operations_dashboard/index.html') 'empty-dashboard-help-path' => help_page_path('user/operations_dashboard/index.html')
} }
end end
def environments_data
{
'add-path' => add_operations_project_path,
'list-path' => operations_environments_list_path,
'empty-dashboard-svg-path' => image_path('illustrations/operations-dashboard_empty.svg'),
'empty-dashboard-help-path' => help_page_path('user/operations_dashboard/index.html')
}
end
end end
# frozen_string_literal: true
class DashboardEnvironmentsProjectEntity < Grape::Entity
include RequestAwareEntity
expose :id
expose :name
expose :avatar_url
expose :web_url
expose :remove_path do |project_object|
remove_operations_project_path(project_id: project_object.id)
end
expose :namespace, using: API::Entities::NamespaceBasic
end
# frozen_string_literal: true
class DashboardEnvironmentsSerializer < BaseSerializer
entity DashboardEnvironmentsProjectEntity
end
# frozen_string_literal: true
module Dashboard
module Environments
class ListService
def initialize(user)
@user = user
end
def execute
load_projects(user)
end
private
attr_reader :user
def load_projects(user)
projects = user.ops_dashboard_projects
::Dashboard::Operations::ProjectsService
.new(user)
.execute(projects)
.to_a
end
end
end
end
- page_title _('Environments Dashboard') - page_title _('Environments Dashboard')
- @hide_breadcrumbs = true - @hide_breadcrumbs = true
#js-environments{ data: operations_data } #js-environments{ data: environments_data }
...@@ -3,5 +3,6 @@ ...@@ -3,5 +3,6 @@
get 'operations' => 'operations#index' get 'operations' => 'operations#index'
get 'operations/environments' => 'operations#environments' get 'operations/environments' => 'operations#environments'
get 'operations/list' => 'operations#list' get 'operations/list' => 'operations#list'
get 'operations/environments_list' => 'operations#environments_list'
post 'operations' => 'operations#create', as: :add_operations_project post 'operations' => 'operations#create', as: :add_operations_project
delete 'operations' => 'operations#destroy', as: :remove_operations_project delete 'operations' => 'operations#destroy', as: :remove_operations_project
...@@ -47,6 +47,29 @@ describe OperationsController do ...@@ -47,6 +47,29 @@ describe OperationsController do
end end
end end
describe 'GET #environments' do
it_behaves_like 'unlicensed', :get, :environments
it 'renders the view' do
get :environments
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:environments)
end
context 'with an anonymous user' do
before do
sign_out(user)
end
it 'redirects to sign-in page' do
get :environments
expect(response).to redirect_to(new_user_session_path)
end
end
end
describe 'GET #list' do describe 'GET #list' do
let(:now) { Time.now.change(usec: 0) } let(:now) { Time.now.change(usec: 0) }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
...@@ -141,6 +164,78 @@ describe OperationsController do ...@@ -141,6 +164,78 @@ describe OperationsController do
end end
end end
describe 'GET #environment_list' do
it_behaves_like 'unlicensed', :get, :environments_list
context 'with an anonymous user' do
before do
sign_out(user)
end
it 'redirects to sign-in page' do
get :environments_list
expect(response).to redirect_to(new_user_session_path)
end
end
context 'with an authenticated user without sufficient access_level' do
it 'returns an empty project list' do
project = create(:project)
project.add_reporter(user)
user.update!(ops_dashboard_projects: [project])
get :environments_list
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['projects']).to eq([])
end
end
context 'with an authenticated developer' do
it 'returns an empty project list' do
get :environments_list
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['projects']).to eq([])
end
it 'sets the polling interval header' do
get :environments_list
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers[Gitlab::PollingInterval::HEADER_NAME]).to eq('120000')
end
it "returns an empty project list when the project is not in the developer's dashboard" do
project = create(:project)
project.add_developer(user)
user.update!(ops_dashboard_projects: [])
get :environments_list
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['projects']).to eq([])
end
it 'returns a list with one project when the developer has added that project to the dashboard' do
project = create(:project, :with_avatar)
project.add_developer(user)
user.update!(ops_dashboard_projects: [project])
get :environments_list
project_json = json_response['projects'].first
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('dashboard/operations/environments_list', dir: 'ee')
expect(project_json['id']).to eq(project.id)
expect(project_json['name']).to eq(project.name)
expect(project_json['namespace']['id']).to eq(project.namespace.id)
expect(project_json['namespace']['name']).to eq(project.namespace.name)
end
end
end
describe 'POST #create' do describe 'POST #create' do
it_behaves_like 'unlicensed', :post, :create it_behaves_like 'unlicensed', :post, :create
......
# frozen_string_literal: true
require 'spec_helper'
describe 'Dashboard operations', :js do
it 'displays information about the last pipeline to an authenticated developer on the project' do
stub_licensed_features(operations_dashboard: true)
user = create(:user)
project = create(:project, :repository, name: 'Great Project')
pipeline = create(:ci_pipeline, project: project, sha: project.commit.sha, status: :running)
project.add_developer(user)
user.update(ops_dashboard_projects: [project])
sign_in(user)
visit operations_path
expect(page).to have_text(project.name)
expect(page).to have_text(pipeline.ref)
expect(page).to have_text(pipeline.short_sha)
expect(page).to have_text('Alerts')
expect(page).to have_text(pipeline.status)
end
end
{
"type": "object",
"required": [
"projects"
],
"additionalProperties": false,
"properties": {
"projects": {
"type": "array",
"items": {
"$ref": "#/definitions/project"
}
}
},
"definitions": {
"project": {
"type": "object",
"required": [
"id",
"name",
"avatar_url",
"remove_path",
"web_url",
"namespace"
],
"additionalProperties": false,
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"avatar_url": { "type": ["string", "null"] },
"remove_path": { "type": "string" },
"web_url": { "type": "string" },
"namespace": { "$ref": "#/definitions/namespace" }
}
},
"namespace": {
"type": "object",
"required": [
"id",
"name",
"avatar_url",
"full_path"
],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"avatar_url": { "type": ["string", "null"] },
"full_path": { "type": "string" }
}
}
}
}
# frozen_string_literal: true
require 'spec_helper'
describe OperationsHelper do
include Gitlab::Routing.url_helpers
describe '#operations_data' do
it 'returns frontend configuration' do
expect(operations_data).to eq(
'add-path' => '/-/operations',
'list-path' => '/-/operations/list',
'empty-dashboard-svg-path' => '/images/illustrations/operations-dashboard_empty.svg',
'empty-dashboard-help-path' => '/help/user/operations_dashboard/index.html'
)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'operations/environments.html.haml' do
it 'renders the frontend configuration' do
render
expect(rendered).to match %r{data-add-path="/-/operations"}
expect(rendered).to match %r{data-list-path="/-/operations/environments_list"}
expect(rendered).to match %r{data-empty-dashboard-svg-path="/assets/illustrations/operations-dashboard_empty.*\.svg"}
expect(rendered).to match %r{data-empty-dashboard-help-path="/help/user/operations_dashboard/index.html"}
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'operations/index.html.haml' do
it 'renders the frontend configuration' do
render
expect(rendered).to match %r{data-add-path="/-/operations"}
expect(rendered).to match %r{data-list-path="/-/operations/list"}
expect(rendered).to match %{data-empty-dashboard-svg-path="/assets/illustrations/operations-dashboard_empty.*\.svg"}
expect(rendered).to match %r{data-empty-dashboard-help-path="/help/user/operations_dashboard/index.html"}
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment