Skip to content
Snippets Groups Projects
Commit be81c157 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent bb19d187
No related branches found
No related tags found
No related merge requests found
Showing
with 291 additions and 12 deletions
<script>
import { mapState, mapActions } from 'vuex';
import { GlTable, GlLoadingIcon, GlBadge } from '@gitlab/ui';
import { CLUSTER_TYPES } from '../constants';
import { __ } from '~/locale';
export default {
components: {
GlTable,
GlLoadingIcon,
GlBadge,
},
fields: [
{
key: 'name',
label: __('Kubernetes cluster'),
},
{
key: 'environmentScope',
label: __('Environment scope'),
},
{
key: 'size',
label: __('Size'),
},
{
key: 'clusterType',
label: __('Cluster level'),
formatter: value => CLUSTER_TYPES[value],
},
],
computed: {
...mapState(['clusters', 'loading']),
},
mounted() {
// TODO - uncomment this once integrated with BE
// this.fetchClusters();
},
methods: {
...mapActions(['fetchClusters']),
},
};
</script>
<template>
<gl-loading-icon v-if="loading" size="md" class="mt-3" />
<gl-table
v-else
:items="clusters"
:fields="$options.fields"
stacked="md"
variant="light"
class="qa-clusters-table"
>
<template #cell(clusterType)="{value}">
<gl-badge variant="light">
{{ value }}
</gl-badge>
</template>
</gl-table>
</template>
import { __ } from '~/locale';
export const CLUSTER_TYPES = {
project_type: __('Project'),
group_type: __('Group'),
instance_type: __('Instance'),
};
export default {
CLUSTER_TYPES,
};
import Vue from 'vue';
import Clusters from './components/clusters.vue';
import { createStore } from './store';
export default () => {
const entryPoint = document.querySelector('#js-clusters-list-app');
if (!entryPoint) {
return;
}
const { endpoint } = entryPoint.dataset;
// eslint-disable-next-line no-new
new Vue({
el: '#js-clusters-list-app',
store: createStore({ endpoint }),
render(createElement) {
return createElement(Clusters);
},
});
};
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import axios from '~/lib/utils/axios_utils';
import flash from '~/flash';
import { __ } from '~/locale';
import * as types from './mutation_types';
export const fetchClusters = ({ state, commit }) => {
return axios
.get(state.endpoint)
.then(({ data }) => {
commit(types.SET_CLUSTERS_DATA, convertObjectPropsToCamelCase(data, { deep: true }));
commit(types.SET_LOADING_STATE, false);
})
.catch(() => flash(__('An error occurred while loading clusters')));
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
import Vue from 'vue';
import Vuex from 'vuex';
import state from './state';
import mutations from './mutations';
import * as actions from './actions';
Vue.use(Vuex);
export const createStore = initialState =>
new Vuex.Store({
actions,
mutations,
state: state(initialState),
});
export default createStore;
export const SET_CLUSTERS_DATA = 'SET_CLUSTERS_DATA';
export const SET_LOADING_STATE = 'SET_LOADING_STATE';
import * as types from './mutation_types';
export default {
[types.SET_LOADING_STATE](state, value) {
state.loading = value;
},
[types.SET_CLUSTERS_DATA](state, clusters) {
Object.assign(state, {
clusters,
});
},
};
export default (initialState = {}) => ({
endpoint: initialState.endpoint,
loading: false, // TODO - set this to true once integrated with BE
clusters: [
// TODO - remove mock data once integrated with BE
// {
// name: 'My Cluster',
// environmentScope: '*',
// size: '3',
// clusterType: 'group_type',
// },
// {
// name: 'My other cluster',
// environmentScope: 'production',
// size: '12',
// clusterType: 'project_type',
// },
],
});
import PersistentUserCallout from '~/persistent_user_callout';
import initClustersListApp from '~/clusters_list';
 
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.gcp-signup-offer');
PersistentUserCallout.factory(callout);
initClustersListApp();
});
import PersistentUserCallout from '~/persistent_user_callout';
import initClustersListApp from '~/clusters_list';
 
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.gcp-signup-offer');
PersistentUserCallout.factory(callout);
initClustersListApp();
});
import PersistentUserCallout from '~/persistent_user_callout';
import initClustersListApp from '~/clusters_list';
 
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.gcp-signup-offer');
PersistentUserCallout.factory(callout);
initClustersListApp();
});
Loading
Loading
@@ -180,6 +180,7 @@ export default class MergeRequestStore {
this.mergeRequestAddCiConfigPath = data.merge_request_add_ci_config_path;
this.pipelinesEmptySvgPath = data.pipelines_empty_svg_path;
this.humanAccess = data.human_access;
this.newPipelinePath = data.new_project_pipeline_path;
}
 
