Commit 999f47e9 authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 20bd3b7d
......@@ -34,14 +34,17 @@ const setupAxiosStartupCalls = axios => {
});
// eslint-disable-next-line promise/no-nesting
return res.json().then(data => ({
data,
status: res.status,
statusText: res.statusText,
headers: fetchHeaders,
config: req,
request: req,
}));
return res
.clone()
.json()
.then(data => ({
data,
status: res.status,
statusText: res.statusText,
headers: fetchHeaders,
config: req,
request: req,
}));
});
}
......
......@@ -11,6 +11,8 @@ import {
GlTooltipDirective,
} from '@gitlab/ui';
import CustomMetricsFormFields from '~/custom_metrics/components/custom_metrics_form_fields.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { PANEL_NEW_PAGE } from '../router/constants';
import DuplicateDashboardModal from './duplicate_dashboard_modal.vue';
import CreateDashboardModal from './create_dashboard_modal.vue';
import { s__ } from '~/locale';
......@@ -36,6 +38,7 @@ export default {
GlTooltip: GlTooltipDirective,
TrackEvent: TrackEventDirective,
},
mixins: [glFeatureFlagsMixin()],
props: {
addingMetricsAvailable: {
type: Boolean,
......@@ -56,6 +59,10 @@ export default {
type: String,
required: true,
},
isOotbDashboard: {
type: Boolean,
required: true,
},
},
data() {
return { customMetricsFormIsValid: null };
......@@ -72,15 +79,22 @@ export default {
},
isMenuItemEnabled() {
return {
addPanel: !this.isOotbDashboard,
createDashboard: Boolean(this.projectPath),
editDashboard: this.selectedDashboard?.can_edit,
};
},
isMenuItemShown() {
return {
addPanel: this.glFeatures.metricsDashboardNewPanelPage,
duplicateDashboard: this.isOutOfTheBoxDashboard,
};
},
newPanelPageLocation() {
// Retains params/query if any
const { params, query } = this.$route ?? {};
return { name: PANEL_NEW_PAGE, params, query };
},
},
methods: {
...mapActions('monitoringDashboard', ['toggleStarredValue']),
......@@ -117,7 +131,9 @@ export default {
starDashboard: s__('Metrics|Star dashboard'),
unstarDashboard: s__('Metrics|Unstar dashboard'),
addMetric: s__('Metrics|Add metric'),
editDashboardInfo: s__('Metrics|Duplicate this dashboard to edit dashboard YAML'),
addPanel: s__('Metrics|Add panel'),
addPanelInfo: s__('Metrics|Duplicate this dashboard to add panel or edit dashboard YAML.'),
editDashboardInfo: s__('Metrics|Duplicate this dashboard to add panel or edit dashboard YAML.'),
editDashboard: s__('Metrics|Edit dashboard YAML'),
createDashboard: s__('Metrics|Create new dashboard'),
},
......@@ -176,6 +192,32 @@ export default {
</gl-modal>
</template>
<template v-if="isMenuItemShown.addPanel">
<gl-new-dropdown-item
v-if="isMenuItemEnabled.addPanel"
data-testid="add-panel-item-enabled"
:to="newPanelPageLocation"
>
{{ $options.i18n.addPanel }}
</gl-new-dropdown-item>
<!--
wrapper for tooltip as button can be `disabled`
https://bootstrap-vue.org/docs/components/tooltip#disabled-elements
-->
<div v-else v-gl-tooltip :title="$options.i18n.addPanelInfo">
<gl-new-dropdown-item
:alt="$options.i18n.addPanelInfo"
:to="newPanelPageLocation"
data-testid="add-panel-item-disabled"
disabled
class="gl-cursor-not-allowed"
>
<span class="gl-text-gray-400">{{ $options.i18n.addPanel }}</span>
</gl-new-dropdown-item>
</div>
</template>
<gl-new-dropdown-item
v-if="isMenuItemEnabled.editDashboard"
:href="selectedDashboard ? selectedDashboard.project_blob_path : null"
......
......@@ -118,6 +118,9 @@ export default {
shouldShowSettingsButton() {
return this.canAccessOperationsSettings && this.operationsSettingsPath;
},
isOOTBDashboard() {
return this.selectedDashboard?.out_of_the_box_dashboard ?? false;
},
},
methods: {
...mapActions('monitoringDashboard', ['filterEnvironments']),
......@@ -266,6 +269,7 @@ export default {
:custom-metrics-path="customMetricsPath"
:validate-query-path="validateQueryPath"
:default-branch="defaultBranch"
:is-ootb-dashboard="isOOTBDashboard"
/>
</div>
......
......@@ -5,6 +5,7 @@ query getAnnotations(
$startingFrom: Time!
) {
project(fullPath: $projectPath) {
id
environments(name: $environmentName) {
nodes {
id
......
query getEnvironments($projectPath: ID!, $search: String, $states: [String!]) {
project(fullPath: $projectPath) {
id
data: environments(search: $search, states: $states) {
environments: nodes {
name
......
......@@ -13,12 +13,12 @@ import { DASHBOARD_PAGE, PANEL_NEW_PAGE } from './constants';
export default [
{
name: PANEL_NEW_PAGE,
path: '/:dashboard(.*)?/panel/new',
path: '/:dashboard(.+)?/panel/new',
component: PanelNewPage,
},
{
name: DASHBOARD_PAGE,
path: '/:dashboard(.*)?',
path: '/:dashboard(.+)?',
component: DashboardPage,
},
];
......@@ -136,6 +136,8 @@ export default {
}
window.addEventListener('hashchange', this.handleHashChanged);
eventHub.$on('notesApp.updateIssuableConfidentiality', this.setConfidentiality);
},
updated() {
this.$nextTick(() => {
......@@ -146,6 +148,7 @@ export default {
beforeDestroy() {
this.stopPolling();
window.removeEventListener('hashchange', this.handleHashChanged);
eventHub.$off('notesApp.updateIssuableConfidentiality', this.setConfidentiality);
},
methods: {
...mapActions([
......@@ -164,6 +167,7 @@ export default {
'startTaskList',
'convertToDiscussion',
'stopPolling',
'setConfidentiality',
]),
discussionIsIndividualNoteAndNotConverted(discussion) {
return discussion.individual_note && !this.convertedDisscussionIds.includes(discussion.id);
......
......@@ -21,29 +21,6 @@ import Api from '~/api';
let eTagPoll;
export const updateConfidentialityOnIssue = ({ commit, getters }, { confidential, fullPath }) => {
const { iid } = getters.getNoteableData;
return utils.gqClient
.mutate({
mutation: updateIssueConfidentialMutation,
variables: {
input: {
projectPath: fullPath,
iid: String(iid),
confidential,
},
},
})
.then(({ data }) => {
const {
issueSetConfidential: { issue },
} = data;
commit(types.SET_ISSUE_CONFIDENTIAL, issue.confidential);
});
};
export const updateLockedAttribute = ({ commit, getters }, { locked, fullPath }) => {
const { iid, targetType } = getters.getNoteableData;
......@@ -712,3 +689,29 @@ export const updateAssignees = ({ commit }, assignees) => {
export const updateDiscussionPosition = ({ commit }, updatedPosition) => {
commit(types.UPDATE_DISCUSSION_POSITION, updatedPosition);
};
export const updateConfidentialityOnIssuable = (
{ getters, commit },
{ confidential, fullPath },
) => {
const { iid } = getters.getNoteableData;
return utils.gqClient
.mutate({
mutation: updateIssueConfidentialMutation,
variables: {
input: {
projectPath: fullPath,
iid: String(iid),
confidential,
},
},
})
.then(({ data }) => {
const {
issueSetConfidential: { issue },
} = data;
setConfidentiality({ commit }, issue.confidential);
});
};
......@@ -7,23 +7,47 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
import initNotes from '~/init_notes';
import initChangesDropdown from '~/init_changes_dropdown';
import initDiffNotes from '~/diff_notes/diff_notes_bundle';
import { fetchCommitMergeRequests } from '~/commit_merge_requests';
import '~/sourcegraph/load';
import { handleLocationHash } from '~/lib/utils/common_utils';
import axios from '~/lib/utils/axios_utils';
import syntaxHighlight from '~/syntax_highlight';
import flash from '~/flash';
import { __ } from '~/locale';
document.addEventListener('DOMContentLoaded', () => {
const hasPerfBar = document.querySelector('.with-performance-bar');
const performanceHeight = hasPerfBar ? 35 : 0;
new Diff();
new ZenMode();
new ShortcutsNavigation();
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
initNotes();
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight + performanceHeight);
// eslint-disable-next-line no-jquery/no-load
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
fetchCommitMergeRequests();
initDiffNotes();
const filesContainer = $('.js-diffs-batch');
const initAfterPageLoad = () => {
new Diff();
new ZenMode();
new ShortcutsNavigation();
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
initNotes();
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight + performanceHeight);
// eslint-disable-next-line no-jquery/no-load
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
fetchCommitMergeRequests();
};
if (filesContainer.length) {
const batchPath = filesContainer.data('diffFilesPath');
axios
.get(batchPath)
.then(({ data }) => {
filesContainer.html($(data.html));
syntaxHighlight(filesContainer);
handleLocationHash();
initAfterPageLoad();
})
.catch(() => {
flash(__('An error occurred while retrieving diff files'));
});
} else {
initAfterPageLoad();
}
});
<script>
import { GlButton } from '@gitlab/ui';
import createFlash from '~/flash';
import { __ } from '../../locale';
import FileTable from './table/index.vue';
......@@ -8,12 +9,15 @@ import projectPathQuery from '../queries/project_path.query.graphql';
import FilePreview from './preview/index.vue';
import { readmeFile } from '../utils/readme';
const LIMIT = 1000;
const PAGE_SIZE = 100;
export const INITIAL_FETCH_COUNT = LIMIT / PAGE_SIZE;
export default {
components: {
FileTable,
FilePreview,
GlButton,
},
mixins: [getRefMixin],
apollo: {
......@@ -43,12 +47,19 @@ export default {
blobs: [],
},
isLoadingFiles: false,
isOverLimit: false,
clickedShowMore: false,
pageSize: PAGE_SIZE,
fetchCounter: 0,
};
},
computed: {
readme() {
return readmeFile(this.entries.blobs);
},
hasShowMore() {
return !this.clickedShowMore && this.fetchCounter === INITIAL_FETCH_COUNT;
},
},
watch: {
......@@ -76,7 +87,7 @@ export default {
ref: this.ref,
path: this.path || '/',
nextPageCursor: this.nextPageCursor,
pageSize: PAGE_SIZE,
pageSize: this.pageSize,
},
})
.then(({ data }) => {
......@@ -96,7 +107,11 @@ export default {
if (pageInfo?.hasNextPage) {
this.nextPageCursor = pageInfo.endCursor;
this.fetchFiles();
this.fetchCounter += 1;
if (this.fetchCounter < INITIAL_FETCH_COUNT || this.clickedShowMore) {
this.fetchFiles();
this.clickedShowMore = false;
}
}
})
.catch(error => {
......@@ -112,6 +127,10 @@ export default {
.concat(data.trees.pageInfo, data.submodules.pageInfo, data.blobs.pageInfo)
.find(({ hasNextPage }) => hasNextPage);
},
showMore() {
this.clickedShowMore = true;
this.fetchFiles();
},
},
};
</script>
......@@ -124,6 +143,19 @@ export default {
:is-loading="isLoadingFiles"
:loading-path="loadingPath"
/>
<div
v-if="hasShowMore"
class="gl-border-1 gl-border-gray-100 gl-rounded-base gl-border-t-none gl-border-b-solid gl-border-l-solid gl-border-r-solid gl-rounded-top-right-none gl-rounded-top-left-none gl-mt-n1"
>
<gl-button
variant="link"
class="gl-display-flex gl-w-full gl-py-4!"
:loading="isLoadingFiles"
@click="showMore"
>
{{ s__('ProjectFileTree|Show more') }}
</gl-button>
</div>
<file-preview v-if="readme" :blob="readme" />
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
import { __ } from '~/locale';
import { mapState } from 'vuex';
import { __, sprintf } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
import Icon from '~/vue_shared/components/icon.vue';
import eventHub from '~/sidebar/event_hub';
......@@ -23,9 +23,10 @@ export default {
required: true,
type: Boolean,
},
service: {
required: true,
type: Object,
issuableType: {
required: false,
type: String,
default: 'issue',
},
},
data() {
......@@ -34,13 +35,25 @@ export default {
};
},
computed: {
...mapState({ confidential: ({ noteableData }) => noteableData.confidential }),
...mapState({
confidential: ({ noteableData, confidential }) => {
if (noteableData) {
return noteableData.confidential;
}
return Boolean(confidential);
},
}),
confidentialityIcon() {
return this.confidential ? 'eye-slash' : 'eye';
},
tooltipLabel() {
return this.confidential ? __('Confidential') : __('Not confidential');
},
confidentialText() {
return sprintf(__('This %{issuableType} is confidential'), {
issuableType: this.issuableType,
});
},
},
created() {
eventHub.$on('closeConfidentialityForm', this.toggleForm);
......@@ -49,7 +62,6 @@ export default {
eventHub.$off('closeConfidentialityForm', this.toggleForm);
},
methods: {
...mapActions(['setConfidentiality']),
toggleForm() {
this.edit = !this.edit;
},
......@@ -86,7 +98,12 @@ export default {
>
</div>
<div class="value sidebar-item-value hide-collapsed">
<edit-form v-if="edit" :is-confidential="confidential" :full-path="fullPath" />
<edit-form
v-if="edit"
:confidential="confidential"
:full-path="fullPath"
:issuable-type="issuableType"
/>
<div v-if="!confidential" class="no-value sidebar-item-value" data-testid="not-confidential">
<icon :size="16" name="eye" aria-hidden="true" class="sidebar-item-icon inline" />
{{ __('Not confidential') }}
......@@ -98,7 +115,7 @@ export default {
aria-hidden="true"
class="sidebar-item-icon inline is-active"
/>
{{ __('This issue is confidential') }}
{{ confidentialText }}
</div>
</div>
</div>
......
<script>
import editFormButtons from './edit_form_buttons.vue';
import { s__ } from '../../../locale';
import { __, sprintf } from '../../../locale';
export default {
components: {
editFormButtons,
},
props: {
isConfidential: {
confidential: {
required: true,
type: Boolean,
},
......@@ -15,16 +15,32 @@ export default {
required: true,
type: String,
},
issuableType: {
required: true,
type: String,
},
},
computed: {
confidentialityOnWarning() {
return s__(
'confidentiality|You are going to turn on the confidentiality. This means that only team members with <strong>at least Reporter access</strong> are able to see and leave comments on the issue.',
const accessLevel = __('at least Reporter access');
return sprintf(
__(
'You are going to turn on the confidentiality. This means that only team members with %{accessLevel} are able to see and leave comments on the %{issuableType}.',
),
{ issuableType: this.issuableType, accessLevel: `<strong>${accessLevel}</strong>` },
false,
);
},
confidentialityOffWarning() {
return s__(
'confidentiality|You are going to turn off the confidentiality. This means <strong>everyone</strong> will be able to see and leave a comment on this issue.',
const accessLevel = __('everyone');
return sprintf(
__(
'You are going to turn off the confidentiality. This means %{accessLevel} will be able to see and leave a comment on this %{issuableType}.',
),
{ issuableType: this.issuableType, accessLevel: `<strong>${accessLevel}</strong>` },
false,
);
},
},
......@@ -35,9 +51,9 @@ export default {
<div class="dropdown show">
<div class="dropdown-menu sidebar-item-warning-message">
<div>
<p v-if="!isConfidential" v-html="confidentialityOnWarning"></p>
<p v-if="!confidential" v-html="confidentialityOnWarning"></p>
<p v-else v-html="confidentialityOffWarning"></p>
<edit-form-buttons :full-path="fullPath" />
<edit-form-buttons :full-path="fullPath" :confidential="confidential" />
</div>
</div>
</div>
......