diff options
Diffstat (limited to 'app/assets')
20 files changed, 112 insertions, 62 deletions
diff --git a/app/assets/javascripts/blob/file_template_selector.js b/app/assets/javascripts/blob/file_template_selector.js index 2532aeea989..a5c8050b772 100644 --- a/app/assets/javascripts/blob/file_template_selector.js +++ b/app/assets/javascripts/blob/file_template_selector.js @@ -66,6 +66,8 @@ export default class FileTemplateSelector { reportSelectionName(options) { const opts = options; opts.query = options.selectedObj.name; + opts.data = options.selectedObj; + opts.data.source_template_project_id = options.selectedObj.project_id; this.reportSelection(opts); } diff --git a/app/assets/javascripts/blob/template_selectors/license_selector.js b/app/assets/javascripts/blob/template_selectors/license_selector.js index affa20997e9..7e32ede96df 100644 --- a/app/assets/javascripts/blob/template_selectors/license_selector.js +++ b/app/assets/javascripts/blob/template_selectors/license_selector.js @@ -30,6 +30,7 @@ export default class BlobLicenseSelector extends FileTemplateSelector { const data = { project: this.$dropdown.data('project'), fullname: this.$dropdown.data('fullname'), + source_template_project_id: query.project_id, }; this.reportSelection({ diff --git a/app/assets/javascripts/boards/components/board_card_layout.vue b/app/assets/javascripts/boards/components/board_card_layout.vue index 350d709abfd..8b0265237ba 100644 --- a/app/assets/javascripts/boards/components/board_card_layout.vue +++ b/app/assets/javascripts/boards/components/board_card_layout.vue @@ -4,7 +4,7 @@ import IssueCardInnerDeprecated from './issue_card_inner_deprecated.vue'; import boardsStore from '../stores/boards_store'; export default { - name: 'BoardsIssueCard', + name: 'BoardCardLayout', components: { IssueCardInner: gon.features?.graphqlBoardLists ? IssueCardInner : IssueCardInnerDeprecated, }, @@ -81,7 +81,7 @@ export default { :data-issue-iid="issue.iid" :data-issue-path="issue.referencePath" data-testid="board_card" - class="board-card p-3 rounded" + class="board-card gl-p-5 gl-rounded-base" @mousedown="mouseDown" @mousemove="mouseMove" @mouseup="showIssue($event)" diff --git a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js index 99351231520..98858f20518 100644 --- a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js +++ b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js @@ -437,6 +437,7 @@ export class GitLabDropdown { groupName = el.data('group'); if (groupName) { selectedIndex = el.data('index'); + this.selectedIndex = selectedIndex; selectedObject = this.renderedData[groupName][selectedIndex]; } else { selectedIndex = el.closest('li').index(); diff --git a/app/assets/javascripts/editor/extensions/editor_ci_schema_ext.js b/app/assets/javascripts/editor/extensions/editor_ci_schema_ext.js index 05d938c57ce..eb47c20912e 100644 --- a/app/assets/javascripts/editor/extensions/editor_ci_schema_ext.js +++ b/app/assets/javascripts/editor/extensions/editor_ci_schema_ext.js @@ -17,15 +17,21 @@ export class CiSchemaExtension extends EditorLiteExtension { * @param {String?} opts.ref - Current ref. Defaults to master */ registerCiSchema({ projectNamespace, projectPath, ref = 'master' } = {}) { - const ciSchemaUri = Api.buildUrl(Api.projectFileSchemaPath) + const ciSchemaPath = Api.buildUrl(Api.projectFileSchemaPath) .replace(':namespace_path', projectNamespace) .replace(':project_path', projectPath) .replace(':ref', ref) .replace(':filename', EXTENSION_CI_SCHEMA_FILE_NAME_MATCH); + // In order for workers loaded from `data://` as the + // ones loaded by monaco editor, we use absolute URLs + // to fetch schema files, hence the `gon.gitlab_url` + // reference. This prevents error: + // "Failed to execute 'fetch' on 'WorkerGlobalScope'" + const absoluteSchemaUrl = gon.gitlab_url + ciSchemaPath; const modelFileName = this.getModel().uri.path.split('/').pop(); registerSchema({ - uri: ciSchemaUri, + uri: absoluteSchemaUrl, fileMatch: [modelFileName], }); } diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index 004e38b0a25..42668dec63a 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -17,15 +17,8 @@ export const closeFile = ({ commit, state, dispatch, getters }, file) => { const indexOfClosedFile = state.openFiles.findIndex((f) => f.key === file.key); const fileWasActive = file.active; - if (file.pending) { - commit(types.REMOVE_PENDING_TAB, file); - } else { - commit(types.TOGGLE_FILE_OPEN, path); - commit(types.SET_FILE_ACTIVE, { path, active: false }); - } - - if (state.openFiles.length > 0 && fileWasActive) { - const nextIndexToOpen = indexOfClosedFile === 0 ? 0 : indexOfClosedFile - 1; + if (state.openFiles.length > 1 && fileWasActive) { + const nextIndexToOpen = indexOfClosedFile === 0 ? 1 : indexOfClosedFile - 1; const nextFileToOpen = state.openFiles[nextIndexToOpen]; if (nextFileToOpen.pending) { @@ -35,14 +28,22 @@ export const closeFile = ({ commit, state, dispatch, getters }, file) => { keyPrefix: nextFileToOpen.staged ? 'staged' : 'unstaged', }); } else { + dispatch('setFileActive', nextFileToOpen.path); dispatch('router/push', getters.getUrlForPath(nextFileToOpen.path), { root: true }); } - } else if (!state.openFiles.length) { + } else if (state.openFiles.length === 1) { dispatch('router/push', `/project/${state.currentProjectId}/tree/${state.currentBranchId}/`, { root: true, }); } + if (file.pending) { + commit(types.REMOVE_PENDING_TAB, file); + } else { + commit(types.TOGGLE_FILE_OPEN, path); + commit(types.SET_FILE_ACTIVE, { path, active: false }); + } + eventHub.$emit(`editor.update.model.dispose.${file.key}`); }; diff --git a/app/assets/javascripts/incidents_settings/constants.js b/app/assets/javascripts/incidents_settings/constants.js index fcac9c519c2..818af4ecb90 100644 --- a/app/assets/javascripts/incidents_settings/constants.js +++ b/app/assets/javascripts/incidents_settings/constants.js @@ -51,7 +51,7 @@ export const NO_ISSUE_TEMPLATE_SELECTED = { key: '', name: __('No template selec export const TAKING_INCIDENT_ACTION_DOCS_LINK = '/help/operations/metrics/alerts#trigger-actions-from-alerts'; export const ISSUE_TEMPLATES_DOCS_LINK = - '/help/user/project/description_templates#creating-issue-templates'; + '/help/user/project/description_templates#create-an-issue-template'; /* PagerDuty integration settings constants */ diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index d569ad573a2..87dc31e6292 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -132,6 +132,10 @@ export default { type: String, required: true, }, + projectId: { + type: Number, + required: true, + }, projectNamespace: { type: String, required: true, @@ -303,7 +307,7 @@ export default { }); }, - updateAndShowForm(templates = []) { + updateAndShowForm(templates = {}) { if (!this.showForm) { this.showForm = true; this.store.setFormState({ @@ -419,6 +423,7 @@ export default { :markdown-docs-path="markdownDocsPath" :markdown-preview-path="markdownPreviewPath" :project-path="projectPath" + :project-id="projectId" :project-namespace="projectNamespace" :show-delete-button="showDeleteButton" :can-attach-file="canAttachFile" diff --git a/app/assets/javascripts/issue_show/components/fields/description_template.vue b/app/assets/javascripts/issue_show/components/fields/description_template.vue index 71299381aae..f23bb394683 100644 --- a/app/assets/javascripts/issue_show/components/fields/description_template.vue +++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue @@ -13,14 +13,18 @@ export default { required: true, }, issuableTemplates: { - type: Array, + type: Object, required: false, - default: () => [], + default: () => {}, }, projectPath: { type: String, required: true, }, + projectId: { + type: Number, + required: true, + }, projectNamespace: { type: String, required: true, @@ -48,11 +52,12 @@ export default { </script> <template> - <div class="dropdown js-issuable-selector-wrap" data-issuable-type="issue"> + <div class="dropdown js-issuable-selector-wrap" data-issuable-type="issues"> <button ref="toggle" :data-namespace-path="projectNamespace" :data-project-path="projectPath" + :data-project-id="projectId" :data-data="issuableTemplatesJson" class="dropdown-menu-toggle js-issuable-selector" type="button" diff --git a/app/assets/javascripts/issue_show/components/form.vue b/app/assets/javascripts/issue_show/components/form.vue index d48bf1fe7a9..9d1ce01116b 100644 --- a/app/assets/javascripts/issue_show/components/form.vue +++ b/app/assets/javascripts/issue_show/components/form.vue @@ -26,9 +26,9 @@ export default { required: true, }, issuableTemplates: { - type: Array, + type: Object, required: false, - default: () => [], + default: () => {}, }, issuableType: { type: String, @@ -46,6 +46,10 @@ export default { type: String, required: true, }, + projectId: { + type: Number, + required: true, + }, projectNamespace: { type: String, required: true, @@ -68,7 +72,7 @@ export default { }, computed: { hasIssuableTemplates() { - return this.issuableTemplates.length; + return Object.values(Object(this.issuableTemplates)).length; }, showLockedWarning() { return this.formState.lockedWarningVisible && !this.formState.updateLoading; @@ -127,6 +131,7 @@ export default { :form-state="formState" :issuable-templates="issuableTemplates" :project-path="projectPath" + :project-id="projectId" :project-namespace="projectNamespace" /> </div> diff --git a/app/assets/javascripts/issue_show/issue.js b/app/assets/javascripts/issue_show/issue.js index 83fd1355f26..a93abbf64df 100644 --- a/app/assets/javascripts/issue_show/issue.js +++ b/app/assets/javascripts/issue_show/issue.js @@ -54,6 +54,7 @@ export function initIssueHeaderActions(store) { issueType: el.dataset.issueType, newIssuePath: el.dataset.newIssuePath, projectPath: el.dataset.projectPath, + projectId: el.dataset.projectId, reportAbusePath: el.dataset.reportAbusePath, submitAsSpamPath: el.dataset.submitAsSpamPath, }, diff --git a/app/assets/javascripts/issue_show/stores/index.js b/app/assets/javascripts/issue_show/stores/index.js index 06bbd406e3a..a50913d3455 100644 --- a/app/assets/javascripts/issue_show/stores/index.js +++ b/app/assets/javascripts/issue_show/stores/index.js @@ -11,7 +11,7 @@ export default class Store { lockedWarningVisible: false, updateLoading: false, lock_version: 0, - issuableTemplates: [], + issuableTemplates: {}, }; } diff --git a/app/assets/javascripts/pipeline_editor/components/lint/ci_lint.vue b/app/assets/javascripts/pipeline_editor/components/lint/ci_lint.vue index 22f734be5aa..b27ab9a39d3 100644 --- a/app/assets/javascripts/pipeline_editor/components/lint/ci_lint.vue +++ b/app/assets/javascripts/pipeline_editor/components/lint/ci_lint.vue @@ -1,4 +1,5 @@ <script> +import { flatten } from 'lodash'; import { CI_CONFIG_STATUS_VALID } from '../../constants'; import CiLintResults from './ci_lint_results.vue'; @@ -25,14 +26,18 @@ export default { return this.ciConfig?.stages || []; }, jobs() { - return this.stages.reduce((acc, { groups, name: stageName }) => { + const groupedJobs = this.stages.reduce((acc, { groups, name: stageName }) => { return acc.concat( - groups.map(({ name: groupName }) => ({ - stage: stageName, - name: groupName, - })), + groups.map(({ jobs }) => { + return jobs.map((job) => ({ + stage: stageName, + ...job, + })); + }), ); }, []); + + return flatten(groupedJobs); }, }, }; diff --git a/app/assets/javascripts/pipeline_editor/components/lint/ci_lint_results_value.vue b/app/assets/javascripts/pipeline_editor/components/lint/ci_lint_results_value.vue index 6c7e03e4920..e2529613844 100644 --- a/app/assets/javascripts/pipeline_editor/components/lint/ci_lint_results_value.vue +++ b/app/assets/javascripts/pipeline_editor/components/lint/ci_lint_results_value.vue @@ -14,7 +14,7 @@ export default { }, computed: { tagList() { - return this.item.tagList?.join(', '); + return this.item.tags?.join(', '); }, onlyPolicy() { return this.item.only ? this.item.only.refs.join(', ') : this.item.only; diff --git a/app/assets/javascripts/pipeline_editor/graphql/mutations/lint_ci.mutation.graphql b/app/assets/javascripts/pipeline_editor/graphql/mutations/lint_ci.mutation.graphql index 496036f690f..5091d63111f 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/mutations/lint_ci.mutation.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/mutations/lint_ci.mutation.graphql @@ -15,7 +15,7 @@ mutation lintCI($endpoint: String, $content: String, $dry: Boolean) { } afterScript stage - tagList + tags when } } diff --git a/app/assets/javascripts/pipeline_editor/graphql/resolvers.js b/app/assets/javascripts/pipeline_editor/graphql/resolvers.js index ec55191c946..81e75c32846 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/resolvers.js +++ b/app/assets/javascripts/pipeline_editor/graphql/resolvers.js @@ -27,7 +27,7 @@ export const resolvers = { beforeScript: job.before_script, script: job.script, afterScript: job.after_script, - tagList: job.tag_list, + tags: job.tag_list, environment: job.environment, when: job.when, allowFailure: job.allow_failure, diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue index 9217466a0b5..d6884ae121f 100644 --- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue +++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue @@ -3,6 +3,7 @@ import { GlAlert, GlLoadingIcon, GlTabs, GlTab } from '@gitlab/ui'; import { __, s__, sprintf } from '~/locale'; import { mergeUrlParams, redirectTo } from '~/lib/utils/url_utility'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import httpStatusCodes from '~/lib/utils/http_status'; import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue'; import CiLint from './components/lint/ci_lint.vue'; @@ -23,7 +24,6 @@ const COMMIT_FAILURE = 'COMMIT_FAILURE'; const COMMIT_SUCCESS = 'COMMIT_SUCCESS'; const DEFAULT_FAILURE = 'DEFAULT_FAILURE'; const LOAD_FAILURE_NO_FILE = 'LOAD_FAILURE_NO_FILE'; -const LOAD_FAILURE_NO_REF = 'LOAD_FAILURE_NO_REF'; const LOAD_FAILURE_UNKNOWN = 'LOAD_FAILURE_UNKNOWN'; export default { @@ -125,6 +125,9 @@ export default { isBlobContentLoading() { return this.$apollo.queries.content.loading; }, + isBlobContentError() { + return this.failureType === LOAD_FAILURE_NO_FILE || this.failureType === LOAD_FAILURE_UNKNOWN; + }, isCiConfigDataLoading() { return this.$apollo.queries.ciConfigData.loading; }, @@ -144,14 +147,11 @@ export default { }, failure() { switch (this.failureType) { - case LOAD_FAILURE_NO_REF: - return { - text: this.$options.alertTexts[LOAD_FAILURE_NO_REF], - variant: 'danger', - }; case LOAD_FAILURE_NO_FILE: return { - text: this.$options.alertTexts[LOAD_FAILURE_NO_FILE], + text: sprintf(this.$options.alertTexts[LOAD_FAILURE_NO_FILE], { + filePath: this.ciConfigPath, + }), variant: 'danger', }; case LOAD_FAILURE_UNKNOWN: @@ -182,9 +182,8 @@ export default { [COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'), [COMMIT_SUCCESS]: __('Your changes have been successfully committed.'), [DEFAULT_FAILURE]: __('Something went wrong on our end.'), - [LOAD_FAILURE_NO_FILE]: s__('Pipelines|No CI file found in this repository, please add one.'), - [LOAD_FAILURE_NO_REF]: s__( - 'Pipelines|Repository does not have a default branch, please set one.', + [LOAD_FAILURE_NO_FILE]: s__( + 'Pipelines|There is no %{filePath} file in this repository, please add one and visit the Pipeline Editor again.', ), [LOAD_FAILURE_UNKNOWN]: s__('Pipelines|The CI configuration was not loaded, please try again.'), }, @@ -193,12 +192,13 @@ export default { const { networkError } = error; const { response } = networkError; - if (response?.status === 404) { - // 404 for missing CI file + // 404 for missing CI file + // 400 for blank projects with no repository + if ( + response?.status === httpStatusCodes.NOT_FOUND || + response?.status === httpStatusCodes.BAD_REQUEST + ) { this.reportFailure(LOAD_FAILURE_NO_FILE); - } else if (response?.status === 400) { - // 400 for a missing ref when no default branch is set - this.reportFailure(LOAD_FAILURE_NO_REF); } else { this.reportFailure(LOAD_FAILURE_UNKNOWN); } @@ -299,9 +299,9 @@ export default { <li v-for="reason in failureReasons" :key="reason">{{ reason }}</li> </ul> </gl-alert> - <div class="gl-mt-4"> - <gl-loading-icon v-if="isBlobContentLoading" size="lg" class="gl-m-3" /> - <div v-else class="file-editor gl-mb-3"> + <gl-loading-icon v-if="isBlobContentLoading" size="lg" class="gl-m-3" /> + <div v-else-if="!isBlobContentError" class="gl-mt-4"> + <div class="file-editor gl-mb-3"> <div class="info-well gl-display-none gl-display-sm-block"> <validation-segment class="well-segment" diff --git a/app/assets/javascripts/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql b/app/assets/javascripts/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql index 683e0ee6a14..f93908aeb04 100644 --- a/app/assets/javascripts/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql +++ b/app/assets/javascripts/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql @@ -8,6 +8,19 @@ fragment PipelineStagesConnection on CiConfigStageConnection { jobs { nodes { name + script + beforeScript + afterScript + environment + allowFailure + tags + when + only { + refs + } + except { + refs + } needs { nodes { name diff --git a/app/assets/javascripts/templates/issuable_template_selector.js b/app/assets/javascripts/templates/issuable_template_selector.js index 22bbd083a5d..bcae79c9679 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js +++ b/app/assets/javascripts/templates/issuable_template_selector.js @@ -9,6 +9,7 @@ export default class IssuableTemplateSelector extends TemplateSelector { constructor(...args) { super(...args); + this.projectId = this.dropdown.data('projectId'); this.projectPath = this.dropdown.data('projectPath'); this.namespacePath = this.dropdown.data('namespacePath'); this.issuableType = this.$dropdownContainer.data('issuableType'); @@ -81,21 +82,21 @@ export default class IssuableTemplateSelector extends TemplateSelector { } requestFile(query) { + const callback = (currentTemplate) => { + this.currentTemplate = currentTemplate; + this.stopLoadingSpinner(); + this.setInputValueToTemplateContent(); + }; + this.startLoadingSpinner(); - Api.issueTemplate( - this.namespacePath, - this.projectPath, - query.name, + Api.projectTemplate( + this.projectId, this.issuableType, - (err, currentTemplate) => { - this.currentTemplate = currentTemplate; - this.stopLoadingSpinner(); - if (err) return; // Error handled by global AJAX error handler - this.setInputValueToTemplateContent(); - }, + query.name, + { source_template_project_id: query.project_id }, + callback, ); - return; } setInputValueToTemplateContent() { diff --git a/app/assets/stylesheets/page_bundles/oncall_schedules.scss b/app/assets/stylesheets/page_bundles/oncall_schedules.scss index c7e90ba3451..2ab3bdcc474 100644 --- a/app/assets/stylesheets/page_bundles/oncall_schedules.scss +++ b/app/assets/stylesheets/page_bundles/oncall_schedules.scss @@ -32,13 +32,17 @@ .rotations-modal { .gl-card { min-width: 75%; - width: fit-content; - @include gl-bg-gray-10; } &.gl-modal .modal-md { max-width: 640px; } + + // TODO: move to gitlab/ui utilities + // https://gitlab.com/gitlab-org/gitlab/-/issues/297502 + .gl-w-fit-content { + width: fit-content; + } } //// Copied from roadmaps.scss - adapted for on-call schedules |