Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_mermaid.js2
-rw-r--r--app/assets/javascripts/boards/stores/actions.js65
-rw-r--r--app/assets/javascripts/boards/stores/index.js14
-rw-r--r--app/assets/javascripts/boards/stores/mutation_types.js21
-rw-r--r--app/assets/javascripts/boards/stores/mutations.js91
-rw-r--r--app/assets/javascripts/boards/stores/state.js3
-rw-r--r--app/assets/javascripts/gl_field_error.js3
-rw-r--r--app/assets/javascripts/gpg_badges.js2
-rw-r--r--app/assets/javascripts/groups_select.js3
-rw-r--r--app/assets/javascripts/lib/utils/highlight.js6
-rw-r--r--app/assets/javascripts/main.js2
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js8
-rw-r--r--app/assets/javascripts/pages/projects/tree/show/index.js8
-rw-r--r--app/assets/javascripts/reports/components/issues_list.vue6
-rw-r--r--app/assets/javascripts/reports/components/report_item.vue12
-rw-r--r--app/assets/javascripts/reports/components/report_section.vue6
-rw-r--r--app/assets/javascripts/reports/store/state.js5
-rw-r--r--app/assets/javascripts/repository/components/app.vue3
-rw-r--r--app/assets/javascripts/repository/graphql.js11
-rw-r--r--app/assets/javascripts/repository/index.js25
-rw-r--r--app/assets/javascripts/repository/pages/index.vue24
-rw-r--r--app/assets/javascripts/repository/pages/tree.vue15
-rw-r--r--app/assets/javascripts/repository/queries/getRef.graphql3
-rw-r--r--app/assets/javascripts/repository/router.js36
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment.vue37
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue38
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/clipboard_button.vue2
-rw-r--r--app/assets/stylesheets/components/toast.scss54
-rw-r--r--app/assets/stylesheets/framework/common.scss3
-rw-r--r--app/assets/stylesheets/framework/variables.scss13
-rw-r--r--app/assets/stylesheets/pages/members.scss2
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss4
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss2
-rw-r--r--app/controllers/projects/environments_controller.rb1
-rw-r--r--app/graphql/resolvers/issues_resolver.rb2
-rw-r--r--app/models/ci/build.rb4
-rw-r--r--app/models/clusters/applications/jupyter.rb2
-rw-r--r--app/models/clusters/concerns/application_data.rb74
-rw-r--r--app/models/environment.rb4
-rw-r--r--app/serializers/test_case_entity.rb1
-rw-r--r--app/services/ci/register_job_service.rb5
-rw-r--r--app/services/clusters/refresh_service.rb6
-rw-r--r--app/services/git/base_hooks_service.rb9
-rw-r--r--app/services/git/branch_push_service.rb1
-rw-r--r--app/services/projects/create_service.rb6
-rw-r--r--app/services/projects/transfer_service.rb5
-rw-r--r--app/uploaders/file_uploader.rb12
-rw-r--r--app/uploaders/personal_file_uploader.rb68
-rw-r--r--app/views/admin/groups/_form.html.haml2
-rw-r--r--app/views/admin/users/_head.html.haml1
-rw-r--r--app/views/groups/settings/_general.html.haml20
-rw-r--r--app/views/layouts/header/_default.html.haml2
-rw-r--r--app/views/projects/_files.html.haml10
-rw-r--r--app/views/projects/_home_panel.html.haml2
-rw-r--r--app/views/projects/commits/show.html.haml2
-rw-r--r--app/views/projects/protected_branches/_protected_branch.html.haml2
-rw-r--r--app/views/projects/settings/_general.html.haml2
-rw-r--r--app/views/projects/tree/_readme.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/workers/cluster_configure_worker.rb2
-rw-r--r--app/workers/pages_domain_removal_cron_worker.rb2
62 files changed, 649 insertions, 133 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/render_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
index 798114b4b0b..d0b7f3ff7a2 100644
--- a/app/assets/javascripts/behaviors/markdown/render_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
@@ -15,7 +15,7 @@ import { sprintf, __ } from '../../locale';
// </pre>
//
-// This is an arbitary number; Can be iterated upon when suitable.
+// This is an arbitrary number; Can be iterated upon when suitable.
const MAX_CHAR_LIMIT = 5000;
export default function renderMermaid($els) {
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
new file mode 100644
index 00000000000..da82b52330a
--- /dev/null
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -0,0 +1,65 @@
+const notImplemented = () => {
+ throw new Error('Not implemented!');
+};
+
+export default {
+ setEndpoints: () => {
+ notImplemented();
+ },
+
+ fetchLists: () => {
+ notImplemented();
+ },
+
+ generateDefaultLists: () => {
+ notImplemented();
+ },
+
+ createList: () => {
+ notImplemented();
+ },
+
+ updateList: () => {
+ notImplemented();
+ },
+
+ deleteList: () => {
+ notImplemented();
+ },
+
+ fetchIssuesForList: () => {
+ notImplemented();
+ },
+
+ moveIssue: () => {
+ notImplemented();
+ },
+
+ createNewIssue: () => {
+ notImplemented();
+ },
+
+ fetchBacklog: () => {
+ notImplemented();
+ },
+
+ bulkUpdateIssues: () => {
+ notImplemented();
+ },
+
+ fetchIssue: () => {
+ notImplemented();
+ },
+
+ toggleIssueSubscription: () => {
+ notImplemented();
+ },
+
+ showPage: () => {
+ notImplemented();
+ },
+
+ toggleEmptyState: () => {
+ notImplemented();
+ },
+};
diff --git a/app/assets/javascripts/boards/stores/index.js b/app/assets/javascripts/boards/stores/index.js
new file mode 100644
index 00000000000..f70395a3771
--- /dev/null
+++ b/app/assets/javascripts/boards/stores/index.js
@@ -0,0 +1,14 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import state from 'ee_else_ce/boards/stores/state';
+import actions from 'ee_else_ce/boards/stores/actions';
+import mutations from 'ee_else_ce/boards/stores/mutations';
+
+Vue.use(Vuex);
+
+export default () =>
+ new Vuex.Store({
+ state,
+ actions,
+ mutations,
+ });
diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js
new file mode 100644
index 00000000000..fcdfa6799b6
--- /dev/null
+++ b/app/assets/javascripts/boards/stores/mutation_types.js
@@ -0,0 +1,21 @@
+export const SET_ENDPOINTS = 'SET_ENDPOINTS';
+export const REQUEST_ADD_LIST = 'REQUEST_ADD_LIST';
+export const RECEIVE_ADD_LIST_SUCCESS = 'RECEIVE_ADD_LIST_SUCCESS';
+export const RECEIVE_ADD_LIST_ERROR = 'RECEIVE_ADD_LIST_ERROR';
+export const REQUEST_UPDATE_LIST = 'REQUEST_UPDATE_LIST';
+export const RECEIVE_UPDATE_LIST_SUCCESS = 'RECEIVE_UPDATE_LIST_SUCCESS';
+export const RECEIVE_UPDATE_LIST_ERROR = 'RECEIVE_UPDATE_LIST_ERROR';
+export const REQUEST_REMOVE_LIST = 'REQUEST_REMOVE_LIST';
+export const RECEIVE_REMOVE_LIST_SUCCESS = 'RECEIVE_REMOVE_LIST_SUCCESS';
+export const RECEIVE_REMOVE_LIST_ERROR = 'RECEIVE_REMOVE_LIST_ERROR';
+export const REQUEST_ADD_ISSUE = 'REQUEST_ADD_ISSUE';
+export const RECEIVE_ADD_ISSUE_SUCCESS = 'RECEIVE_ADD_ISSUE_SUCCESS';
+export const RECEIVE_ADD_ISSUE_ERROR = 'RECEIVE_ADD_ISSUE_ERROR';
+export const REQUEST_MOVE_ISSUE = 'REQUEST_MOVE_ISSUE';
+export const RECEIVE_MOVE_ISSUE_SUCCESS = 'RECEIVE_MOVE_ISSUE_SUCCESS';
+export const RECEIVE_MOVE_ISSUE_ERROR = 'RECEIVE_MOVE_ISSUE_ERROR';
+export const REQUEST_UPDATE_ISSUE = 'REQUEST_UPDATE_ISSUE';
+export const RECEIVE_UPDATE_ISSUE_SUCCESS = 'RECEIVE_UPDATE_ISSUE_SUCCESS';
+export const RECEIVE_UPDATE_ISSUE_ERROR = 'RECEIVE_UPDATE_ISSUE_ERROR';
+export const SET_CURRENT_PAGE = 'SET_CURRENT_PAGE';
+export const TOGGLE_EMPTY_STATE = 'TOGGLE_EMPTY_STATE';
diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js
new file mode 100644
index 00000000000..77ba68be07e
--- /dev/null
+++ b/app/assets/javascripts/boards/stores/mutations.js
@@ -0,0 +1,91 @@
+import * as mutationTypes from './mutation_types';
+
+const notImplemented = () => {
+ throw new Error('Not implemented!');
+};
+
+export default {
+ [mutationTypes.SET_ENDPOINTS]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.REQUEST_ADD_LIST]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_ADD_LIST_SUCCESS]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_ADD_LIST_ERROR]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.REQUEST_UPDATE_LIST]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_UPDATE_LIST_SUCCESS]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_UPDATE_LIST_ERROR]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.REQUEST_REMOVE_LIST]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_REMOVE_LIST_SUCCESS]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_REMOVE_LIST_ERROR]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.REQUEST_ADD_ISSUE]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_ADD_ISSUE_SUCCESS]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_ADD_ISSUE_ERROR]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.REQUEST_MOVE_ISSUE]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_MOVE_ISSUE_SUCCESS]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_MOVE_ISSUE_ERROR]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.REQUEST_UPDATE_ISSUE]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_UPDATE_ISSUE_SUCCESS]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.RECEIVE_UPDATE_ISSUE_ERROR]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.SET_CURRENT_PAGE]: () => {
+ notImplemented();
+ },
+
+ [mutationTypes.TOGGLE_EMPTY_STATE]: () => {
+ notImplemented();
+ },
+};
diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js
new file mode 100644
index 00000000000..dd16abb01a5
--- /dev/null
+++ b/app/assets/javascripts/boards/stores/state.js
@@ -0,0 +1,3 @@
+export default () => ({
+ // ...
+});
diff --git a/app/assets/javascripts/gl_field_error.js b/app/assets/javascripts/gl_field_error.js
index a5b8c357e8a..04301c9ce12 100644
--- a/app/assets/javascripts/gl_field_error.js
+++ b/app/assets/javascripts/gl_field_error.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { __ } from '~/locale';
/**
* This class overrides the browser's validation error bubbles, displaying custom
@@ -61,7 +62,7 @@ export default class GlFieldError {
this.inputElement = $(input);
this.inputDomElement = this.inputElement.get(0);
this.form = formErrors;
- this.errorMessage = this.inputElement.attr('title') || 'This field is required.';
+ this.errorMessage = this.inputElement.attr('title') || __('This field is required.');
this.fieldErrorElement = $(`<p class='${errorMessageClass} hidden'>${this.errorMessage}</p>`);
this.state = {
diff --git a/app/assets/javascripts/gpg_badges.js b/app/assets/javascripts/gpg_badges.js
index efba6fc1aff..96051b612b5 100644
--- a/app/assets/javascripts/gpg_badges.js
+++ b/app/assets/javascripts/gpg_badges.js
@@ -20,7 +20,7 @@ export default class GpgBadges {
const endpoint = tag.data('signaturesPath');
if (!endpoint) {
displayError();
- return Promise.reject(new Error('Missing commit signatures endpoint!'));
+ return Promise.reject(new Error(__('Missing commit signatures endpoint!')));
}
const params = parseQueryStringIntoObject(tag.serialize());
diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js
index bdadbb1bb2a..a1263d1cdab 100644
--- a/app/assets/javascripts/groups_select.js
+++ b/app/assets/javascripts/groups_select.js
@@ -2,6 +2,7 @@ import $ from 'jquery';
import axios from './lib/utils/axios_utils';
import Api from './api';
import { normalizeHeaders } from './lib/utils/common_utils';
+import { __ } from '~/locale';
export default function groupsSelect() {
import(/* webpackChunkName: 'select2' */ 'select2/select2')
@@ -18,7 +19,7 @@ export default function groupsSelect() {
: Api.groupsPath;
$select.select2({
- placeholder: 'Search for a group',
+ placeholder: __('Search for a group'),
allowClear: $select.hasClass('allowClear'),
multiple: $select.hasClass('multiselect'),
minimumInputLength: 0,
diff --git a/app/assets/javascripts/lib/utils/highlight.js b/app/assets/javascripts/lib/utils/highlight.js
index 4f7eff2cca1..8f0afa3467d 100644
--- a/app/assets/javascripts/lib/utils/highlight.js
+++ b/app/assets/javascripts/lib/utils/highlight.js
@@ -27,14 +27,14 @@ export default function highlight(string, match = '', matchPrefix = '<b>', match
const sanitizedValue = sanitize(string.toString(), { allowedTags: [] });
- // occurences is an array of character indices that should be
+ // occurrences is an array of character indices that should be
// highlighted in the original string, i.e. [3, 4, 5, 7]
- const occurences = fuzzaldrinPlus.match(sanitizedValue, match.toString());
+ const occurrences = fuzzaldrinPlus.match(sanitizedValue, match.toString());
return sanitizedValue
.split('')
.map((character, i) => {
- if (_.contains(occurences, i)) {
+ if (_.contains(occurrences, i)) {
return `${matchPrefix}${character}${matchSuffix}`;
}
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 1af21715551..9f30a989295 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -148,7 +148,7 @@ function deferredInitialisation() {
const canaryBadge = document.querySelector('.js-canary-badge');
const canaryLink = document.querySelector('.js-canary-link');
if (canaryBadge) {
- canaryBadge.classList.add('hidden');
+ canaryBadge.classList.remove('hidden');
}
if (canaryLink) {
canaryLink.classList.add('hidden');
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js
index 869f70e7d33..6aa41d0825b 100644
--- a/app/assets/javascripts/pages/projects/show/index.js
+++ b/app/assets/javascripts/pages/projects/show/index.js
@@ -46,4 +46,12 @@ document.addEventListener('DOMContentLoaded', () => {
GpgBadges.fetch();
leaveByUrl('project');
+
+ if (document.getElementById('js-tree-list')) {
+ import('~/repository')
+ .then(m => m.default())
+ .catch(e => {
+ throw e;
+ });
+ }
});
diff --git a/app/assets/javascripts/pages/projects/tree/show/index.js b/app/assets/javascripts/pages/projects/tree/show/index.js
index 400aed35e32..7b90a3a4f6e 100644
--- a/app/assets/javascripts/pages/projects/tree/show/index.js
+++ b/app/assets/javascripts/pages/projects/tree/show/index.js
@@ -40,4 +40,12 @@ document.addEventListener('DOMContentLoaded', () => {
}
GpgBadges.fetch();
+
+ if (document.getElementById('js-tree-list')) {
+ import('~/repository')
+ .then(m => m.default())
+ .catch(e => {
+ throw e;
+ });
+ }
});
diff --git a/app/assets/javascripts/reports/components/issues_list.vue b/app/assets/javascripts/reports/components/issues_list.vue
index f4243522ef8..50f2910e02d 100644
--- a/app/assets/javascripts/reports/components/issues_list.vue
+++ b/app/assets/javascripts/reports/components/issues_list.vue
@@ -52,6 +52,11 @@ export default {
required: false,
default: '',
},
+ showReportSectionStatus: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
computed: {
issuesWithState() {
@@ -81,6 +86,7 @@ export default {
:status="wrapped.status"
:component="component"
:is-new="wrapped.isNew"
+ :show-report-section-status="showReportSectionStatus"
/>
</smart-virtual-list>
</template>
diff --git a/app/assets/javascripts/reports/components/report_item.vue b/app/assets/javascripts/reports/components/report_item.vue
index d2106f9ad2e..01a30809e1a 100644
--- a/app/assets/javascripts/reports/components/report_item.vue
+++ b/app/assets/javascripts/reports/components/report_item.vue
@@ -34,12 +34,22 @@ export default {
required: false,
default: false,
},
+ showReportSectionStatusIcon: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
};
</script>
<template>
<li :class="{ 'is-dismissed': issue.isDismissed }" class="report-block-list-issue">
- <issue-status-icon :status="status" :status-icon-size="statusIconSize" class="append-right-5" />
+ <issue-status-icon
+ v-if="showReportSectionStatusIcon"
+ :status="status"
+ :status-icon-size="statusIconSize"
+ class="append-right-5"
+ />
<component :is="component" v-if="component" :issue="issue" :status="status" :is-new="isNew" />
</li>
diff --git a/app/assets/javascripts/reports/components/report_section.vue b/app/assets/javascripts/reports/components/report_section.vue
index d6483e95278..420e71f5e86 100644
--- a/app/assets/javascripts/reports/components/report_section.vue
+++ b/app/assets/javascripts/reports/components/report_section.vue
@@ -73,6 +73,11 @@ export default {
default: () => ({}),
required: false,
},
+ showReportSectionStatusIcon: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
@@ -166,6 +171,7 @@ export default {
:resolved-issues="resolvedIssues"
:neutral-issues="neutralIssues"
:component="component"
+ :show-report-section-status-icon="showReportSectionStatusIcon"
/>
</slot>
</div>
diff --git a/app/assets/javascripts/reports/store/state.js b/app/assets/javascripts/reports/store/state.js
index 5484900276c..25f9f70d095 100644
--- a/app/assets/javascripts/reports/store/state.js
+++ b/app/assets/javascripts/reports/store/state.js
@@ -40,6 +40,11 @@ export default () => ({
text: s__('Reports|Class'),
type: fieldTypes.link,
},
+ classname: {
+ value: null,
+ text: s__('Reports|Classname'),
+ type: fieldTypes.text,
+ },
execution_time: {
value: null,
text: s__('Reports|Execution time'),
diff --git a/app/assets/javascripts/repository/components/app.vue b/app/assets/javascripts/repository/components/app.vue
new file mode 100644
index 00000000000..98240aef810
--- /dev/null
+++ b/app/assets/javascripts/repository/components/app.vue
@@ -0,0 +1,3 @@
+<template>
+ <router-view />
+</template>
diff --git a/app/assets/javascripts/repository/graphql.js b/app/assets/javascripts/repository/graphql.js
new file mode 100644
index 00000000000..febfcce780c
--- /dev/null
+++ b/app/assets/javascripts/repository/graphql.js
@@ -0,0 +1,11 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+
+Vue.use(VueApollo);
+
+const defaultClient = createDefaultClient({});
+
+export default new VueApollo({
+ defaultClient,
+});
diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js
new file mode 100644
index 00000000000..00b69362312
--- /dev/null
+++ b/app/assets/javascripts/repository/index.js
@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import createRouter from './router';
+import App from './components/app.vue';
+import apolloProvider from './graphql';
+
+export default function setupVueRepositoryList() {
+ const el = document.getElementById('js-tree-list');
+ const { projectPath, ref } = el.dataset;
+
+ apolloProvider.clients.defaultClient.cache.writeData({
+ data: {
+ projectPath,
+ ref,
+ },
+ });
+
+ return new Vue({
+ el,
+ router: createRouter(projectPath, ref),
+ apolloProvider,
+ render(h) {
+ return h(App);
+ },
+ });
+}
diff --git a/app/assets/javascripts/repository/pages/index.vue b/app/assets/javascripts/repository/pages/index.vue
new file mode 100644
index 00000000000..fdbf195f0f6
--- /dev/null
+++ b/app/assets/javascripts/repository/pages/index.vue
@@ -0,0 +1,24 @@
+<script>
+import getRef from '../queries/getRef.graphql';
+
+export default {
+ apollo: {
+ ref: {
+ query: getRef,
+ },
+ },
+ data() {
+ return {
+ ref: '',
+ };
+ },
+};
+</script>
+
+<template>
+ <div>
+ <router-link :to="{ path: `/tree/${ref}/app` }">
+ Go to tree
+ </router-link>
+ </div>
+</template>
diff --git a/app/assets/javascripts/repository/pages/tree.vue b/app/assets/javascripts/repository/pages/tree.vue
new file mode 100644
index 00000000000..f51aafee775
--- /dev/null
+++ b/app/assets/javascripts/repository/pages/tree.vue
@@ -0,0 +1,15 @@
+<script>
+export default {
+ props: {
+ path: {
+ type: String,
+ required: false,
+ default: '/',
+ },
+ },
+};
+</script>
+
+<template>
+ <div>{{ path }}</div>
+</template>
diff --git a/app/assets/javascripts/repository/queries/getRef.graphql b/app/assets/javascripts/repository/queries/getRef.graphql
new file mode 100644
index 00000000000..58c09844c3f
--- /dev/null
+++ b/app/assets/javascripts/repository/queries/getRef.graphql
@@ -0,0 +1,3 @@
+query getRef {
+ ref @client
+}
diff --git a/app/assets/javascripts/repository/router.js b/app/assets/javascripts/repository/router.js
new file mode 100644
index 00000000000..b42a96a4ee2
--- /dev/null
+++ b/app/assets/javascripts/repository/router.js
@@ -0,0 +1,36 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import { joinPaths } from '../lib/utils/url_utility';
+import IndexPage from './pages/index.vue';
+import TreePage from './pages/tree.vue';
+
+Vue.use(VueRouter);
+
+export default function createRouter(base, baseRef) {
+ return new VueRouter({
+ mode: 'history',
+ base: joinPaths(gon.relative_url_root || '', base),
+ routes: [
+ {
+ path: '/',
+ name: 'projectRoot',
+ component: IndexPage,
+ },
+ {
+ path: `/tree/${baseRef}(/.*)?`,
+ name: 'treePath',
+ component: TreePage,
+ props: route => ({
+ path: route.params.pathMatch,
+ }),
+ beforeEnter(to, from, next) {
+ document
+ .querySelectorAll('.js-hide-on-navigation')
+ .forEach(el => el.classList.add('hidden'));
+
+ next();
+ },
+ },
+ ],
+ });
+}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
index da0a9483f8e..8f4cae8ae58 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
@@ -23,6 +23,8 @@ export default {
TooltipOnTruncate,
FilteredSearchDropdown,
ReviewAppLink,
+ VisualReviewAppLink: () =>
+ import('ee_component/vue_merge_request_widget/components/visual_review_app_link.vue'),
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -37,6 +39,20 @@ export default {
type: Boolean,
required: true,
},
+ showVisualReviewApp: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ visualReviewAppMeta: {
+ type: Object,
+ required: false,
+ default: () => ({
+ sourceProjectId: '',
+ issueId: '',
+ appUrl: '',
+ }),
+ },
},
deployedTextMap: {
running: __('Deploying to'),
@@ -168,6 +184,11 @@ export default {
:link="deploymentExternalUrl"
:css-class="`deploy-link js-deploy-url inline ${slotProps.className}`"
/>
+ <visual-review-app-link
+ v-if="showVisualReviewApp"
+ :link="deploymentExternalUrl"
+ :app-metadata="visualReviewAppMeta"
+ />
</template>
<template slot="result" slot-scope="slotProps">
@@ -187,11 +208,17 @@ export default {
</a>
</template>
</filtered-search-dropdown>
- <review-app-link
- v-else
- :link="deploymentExternalUrl"
- css-class="js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inlin"
- />
+ <template v-else>
+ <review-app-link
+ :link="deploymentExternalUrl"
+ css-class="js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inline"
+ />
+ <visual-review-app-link
+ v-if="showVisualReviewApp"
+ :link="deploymentExternalUrl"
+ :app-metadata="visualReviewAppMeta"
+ />
+ </template>
</template>
<span
v-if="deployment.stop_url"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
index 5f5fe67b3c1..b9f5f602117 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
@@ -30,9 +30,6 @@ export default {
},
},
computed: {
- pipeline() {
- return this.isPostMerge ? this.mr.mergePipeline : this.mr.pipeline;
- },
branch() {
return this.isPostMerge ? this.mr.targetBranch : this.mr.sourceBranch;
},
@@ -48,6 +45,19 @@ export default {
hasDeploymentMetrics() {
return this.isPostMerge;
},
+ visualReviewAppMeta() {
+ return {
+ appUrl: this.mr.appUrl,
+ issueId: this.mr.iid,
+ sourceProjectId: this.mr.sourceProjectId,
+ };
+ },
+ pipeline() {
+ return this.isPostMerge ? this.mr.mergePipeline : this.mr.pipeline;
+ },
+ showVisualReviewAppLink() {
+ return !!(this.mr.visualReviewFF && this.mr.visualReviewAppAvailable);
+ },
},
};
</script>
@@ -61,14 +71,18 @@ export default {
:source-branch-link="branchLink"
:troubleshooting-docs-path="mr.troubleshootingDocsPath"
/>
- <div v-if="deployments.length" slot="footer" class="mr-widget-extension">
- <deployment
- v-for="deployment in deployments"
- :key="deployment.id"
- :class="deploymentClass"
- :deployment="deployment"
- :show-metrics="hasDeploymentMetrics"
- />
- </div>
+ <template v-slot:footer>
+ <div v-if="deployments.length" class="mr-widget-extension">
+ <deployment
+ v-for="deployment in deployments"
+ :key="deployment.id"
+ :class="deploymentClass"
+ :deployment="deployment"
+ :show-metrics="hasDeploymentMetrics"
+ :show-visual-review-app="true"
+ :visual-review-app-meta="visualReviewAppMeta"
+ />
+ </div>
+ </template>
</mr-widget-container>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue b/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue
index de9c122f268..457a71cab95 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue
@@ -19,6 +19,6 @@ export default {
</script>
<template>
<a :href="link" target="_blank" rel="noopener noreferrer nofollow" :class="cssClass">
- {{ __('View app') }} <icon name="external-link" />
+ {{ __('View app') }} <icon css-classes="fgray" name="external-link" />
</a>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
index 671b4909839..a620f560b52 100644
--- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue
+++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
@@ -7,7 +7,7 @@
*
* @example
* <clipboard-button
- * title="Copy to clipbard"
+ * title="Copy to clipboard"
* text="Content to be copied"
* css-class="btn-transparent"
* />
diff --git a/app/assets/stylesheets/components/toast.scss b/app/assets/stylesheets/components/toast.scss
index 91d16c8e98d..33e1c4e5349 100644
--- a/app/assets/stylesheets/components/toast.scss
+++ b/app/assets/stylesheets/components/toast.scss
@@ -1,3 +1,53 @@
-.toast-close {
- font-size: $default-icon-size !important;
+/*
+* These styles are specific to the gl-toast component.
+* Documentation: https://design.gitlab.com/components/toasts
+* Note: Styles below are nested in order to override some of vue-toasted's default styling
+*/
+.toasted-container {
+
+ max-width: $toast-max-width;
+
+ @include media-breakpoint-down(xs) {
+ width: 100%;
+ padding-right: $toast-padding-right;
+ }
+
+ .toasted.gl-toast {
+ border-radius: $border-radius-default;
+ font-size: $gl-font-size;
+ padding: $gl-padding-8 $gl-padding-24;
+ margin-top: $toast-default-margin;
+ line-height: $gl-line-height;
+ background-color: rgba($gray-900, $toast-background-opacity);
+
+ @include media-breakpoint-down(xs) {
+ .action:first-child {
+ // Ensures actions buttons are right aligned on mobile
+ margin-left: auto;
+ }
+ }
+
+ .action {
+ color: $blue-300;
+ margin: 0 0 0 $toast-action-margin-left;
+ text-transform: none;
+ font-size: $gl-font-size;
+
+ &:first-child {
+ padding-right: 0;
+ }
+ }
+
+ .toast-close {
+ font-size: $default-icon-size;
+ margin-left: $toast-default-margin;
+ padding-left: $gl-padding;
+ }
+ }
+}
+
+// Overrides the default positioning of toasts
+body .toasted-container.bottom-left {
+ bottom: $toast-offset;
+ left: $toast-offset;
}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 2e38b260f5f..fc488b85138 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -5,6 +5,9 @@
.cgreen { color: $green-600; }
.cdark { color: $common-gray-dark; }
+.fwhite { fill: $white-light; }
+.fgray { fill: $gray-700; }
+
.text-plain,
.text-plain:hover {
color: $gl-text-color;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 4a034e1e547..1cf122102cc 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -432,7 +432,7 @@ $diff-jagged-border-gradient-color: darken($white-normal, 8%);
*/
$monospace-font: 'Menlo', 'DejaVu Sans Mono', 'Liberation Mono', 'Consolas', 'Ubuntu Mono',
'Courier New', 'andale mono', 'lucida console', monospace;
-$regular-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell,
+$regular-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, Cantarell,
'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
@@ -498,6 +498,17 @@ $pagination-line-height: 20px;
$pagination-disabled-color: #cdcdcd;
/*
+* Toasts
+*/
+$toast-offset: 24px;
+$toast-height: 48px;
+$toast-max-width: 586px;
+$toast-padding-right: 42px;
+$toast-default-margin: 8px;
+$toast-action-margin-left: 16px;
+$toast-background-opacity: 0.95;
+
+/*
* Status icons
*/
$status-icon-size: 22px;
diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss
index 47ffdbae4b6..f8e273a2735 100644
--- a/app/assets/stylesheets/pages/members.scss
+++ b/app/assets/stylesheets/pages/members.scss
@@ -14,7 +14,7 @@
}
.member {
- &.is-overriden {
+ &.is-overridden {
.btn-ldap-override {
display: none !important;
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 709940ba6c8..44b558dd5ff 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -972,10 +972,6 @@
}
}
- .btn svg {
- fill: $gray-700;
- }
-
.dropdown-menu {
width: 400px;
}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 12a3b8c88f3..aa6bbc8e473 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -903,7 +903,7 @@ button.mini-pipeline-graph-dropdown-toggle {
// Match dropdown.scss for all `a` tags
&.non-details-job-component {
- padding: 8px 16px;
+ padding: $gl-padding-8 $gl-btn-horz-padding;
}
.ci-job-name-component {
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 5a4adea497b..c342e1c80b0 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -221,7 +221,6 @@ class Projects::EnvironmentsController < Projects::ApplicationController
def metrics_params
return unless Feature.enabled?(:metrics_time_window, project)
- return unless params[:start].present? || params[:end].present?
params.require([:start, :end])
end
diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb
index 1c3c24ad6dc..f7e49166ca0 100644
--- a/app/graphql/resolvers/issues_resolver.rb
+++ b/app/graphql/resolvers/issues_resolver.rb
@@ -46,7 +46,7 @@ module Resolvers
def resolve(**args)
# The project could have been loaded in batch by `BatchLoader`.
# At this point we need the `id` of the project to query for issues, so
- # make sure it's loaded and not `nil` before continueing.
+ # make sure it's loaded and not `nil` before continuing.
project.sync if project.respond_to?(:sync)
return Issue.none if project.nil?
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index d2f5ff13408..1b67a7272bc 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -140,6 +140,8 @@ module Ci
where("EXISTS (?)", matcher)
end
+ scope :queued_before, ->(time) { where(arel_table[:queued_at].lt(time)) }
+
##
# TODO: Remove these mounters when we remove :ci_enable_legacy_artifacts feature flag
mount_uploader :legacy_artifacts_file, LegacyArtifactUploader, mount_on: :artifacts_file
@@ -378,8 +380,6 @@ module Ci
end
def any_unmet_prerequisites?
- return false unless Feature.enabled?(:ci_preparing_state, default_enabled: true)
-
prerequisites.present?
end
diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb
index 987c057ad6d..36c51522089 100644
--- a/app/models/clusters/applications/jupyter.rb
+++ b/app/models/clusters/applications/jupyter.rb
@@ -39,7 +39,7 @@ module Clusters
end
# Will be addressed in future MRs
- # We need to investigate and document what will be permenantly deleted.
+ # We need to investigate and document what will be permanently deleted.
def allowed_to_uninstall?
false
end
diff --git a/app/models/clusters/concerns/application_data.rb b/app/models/clusters/concerns/application_data.rb
index a48ee340fac..3479fea415e 100644
--- a/app/models/clusters/concerns/application_data.rb
+++ b/app/models/clusters/concerns/application_data.rb
@@ -3,56 +3,52 @@
module Clusters
module Concerns
module ApplicationData
- extend ActiveSupport::Concern
-
- included do
- def uninstall_command
- Gitlab::Kubernetes::Helm::DeleteCommand.new(
- name: name,
- rbac: cluster.platform_kubernetes_rbac?,
- files: files
- )
- end
+ def uninstall_command
+ Gitlab::Kubernetes::Helm::DeleteCommand.new(
+ name: name,
+ rbac: cluster.platform_kubernetes_rbac?,
+ files: files
+ )
+ end
- def repository
- nil
- end
+ def repository
+ nil
+ end
- def values
- File.read(chart_values_file)
- end
+ def values
+ File.read(chart_values_file)
+ end
- def files
- @files ||= begin
- files = { 'values.yaml': values }
+ def files
+ @files ||= begin
+ files = { 'values.yaml': values }
- files.merge!(certificate_files) if cluster.application_helm.has_ssl?
+ files.merge!(certificate_files) if cluster.application_helm.has_ssl?
- files
- end
+ files
end
+ end
- private
+ private
- def certificate_files
- {
- 'ca.pem': ca_cert,
- 'cert.pem': helm_cert.cert_string,
- 'key.pem': helm_cert.key_string
- }
- end
+ def certificate_files
+ {
+ 'ca.pem': ca_cert,
+ 'cert.pem': helm_cert.cert_string,
+ 'key.pem': helm_cert.key_string
+ }
+ end
- def ca_cert
- cluster.application_helm.ca_cert
- end
+ def ca_cert
+ cluster.application_helm.ca_cert
+ end
- def helm_cert
- @helm_cert ||= cluster.application_helm.issue_client_cert
- end
+ def helm_cert
+ @helm_cert ||= cluster.application_helm.issue_client_cert
+ end
- def chart_values_file
- "#{Rails.root}/vendor/#{name}/values.yaml"
- end
+ def chart_values_file
+ "#{Rails.root}/vendor/#{name}/values.yaml"
end
end
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 0eda7a2513f..aff20dae09b 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -155,11 +155,11 @@ class Environment < ApplicationRecord
end
def has_terminals?
- project.deployment_platform.present? && available? && last_deployment.present?
+ deployment_platform.present? && available? && last_deployment.present?
end
def terminals
- project.deployment_platform.terminals(self) if has_terminals?
+ deployment_platform.terminals(self) if has_terminals?
end
def has_metrics?
diff --git a/app/serializers/test_case_entity.rb b/app/serializers/test_case_entity.rb
index ec60055ba5b..5c915c1302c 100644
--- a/app/serializers/test_case_entity.rb
+++ b/app/serializers/test_case_entity.rb
@@ -3,6 +3,7 @@
class TestCaseEntity < Grape::Entity
expose :status
expose :name
+ expose :classname
expose :execution_time
expose :system_output
expose :stack_trace
diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb
index 6707a1363d0..baa3f898b2d 100644
--- a/app/services/ci/register_job_service.rb
+++ b/app/services/ci/register_job_service.rb
@@ -36,6 +36,11 @@ module Ci
builds = builds.with_any_tags
end
+ # pick builds that older than specified age
+ if params.key?(:job_age)
+ builds = builds.queued_before(params[:job_age].seconds.ago)
+ end
+
builds.each do |build|
next unless runner.can_pick?(build)
diff --git a/app/services/clusters/refresh_service.rb b/app/services/clusters/refresh_service.rb
index b02bb9c0247..3752a306793 100644
--- a/app/services/clusters/refresh_service.rb
+++ b/app/services/clusters/refresh_service.rb
@@ -21,11 +21,7 @@ module Clusters
private_class_method :projects_with_missing_kubernetes_namespaces_for_cluster
def self.clusters_with_missing_kubernetes_namespaces_for_project(project)
- if Feature.enabled?(:ci_preparing_state, default_enabled: true)
- project.clusters.managed.missing_kubernetes_namespace(project.kubernetes_namespaces)
- else
- project.all_clusters.managed.missing_kubernetes_namespace(project.kubernetes_namespaces)
- end
+ project.clusters.managed.missing_kubernetes_namespace(project.kubernetes_namespaces)
end
private_class_method :clusters_with_missing_kubernetes_namespaces_for_project
diff --git a/app/services/git/base_hooks_service.rb b/app/services/git/base_hooks_service.rb
index 9d371e234ee..d30df34e54b 100644
--- a/app/services/git/base_hooks_service.rb
+++ b/app/services/git/base_hooks_service.rb
@@ -17,6 +17,8 @@ module Git
# Not a hook, but it needs access to the list of changed commits
enqueue_invalidate_cache
+ update_remote_mirrors
+
push_data
end
@@ -92,5 +94,12 @@ module Git
def pipeline_options
{}
end
+
+ def update_remote_mirrors
+ return unless project.has_remote_mirror?
+
+ project.mark_stuck_remote_mirrors_as_failed!
+ project.update_remote_mirrors
+ end
end
end
diff --git a/app/services/git/branch_push_service.rb b/app/services/git/branch_push_service.rb
index abf11f253f6..c4910180787 100644
--- a/app/services/git/branch_push_service.rb
+++ b/app/services/git/branch_push_service.rb
@@ -27,7 +27,6 @@ module Git
execute_related_hooks
perform_housekeeping
- update_remote_mirrors
stop_environments
true
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 4ea40e3c8ce..9f335cceb67 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -100,8 +100,6 @@ module Projects
current_user.invalidate_personal_projects_count
create_readme if @initialize_with_readme
-
- configure_group_clusters_for_project
end
# Refresh the current user's authorizations inline (so they can access the
@@ -127,10 +125,6 @@ module Projects
Files::CreateService.new(@project, current_user, commit_attrs).execute
end
- def configure_group_clusters_for_project
- ClusterProjectConfigureWorker.perform_async(@project.id)
- end
-
def skip_wiki?
!@project.feature_available?(:wiki, current_user) || @skip_wiki
end
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 91c01eca75c..233dcf37e35 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -54,7 +54,6 @@ module Projects
end
attempt_transfer_transaction
- configure_group_clusters_for_project
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -164,9 +163,5 @@ module Projects
@new_namespace.full_path
)
end
-
- def configure_group_clusters_for_project
- ClusterProjectConfigureWorker.perform_async(project.id)
- end
end
end
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index 6dfe2bed0ba..1c7582533ad 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -109,12 +109,20 @@ class FileUploader < GitlabUploader
def upload_path
if file_storage?
# Legacy path relative to project.full_path
- File.join(dynamic_segment, identifier)
+ local_storage_path(identifier)
else
- File.join(store_dir, identifier)
+ remote_storage_path(identifier)
end
end
+ def local_storage_path(file_identifier)
+ File.join(dynamic_segment, file_identifier)
+ end
+
+ def remote_storage_path(file_identifier)
+ File.join(store_dir, file_identifier)
+ end
+
def store_dirs
{
Store::LOCAL => File.join(base_dir, dynamic_segment),
diff --git a/app/uploaders/personal_file_uploader.rb b/app/uploaders/personal_file_uploader.rb
index f4697d898af..b43162f0935 100644
--- a/app/uploaders/personal_file_uploader.rb
+++ b/app/uploaders/personal_file_uploader.rb
@@ -6,15 +6,12 @@ class PersonalFileUploader < FileUploader
options.storage_path
end
- def self.base_dir(model, store = nil)
- base_dirs(model)[store || Store::LOCAL]
- end
-
- def self.base_dirs(model)
- {
- Store::LOCAL => File.join(options.base_dir, model_path_segment(model)),
- Store::REMOTE => model_path_segment(model)
- }
+ def self.base_dir(model, _store = nil)
+ # base_dir is the path seen by the user when rendering Markdown, so
+ # it should be the same for both local and object storage. It is
+ # typically prefaced with uploads/-/system, but that prefix
+ # is omitted in the path stored on disk.
+ File.join(options.base_dir, model_path_segment(model))
end
def self.model_path_segment(model)
@@ -40,8 +37,61 @@ class PersonalFileUploader < FileUploader
store_dirs[object_store]
end
+ # A personal snippet path is stored using FileUploader#upload_path.
+ #
+ # The format for the path:
+ #
+ # Local storage: :random_hex/:filename.
+ # Object storage: personal_snippet/:id/:random_hex/:filename.
+ #
+ # upload_paths represent the possible paths for a given identifier,
+ # which will vary depending on whether the file is stored in local or
+ # object storage. upload_path should match an element in upload_paths.
+ #
+ # base_dir represents the path seen by the user in Markdown, and it
+ # should always be prefixed with uploads/-/system.
+ #
+ # store_dirs represent the paths that are actually used on disk. For
+ # object storage, this should omit the prefix /uploads/-/system.
+ #
+ # For example, consider the requested path /uploads/-/system/personal_snippet/172/ff4ad5c2e40b39ae57cda51577317d20/file.png.
+ #
+ # For local storage:
+ #
+ # File on disk: /opt/gitlab/embedded/service/gitlab-rails/public/uploads/-/system/personal_snippet/172/ff4ad5c2e40b39ae57cda51577317d20/file.png.
+ #
+ # base_dir: uploads/-/system/personal_snippet/172
+ # upload_path: ff4ad5c2e40b39ae57cda51577317d20/file.png
+ # upload_paths: ["ff4ad5c2e40b39ae57cda51577317d20/file.png", "personal_snippet/172/ff4ad5c2e40b39ae57cda51577317d20/file.png"].
+ # store_dirs:
+ # => {1=>"uploads/-/system/personal_snippet/172/ff4ad5c2e40b39ae57cda51577317d20", 2=>"personal_snippet/172/ff4ad5c2e40b39ae57cda51577317d20"}
+ #
+ # For object storage:
+ #
+ # upload_path: personal_snippet/172/ff4ad5c2e40b39ae57cda51577317d20/file.png
+ def upload_paths(identifier)
+ [
+ local_storage_path(identifier),
+ File.join(remote_storage_base_path, identifier)
+ ]
+ end
+
+ def store_dirs
+ {
+ Store::LOCAL => File.join(base_dir, dynamic_segment),
+ Store::REMOTE => remote_storage_base_path
+ }
+ end
+
private
+ # To avoid prefacing the remote storage path with `/uploads/-/system`,
+ # we just drop that part so that the destination path will be
+ # personal_snippet/:id/:random_hex/:filename.
+ def remote_storage_base_path
+ File.join(self.class.model_path_segment(model), dynamic_segment)
+ end
+
def secure_url
File.join('/', base_dir, secret, file.filename)
end
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index 8fb38f6a690..62d1d01cc83 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -2,7 +2,7 @@
= form_errors(@group)
= render 'shared/group_form', f: f
- = render_if_exists 'shared/repository_size_limit_setting', form: f, type: :group
+ = render_if_exists 'shared/old_repository_size_limit_setting', form: f, type: :group
= render_if_exists 'admin/namespace_plan', f: f
.form-group.row.group-description-holder
diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml
index a733f420d11..e7dde7985fd 100644
--- a/app/views/admin/users/_head.html.haml
+++ b/app/views/admin/users/_head.html.haml
@@ -6,6 +6,7 @@
%span.cred (Internal)
- if @user.admin
%span.cred (Admin)
+ = render_if_exists 'admin/users/audtior_user_badge'
.float-right
- if impersonation_enabled? && @user != current_user && @user.can?(:log_in)
diff --git a/app/views/groups/settings/_general.html.haml b/app/views/groups/settings/_general.html.haml
index c382a1ed168..e12748666c8 100644
--- a/app/views/groups/settings/_general.html.haml
+++ b/app/views/groups/settings/_general.html.haml
@@ -17,17 +17,17 @@
= f.label :description, _('Group description (optional)'), class: 'label-bold'
= f.text_area :description, class: 'form-control', rows: 3, maxlength: 250
- = render_if_exists 'shared/repository_size_limit_setting', form: f, type: :group
+ = render_if_exists 'shared/repository_size_limit_setting', form: f, type: :group
- .form-group.prepend-top-default.append-bottom-20
- .avatar-container.rect-avatar.s90
- = group_icon(@group, alt: '', class: 'avatar group-avatar s90')
- = f.label :avatar, _('Group avatar'), class: 'label-bold d-block'
- = render 'shared/choose_avatar_button', f: f
- - if @group.avatar?
- %hr
- = link_to _('Remove avatar'), group_avatar_path(@group.to_param), data: { confirm: _('Avatar will be removed. Are you sure?')}, method: :delete, class: 'btn btn-link'
+ .form-group.prepend-top-default.append-bottom-20
+ .avatar-container.rect-avatar.s90
+ = group_icon(@group, alt: '', class: 'avatar group-avatar s90')
+ = f.label :avatar, _('Group avatar'), class: 'label-bold d-block'
+ = render 'shared/choose_avatar_button', f: f
+ - if @group.avatar?
+ %hr
+ = link_to _('Remove avatar'), group_avatar_path(@group.to_param), data: { confirm: _('Avatar will be removed. Are you sure?')}, method: :delete, class: 'btn btn-link'
- = render 'shared/visibility_level', f: f, visibility_level: @group.visibility_level, can_change_visibility_level: can_change_group_visibility_level?(@group), form_model: @group
+ = render 'shared/visibility_level', f: f, visibility_level: @group.visibility_level, can_change_visibility_level: can_change_group_visibility_level?(@group), form_model: @group
= f.submit _('Save changes'), class: 'btn btn-success mt-4 js-dirty-submit'
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 1c1d1ea4645..f8b7d0c530a 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -18,7 +18,7 @@
%span.logo-text.d-none.d-lg-block.prepend-left-8
= logo_text
- if Gitlab.com?
- = link_to 'https://next.gitlab.com', class: 'label-link js-canary-badge canary-badge bg-transparent', target: :_blank do
+ = link_to 'https://next.gitlab.com', class: 'label-link js-canary-badge canary-badge bg-transparent hidden', target: :_blank do
%span.color-label.has-tooltip.badge.badge-pill.green-badge
= _('Next')
diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml
index 22a721ee9ad..0edd8ee5e46 100644
--- a/app/views/projects/_files.html.haml
+++ b/app/views/projects/_files.html.haml
@@ -4,6 +4,7 @@
- project = local_assigns.fetch(:project) { @project }
- content_url = local_assigns.fetch(:content_url) { @tree.readme ? project_blob_path(@project, tree_join(@ref, @tree.readme.path)) : project_tree_path(@project, @ref) }
- show_auto_devops_callout = show_auto_devops_callout?(@project)
+- vue_file_list = Feature.enabled?(:vue_file_list, @project)
#tree-holder.tree-holder.clearfix
.nav-block
@@ -13,7 +14,12 @@
= render 'shared/commit_well', commit: commit, ref: ref, project: project
- if is_project_overview
- .project-buttons.append-bottom-default
+ .project-buttons.append-bottom-default{ class: ("js-hide-on-navigation" if vue_file_list) }
= render 'stat_anchor_list', anchors: @project.statistics_buttons(show_auto_devops_callout: show_auto_devops_callout)
- = render 'projects/tree/tree_content', tree: @tree, content_url: content_url
+ - if vue_file_list
+ #js-tree-list{ data: { project_path: @project.full_path, ref: ref } }
+ - if @tree.readme
+ = render "projects/tree/readme", readme: @tree.readme
+ - else
+ = render 'projects/tree/tree_content', tree: @tree, content_url: content_url
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 3ca4abddbb8..a97322dace4 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -1,7 +1,7 @@
- empty_repo = @project.empty_repo?
- show_auto_devops_callout = show_auto_devops_callout?(@project)
- max_project_topic_length = 15
-.project-home-panel{ class: ("empty-project" if empty_repo) }
+.project-home-panel{ class: [("empty-project" if empty_repo), ("js-hide-on-navigation" if Feature.enabled?(:vue_file_list, @project))] }
.row.append-bottom-8
.home-panel-title-row.col-md-12.col-lg-6.d-flex
.avatar-container.rect-avatar.s64.home-panel-avatar.append-right-default.float-none
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 9d254463fb6..2db1efdd52f 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -30,6 +30,8 @@
= link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
= icon("rss")
+ = render_if_exists 'projects/commits/mirror_status'
+
%div{ id: dom_id(@project) }
%ol#commits-list.list-unstyled.content_list
= render 'commits', project: @project, ref: @ref
diff --git a/app/views/projects/protected_branches/_protected_branch.html.haml b/app/views/projects/protected_branches/_protected_branch.html.haml
index b12ae995ece..366d7a7a2eb 100644
--- a/app/views/projects/protected_branches/_protected_branch.html.haml
+++ b/app/views/projects/protected_branches/_protected_branch.html.haml
@@ -1,2 +1,2 @@
= render layout: 'projects/protected_branches/shared/protected_branch', locals: { protected_branch: protected_branch } do
- = render partial: 'projects/protected_branches/update_protected_branch', locals: { protected_branch: protected_branch }
+ = render_if_exists 'projects/protected_branches/update_protected_branch', protected_branch: protected_branch
diff --git a/app/views/projects/settings/_general.html.haml b/app/views/projects/settings/_general.html.haml
index 380430ff52b..520f342f567 100644
--- a/app/views/projects/settings/_general.html.haml
+++ b/app/views/projects/settings/_general.html.haml
@@ -27,7 +27,7 @@
.row= render_if_exists 'projects/classification_policy_settings', f: f
- .row= render_if_exists 'shared/repository_size_limit_setting', form: f, type: :project
+ = render_if_exists 'shared/repository_size_limit_setting', form: f, type: :project
.form-group.prepend-top-default.append-bottom-20
.avatar-container.s90
diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml
index 4daacbe157c..e935af23659 100644
--- a/app/views/projects/tree/_readme.html.haml
+++ b/app/views/projects/tree/_readme.html.haml
@@ -1,5 +1,5 @@
- if readme.rich_viewer
- %article.file-holder.readme-holder{ id: 'readme', class: ("limited-width-container" unless fluid_layout) }
+ %article.file-holder.readme-holder{ id: 'readme', class: [("limited-width-container" unless fluid_layout), ("js-hide-on-navigation" if Feature.enabled?(:vue_file_list, @project))] }
.js-file-title.file-title
= blob_icon readme.mode, readme.name
= link_to project_blob_path(@project, tree_join(@ref, readme.path)) do
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 2c185549b24..63557c882f4 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -164,7 +164,7 @@
= dropdown_content
= dropdown_loading
= dropdown_footer add_content_class: true do
- %button.btn.btn-success.sidebar-move-issue-confirmation-button.js-move-issue-confirmation-button{ disabled: true }
+ %button.btn.btn-success.sidebar-move-issue-confirmation-button.js-move-issue-confirmation-button{ type: 'button', disabled: true }
= _('Move')
= icon('spinner spin', class: 'sidebar-move-issue-confirmation-loading-icon')
diff --git a/app/workers/cluster_configure_worker.rb b/app/workers/cluster_configure_worker.rb
index 37ea7dde7a1..6f64b7ea0ab 100644
--- a/app/workers/cluster_configure_worker.rb
+++ b/app/workers/cluster_configure_worker.rb
@@ -6,7 +6,7 @@ class ClusterConfigureWorker
def perform(cluster_id)
Clusters::Cluster.managed.find_by_id(cluster_id).try do |cluster|
- if cluster.project_type? || Feature.disabled?(:ci_preparing_state, default_enabled: true)
+ if cluster.project_type?
Clusters::RefreshService.create_or_update_namespaces_for_cluster(cluster)
end
end
diff --git a/app/workers/pages_domain_removal_cron_worker.rb b/app/workers/pages_domain_removal_cron_worker.rb
index 3aca123e5ac..79f38e1b89f 100644
--- a/app/workers/pages_domain_removal_cron_worker.rb
+++ b/app/workers/pages_domain_removal_cron_worker.rb
@@ -5,8 +5,6 @@ class PagesDomainRemovalCronWorker
include CronjobQueue
def perform
- return unless Feature.enabled?(:remove_disabled_domains)
-
PagesDomain.for_removal.find_each do |domain|
domain.destroy!
rescue => e