summaryrefslogtreecommitdiff
path: root/app/assets/javascripts
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/actions.vue31
-rw-r--r--app/assets/javascripts/ide/constants.js1
-rw-r--r--app/assets/javascripts/ide/queries/getUserPermissions.query.graphql3
-rw-r--r--app/assets/javascripts/ide/stores/actions/project.js60
-rw-r--r--app/assets/javascripts/ide/stores/getters.js9
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/actions.js15
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/getters.js2
-rw-r--r--app/assets/javascripts/mirrors/ssh_mirror.js1
-rw-r--r--app/assets/javascripts/monitoring/components/charts/annotations.js67
-rw-r--r--app/assets/javascripts/monitoring/components/charts/time_series.vue74
-rw-r--r--app/assets/javascripts/monitoring/constants.js9
-rw-r--r--app/assets/javascripts/projects/default_project_templates.js4
12 files changed, 183 insertions, 93 deletions
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
index 3276d21a04e..6a8ea506d1b 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
@@ -18,7 +18,7 @@ export default {
computed: {
...mapState(['currentBranchId', 'changedFiles', 'stagedFiles']),
...mapCommitState(['commitAction']),
- ...mapGetters(['currentBranch']),
+ ...mapGetters(['currentBranch', 'emptyRepo', 'canPushToBranch']),
commitToCurrentBranchText() {
return sprintf(
s__('IDE|Commit to %{branchName} branch'),
@@ -29,6 +29,13 @@ export default {
containsStagedChanges() {
return this.changedFiles.length > 0 && this.stagedFiles.length > 0;
},
+ shouldDefaultToCurrentBranch() {
+ if (this.emptyRepo) {
+ return true;
+ }
+
+ return this.canPushToBranch && !this.currentBranch?.default;
+ },
},
watch: {
containsStagedChanges() {
@@ -43,13 +50,11 @@ export default {
methods: {
...mapCommitActions(['updateCommitAction']),
updateSelectedCommitAction() {
- if (!this.currentBranch) {
+ if (!this.currentBranch && !this.emptyRepo) {
return;
}
- const { can_push: canPush = false, default: isDefault = false } = this.currentBranch;
-
- if (canPush && !isDefault) {
+ if (this.shouldDefaultToCurrentBranch) {
this.updateCommitAction(consts.COMMIT_TO_CURRENT_BRANCH);
} else {
this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH);
@@ -68,7 +73,7 @@ export default {
<div class="append-bottom-15 ide-commit-options">
<radio-group
:value="$options.commitToCurrentBranch"
- :disabled="currentBranch && !currentBranch.can_push"
+ :disabled="!canPushToBranch"
:title="$options.currentBranchPermissionsTooltip"
>
<span
@@ -77,11 +82,13 @@ export default {
v-html="commitToCurrentBranchText"
></span>
</radio-group>
- <radio-group
- :value="$options.commitToNewBranch"
- :label="__('Create a new branch')"
- :show-input="true"
- />
- <new-merge-request-option />
+ <template v-if="!emptyRepo">
+ <radio-group
+ :value="$options.commitToNewBranch"
+ :label="__('Create a new branch')"
+ :show-input="true"
+ />
+ <new-merge-request-option />
+ </template>
</div>
</template>
diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js
index e7762f9e0f2..fa2672aaece 100644
--- a/app/assets/javascripts/ide/constants.js
+++ b/app/assets/javascripts/ide/constants.js
@@ -10,6 +10,7 @@ export const FILE_VIEW_MODE_PREVIEW = 'preview';
export const PERMISSION_CREATE_MR = 'createMergeRequestIn';
export const PERMISSION_READ_MR = 'readMergeRequest';
+export const PERMISSION_PUSH_CODE = 'pushCode';
export const viewerTypes = {
mr: 'mrdiff',
diff --git a/app/assets/javascripts/ide/queries/getUserPermissions.query.graphql b/app/assets/javascripts/ide/queries/getUserPermissions.query.graphql
index 48f63995f44..2c9013ffa9c 100644
--- a/app/assets/javascripts/ide/queries/getUserPermissions.query.graphql
+++ b/app/assets/javascripts/ide/queries/getUserPermissions.query.graphql
@@ -2,7 +2,8 @@ query getUserPermissions($projectPath: ID!) {
project(fullPath: $projectPath) {
userPermissions {
createMergeRequestIn,
- readMergeRequest
+ readMergeRequest,
+ pushCode
}
}
}
diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js
index 0b168009847..ae3829dc35e 100644
--- a/app/assets/javascripts/ide/stores/actions/project.js
+++ b/app/assets/javascripts/ide/stores/actions/project.js
@@ -83,10 +83,14 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => {
});
};
-export const showEmptyState = ({ commit, state, dispatch }, { projectId, branchId }) => {
+export const loadEmptyBranch = ({ commit, state }, { projectId, branchId }) => {
const treePath = `${projectId}/${branchId}`;
+ const currentTree = state.trees[`${projectId}/${branchId}`];
- dispatch('setCurrentBranchId', branchId);
+ // If we already have a tree, let's not recreate an empty one
+ if (currentTree) {
+ return;
+ }
commit(types.CREATE_TREE, { treePath });
commit(types.TOGGLE_LOADING, {
@@ -114,8 +118,16 @@ export const loadFile = ({ dispatch, state }, { basePath }) => {
}
};
-export const loadBranch = ({ dispatch, getters }, { projectId, branchId }) =>
- dispatch('getBranchData', {
+export const loadBranch = ({ dispatch, getters, state }, { projectId, branchId }) => {
+ const currentProject = state.projects[projectId];
+
+ if (currentProject?.branches?.[branchId]) {
+ return Promise.resolve();
+ } else if (getters.emptyRepo) {
+ return dispatch('loadEmptyBranch', { projectId, branchId });
+ }
+
+ return dispatch('getBranchData', {
projectId,
branchId,
})
@@ -137,29 +149,23 @@ export const loadBranch = ({ dispatch, getters }, { projectId, branchId }) =>
dispatch('showBranchNotFoundError', branchId);
throw err;
});
+};
-export const openBranch = ({ dispatch, state, getters }, { projectId, branchId, basePath }) => {
- const currentProject = state.projects[projectId];
- if (getters.emptyRepo) {
- return dispatch('showEmptyState', { projectId, branchId });
- }
- if (!currentProject || !currentProject.branches[branchId]) {
- dispatch('setCurrentBranchId', branchId);
-
- return dispatch('loadBranch', { projectId, branchId })
- .then(() => dispatch('loadFile', { basePath }))
- .catch(
- () =>
- new Error(
- sprintf(
- __('An error occurred while getting files for - %{branchId}'),
- {
- branchId: `<strong>${esc(projectId)}/${esc(branchId)}</strong>`,
- },
- false,
- ),
+export const openBranch = ({ dispatch }, { projectId, branchId, basePath }) => {
+ dispatch('setCurrentBranchId', branchId);
+
+ return dispatch('loadBranch', { projectId, branchId })
+ .then(() => dispatch('loadFile', { basePath }))
+ .catch(
+ () =>
+ new Error(
+ sprintf(
+ __('An error occurred while getting files for - %{branchId}'),
+ {
+ branchId: `<strong>${esc(projectId)}/${esc(branchId)}</strong>`,
+ },
+ false,
),
- );
- }
- return Promise.resolve(dispatch('loadFile', { basePath }));
+ ),
+ );
};
diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js
index d7ad39019a5..5d0a8570906 100644
--- a/app/assets/javascripts/ide/stores/getters.js
+++ b/app/assets/javascripts/ide/stores/getters.js
@@ -4,6 +4,7 @@ import {
packageJsonPath,
PERMISSION_READ_MR,
PERMISSION_CREATE_MR,
+ PERMISSION_PUSH_CODE,
} from '../constants';
export const activeFile = state => state.openFiles.find(file => file.active) || null;
@@ -120,8 +121,9 @@ export const packageJson = state => state.entries[packageJsonPath];
export const isOnDefaultBranch = (_state, getters) =>
getters.currentProject && getters.currentProject.default_branch === getters.branchName;
-export const canPushToBranch = (_state, getters) =>
- getters.currentBranch && getters.currentBranch.can_push;
+export const canPushToBranch = (_state, getters) => {
+ return Boolean(getters.currentBranch ? getters.currentBranch.can_push : getters.canPushCode);
+};
export const isFileDeletedAndReadded = (state, getters) => path => {
const stagedFile = getters.getStagedFile(path);
@@ -157,5 +159,8 @@ export const canReadMergeRequests = (state, getters) =>
export const canCreateMergeRequests = (state, getters) =>
Boolean(getters.findProjectPermissions(state.currentProjectId)[PERMISSION_CREATE_MR]);
+export const canPushCode = (state, getters) =>
+ Boolean(getters.findProjectPermissions(state.currentProjectId)[PERMISSION_PUSH_CODE]);
+
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js
index 9bf0542cd0b..505daa8834d 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js
@@ -106,6 +106,9 @@ export const updateFilesAfterCommit = ({ commit, dispatch, rootState, rootGetter
};
export const commitChanges = ({ commit, state, getters, dispatch, rootState, rootGetters }) => {
+ // Pull commit options out because they could change
+ // During some of the pre and post commit processing
+ const { shouldCreateMR, isCreatingNewBranch, branchName } = getters;
const newBranch = state.commitAction !== consts.COMMIT_TO_CURRENT_BRANCH;
const stageFilesPromise = rootState.stagedFiles.length
? Promise.resolve()
@@ -116,7 +119,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
return stageFilesPromise
.then(() => {
const payload = createCommitPayload({
- branch: getters.branchName,
+ branch: branchName,
newBranch,
getters,
state,
@@ -149,7 +152,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
dispatch('updateCommitMessage', '');
return dispatch('updateFilesAfterCommit', {
data,
- branch: getters.branchName,
+ branch: branchName,
})
.then(() => {
commit(rootTypes.CLEAR_STAGED_CHANGES, null, { root: true });
@@ -158,15 +161,15 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
commit(rootTypes.SET_LAST_COMMIT_MSG, '', { root: true });
}, 5000);
- if (getters.shouldCreateMR) {
+ if (shouldCreateMR) {
const { currentProject } = rootGetters;
- const targetBranch = getters.isCreatingNewBranch
+ const targetBranch = isCreatingNewBranch
? rootState.currentBranchId
: currentProject.default_branch;
dispatch(
'redirectToUrl',
- createNewMergeRequestUrl(currentProject.web_url, getters.branchName, targetBranch),
+ createNewMergeRequestUrl(currentProject.web_url, branchName, targetBranch),
{ root: true },
);
}
@@ -194,7 +197,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
if (rootGetters.activeFile) {
router.push(
- `/project/${rootState.currentProjectId}/blob/${getters.branchName}/-/${rootGetters.activeFile.path}`,
+ `/project/${rootState.currentProjectId}/blob/${branchName}/-/${rootGetters.activeFile.path}`,
);
}
}
diff --git a/app/assets/javascripts/ide/stores/modules/commit/getters.js b/app/assets/javascripts/ide/stores/modules/commit/getters.js
index e421d44b6de..413c4b0110d 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/getters.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/getters.js
@@ -55,7 +55,7 @@ export const shouldHideNewMrOption = (_state, getters, _rootState, rootGetters)
rootGetters.canPushToBranch;
export const shouldDisableNewMrOption = (state, getters, rootState, rootGetters) =>
- !rootGetters.canCreateMergeRequests;
+ !rootGetters.canCreateMergeRequests || rootGetters.emptyRepo;
export const shouldCreateMR = (state, getters) =>
state.shouldCreateMR && !getters.shouldDisableNewMrOption;
diff --git a/app/assets/javascripts/mirrors/ssh_mirror.js b/app/assets/javascripts/mirrors/ssh_mirror.js
index 550e1aeeb9c..2276a723326 100644
--- a/app/assets/javascripts/mirrors/ssh_mirror.js
+++ b/app/assets/javascripts/mirrors/ssh_mirror.js
@@ -22,7 +22,6 @@ export default class SSHMirror {
this.$dropdownAuthType = this.$form.find('.js-mirror-auth-type');
this.$hiddenAuthType = this.$form.find('.js-hidden-mirror-auth-type');
- this.$wellAuthTypeChanging = this.$form.find('.js-well-changing-auth');
this.$wellPasswordAuth = this.$form.find('.js-well-password-auth');
}
diff --git a/app/assets/javascripts/monitoring/components/charts/annotations.js b/app/assets/javascripts/monitoring/components/charts/annotations.js
index cc2b2bd0900..b0c89d5e374 100644
--- a/app/assets/javascripts/monitoring/components/charts/annotations.js
+++ b/app/assets/javascripts/monitoring/components/charts/annotations.js
@@ -1,4 +1,4 @@
-import { graphTypes, symbolSizes } from '../../constants';
+import { graphTypes, symbolSizes, colorValues } from '../../constants';
/**
* Annotations and deployments are decoration layers on
@@ -40,33 +40,50 @@ export const annotationsYAxis = {
formatter: () => {},
},
};
+
/**
- * This util method check if a particular series data point
- * is of annotation type. Annotations are generally scatter
- * plot charts
+ * Fetched list of annotations are parsed into a
+ * format the eCharts accepts to draw markLines
+ *
+ * If Annotation is a single line, the `from` property
+ * has a value and the `to` is null. Because annotations
+ * only supports lines the from value does not exist yet.
+ *
*
- * @param {String} type series component type
- * @returns {Boolean}
+ * @param {Object} annotation object
+ * @returns {Object} markLine object
*/
-export const isAnnotation = type => type === graphTypes.annotationsData;
+export const parseAnnotations = ({
+ from: annotationFrom = '',
+ color = colorValues.primaryColor,
+}) => ({
+ xAxis: annotationFrom,
+ lineStyle: {
+ color,
+ },
+});
/**
- * This method currently supports only deployments. After
- * https://gitlab.com/gitlab-org/gitlab/-/issues/211418 annotations
- * support will be added in this method.
+ * This method currently generates deployments and annotations
+ * but are not used in the chart. The method calling
+ * generateAnnotationsSeries will not pass annotations until
+ * https://gitlab.com/gitlab-org/gitlab/-/issues/211330 is
+ * implemented.
*
* This method is extracted out of the charts so that
* annotation lines can be easily supported in
* the future.
*
+ * In order to make hover work, hidden annotation data points
+ * are created along with the markLines. These data points have
+ * the necessart metadata that is used to display in the tooltip.
+ *
* @param {Array} deployments deployments data
* @returns {Object} annotation series object
*/
-export const generateAnnotationsSeries = (deployments = []) => {
- if (!deployments.length) {
- return [];
- }
- const data = deployments.map(deployment => {
+export const generateAnnotationsSeries = ({ deployments = [], annotations = [] } = {}) => {
+ // deployment data points
+ const deploymentsData = deployments.map(deployment => {
return {
name: 'deployments',
value: [deployment.createdAt, annotationsYAxisCoords.pos],
@@ -78,9 +95,27 @@ export const generateAnnotationsSeries = (deployments = []) => {
};
});
+ // annotation data points
+ const annotationsData = annotations.map(annotation => {
+ return {
+ name: 'annotations',
+ value: [annotation.from, annotationsYAxisCoords.pos],
+ symbol: 'none',
+ description: annotation.description,
+ };
+ });
+
+ // annotation markLine option
+ const markLine = {
+ symbol: 'none',
+ silent: true,
+ data: annotations.map(parseAnnotations),
+ };
+
return {
type: graphTypes.annotationsData,
yAxisIndex: 1, // annotationsYAxis index
- data,
+ data: [...deploymentsData, ...annotationsData],
+ markLine,
};
};
diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue
index 73c63a0580f..e43a0131528 100644
--- a/app/assets/javascripts/monitoring/components/charts/time_series.vue
+++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue
@@ -6,9 +6,9 @@ import dateFormat from 'dateformat';
import { s__, __ } from '~/locale';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import Icon from '~/vue_shared/components/icon.vue';
-import { chartHeight, lineTypes, lineWidths, dateFormats } from '../../constants';
+import { chartHeight, lineTypes, lineWidths, dateFormats, tooltipTypes } from '../../constants';
import { getYAxisOptions, getChartGrid, getTooltipFormatter } from './options';
-import { annotationsYAxis, generateAnnotationsSeries, isAnnotation } from './annotations';
+import { annotationsYAxis, generateAnnotationsSeries } from './annotations';
import { makeDataSeries } from '~/helpers/monitor_helper';
import { graphDataValidatorForValues } from '../../utils';
@@ -20,6 +20,7 @@ const events = {
};
export default {
+ tooltipTypes,
components: {
GlAreaChart,
GlLineChart,
@@ -88,10 +89,10 @@ export default {
data() {
return {
tooltip: {
+ type: '',
title: '',
content: [],
commitUrl: '',
- isDeployment: false,
sha: '',
},
width: 0,
@@ -137,7 +138,13 @@ export default {
}, []);
},
chartOptionSeries() {
- return (this.option.series || []).concat(generateAnnotationsSeries(this.recentDeployments));
+ // After https://gitlab.com/gitlab-org/gitlab/-/issues/211330 is implemented,
+ // this method will have access to annotations data
+ return (this.option.series || []).concat(
+ generateAnnotationsSeries({
+ deployments: this.recentDeployments,
+ }),
+ );
},
chartOptions() {
const { yAxis, xAxis } = this.option;
@@ -246,6 +253,9 @@ export default {
formatLegendLabel(query) {
return `${query.label}`;
},
+ isTooltipOfType(tooltipType, defaultType) {
+ return tooltipType === defaultType;
+ },
formatTooltipText(params) {
this.tooltip.title = dateFormat(params.value, dateFormats.default);
this.tooltip.content = [];
@@ -253,13 +263,18 @@ export default {
params.seriesData.forEach(dataPoint => {
if (dataPoint.value) {
const [xVal, yVal] = dataPoint.value;
- this.tooltip.isDeployment = isAnnotation(dataPoint.componentSubType);
- if (this.tooltip.isDeployment) {
+ this.tooltip.type = dataPoint.name;
+ if (this.isTooltipOfType(this.tooltip.type, this.$options.tooltipTypes.deployments)) {
const [deploy] = this.recentDeployments.filter(
deployment => deployment.createdAt === xVal,
);
this.tooltip.sha = deploy.sha.substring(0, 8);
this.tooltip.commitUrl = deploy.commitUrl;
+ } else if (
+ this.isTooltipOfType(this.tooltip.type, this.$options.tooltipTypes.annotations)
+ ) {
+ const { data } = dataPoint;
+ this.tooltip.content.push(data?.description);
} else {
const { seriesName, color, dataIndex } = dataPoint;
@@ -288,7 +303,6 @@ export default {
onChartUpdated(eChart) {
[this.primaryColor] = eChart.getOption().color;
},
-
onChartCreated(eChart) {
// Emit a datazoom event that corresponds to the eChart
// `datazoom` event.
@@ -346,7 +360,7 @@ export default {
@created="onChartCreated"
@updated="onChartUpdated"
>
- <template v-if="tooltip.isDeployment">
+ <template v-if="isTooltipOfType(tooltip.type, this.$options.tooltipTypes.deployments)">
<template slot="tooltipTitle">
{{ __('Deployed') }}
</template>
@@ -355,29 +369,35 @@ export default {
<gl-link :href="tooltip.commitUrl">{{ tooltip.sha }}</gl-link>
</div>
</template>
+ <template v-else-if="isTooltipOfType(tooltip.type, this.$options.tooltipTypes.annotations)">
+ <template slot="tooltipTitle">
+ <div class="text-nowrap">
+ {{ tooltip.title }}
+ </div>
+ </template>
+ <div slot="tooltipContent" class="d-flex align-items-center">
+ {{ tooltip.content.join('\n') }}
+ </div>
+ </template>
<template v-else>
<template slot="tooltipTitle">
- <slot name="tooltipTitle">
- <div class="text-nowrap">
- {{ tooltip.title }}
- </div>
- </slot>
+ <div class="text-nowrap">
+ {{ tooltip.title }}
+ </div>
</template>
- <template slot="tooltipContent">
- <slot name="tooltipContent" :tooltip="tooltip">
- <div
- v-for="(content, key) in tooltip.content"
- :key="key"
- class="d-flex justify-content-between"
- >
- <gl-chart-series-label :color="isMultiSeries ? content.color : ''">
- {{ content.name }}
- </gl-chart-series-label>
- <div class="prepend-left-32">
- {{ content.value }}
- </div>
+ <template slot="tooltipContent" :tooltip="tooltip">
+ <div
+ v-for="(content, key) in tooltip.content"
+ :key="key"
+ class="d-flex justify-content-between"
+ >
+ <gl-chart-series-label :color="isMultiSeries ? content.color : ''">
+ {{ content.name }}
+ </gl-chart-series-label>
+ <div class="prepend-left-32">
+ {{ content.value }}
</div>
- </slot>
+ </div>
</template>
</template>
</component>
diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js
index e092c0ccae0..6af1d399cfc 100644
--- a/app/assets/javascripts/monitoring/constants.js
+++ b/app/assets/javascripts/monitoring/constants.js
@@ -115,3 +115,12 @@ export const NOT_IN_DB_PREFIX = 'NO_DB';
* Used as a value for the 'states' query filter
*/
export const ENVIRONMENT_AVAILABLE_STATE = 'available';
+
+/**
+ * Time series charts have different types of
+ * tooltip based on the hovered data point.
+ */
+export const tooltipTypes = {
+ deployments: 'deployments',
+ annotations: 'annotations',
+};
diff --git a/app/assets/javascripts/projects/default_project_templates.js b/app/assets/javascripts/projects/default_project_templates.js
index 37bad1efaaf..e5898c3b047 100644
--- a/app/assets/javascripts/projects/default_project_templates.js
+++ b/app/assets/javascripts/projects/default_project_templates.js
@@ -81,4 +81,8 @@ export default {
text: s__('ProjectTemplates|Serverless Framework/JS'),
icon: '.template-option .icon-serverless_framework',
},
+ cluster_management: {
+ text: s__('ProjectTemplates|GitLab Cluster Management'),
+ icon: '.template-option .icon-cluster_management',
+ },
};