get isNothingToMergeState() {
Loading
Loading
Loading
Loading
@@ -64,6 +64,10 @@ class MergeRequestWidgetEntity < Grape::Entity
merge_request.project.team.human_max_access(current_user&.id)
end
 
expose :new_project_pipeline_path do |merge_request|
new_project_pipeline_path(merge_request.project)
end
# Rendering and redacting Markdown can be expensive. These links are
# just nice to have in the merge request widget, so only
# include them if they are explicitly requested on first load.
Loading
Loading
Loading
Loading
@@ -18,13 +18,16 @@
%strong
= link_to _('More information'), help_page_path('user/group/clusters/index', anchor: 'cluster-precedence')
 
.clusters-table.js-clusters-list
.gl-responsive-table-row.table-row-header{ role: "row" }
.table-section.section-60{ role: "rowheader" }
= s_("ClusterIntegration|Kubernetes cluster")
.table-section.section-30{ role: "rowheader" }
= s_("ClusterIntegration|Environment scope")
.table-section.section-10{ role: "rowheader" }
- @clusters.each do |cluster|
= render "cluster", cluster: cluster.present(current_user: current_user)
= paginate @clusters, theme: "gitlab"
- if Feature.enabled?(:clusters_list_redesign)
#js-clusters-list-app{ data: { endpoint: 'todo/add/endpoint' } }
- else
.clusters-table.js-clusters-list
.gl-responsive-table-row.table-row-header{ role: "row" }
.table-section.section-60{ role: "rowheader" }
= s_("ClusterIntegration|Kubernetes cluster")
.table-section.section-30{ role: "rowheader" }
= s_("ClusterIntegration|Environment scope")
.table-section.section-10{ role: "rowheader" }
- @clusters.each do |cluster|
= render "cluster", cluster: cluster.present(current_user: current_user)
= paginate @clusters, theme: "gitlab"
---
title: Create table & setup operations endpoint for Status Page Settings
merge_request: 25863
author:
type: added
# frozen_string_literal: true
class AddStatusPageSettings < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
create_table :status_page_settings, id: false do |t|
t.references :project, index: true, primary_key: true, foreign_key: { on_delete: :cascade }, unique: true, null: false
t.timestamps_with_timezone null: false
t.boolean :enabled, default: false, null: false
t.string :aws_s3_bucket_name, limit: 63, null: false
t.string :aws_region, limit: 255, null: false
t.string :aws_access_key, limit: 255, null: false
t.string :encrypted_aws_secret_key, limit: 255, null: false
t.string :encrypted_aws_secret_key_iv, limit: 255, null: false
end
end
end
Loading
Loading
@@ -4002,6 +4002,18 @@ ActiveRecord::Schema.define(version: 2020_02_27_165129) do
t.boolean "recaptcha_verified", default: false, null: false
end
 
create_table "status_page_settings", primary_key: "project_id", force: :cascade do |t|
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.boolean "enabled", default: false, null: false
t.string "aws_s3_bucket_name", limit: 63, null: false
t.string "aws_region", limit: 255, null: false
t.string "aws_access_key", limit: 255, null: false
t.string "encrypted_aws_secret_key", limit: 255, null: false
t.string "encrypted_aws_secret_key_iv", limit: 255, null: false
t.index ["project_id"], name: "index_status_page_settings_on_project_id"
end
create_table "subscriptions", id: :serial, force: :cascade do |t|
t.integer "user_id"
t.integer "subscribable_id"
Loading
Loading
@@ -5018,6 +5030,7 @@ ActiveRecord::Schema.define(version: 2020_02_27_165129) do
add_foreign_key "snippets", "projects", name: "fk_be41fd4bb7", on_delete: :cascade
add_foreign_key "software_license_policies", "projects", on_delete: :cascade
add_foreign_key "software_license_policies", "software_licenses", on_delete: :cascade
add_foreign_key "status_page_settings", "projects", on_delete: :cascade
add_foreign_key "subscriptions", "projects", on_delete: :cascade
add_foreign_key "suggestions", "notes", on_delete: :cascade
add_foreign_key "system_note_metadata", "description_versions", name: "fk_fbd87415c9", on_delete: :nullify
Loading
Loading
Loading
Loading
@@ -1862,6 +1862,9 @@ msgstr ""
msgid "An error occurred while loading chart data"
msgstr ""
 
msgid "An error occurred while loading clusters"
msgstr ""
msgid "An error occurred while loading commit signatures"
msgstr ""
 
Loading
Loading
@@ -3962,6 +3965,9 @@ msgstr ""
msgid "Cluster does not exist"
msgstr ""
 
msgid "Cluster level"
msgstr ""
msgid "ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}."
msgstr ""
 
Loading
Loading
@@ -7454,6 +7460,9 @@ msgstr ""
msgid "Environment does not have deployments"
msgstr ""
 
msgid "Environment scope"
msgstr ""
msgid "Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. Additionally, they can be masked so they are hidden in job logs, though they must match certain regexp requirements to do so. You can use environment variables for passwords, secret keys, or whatever you want."
msgstr ""
 
Loading
Loading
@@ -11181,6 +11190,9 @@ msgstr ""
msgid "Kubernetes Clusters"
msgstr ""
 
msgid "Kubernetes cluster"
msgstr ""
msgid "Kubernetes cluster creation time exceeds timeout; %{timeout}"
msgstr ""
 
Loading
Loading
@@ -17192,10 +17204,10 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
 
msgid "Security report is out of date. Please incorporate latest changes from %{targetBranchName}"
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
 
msgid "Security report is out of date. Retry the pipeline for the target branch."
msgid "Security report is out of date. Run %{newPipelineLinkStart}a new pipeline%{newPipelineLinkEnd} for the target branch (%{targetBranchName})"
msgstr ""
 
msgid "SecurityConfiguration|Configured"
Loading
Loading
Loading
Loading
@@ -11,6 +11,7 @@ describe 'Clusters', :js do
before do
project.add_maintainer(user)
gitlab_sign_in(user)
stub_feature_flags(clusters_list_redesign: false)
end
 
context 'when user does not have a cluster and visits cluster index page' do
Loading
Loading
import { createLocalVue, mount } from '@vue/test-utils';
import { GlTable, GlLoadingIcon } from '@gitlab/ui';
import Clusters from '~/clusters_list/components/clusters.vue';
import Vuex from 'vuex';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Clusters', () => {
let wrapper;
const findTable = () => wrapper.find(GlTable);
const findLoader = () => wrapper.find(GlLoadingIcon);
const mountComponent = _state => {
const state = { clusters: [], endpoint: 'some/endpoint', ..._state };
const store = new Vuex.Store({
state,
});
wrapper = mount(Clusters, { localVue, store });
};
beforeEach(() => {
mountComponent({ loading: false });
});
describe('clusters table', () => {
it('displays a loader instead of the table while loading', () => {
mountComponent({ loading: true });
expect(findLoader().exists()).toBe(true);
expect(findTable().exists()).toBe(false);
});
it('displays a table component', () => {
expect(findTable().exists()).toBe(true);
expect(findTable().exists()).toBe(true);
});
it('renders the correct table headers', () => {
const tableHeaders = wrapper.vm.$options.fields;
const headers = findTable().findAll('th');
expect(headers.length).toBe(tableHeaders.length);
tableHeaders.forEach((headerText, i) =>
expect(headers.at(i).text()).toEqual(headerText.label),
);
});
it('should stack on smaller devices', () => {
expect(findTable().classes()).toContain('b-table-stacked-md');
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment