Commit 6f7a8485 authored by Frédéric Caplette's avatar Frédéric Caplette

Fix pipeline editor crashing the browser when getting a 500 error

Removes the error state in apollo cache which caused the
update hook of the query to be retrigger indefinitly.

Changelog: fixed
parent 88828963
......@@ -75,7 +75,7 @@ export default {
return this.$options.i18n.valid;
default:
// Only display first error as a reason
return this.ciConfig?.errors.length > 0
return this.ciConfig?.errors?.length > 0
? sprintf(this.$options.i18n.invalidWithReason, { reason }, false)
: this.$options.i18n.invalid;
}
......
......@@ -7,7 +7,6 @@ import { getParameterValues, setUrlParams, updateHistory } from '~/lib/utils/url
import {
CREATE_TAB,
EDITOR_APP_STATUS_EMPTY,
EDITOR_APP_STATUS_ERROR,
EDITOR_APP_STATUS_INVALID,
EDITOR_APP_STATUS_LOADING,
EDITOR_APP_STATUS_VALID,
......@@ -87,9 +86,8 @@ export default {
},
},
computed: {
hasAppError() {
// Not an invalid config and with `mergedYaml` data missing
return this.appStatus === EDITOR_APP_STATUS_ERROR;
isMergedYamlAvailable() {
return this.ciConfigData?.mergedYaml;
},
isEmpty() {
return this.appStatus === EDITOR_APP_STATUS_EMPTY;
......@@ -183,7 +181,7 @@ export default {
@click="setCurrentTab($options.tabConstants.MERGED_TAB)"
>
<gl-loading-icon v-if="isLoading" size="lg" class="gl-m-3" />
<gl-alert v-else-if="hasAppError" variant="danger" :dismissible="false">
<gl-alert v-else-if="!isMergedYamlAvailable" variant="danger" :dismissible="false">
{{ $options.errorTexts.loadMergedYaml }}
</gl-alert>
<ci-config-merged-preview v-else :ci-config-data="ciConfigData" v-on="$listeners" />
......
......@@ -5,11 +5,17 @@ export const CI_CONFIG_STATUS_VALID = 'VALID';
// Values for EDITOR_APP_STATUS_* are frontend specifics and
// represent the global state of the pipeline editor app.
export const EDITOR_APP_STATUS_EMPTY = 'EMPTY';
export const EDITOR_APP_STATUS_ERROR = 'ERROR';
export const EDITOR_APP_STATUS_INVALID = CI_CONFIG_STATUS_INVALID;
export const EDITOR_APP_STATUS_LOADING = 'LOADING';
export const EDITOR_APP_STATUS_VALID = CI_CONFIG_STATUS_VALID;
export const EDITOR_APP_VALID_STATUSES = [
EDITOR_APP_STATUS_EMPTY,
EDITOR_APP_STATUS_INVALID,
EDITOR_APP_STATUS_LOADING,
EDITOR_APP_STATUS_VALID,
];
export const COMMIT_FAILURE = 'COMMIT_FAILURE';
export const COMMIT_SUCCESS = 'COMMIT_SUCCESS';
......
......@@ -12,7 +12,7 @@ import PipelineEditorMessages from './components/ui/pipeline_editor_messages.vue
import {
COMMIT_SHA_POLL_INTERVAL,
EDITOR_APP_STATUS_EMPTY,
EDITOR_APP_STATUS_ERROR,
EDITOR_APP_VALID_STATUSES,
EDITOR_APP_STATUS_LOADING,
LOAD_FAILURE_UNKNOWN,
STARTER_TEMPLATE_NAME,
......@@ -141,10 +141,10 @@ export default {
return { ...ciConfig, stages };
},
result({ data }) {
this.setAppStatus(data?.ciConfig?.status || EDITOR_APP_STATUS_ERROR);
this.setAppStatus(data?.ciConfig?.status);
},
error() {
this.reportFailure(LOAD_FAILURE_UNKNOWN);
error(err) {
this.reportFailure(LOAD_FAILURE_UNKNOWN, [String(err)]);
},
watchLoading(isLoading) {
if (isLoading) {
......@@ -242,8 +242,6 @@ export default {
await this.$apollo.queries.initialCiFileContent.refetch();
},
reportFailure(type, reasons = []) {
this.setAppStatus(EDITOR_APP_STATUS_ERROR);
window.scrollTo({ top: 0, behavior: 'smooth' });
this.showFailure = true;
this.failureType = type;
......@@ -258,7 +256,9 @@ export default {
this.currentCiFileContent = this.lastCommittedContent;
},
setAppStatus(appStatus) {
this.$apollo.mutate({ mutation: updateAppStatus, variables: { appStatus } });
if (EDITOR_APP_VALID_STATUSES.includes(appStatus)) {
this.$apollo.mutate({ mutation: updateAppStatus, variables: { appStatus } });
}
},
setNewEmptyCiConfigFile() {
this.isNewCiConfigFile = true;
......
......@@ -9,7 +9,6 @@ import EditorTab from '~/pipeline_editor/components/ui/editor_tab.vue';
import {
CREATE_TAB,
EDITOR_APP_STATUS_EMPTY,
EDITOR_APP_STATUS_ERROR,
EDITOR_APP_STATUS_LOADING,
EDITOR_APP_STATUS_INVALID,
EDITOR_APP_STATUS_VALID,
......@@ -18,7 +17,7 @@ import {
TABS_INDEX,
} from '~/pipeline_editor/constants';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import { mockLintResponse, mockCiYml } from '../mock_data';
import { mockLintResponse, mockLintResponseWithoutMerged, mockCiYml } from '../mock_data';
describe('Pipeline editor tabs component', () => {
let wrapper;
......@@ -143,7 +142,7 @@ describe('Pipeline editor tabs component', () => {
describe('when there is a fetch error', () => {
beforeEach(() => {
createComponent({ appStatus: EDITOR_APP_STATUS_ERROR });
createComponent({ props: { ciConfigData: mockLintResponseWithoutMerged } });
});
it('show an error message', () => {
......
import { CI_CONFIG_STATUS_VALID } from '~/pipeline_editor/constants';
import { CI_CONFIG_STATUS_INVALID, CI_CONFIG_STATUS_VALID } from '~/pipeline_editor/constants';
import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils';
export const mockProjectNamespace = 'user1';
......@@ -393,6 +393,14 @@ export const mockLintResponse = {
],
};
export const mockLintResponseWithoutMerged = {
valid: false,
status: CI_CONFIG_STATUS_INVALID,
errors: ['error'],
warnings: [],
jobs: [],
};
export const mockJobs = [
{
name: 'job_1',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment