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/gfm_auto_complete.js4
-rw-r--r--app/assets/javascripts/behaviors/secret_values.js8
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js3
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js8
-rw-r--r--app/assets/javascripts/boards/index.js4
-rw-r--r--app/assets/javascripts/boards/stores/boards_store.js4
-rw-r--r--app/assets/javascripts/build_artifacts.js4
-rw-r--r--app/assets/javascripts/ci_variable_list/ajax_variable_list.js4
-rw-r--r--app/assets/javascripts/ci_variable_list/ci_variable_list.js4
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue57
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js3
-rw-r--r--app/assets/javascripts/contextual_sidebar.js3
-rw-r--r--app/assets/javascripts/diffs/components/tree_list.vue5
-rw-r--r--app/assets/javascripts/diffs/store/modules/diff_state.js3
-rw-r--r--app/assets/javascripts/environments/folder/environments_folder_bundle.js6
-rw-r--r--app/assets/javascripts/environments/index.js8
-rw-r--r--app/assets/javascripts/groups/index.js3
-rw-r--r--app/assets/javascripts/header.js3
-rw-r--r--app/assets/javascripts/ide/index.js4
-rw-r--r--app/assets/javascripts/importer_status.js4
-rw-r--r--app/assets/javascripts/landing.js3
-rw-r--r--app/assets/javascripts/lazy_loader.js4
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js18
-rw-r--r--app/assets/javascripts/merge_request_tabs.js9
-rw-r--r--app/assets/javascripts/monitoring/components/empty_state.vue48
-rw-r--r--app/assets/javascripts/monitoring/monitoring_bundle.js4
-rw-r--r--app/assets/javascripts/namespace_select.js3
-rw-r--r--app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js3
-rw-r--r--app/assets/javascripts/pages/profiles/two_factor_auths/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue3
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/index/index.js6
-rw-r--r--app/assets/javascripts/performance_bar/services/performance_bar_service.js4
-rw-r--r--app/assets/javascripts/profile/profile.js3
-rw-r--r--app/assets/javascripts/toggle_buttons.js6
-rw-r--r--app/assets/javascripts/usage_ping_consent.js6
-rw-r--r--app/assets/stylesheets/pages/environments.scss15
-rw-r--r--app/helpers/tree_helper.rb4
-rw-r--r--app/models/clusters/applications/ingress.rb4
-rw-r--r--app/models/clusters/applications/knative.rb32
-rw-r--r--app/models/merge_request_diff.rb3
-rw-r--r--app/models/project.rb5
-rw-r--r--app/models/repository.rb2
-rw-r--r--app/models/site_statistic.rb76
-rw-r--r--app/models/user.rb2
-rw-r--r--app/services/clusters/applications/check_ingress_ip_address_service.rb2
-rw-r--r--app/views/layouts/header/_new_dropdown.haml26
-rw-r--r--app/views/projects/branches/new.html.haml2
-rw-r--r--app/workers/all_queues.yml2
48 files changed, 226 insertions, 214 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
index a303e504cc7..55c68139ded 100644
--- a/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
+++ b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
@@ -1,11 +1,11 @@
import $ from 'jquery';
-import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
+import { parseBoolean } from '~/lib/utils/common_utils';
import GfmAutoComplete from '~/gfm_auto_complete';
export default function initGFMInput() {
$('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
- const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
+ const enableGFM = parseBoolean(el.dataset.supportsAutocomplete);
gfm.setup($(el), {
emojis: true,
diff --git a/app/assets/javascripts/behaviors/secret_values.js b/app/assets/javascripts/behaviors/secret_values.js
index f6bf62d734e..5b92608d536 100644
--- a/app/assets/javascripts/behaviors/secret_values.js
+++ b/app/assets/javascripts/behaviors/secret_values.js
@@ -1,5 +1,5 @@
import { n__ } from '../locale';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
export default class SecretValues {
constructor({
@@ -16,7 +16,7 @@ export default class SecretValues {
this.revealButton = this.container.querySelector('.js-secret-value-reveal-button');
if (this.revealButton) {
- const isRevealed = convertPermissionToBoolean(this.revealButton.dataset.secretRevealStatus);
+ const isRevealed = parseBoolean(this.revealButton.dataset.secretRevealStatus);
this.updateDom(isRevealed);
this.revealButton.addEventListener('click', this.onRevealButtonClicked.bind(this));
@@ -24,9 +24,7 @@ export default class SecretValues {
}
onRevealButtonClicked() {
- const previousIsRevealed = convertPermissionToBoolean(
- this.revealButton.dataset.secretRevealStatus,
- );
+ const previousIsRevealed = parseBoolean(this.revealButton.dataset.secretRevealStatus);
this.updateDom(!previousIsRevealed);
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index 8b5a3c1c69d..eade1283513 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -4,6 +4,7 @@ import Mousetrap from 'mousetrap';
import axios from '../../lib/utils/axios_utils';
import { refreshCurrentPage, visitUrl } from '../../lib/utils/url_utility';
import findAndFollowLink from '../../lib/utils/navigation_utility';
+import { parseBoolean } from '~/lib/utils/common_utils';
const defaultStopCallback = Mousetrap.stopCallback;
Mousetrap.stopCallback = (e, element, combo) => {
@@ -61,7 +62,7 @@ export default class Shortcuts {
static onTogglePerfBar(e) {
e.preventDefault();
const performanceBarCookieName = 'perf_bar_enabled';
- if (Cookies.get(performanceBarCookieName) === 'true') {
+ if (parseBoolean(Cookies.get(performanceBarCookieName))) {
Cookies.set(performanceBarCookieName, 'false', { path: '/' });
} else {
Cookies.set(performanceBarCookieName, 'true', { path: '/' });
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index ec27ae8c291..9f547471170 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -16,9 +16,17 @@ export default () => {
const filePath = editBlobForm.data('blobFilename');
const currentAction = $('.js-file-title').data('currentAction');
const projectId = editBlobForm.data('project-id');
+ const commitButton = $('.js-commit-button');
+
+ commitButton.on('click', () => {
+ window.onbeforeunload = null;
+ });
new EditBlob(`${urlRoot}${assetsPath}`, filePath, currentAction, projectId);
new NewCommitForm(editBlobForm);
+
+ // returning here blocks page navigation
+ window.onbeforeunload = () => '';
}
if (uploadBlobForm.length) {
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index 61a3072ac27..f88e9b55988 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -24,7 +24,7 @@ import BoardSidebar from './components/board_sidebar';
import initNewListDropdown from './components/new_list_dropdown';
import BoardAddIssuesModal from './components/modal/index.vue';
import '~/vue_shared/vue_resource_interceptor';
-import { NavigationType } from '~/lib/utils/common_utils';
+import { NavigationType, parseBoolean } from '~/lib/utils/common_utils';
let issueBoardsApp;
@@ -60,7 +60,7 @@ export default () => {
boardsEndpoint: $boardApp.dataset.boardsEndpoint,
listsEndpoint: $boardApp.dataset.listsEndpoint,
boardId: $boardApp.dataset.boardId,
- disabled: $boardApp.dataset.disabled === 'true',
+ disabled: parseBoolean($boardApp.dataset.disabled),
issueLinkBase: $boardApp.dataset.issueLinkBase,
rootPath: $boardApp.dataset.rootPath,
bulkUpdatePath: $boardApp.dataset.bulkUpdatePath,
diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js
index eefe14a1d79..cf88a973d33 100644
--- a/app/assets/javascripts/boards/stores/boards_store.js
+++ b/app/assets/javascripts/boards/stores/boards_store.js
@@ -5,7 +5,7 @@ import $ from 'jquery';
import _ from 'underscore';
import Vue from 'vue';
import Cookies from 'js-cookie';
-import { getUrlParamsArray } from '~/lib/utils/common_utils';
+import { getUrlParamsArray, parseBoolean } from '~/lib/utils/common_utils';
const boardsStore = {
disabled: false,
@@ -78,7 +78,7 @@ const boardsStore = {
});
},
welcomeIsHidden() {
- return Cookies.get('issue_board_welcome_hidden') === 'true';
+ return parseBoolean(Cookies.get('issue_board_welcome_hidden'));
},
removeList(id, type = 'blank') {
const list = this.findList('id', id, type);
diff --git a/app/assets/javascripts/build_artifacts.js b/app/assets/javascripts/build_artifacts.js
index 97a1645aa51..b2c88e8c14e 100644
--- a/app/assets/javascripts/build_artifacts.js
+++ b/app/assets/javascripts/build_artifacts.js
@@ -2,7 +2,7 @@
import $ from 'jquery';
import { visitUrl } from './lib/utils/url_utility';
-import { convertPermissionToBoolean } from './lib/utils/common_utils';
+import { parseBoolean } from './lib/utils/common_utils';
export default class BuildArtifacts {
constructor() {
@@ -22,7 +22,7 @@ export default class BuildArtifacts {
// eslint-disable-next-line class-methods-use-this
setupEntryClick() {
return $('.tree-holder').on('click', 'tr[data-link]', function() {
- visitUrl(this.dataset.link, convertPermissionToBoolean(this.dataset.externalLink));
+ visitUrl(this.dataset.link, parseBoolean(this.dataset.externalLink));
});
}
// eslint-disable-next-line class-methods-use-this
diff --git a/app/assets/javascripts/ci_variable_list/ajax_variable_list.js b/app/assets/javascripts/ci_variable_list/ajax_variable_list.js
index dffabbfe1b8..592e1fd1c31 100644
--- a/app/assets/javascripts/ci_variable_list/ajax_variable_list.js
+++ b/app/assets/javascripts/ci_variable_list/ajax_variable_list.js
@@ -2,7 +2,7 @@ import _ from 'underscore';
import axios from '../lib/utils/axios_utils';
import { s__ } from '../locale';
import Flash from '../flash';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
import statusCodes from '../lib/utils/http_status';
import VariableList from './ci_variable_list';
@@ -101,7 +101,7 @@ export default class AjaxVariableList {
// If we submitted a row that was destroyed, remove it so we don't try
// to destroy it again which would cause a BE error
const destroyInput = row.querySelector('.js-ci-variable-input-destroy');
- if (convertPermissionToBoolean(destroyInput.value)) {
+ if (parseBoolean(destroyInput.value)) {
row.remove();
// Update the ID input so any future edits and `_destroy` will apply on the BE
} else {
diff --git a/app/assets/javascripts/ci_variable_list/ci_variable_list.js b/app/assets/javascripts/ci_variable_list/ci_variable_list.js
index 7bdc18ce03e..ee0f7cda189 100644
--- a/app/assets/javascripts/ci_variable_list/ci_variable_list.js
+++ b/app/assets/javascripts/ci_variable_list/ci_variable_list.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
import { s__ } from '../locale';
import setupToggleButtons from '../toggle_buttons';
import CreateItemDropdown from '../create_item_dropdown';
@@ -150,7 +150,7 @@ export default class VariableList {
removeRow(row) {
const $row = $(row);
- const isPersisted = convertPermissionToBoolean($row.attr('data-is-persisted'));
+ const isPersisted = parseBoolean($row.attr('data-is-persisted'));
if (isPersisted) {
$row.hide();
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index 8354c28778c..a37cb4def28 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -168,6 +168,9 @@ export default {
knativeInstalled() {
return this.applications.knative.status === APPLICATION_STATUS.INSTALLED;
},
+ knativeExternalIp() {
+ return this.applications.knative.externalIp;
+ },
},
created() {
this.helmInstallIllustration = helmInstallIllustration;
@@ -408,12 +411,11 @@ export default {
<div slot="description">
<p>
{{
- s__(`ClusterIntegration|A Knative build extends Kubernetes
- and utilizes existing Kubernetes primitives to provide you with
- the ability to run on-cluster container builds from source.
- For example, you can write a build that uses Kubernetes-native
- resources to obtain your source code from a repository,
- build it into container a image, and then run that image.`)
+ s__(`ClusterIntegration|Knative (pronounced kay-nay-tiv) extends
+ Kubernetes to provide a set of middleware components that are
+ essential to build modern, source-centric, and container-based
+ applications that can run anywhere: on premises, in the cloud, or
+ even in a third-party data center.`)
}}
</p>
@@ -444,6 +446,49 @@ export default {
/>
</div>
</template>
+ <template v-if="knativeInstalled">
+ <div class="form-group">
+ <label for="knative-ip-address">
+ {{ s__('ClusterIntegration|Knative IP Address:') }}
+ </label>
+ <div v-if="knativeExternalIp" class="input-group">
+ <input
+ id="knative-ip-address"
+ :value="knativeExternalIp"
+ type="text"
+ class="form-control js-ip-address"
+ readonly
+ />
+ <span class="input-group-append">
+ <clipboard-button
+ :text="knativeExternalIp"
+ :title="s__('ClusterIntegration|Copy Knative IP Address to clipboard')"
+ class="input-group-text js-clipboard-btn"
+ />
+ </span>
+ </div>
+ <input v-else type="text" class="form-control js-ip-address" readonly value="?" />
+ </div>
+
+ <p v-if="!knativeExternalIp" class="settings-message js-no-ip-message">
+ {{
+ s__(`ClusterIntegration|The IP address is in
+ the process of being assigned. Please check your Kubernetes
+ cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
+ }}
+ </p>
+
+ <p>
+ {{
+ s__(`ClusterIntegration|Point a wildcard DNS to this
+ generated IP address in order to access
+ your application after it has been deployed.`)
+ }}
+ <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
+ {{ __('More information') }}
+ </a>
+ </p>
+ </template>
</div>
</application-row>
</div>
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index 3678be59d24..2d69da8eaec 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -60,6 +60,7 @@ export default class ClusterStore {
requestStatus: null,
requestReason: null,
hostname: null,
+ externalIp: null,
},
},
};
@@ -111,6 +112,8 @@ export default class ClusterStore {
} else if (appId === KNATIVE) {
this.state.applications.knative.hostname =
serverAppEntry.hostname || this.state.applications.knative.hostname;
+ this.state.applications.knative.externalIp =
+ serverAppEntry.external_ip || this.state.applications.knative.externalIp;
}
});
}
diff --git a/app/assets/javascripts/contextual_sidebar.js b/app/assets/javascripts/contextual_sidebar.js
index dff0adba25a..10f02739ec8 100644
--- a/app/assets/javascripts/contextual_sidebar.js
+++ b/app/assets/javascripts/contextual_sidebar.js
@@ -2,6 +2,7 @@ import $ from 'jquery';
import Cookies from 'js-cookie';
import _ from 'underscore';
import bp from './breakpoints';
+import { parseBoolean } from '~/lib/utils/common_utils';
export default class ContextualSidebar {
constructor() {
@@ -78,7 +79,7 @@ export default class ContextualSidebar {
if (breakpoint === 'sm' || breakpoint === 'md') {
this.toggleCollapsedSidebar(true);
} else if (breakpoint === 'lg') {
- const collapse = Cookies.get('sidebar_collapsed') === 'true';
+ const collapse = parseBoolean(Cookies.get('sidebar_collapsed'));
this.toggleCollapsedSidebar(collapse);
}
}
diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue
index ec4a4aa1d6d..f40a7b25fde 100644
--- a/app/assets/javascripts/diffs/components/tree_list.vue
+++ b/app/assets/javascripts/diffs/components/tree_list.vue
@@ -1,7 +1,7 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlTooltipDirective } from '@gitlab/ui';
-import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
+import { parseBoolean } from '~/lib/utils/common_utils';
import Icon from '~/vue_shared/components/icon.vue';
import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowStats from './file_row_stats.vue';
@@ -18,8 +18,7 @@ export default {
},
data() {
const treeListStored = localStorage.getItem(treeListStorageKey);
- const renderTreeList =
- treeListStored !== null ? convertPermissionToBoolean(treeListStored) : true;
+ const renderTreeList = treeListStored !== null ? parseBoolean(treeListStored) : true;
return {
search: '',
diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js
index 085e255f1d3..2f59a3822f4 100644
--- a/app/assets/javascripts/diffs/store/modules/diff_state.js
+++ b/app/assets/javascripts/diffs/store/modules/diff_state.js
@@ -1,6 +1,7 @@
import Cookies from 'js-cookie';
import { getParameterValues } from '~/lib/utils/url_utility';
import bp from '~/breakpoints';
+import { parseBoolean } from '~/lib/utils/common_utils';
import { INLINE_DIFF_VIEW_TYPE, DIFF_VIEW_COOKIE_NAME, MR_TREE_SHOW_KEY } from '../../constants';
const viewTypeFromQueryString = getParameterValues('view')[0];
@@ -22,7 +23,7 @@ export default () => ({
tree: [],
treeEntries: {},
showTreeList:
- storedTreeShow === null ? bp.getBreakpointSize() !== 'xs' : storedTreeShow === 'true',
+ storedTreeShow === null ? bp.getBreakpointSize() !== 'xs' : parseBoolean(storedTreeShow),
currentDiffFileId: '',
projectPath: '',
commentForms: [],
diff --git a/app/assets/javascripts/environments/folder/environments_folder_bundle.js b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
index f044d31c776..3cf6e4ad14d 100644
--- a/app/assets/javascripts/environments/folder/environments_folder_bundle.js
+++ b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import environmentsFolderApp from './environments_folder_view.vue';
-import { convertPermissionToBoolean } from '../../lib/utils/common_utils';
+import { parseBoolean } from '../../lib/utils/common_utils';
import Translate from '../../vue_shared/translate';
Vue.use(Translate);
@@ -18,8 +18,8 @@ export default () =>
endpoint: environmentsData.endpoint,
folderName: environmentsData.folderName,
cssContainerClass: environmentsData.cssClass,
- canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
- canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
+ canCreateDeployment: parseBoolean(environmentsData.canCreateDeployment),
+ canReadEnvironment: parseBoolean(environmentsData.canReadEnvironment),
};
},
render(createElement) {
diff --git a/app/assets/javascripts/environments/index.js b/app/assets/javascripts/environments/index.js
index 5b6833fb15d..d366e7550b7 100644
--- a/app/assets/javascripts/environments/index.js
+++ b/app/assets/javascripts/environments/index.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import environmentsComponent from './components/environments_app.vue';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
import Translate from '../vue_shared/translate';
Vue.use(Translate);
@@ -19,9 +19,9 @@ export default () =>
newEnvironmentPath: environmentsData.newEnvironmentPath,
helpPagePath: environmentsData.helpPagePath,
cssContainerClass: environmentsData.cssClass,
- canCreateEnvironment: convertPermissionToBoolean(environmentsData.canCreateEnvironment),
- canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
- canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
+ canCreateEnvironment: parseBoolean(environmentsData.canCreateEnvironment),
+ canCreateDeployment: parseBoolean(environmentsData.canCreateDeployment),
+ canReadEnvironment: parseBoolean(environmentsData.canReadEnvironment),
};
},
render(createElement) {
diff --git a/app/assets/javascripts/groups/index.js b/app/assets/javascripts/groups/index.js
index 0f68f05b523..928f1fe409f 100644
--- a/app/assets/javascripts/groups/index.js
+++ b/app/assets/javascripts/groups/index.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
import Translate from '../vue_shared/translate';
import GroupFilterableList from './groups_filterable_list';
import GroupsStore from './store/groups_store';
@@ -38,7 +39,7 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
},
data() {
const { dataset } = dataEl || this.$options.el;
- const hideProjects = dataset.hideProjects === 'true';
+ const hideProjects = parseBoolean(dataset.hideProjects);
const service = new GroupsService(endpoint || dataset.endpoint);
const store = new GroupsStore(hideProjects);
diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js
index 175d0b8498b..2fa7a219ea8 100644
--- a/app/assets/javascripts/header.js
+++ b/app/assets/javascripts/header.js
@@ -4,6 +4,7 @@ import Translate from '~/vue_shared/translate';
import { highCountTrim } from '~/lib/utils/text_utility';
import SetStatusModalTrigger from './set_status_modal/set_status_modal_trigger.vue';
import SetStatusModalWrapper from './set_status_modal/set_status_modal_wrapper.vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
/**
* Updates todo counter when todos are toggled.
@@ -36,7 +37,7 @@ document.addEventListener('DOMContentLoaded', () => {
const { hasStatus } = this.$options.el.dataset;
return {
- hasStatus: hasStatus === 'true',
+ hasStatus: parseBoolean(hasStatus),
};
},
render(createElement) {
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index 7a5a227db30..fbf944499d5 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -4,7 +4,7 @@ import Translate from '~/vue_shared/translate';
import ide from './components/ide.vue';
import store from './stores';
import router from './ide_router';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
Vue.use(Translate);
@@ -40,7 +40,7 @@ export function initIde(el, options = {}) {
webIDEHelpPagePath: el.dataset.webIdeHelpPagePath,
});
this.setInitialData({
- clientsidePreviewEnabled: convertPermissionToBoolean(el.dataset.clientsidePreviewEnabled),
+ clientsidePreviewEnabled: parseBoolean(el.dataset.clientsidePreviewEnabled),
...extraInitialData(el),
});
},
diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js
index f1beb1a8ea5..1ffd5c61282 100644
--- a/app/assets/javascripts/importer_status.js
+++ b/app/assets/javascripts/importer_status.js
@@ -3,7 +3,7 @@ import _ from 'underscore';
import { __, sprintf } from './locale';
import axios from './lib/utils/axios_utils';
import flash from './flash';
-import { convertPermissionToBoolean } from './lib/utils/common_utils';
+import { parseBoolean } from './lib/utils/common_utils';
class ImporterStatus {
constructor({ jobsUrl, importUrl, ciCdOnly }) {
@@ -141,7 +141,7 @@ function initImporterStatus() {
return new ImporterStatus({
jobsUrl: data.jobsImportPath,
importUrl: data.importPath,
- ciCdOnly: convertPermissionToBoolean(data.ciCdOnly),
+ ciCdOnly: parseBoolean(data.ciCdOnly),
});
}
}
diff --git a/app/assets/javascripts/landing.js b/app/assets/javascripts/landing.js
index 8c0950ad5d5..bfb4d9ce67b 100644
--- a/app/assets/javascripts/landing.js
+++ b/app/assets/javascripts/landing.js
@@ -1,4 +1,5 @@
import Cookies from 'js-cookie';
+import { parseBoolean } from '~/lib/utils/common_utils';
class Landing {
constructor(landingElement, dismissButton, cookieName) {
@@ -30,7 +31,7 @@ class Landing {
}
isDismissed() {
- return Cookies.get(this.cookieName) === 'true';
+ return parseBoolean(Cookies.get(this.cookieName));
}
}
diff --git a/app/assets/javascripts/lazy_loader.js b/app/assets/javascripts/lazy_loader.js
index af50ea9d6c2..ee01a73a6e8 100644
--- a/app/assets/javascripts/lazy_loader.js
+++ b/app/assets/javascripts/lazy_loader.js
@@ -91,7 +91,9 @@ export default class LazyLoader {
onIntersection = entries => {
entries.forEach(entry => {
- if (entry.isIntersecting) {
+ // We are using `intersectionRatio > 0` over `isIntersecting`, as some browsers did not ship the latter
+ // See: https://gitlab.com/gitlab-org/gitlab-ce/issues/54407
+ if (entry.intersectionRatio > 0) {
this.intersectionObserver.unobserve(entry.target);
this.lazyImages.push(entry.target);
}
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 3186ae9c133..040d0bc659e 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -421,12 +421,28 @@ export const historyPushState = newUrl => {
};
/**
+ * Returns true for a String "true" and false otherwise.
+ * This is the opposite of Boolean(...).toString()
+ *
+ * @param {String} value
+ * @returns {Boolean}
+ */
+export const parseBoolean = value => value === 'true';
+
+/**
* Converts permission provided as strings to booleans.
*
* @param {String} string
* @returns {Boolean}
*/
-export const convertPermissionToBoolean = permission => permission === 'true';
+export const convertPermissionToBoolean = permission => {
+ if (process.env.NODE_ENV !== 'production') {
+ // eslint-disable-next-line no-console
+ console.warn('convertPermissionToBoolean is deprecated! Please use parseBoolean instead.');
+ }
+
+ return parseBoolean(permission);
+};
/**
* Back Off exponential algorithm
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index d8255181574..28148319c41 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -8,7 +8,12 @@ import flash from './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import initChangesDropdown from './init_changes_dropdown';
import bp from './breakpoints';
-import { parseUrlPathname, handleLocationHash, isMetaClick } from './lib/utils/common_utils';
+import {
+ parseUrlPathname,
+ handleLocationHash,
+ isMetaClick,
+ parseBoolean,
+} from './lib/utils/common_utils';
import { isInVueNoteablePage } from './lib/utils/dom_utils';
import { getLocationHash } from './lib/utils/url_utility';
import Diff from './diff';
@@ -440,7 +445,7 @@ export default class MergeRequestTabs {
// Expand the issuable sidebar unless the user explicitly collapsed it
expandView() {
- if (Cookies.get('collapsed_gutter') === 'true') {
+ if (parseBoolean(Cookies.get('collapsed_gutter'))) {
return;
}
const $gutterIcon = $('.js-sidebar-toggle i:visible');
diff --git a/app/assets/javascripts/monitoring/components/empty_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue
index 23e1e734b37..0e141d02ead 100644
--- a/app/assets/javascripts/monitoring/components/empty_state.vue
+++ b/app/assets/javascripts/monitoring/components/empty_state.vue
@@ -44,9 +44,9 @@ export default {
title: 'Get started with performance monitoring',
description: `Stay updated about the performance and health
of your environment by configuring Prometheus to monitor your deployments.`,
- buttonText: 'Install Prometheus on clusters',
+ buttonText: 'Install on clusters',
buttonPath: this.clustersPath,
- secondaryButtonText: 'Configure existing Prometheus',
+ secondaryButtonText: 'Configure existing installation',
secondaryButtonPath: this.settingsPath,
},
loading: {
@@ -88,26 +88,32 @@ export default {
</script>
<template>
- <div class="prometheus-state">
- <div class="state-svg svg-content"><img :src="currentState.svgUrl" /></div>
- <h4 class="state-title">{{ currentState.title }}</h4>
- <p class="state-description">
- {{ currentState.description }}
- <a v-if="showButtonDescription" :href="settingsPath"> Prometheus server </a>
- </p>
- <div class="state-button">
- <a v-if="currentState.buttonPath" :href="currentState.buttonPath" class="btn btn-success">
- {{ currentState.buttonText }}
- </a>
+ <div class="row empty-state js-empty-state">
+ <div class="col-12">
+ <div class="state-svg svg-content"><img :src="currentState.svgUrl" /></div>
</div>
- <div class="state-button">
- <a
- v-if="currentState.secondaryButtonPath"
- :href="currentState.secondaryButtonPath"
- class="btn"
- >
- {{ currentState.secondaryButtonText }}
- </a>
+
+ <div class="col-12">
+ <div class="text-content">
+ <h4 class="state-title text-center">{{ currentState.title }}</h4>
+ <p class="state-description">
+ {{ currentState.description }}
+ <a v-if="showButtonDescription" :href="settingsPath"> Prometheus server </a>
+ </p>
+
+ <div class="text-center">
+ <a v-if="currentState.buttonPath" :href="currentState.buttonPath" class="btn btn-success">
+ {{ currentState.buttonText }}
+ </a>
+ <a
+ v-if="currentState.secondaryButtonPath"
+ :href="currentState.secondaryButtonPath"
+ class="btn"
+ >
+ {{ currentState.secondaryButtonText }}
+ </a>
+ </div>
+ </div>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js
index 41270e015d4..9d78b5ea110 100644
--- a/app/assets/javascripts/monitoring/monitoring_bundle.js
+++ b/app/assets/javascripts/monitoring/monitoring_bundle.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
+import { parseBoolean } from '~/lib/utils/common_utils';
import Dashboard from './components/dashboard.vue';
export default () => {
@@ -13,7 +13,7 @@ export default () => {
return createElement(Dashboard, {
props: {
...el.dataset,
- hasMetrics: convertPermissionToBoolean(el.dataset.hasMetrics),
+ hasMetrics: parseBoolean(el.dataset.hasMetrics),
},
});
},
diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js
index cba6759ebf5..ee1a5274ff7 100644
--- a/app/assets/javascripts/namespace_select.js
+++ b/app/assets/javascripts/namespace_select.js
@@ -3,10 +3,11 @@
import $ from 'jquery';
import Api from './api';
import { mergeUrlParams } from './lib/utils/url_utility';
+import { parseBoolean } from '~/lib/utils/common_utils';
export default class NamespaceSelect {
constructor(opts) {
- const isFilter = opts.dropdown.dataset.isFilter === 'true';
+ const isFilter = parseBoolean(opts.dropdown.dataset.isFilter);
const fieldName = opts.dropdown.dataset.fieldName || 'namespace_id';
$(opts.dropdown).glDropdown({
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
index d9cf62db3f7..674b807edbe 100644
--- a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
+++ b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
@@ -1,5 +1,6 @@
import $ from 'jquery';
import { truncate } from '../../../lib/utils/text_utility';
+import { parseBoolean } from '~/lib/utils/common_utils';
const MAX_MESSAGE_LENGTH = 500;
const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
@@ -26,7 +27,7 @@ export default class AbuseReports {
const $messageCellElement = $(this);
const originalMessage = $messageCellElement.data('originalMessage');
if (!originalMessage) return;
- if ($messageCellElement.data('messageTruncated') === 'true') {
+ if (parseBoolean($messageCellElement.data('messageTruncated'))) {
$messageCellElement.data('messageTruncated', 'false');
$messageCellElement.text(originalMessage);
} else {
diff --git a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
index 417935e2ad0..10cd8ecfbc9 100644
--- a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
+++ b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
@@ -1,9 +1,10 @@
import $ from 'jquery';
import U2FRegister from '~/u2f/register';
+import { parseBoolean } from '~/lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => {
const twoFactorNode = document.querySelector('.js-two-factor-auth');
- const skippable = twoFactorNode.dataset.twoFactorSkippable === 'true';
+ const skippable = parseBoolean(twoFactorNode.dataset.twoFactorSkippable);
if (skippable) {
const button = `<a class="btn btn-sm btn-warning float-right" data-method="patch" href="${
twoFactorNode.dataset.two_factor_skip_url
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
index 1edd076604c..22512a6f12a 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
@@ -3,6 +3,7 @@ import Vue from 'vue';
import Cookies from 'js-cookie';
import Translate from '../../../../../vue_shared/translate';
import illustrationSvg from '../icons/intro_illustration.svg';
+import { parseBoolean } from '~/lib/utils/common_utils';
Vue.use(Translate);
@@ -13,7 +14,7 @@ export default {
data() {
return {
docsUrl: document.getElementById('pipeline-schedules-callout').dataset.docsUrl,
- calloutDismissed: Cookies.get(cookieKey) === 'true',
+ calloutDismissed: parseBoolean(Cookies.get(cookieKey)),
};
},
created() {
diff --git a/app/assets/javascripts/pages/projects/pipelines/index/index.js b/app/assets/javascripts/pages/projects/pipelines/index/index.js
index fc337a7609b..fd72d2ddbe0 100644
--- a/app/assets/javascripts/pages/projects/pipelines/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipelines/index/index.js
@@ -2,7 +2,7 @@ import Vue from 'vue';
import PipelinesStore from '../../../../pipelines/stores/pipelines_store';
import pipelinesComponent from '../../../../pipelines/components/pipelines.vue';
import Translate from '../../../../vue_shared/translate';
-import { convertPermissionToBoolean } from '../../../../lib/utils/common_utils';
+import { parseBoolean } from '../../../../lib/utils/common_utils';
Vue.use(Translate);
@@ -33,8 +33,8 @@ document.addEventListener(
noPipelinesSvgPath: this.dataset.noPipelinesSvgPath,
autoDevopsPath: this.dataset.helpAutoDevopsPath,
newPipelinePath: this.dataset.newPipelinePath,
- canCreatePipeline: convertPermissionToBoolean(this.dataset.canCreatePipeline),
- hasGitlabCi: convertPermissionToBoolean(this.dataset.hasGitlabCi),
+ canCreatePipeline: parseBoolean(this.dataset.canCreatePipeline),
+ hasGitlabCi: parseBoolean(this.dataset.hasGitlabCi),
ciLintPath: this.dataset.ciLintPath,
resetCachePath: this.dataset.resetCachePath,
},
diff --git a/app/assets/javascripts/performance_bar/services/performance_bar_service.js b/app/assets/javascripts/performance_bar/services/performance_bar_service.js
index 3a496fa2ed8..d8c23c82f7f 100644
--- a/app/assets/javascripts/performance_bar/services/performance_bar_service.js
+++ b/app/assets/javascripts/performance_bar/services/performance_bar_service.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import _ from 'underscore';
import axios from '../../lib/utils/axios_utils';
+import { parseBoolean } from '~/lib/utils/common_utils';
let vueResourceInterceptor;
@@ -41,7 +42,8 @@ export default class PerformanceBarService {
// Vue Resource.
const requestUrl = (response.config || response).url;
const apiRequest = requestUrl && requestUrl.match(/^\/api\//);
- const cachedResponse = response.headers && response.headers['x-gitlab-from-cache'] === 'true';
+ const cachedResponse =
+ response.headers && parseBoolean(response.headers['x-gitlab-from-cache']);
const fireCallback = requestUrl !== peekUrl && requestId && !apiRequest && !cachedResponse;
return [fireCallback, requestId, requestUrl];
diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js
index 8704a655b28..deacff5abe7 100644
--- a/app/assets/javascripts/profile/profile.js
+++ b/app/assets/javascripts/profile/profile.js
@@ -1,6 +1,7 @@
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import flash from '../flash';
+import { parseBoolean } from '~/lib/utils/common_utils';
export default class Profile {
constructor({ form } = {}) {
@@ -80,7 +81,7 @@ export default class Profile {
setRepoRadio() {
const multiEditRadios = $('input[name="user[multi_file]"]');
- if (this.newRepoActivated || this.newRepoActivated === 'true') {
+ if (parseBoolean(this.newRepoActivated)) {
multiEditRadios.filter('[value=on]').prop('checked', true);
} else {
multiEditRadios.filter('[value=off]').prop('checked', true);
diff --git a/app/assets/javascripts/toggle_buttons.js b/app/assets/javascripts/toggle_buttons.js
index d83ffc7e211..bcb44bf7acf 100644
--- a/app/assets/javascripts/toggle_buttons.js
+++ b/app/assets/javascripts/toggle_buttons.js
@@ -1,7 +1,7 @@
import $ from 'jquery';
import Flash from './flash';
import { __ } from './locale';
-import { convertPermissionToBoolean } from './lib/utils/common_utils';
+import { parseBoolean } from './lib/utils/common_utils';
/*
example HAML:
@@ -18,7 +18,7 @@ function updateToggle(toggle, isOn) {
}
function onToggleClicked(toggle, input, clickCallback) {
- const previousIsOn = convertPermissionToBoolean(input.value);
+ const previousIsOn = parseBoolean(input.value);
// Visually change the toggle and start loading
updateToggle(toggle, !previousIsOn);
@@ -51,7 +51,7 @@ export default function setupToggleButtons(container, clickCallback = () => {})
toggles.forEach(toggle => {
const input = toggle.querySelector('.js-project-feature-toggle-input');
- const isOn = convertPermissionToBoolean(input.value);
+ const isOn = parseBoolean(input.value);
// Get the visible toggle in sync with the hidden input
updateToggle(toggle, isOn);
diff --git a/app/assets/javascripts/usage_ping_consent.js b/app/assets/javascripts/usage_ping_consent.js
index 05607f09a7e..d3d745a3c11 100644
--- a/app/assets/javascripts/usage_ping_consent.js
+++ b/app/assets/javascripts/usage_ping_consent.js
@@ -1,7 +1,7 @@
import $ from 'jquery';
import axios from './lib/utils/axios_utils';
import Flash, { hideFlash } from './flash';
-import { convertPermissionToBoolean } from './lib/utils/common_utils';
+import { parseBoolean } from './lib/utils/common_utils';
export default () => {
$('body').on('click', '.js-usage-consent-action', e => {
@@ -11,8 +11,8 @@ export default () => {
const { url, checkEnabled, pingEnabled } = e.target.dataset;
const data = {
application_setting: {
- version_check_enabled: convertPermissionToBoolean(checkEnabled),
- usage_ping_enabled: convertPermissionToBoolean(pingEnabled),
+ version_check_enabled: parseBoolean(checkEnabled),
+ usage_ping_enabled: parseBoolean(pingEnabled),
},
};
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 347fcad771a..75166ffcada 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -203,21 +203,6 @@
stroke: $gray-darkest;
}
-.prometheus-state {
- max-width: 460px;
- margin: 10px auto;
- text-align: center;
-
- .state-svg {
- max-width: 80vw;
- margin: 0 auto;
- }
-
- .state-button {
- padding: $gl-padding / 2;
- }
-}
-
.prometheus-graphs {
.environments {
.dropdown-menu-toggle {
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index 78a11616d4c..e2879bfdcf1 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -37,13 +37,13 @@ module TreeHelper
# Using Rails `*_path` methods can be slow, especially when generating
# many paths, as with a repository tree that has thousands of items.
def fast_project_blob_path(project, blob_path)
- Addressable::URI.escape(
+ ActionDispatch::Journey::Router::Utils.escape_path(
File.join(relative_url_root, project.path_with_namespace, 'blob', blob_path)
)
end
def fast_project_tree_path(project, tree_path)
- Addressable::URI.escape(
+ ActionDispatch::Journey::Router::Utils.escape_path(
File.join(relative_url_root, project.path_with_namespace, 'tree', tree_path)
)
end
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index bd0286ee3f9..8f8790585a3 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -51,6 +51,10 @@ module Clusters
ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end
+
+ def ingress_service
+ cluster.kubeclient.get_service('ingress-nginx-ingress-controller', Gitlab::Kubernetes::Helm::NAMESPACE)
+ end
end
end
end
diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb
index c66d5ce54db..c0aaa8dce20 100644
--- a/app/models/clusters/applications/knative.rb
+++ b/app/models/clusters/applications/knative.rb
@@ -6,9 +6,7 @@ module Clusters
VERSION = '0.1.3'.freeze
REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze
- # This is required for helm version <= 2.10.x in order to support
- # Setting up CRDs
- ISTIO_CRDS = 'https://storage.googleapis.com/triggermesh-charts/istio-crds.yaml'.freeze
+ FETCH_IP_ADDRESS_DELAY = 30.seconds
self.table_name = 'clusters_applications_knative'
@@ -16,6 +14,16 @@ module Clusters
include ::Clusters::Concerns::ApplicationStatus
include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData
+ include AfterCommitQueue
+
+ state_machine :status do
+ before_transition any => [:installed] do |application|
+ application.run_after_commit do
+ ClusterWaitForIngressIpAddressWorker.perform_in(
+ FETCH_IP_ADDRESS_DELAY, application.name, application.id)
+ end
+ end
+ end
default_value_for :version, VERSION
@@ -36,19 +44,23 @@ module Clusters
rbac: cluster.platform_kubernetes_rbac?,
chart: chart,
files: files,
- repository: REPOSITORY,
- preinstall: install_script
+ repository: REPOSITORY
)
end
- def client
- cluster.platform_kubernetes.kubeclient.knative_client
+ def schedule_status_update
+ return unless installed?
+ return if external_ip
+
+ ClusterWaitForIngressIpAddressWorker.perform_async(name, id)
end
- private
+ def ingress_service
+ cluster.kubeclient.get_service('knative-ingressgateway', 'istio-system')
+ end
- def install_script
- ["/usr/bin/kubectl apply -f #{ISTIO_CRDS}"]
+ def client
+ cluster.platform_kubernetes.kubeclient.knative_client
end
end
end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 6f1beede6f9..a3029a54604 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -313,7 +313,8 @@ class MergeRequestDiff < ActiveRecord::Base
# merge_request_diff_commits.reload is preferred way to reload associated
# objects but it returns cached result for some reason in this case
- commits = merge_request_diff_commits(true)
+ # we can circumvent that by specifying that we need an uncached reload
+ commits = self.class.uncached { merge_request_diff_commits.reload }
self.commits_count = commits.size
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 4d1917b9ab2..39978d8a4c4 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -88,9 +88,6 @@ class Project < ActiveRecord::Base
after_create :create_project_feature, unless: :project_feature
- after_create -> { SiteStatistic.track(STATISTICS_ATTRIBUTE) }
- before_destroy -> { SiteStatistic.untrack(STATISTICS_ATTRIBUTE) }
-
after_create :create_ci_cd_settings,
unless: :ci_cd_settings,
if: proc { ProjectCiCdSetting.available? }
@@ -1394,7 +1391,7 @@ class Project < ActiveRecord::Base
def change_head(branch)
if repository.branch_exists?(branch)
repository.before_change_head
- repository.raw_repository.write_ref('HEAD', "refs/heads/#{branch}", shell: false)
+ repository.raw_repository.write_ref('HEAD', "refs/heads/#{branch}")
repository.copy_gitattributes(branch)
repository.after_change_head
reload_default_branch
diff --git a/app/models/repository.rb b/app/models/repository.rb
index a77fa8f2ce7..427dac99b79 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -259,7 +259,7 @@ class Repository
next if kept_around?(sha)
# This will still fail if the file is corrupted (e.g. 0 bytes)
- raw_repository.write_ref(keep_around_ref_name(sha), sha, shell: false)
+ raw_repository.write_ref(keep_around_ref_name(sha), sha)
rescue Gitlab::Git::CommandError => ex
Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}"
end
diff --git a/app/models/site_statistic.rb b/app/models/site_statistic.rb
deleted file mode 100644
index 3a7912ed53a..00000000000
--- a/app/models/site_statistic.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-# frozen_string_literal: true
-
-class SiteStatistic < ActiveRecord::Base
- # prevents the creation of multiple rows
- default_value_for :id, 1
-
- COUNTER_ATTRIBUTES = %w(repositories_count).freeze
- REQUIRED_SCHEMA_VERSION = 20180629153018
-
- # Tracks specific attribute
- #
- # @param [String] raw_attribute must be one of the values listed in COUNTER_ATTRIBUTES
- def self.track(raw_attribute)
- with_statistics_available(raw_attribute) do |attribute|
- SiteStatistic.update_all(["#{attribute} = #{attribute}+1"])
- end
- end
-
- # Untracks specific attribute
- #
- # @param [String] raw_attribute must be one of the values listed in COUNTER_ATTRIBUTES
- def self.untrack(raw_attribute)
- with_statistics_available(raw_attribute) do |attribute|
- SiteStatistic.update_all(["#{attribute} = #{attribute}-1 WHERE #{attribute} > 0"])
- end
- end
-
- # Wrapper for track/untrack operations with basic validations and enforced requirements
- #
- # @param [String] raw_attribute must be one of the values listed in COUNTER_ATTRIBUTES
- # @yield [String] attribute quoted to be used inside SQL / Arel query
- def self.with_statistics_available(raw_attribute)
- unless raw_attribute.in?(COUNTER_ATTRIBUTES)
- raise ArgumentError, "Invalid attribute: '#{raw_attribute}' to '#{caller_locations(1, 1)[0].label}' method. " \
- "Valid attributes are: #{COUNTER_ATTRIBUTES.join(', ')}"
- end
-
- return unless available?
-
- self.fetch # make sure record exists
-
- attribute = self.connection.quote_column_name(raw_attribute)
-
- # will be running on its own transaction context
- yield(attribute)
- end
-
- # Returns a site statistic record with tracked information
- #
- # @return [SiteStatistic] record with tracked information
- def self.fetch
- transaction(requires_new: true) do
- SiteStatistic.first_or_create!
- end
- rescue ActiveRecord::RecordNotUnique
- retry
- end
-
- # Return whether required schema change is available
- #
- # This is needed in order to degrade gracefully when testing schema migrations
- #
- # @return [Boolean] whether schema is available
- def self.available?
- @available_flag ||= ActiveRecord::Migrator.current_version >= REQUIRED_SCHEMA_VERSION
- end
-
- # Resets cached column information
- #
- # This is called during schema migration specs, in order to reset internal cache state
- def self.reset_column_information
- @available_flag = nil
-
- super
- end
-end
diff --git a/app/models/user.rb b/app/models/user.rb
index 01eba7e0426..dbd754dd25a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -363,7 +363,7 @@ class User < ActiveRecord::Base
from_users = from_users.confirmed if confirmed
from_emails = joins(:emails).where(emails: { email: emails })
- from_emails = from_emails.confirmed if confirmed
+ from_emails = from_emails.confirmed.merge(Email.confirmed) if confirmed
items = [from_users, from_emails]
diff --git a/app/services/clusters/applications/check_ingress_ip_address_service.rb b/app/services/clusters/applications/check_ingress_ip_address_service.rb
index f32e73e8b1c..0ec06e776a7 100644
--- a/app/services/clusters/applications/check_ingress_ip_address_service.rb
+++ b/app/services/clusters/applications/check_ingress_ip_address_service.rb
@@ -30,7 +30,7 @@ module Clusters
def service
strong_memoize(:ingress_service) do
- kubeclient.get_service('ingress-nginx-ingress-controller', Gitlab::Kubernetes::Helm::NAMESPACE)
+ app.ingress_service
end
end
end
diff --git a/app/views/layouts/header/_new_dropdown.haml b/app/views/layouts/header/_new_dropdown.haml
index e134f416c70..5cb8aebadb3 100644
--- a/app/views/layouts/header/_new_dropdown.haml
+++ b/app/views/layouts/header/_new_dropdown.haml
@@ -7,15 +7,14 @@
- if @group&.persisted?
- create_group_project = can?(current_user, :create_projects, @group)
- create_group_subgroup = can?(current_user, :create_subgroup, @group)
+
- if create_group_project || create_group_subgroup
%li.dropdown-bold-header
= _('This group')
- if create_group_project
- %li.header-new-group-project
- = link_to _('New project'), new_project_path(namespace_id: @group.id)
+ %li= link_to _('New project'), new_project_path(namespace_id: @group.id)
- if create_group_subgroup
- %li
- = link_to _('New subgroup'), new_group_path(parent_id: @group.id)
+ %li= link_to _('New subgroup'), new_group_path(parent_id: @group.id)
%li.divider
%li.dropdown-bold-header GitLab
@@ -23,25 +22,20 @@
- create_project_issue = show_new_issue_link?(@project)
- merge_project = merge_request_source_project_for_project(@project)
- create_project_snippet = can?(current_user, :create_project_snippet, @project)
+
- if create_project_issue || merge_project || create_project_snippet
%li.dropdown-bold-header
= _('This project')
- if create_project_issue
- %li
- = link_to _('New issue'), new_project_issue_path(@project)
+ %li= link_to _('New issue'), new_project_issue_path(@project)
- if merge_project
- %li
- = link_to _('New merge request'), project_new_merge_request_path(merge_project)
+ %li= link_to _('New merge request'), project_new_merge_request_path(merge_project)
- if create_project_snippet
- %li.header-new-project-snippet
- = link_to _('New snippet'), new_project_snippet_path(@project)
+ %li= link_to _('New snippet'), new_project_snippet_path(@project)
%li.divider
%li.dropdown-bold-header GitLab
- if current_user.can_create_project?
- %li
- = link_to _('New project'), new_project_path, class: 'qa-global-new-project-link'
+ %li= link_to _('New project'), new_project_path, class: 'qa-global-new-project-link'
- if current_user.can_create_group?
- %li
- = link_to _('New group'), new_group_path
- %li
- = link_to _('New snippet'), new_snippet_path
+ %li= link_to _('New group'), new_group_path
+ %li= link_to _('New snippet'), new_snippet_path
diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml
index 8181ee9eea1..af8887b0c39 100644
--- a/app/views/projects/branches/new.html.haml
+++ b/app/views/projects/branches/new.html.haml
@@ -13,7 +13,7 @@
.form-group.row
= label_tag :branch_name, nil, class: 'col-form-label col-sm-2'
.col-sm-10
- = text_field_tag :branch_name, params[:branch_name], required: true, autofocus: true, class: 'form-control js-branch-name'
+ = text_field_tag :branch_name, params[:branch_name], required: true, autofocus: true, class: 'form-control js-branch-name monospace'
.form-text.text-muted.text-danger.js-branch-name-error
.form-group.row
= label_tag :ref, 'Create from', class: 'col-form-label col-sm-2'
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 953ab95735b..c0b410472eb 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -81,9 +81,9 @@
- todos_destroyer:todos_destroyer_confidential_issue
- todos_destroyer:todos_destroyer_entity_leave
+- todos_destroyer:todos_destroyer_group_private
- todos_destroyer:todos_destroyer_project_private
- todos_destroyer:todos_destroyer_private_features
-- todos_destroyer:todos_destroyer_group_private
- default
- mailers # ActionMailer::DeliveryJob.queue_name