diff options
Diffstat (limited to 'app/assets/javascripts/ide')
44 files changed, 772 insertions, 291 deletions
diff --git a/app/assets/javascripts/ide/components/changed_file_icon.vue b/app/assets/javascripts/ide/components/changed_file_icon.vue index 1cec84706fc..a4e06bbbe3c 100644 --- a/app/assets/javascripts/ide/components/changed_file_icon.vue +++ b/app/assets/javascripts/ide/components/changed_file_icon.vue @@ -43,7 +43,7 @@ export default { return `${this.changedIcon}-solid`; }, changedIconClass() { - return `multi-${this.changedIcon} pull-left`; + return `multi-${this.changedIcon} float-left`; }, tooltipTitle() { if (!this.showTooltip) return undefined; diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue index 81961fe3c57..e2b42ab2642 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue @@ -126,7 +126,6 @@ export default { </div> <form v-if="!isCompact" - class="form-horizontal" @submit.prevent.stop="commitChanges" ref="formEl" > @@ -144,14 +143,14 @@ export default { <loading-button :loading="submitCommitLoading" :disabled="commitButtonDisabled" - container-class="btn btn-success btn-sm pull-left" + container-class="btn btn-success btn-sm float-left" :label="__('Commit')" @click="commitChanges" /> <button v-if="!discardDraftButtonDisabled" type="button" - class="btn btn-default btn-sm pull-right" + class="btn btn-default btn-sm float-right" @click="discardDraft" > {{ __('Discard draft') }} @@ -159,7 +158,7 @@ export default { <button v-else type="button" - class="btn btn-default btn-sm pull-right" + class="btn btn-default btn-sm float-right" @click="toggleIsSmall" > {{ __('Collapse') }} diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list.vue b/app/assets/javascripts/ide/components/commit_sidebar/list.vue index c3ac18bfb83..1325fc993b2 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list.vue @@ -120,7 +120,7 @@ export default { </ul> <p v-else - class="multi-file-commit-list help-block" + class="multi-file-commit-list form-text text-muted" > {{ __('No changes') }} </p> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue index dcd934f76b7..0ac0af2feaa 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue @@ -54,7 +54,7 @@ export default { placement: 'top', content: sprintf( __(` - The character highligher helps you keep the subject line to %{titleLength} characters + The character highlighter helps you keep the subject line to %{titleLength} characters and wrap the body at %{bodyLength} so they are readable in git. `), { titleLength: MAX_TITLE_LENGTH, bodyLength: MAX_BODY_LENGTH }, @@ -80,7 +80,7 @@ export default { {{ __('Commit Message') }} <span v-popover="$options.popoverOptions" - class="help-block prepend-left-10" + class="form-text text-muted prepend-left-10" > <icon name="question" diff --git a/app/assets/javascripts/ide/components/external_link.vue b/app/assets/javascripts/ide/components/external_link.vue new file mode 100644 index 00000000000..cf3316a8179 --- /dev/null +++ b/app/assets/javascripts/ide/components/external_link.vue @@ -0,0 +1,41 @@ +<script> +import Icon from '~/vue_shared/components/icon.vue'; + +export default { + components: { + Icon, + }, + props: { + file: { + type: Object, + required: true, + }, + }, + computed: { + showButtons() { + return this.file.permalink; + }, + }, +}; +</script> + +<template> + <div + v-if="showButtons" + class="pull-right ide-btn-group" + > + <a + :href="file.permalink" + target="_blank" + :title="s__('IDE|Open in file view')" + rel="noopener noreferrer" + > + <span class="vertical-align-middle">Open in file view</span> + <icon + name="external-link" + css-classes="vertical-align-middle space-right" + :size="16" + /> + </a> + </div> +</template> diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index 2c184ea726c..f5f832521c5 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -6,6 +6,7 @@ import RepoTabs from './repo_tabs.vue'; import IdeStatusBar from './ide_status_bar.vue'; import RepoEditor from './repo_editor.vue'; import FindFile from './file_finder/index.vue'; +import RightPane from './panes/right.vue'; const originalStopCallback = Mousetrap.stopCallback; @@ -16,6 +17,7 @@ export default { IdeStatusBar, RepoEditor, FindFile, + RightPane, }, computed: { ...mapState([ @@ -25,6 +27,7 @@ export default { 'currentMergeRequestId', 'fileFindVisible', 'emptyStateSvgPath', + 'currentProjectId', ]), ...mapGetters(['activeFile', 'hasChanges']), }, @@ -122,6 +125,9 @@ export default { </div> </template> </div> + <right-pane + v-if="currentProjectId" + /> </div> <ide-status-bar :file="activeFile"/> </article> diff --git a/app/assets/javascripts/ide/components/ide_file_buttons.vue b/app/assets/javascripts/ide/components/ide_file_buttons.vue deleted file mode 100644 index 30b00abf6ed..00000000000 --- a/app/assets/javascripts/ide/components/ide_file_buttons.vue +++ /dev/null @@ -1,84 +0,0 @@ -<script> -import { __ } from '~/locale'; -import tooltip from '~/vue_shared/directives/tooltip'; -import Icon from '~/vue_shared/components/icon.vue'; - -export default { - components: { - Icon, - }, - directives: { - tooltip, - }, - props: { - file: { - type: Object, - required: true, - }, - }, - computed: { - showButtons() { - return ( - this.file.rawPath || this.file.blamePath || this.file.commitsPath || this.file.permalink - ); - }, - rawDownloadButtonLabel() { - return this.file.binary ? __('Download') : __('Raw'); - }, - }, -}; -</script> - -<template> - <div - v-if="showButtons" - class="float-right ide-btn-group" - > - <a - v-tooltip - v-if="!file.binary" - :href="file.blamePath" - :title="__('Blame')" - class="btn btn-sm btn-transparent blame" - > - <icon - name="blame" - :size="16" - /> - </a> - <a - v-tooltip - :href="file.commitsPath" - :title="__('History')" - class="btn btn-sm btn-transparent history" - > - <icon - name="history" - :size="16" - /> - </a> - <a - v-tooltip - :href="file.permalink" - :title="__('Permalink')" - class="btn btn-sm btn-transparent permalink" - > - <icon - name="link" - :size="16" - /> - </a> - <a - v-tooltip - :href="file.rawPath" - target="_blank" - class="btn btn-sm btn-transparent prepend-left-10 raw" - rel="noopener noreferrer" - :title="rawDownloadButtonLabel"> - <icon - name="download" - :size="16" - /> - </a> - </div> -</template> diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue index 6f60cfbf184..368a2995ed9 100644 --- a/app/assets/javascripts/ide/components/ide_status_bar.vue +++ b/app/assets/javascripts/ide/components/ide_status_bar.vue @@ -31,6 +31,7 @@ export default { computed: { ...mapState(['currentBranchId', 'currentProjectId']), ...mapGetters(['currentProject', 'lastCommit']), + ...mapState('pipelines', ['latestPipeline']), }, watch: { lastCommit() { @@ -51,14 +52,14 @@ export default { } }, methods: { - ...mapActions(['pipelinePoll', 'stopPipelinePolling']), + ...mapActions('pipelines', ['fetchLatestPipeline', 'stopPipelinePolling']), startTimer() { this.intervalId = setInterval(() => { this.commitAgeUpdate(); }, 1000); }, initPipelinePolling() { - this.pipelinePoll(); + this.fetchLatestPipeline(); this.isPollingInitialized = true; }, commitAgeUpdate() { @@ -81,18 +82,18 @@ export default { > <span class="ide-status-pipeline" - v-if="lastCommit.pipeline && lastCommit.pipeline.details" + v-if="latestPipeline && latestPipeline.details" > <ci-icon - :status="lastCommit.pipeline.details.status" + :status="latestPipeline.details.status" v-tooltip - :title="lastCommit.pipeline.details.status.text" + :title="latestPipeline.details.status.text" /> Pipeline <a class="monospace" - :href="lastCommit.pipeline.details.status.details_path">#{{ lastCommit.pipeline.id }}</a> - {{ lastCommit.pipeline.details.status.text }} + :href="latestPipeline.details.status.details_path">#{{ latestPipeline.id }}</a> + {{ latestPipeline.details.status.text }} for </span> diff --git a/app/assets/javascripts/ide/components/jobs/item.vue b/app/assets/javascripts/ide/components/jobs/item.vue new file mode 100644 index 00000000000..c33936021d4 --- /dev/null +++ b/app/assets/javascripts/ide/components/jobs/item.vue @@ -0,0 +1,46 @@ +<script> +import Icon from '../../../vue_shared/components/icon.vue'; +import CiIcon from '../../../vue_shared/components/ci_icon.vue'; + +export default { + components: { + Icon, + CiIcon, + }, + props: { + job: { + type: Object, + required: true, + }, + }, + computed: { + jobId() { + return `#${this.job.id}`; + }, + }, +}; +</script> + +<template> + <div class="ide-job-item"> + <ci-icon + :status="job.status" + :borderless="true" + :size="24" + /> + <span class="prepend-left-8"> + {{ job.name }} + <a + :href="job.path" + target="_blank" + class="ide-external-link" + > + {{ jobId }} + <icon + name="external-link" + :size="12" + /> + </a> + </span> + </div> +</template> diff --git a/app/assets/javascripts/ide/components/jobs/list.vue b/app/assets/javascripts/ide/components/jobs/list.vue new file mode 100644 index 00000000000..bdd0364c9b9 --- /dev/null +++ b/app/assets/javascripts/ide/components/jobs/list.vue @@ -0,0 +1,44 @@ +<script> +import { mapActions } from 'vuex'; +import LoadingIcon from '../../../vue_shared/components/loading_icon.vue'; +import Stage from './stage.vue'; + +export default { + components: { + LoadingIcon, + Stage, + }, + props: { + stages: { + type: Array, + required: true, + }, + loading: { + type: Boolean, + required: true, + }, + }, + methods: { + ...mapActions('pipelines', ['fetchJobs', 'toggleStageCollapsed']), + }, +}; +</script> + +<template> + <div> + <loading-icon + v-if="loading && !stages.length" + class="prepend-top-default" + size="2" + /> + <template v-else> + <stage + v-for="stage in stages" + :key="stage.id" + :stage="stage" + @fetch="fetchJobs" + @toggleCollapsed="toggleStageCollapsed" + /> + </template> + </div> +</template> diff --git a/app/assets/javascripts/ide/components/jobs/stage.vue b/app/assets/javascripts/ide/components/jobs/stage.vue new file mode 100644 index 00000000000..5b24bb1f5a7 --- /dev/null +++ b/app/assets/javascripts/ide/components/jobs/stage.vue @@ -0,0 +1,108 @@ +<script> +import tooltip from '../../../vue_shared/directives/tooltip'; +import Icon from '../../../vue_shared/components/icon.vue'; +import CiIcon from '../../../vue_shared/components/ci_icon.vue'; +import LoadingIcon from '../../../vue_shared/components/loading_icon.vue'; +import Item from './item.vue'; + +export default { + directives: { + tooltip, + }, + components: { + Icon, + CiIcon, + LoadingIcon, + Item, + }, + props: { + stage: { + type: Object, + required: true, + }, + }, + data() { + return { + showTooltip: false, + }; + }, + computed: { + collapseIcon() { + return this.stage.isCollapsed ? 'angle-left' : 'angle-down'; + }, + showLoadingIcon() { + return this.stage.isLoading && !this.stage.jobs.length; + }, + jobsCount() { + return this.stage.jobs.length; + }, + }, + mounted() { + const { stageTitle } = this.$refs; + + this.showTooltip = stageTitle.scrollWidth > stageTitle.offsetWidth; + + this.$emit('fetch', this.stage); + }, + methods: { + toggleCollapsed() { + this.$emit('toggleCollapsed', this.stage.id); + }, + }, +}; +</script> + +<template> + <div + class="ide-stage card prepend-top-default" + > + <div + class="card-header" + :class="{ + 'border-bottom-0': stage.isCollapsed + }" + @click="toggleCollapsed" + > + <ci-icon + :status="stage.status" + :size="24" + /> + <strong + v-tooltip="showTooltip" + :title="showTooltip ? stage.name : null" + data-container="body" + class="prepend-left-8 ide-stage-title" + ref="stageTitle" + > + {{ stage.name }} + </strong> + <div + v-if="!stage.isLoading || stage.jobs.length" + class="append-right-8 prepend-left-4" + > + <span class="badge badge-pill"> + {{ jobsCount }} + </span> + </div> + <icon + :name="collapseIcon" + css-classes="ide-stage-collapse-icon" + /> + </div> + <div + class="card-body" + v-show="!stage.isCollapsed" + > + <loading-icon + v-if="showLoadingIcon" + /> + <template v-else> + <item + v-for="job in stage.jobs" + :key="job.id" + :job="job" + /> + </template> + </div> + </div> +</template> diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue index d83a90f71e1..dd2800179ff 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue @@ -72,21 +72,19 @@ export default { <form slot="body" @submit.prevent="createEntryInStore" - class="form-group row append-bottom-0" + class="form-group row" > - <fieldset class="form-group append-bottom-0"> - <label class="label-light col-form-label col-sm-3 ide-new-modal-label"> - {{ __('Name') }} - </label> - <div class="col-sm-9"> - <input - type="text" - class="form-control" - v-model="entryName" - ref="fieldName" - /> - </div> - </fieldset> + <label class="label-light col-form-label col-sm-3"> + {{ __('Name') }} + </label> + <div class="col-sm-9"> + <input + type="text" + class="form-control" + v-model="entryName" + ref="fieldName" + /> + </div> </form> </deprecated-modal> </template> diff --git a/app/assets/javascripts/ide/components/panes/right.vue b/app/assets/javascripts/ide/components/panes/right.vue new file mode 100644 index 00000000000..703c4a70cfa --- /dev/null +++ b/app/assets/javascripts/ide/components/panes/right.vue @@ -0,0 +1,65 @@ +<script> +import { mapActions, mapState } from 'vuex'; +import tooltip from '../../../vue_shared/directives/tooltip'; +import Icon from '../../../vue_shared/components/icon.vue'; +import { rightSidebarViews } from '../../constants'; +import PipelinesList from '../pipelines/list.vue'; + +export default { + directives: { + tooltip, + }, + components: { + Icon, + PipelinesList, + }, + computed: { + ...mapState(['rightPane']), + }, + methods: { + ...mapActions(['setRightPane']), + clickTab(e, view) { + e.target.blur(); + + this.setRightPane(view); + }, + }, + rightSidebarViews, +}; +</script> + +<template> + <div + class="multi-file-commit-panel ide-right-sidebar" + > + <div + class="multi-file-commit-panel-inner" + v-if="rightPane" + > + <component :is="rightPane" /> + </div> + <nav class="ide-activity-bar"> + <ul class="list-unstyled"> + <li> + <button + v-tooltip + data-container="body" + data-placement="left" + :title="__('Pipelines')" + class="ide-sidebar-link is-right" + :class="{ + active: rightPane === $options.rightSidebarViews.pipelines + }" + type="button" + @click="clickTab($event, $options.rightSidebarViews.pipelines)" + > + <icon + :size="16" + name="pipeline" + /> + </button> + </li> + </ul> + </nav> + </div> +</template> diff --git a/app/assets/javascripts/ide/components/pipelines/list.vue b/app/assets/javascripts/ide/components/pipelines/list.vue new file mode 100644 index 00000000000..06455fac439 --- /dev/null +++ b/app/assets/javascripts/ide/components/pipelines/list.vue @@ -0,0 +1,146 @@ +<script> +import { mapActions, mapGetters, mapState } from 'vuex'; +import _ from 'underscore'; +import { sprintf, __ } from '../../../locale'; +import LoadingIcon from '../../../vue_shared/components/loading_icon.vue'; +import Icon from '../../../vue_shared/components/icon.vue'; +import CiIcon from '../../../vue_shared/components/ci_icon.vue'; +import Tabs from '../../../vue_shared/components/tabs/tabs'; +import Tab from '../../../vue_shared/components/tabs/tab.vue'; +import EmptyState from '../../../pipelines/components/empty_state.vue'; +import JobsList from '../jobs/list.vue'; + +export default { + components: { + LoadingIcon, + Icon, + CiIcon, + Tabs, + Tab, + JobsList, + EmptyState, + }, + computed: { + ...mapState(['pipelinesEmptyStateSvgPath', 'links']), + ...mapGetters(['currentProject']), + ...mapGetters('pipelines', ['jobsCount', 'failedJobsCount', 'failedStages', 'pipelineFailed']), + ...mapState('pipelines', ['isLoadingPipeline', 'latestPipeline', 'stages', 'isLoadingJobs']), + ciLintText() { + return sprintf( + __('You can also test your .gitlab-ci.yml in the %{linkStart}Lint%{linkEnd}'), + { + linkStart: `<a href="${_.escape(this.currentProject.web_url)}/-/ci/lint">`, + linkEnd: '</a>', + }, + false, + ); + }, + showLoadingIcon() { + return this.isLoadingPipeline && this.latestPipeline === null; + }, + }, + created() { + this.fetchLatestPipeline(); + }, + methods: { + ...mapActions('pipelines', ['fetchLatestPipeline']), + }, +}; +</script> + +<template> + <div class="ide-pipeline"> + <loading-icon + v-if="showLoadingIcon" + class="prepend-top-default" + size="2" + /> + <template v-else-if="latestPipeline !== null"> + <header + v-if="latestPipeline" + class="ide-tree-header ide-pipeline-header" + > + <ci-icon + :status="latestPipeline.details.status" + :size="24" + /> + <span class="prepend-left-8"> + <strong> + {{ __('Pipeline') }} + </strong> + <a + :href="latestPipeline.path" + target="_blank" + class="ide-external-link" + > + #{{ latestPipeline.id }} + <icon + name="external-link" + :size="12" + /> + </a> + </span> + </header> + <empty-state + v-if="latestPipeline === false" + :help-page-path="links.ciHelpPagePath" + :empty-state-svg-path="pipelinesEmptyStateSvgPath" + :can-set-ci="true" + /> + <div + v-else-if="latestPipeline.yamlError" + class="bs-callout bs-callout-danger" + > + <p class="append-bottom-0"> + {{ __('Found errors in your .gitlab-ci.yml:') }} + </p> + <p class="append-bottom-0"> + {{ latestPipeline.yamlError }} + </p> + <p + class="append-bottom-0" + v-html="ciLintText" + ></p> + </div> + <tabs + v-else + class="ide-pipeline-list" + > + <tab + :active="!pipelineFailed" + > + <template slot="title"> + {{ __('Jobs') }} + <span + v-if="jobsCount" + class="badge badge-pill" + > + {{ jobsCount }} + </span> + </template> + <jobs-list + :loading="isLoadingJobs" + :stages="stages" + /> + </tab> + <tab + :active="pipelineFailed" + > + <template slot="title"> + {{ __('Failed Jobs') }} + <span + v-if="failedJobsCount" + class="badge badge-pill" + > + {{ failedJobsCount }} + </span> + </template> + <jobs-list + :loading="isLoadingJobs" + :stages="failedStages" + /> + </tab> + </tabs> + </template> + </div> +</template> diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index a281ecb95c8..93453989c08 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -6,12 +6,12 @@ import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer import { activityBarViews, viewerTypes } from '../constants'; import monacoLoader from '../monaco_loader'; import Editor from '../lib/editor'; -import IdeFileButtons from './ide_file_buttons.vue'; +import ExternalLink from './external_link.vue'; export default { components: { ContentViewer, - IdeFileButtons, + ExternalLink, }, props: { file: { @@ -224,7 +224,7 @@ export default { </a> </li> </ul> - <ide-file-buttons + <external-link :file="file" /> </div> diff --git a/app/assets/javascripts/ide/components/repo_file.vue b/app/assets/javascripts/ide/components/repo_file.vue index 442697e1c80..f56aeced806 100644 --- a/app/assets/javascripts/ide/components/repo_file.vue +++ b/app/assets/javascripts/ide/components/repo_file.vue @@ -169,7 +169,7 @@ export default { :show-tooltip="true" :show-staged-icon="true" :force-modified-icon="true" - class="pull-right" + class="float-right" /> </span> <new-dropdown diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js index 83fe22f40a4..33cd20caf52 100644 --- a/app/assets/javascripts/ide/constants.js +++ b/app/assets/javascripts/ide/constants.js @@ -20,3 +20,7 @@ export const viewerTypes = { edit: 'editor', diff: 'diff', }; + +export const rightSidebarViews = { + pipelines: 'pipelines-list', +}; diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js index a21cec4e8d8..b52618f4fde 100644 --- a/app/assets/javascripts/ide/ide_router.js +++ b/app/assets/javascripts/ide/ide_router.js @@ -63,7 +63,7 @@ router.beforeEach((to, from, next) => { .then(() => { const fullProjectId = `${to.params.namespace}/${to.params.project}`; - const baseSplit = to.params[0].split('/-/'); + const baseSplit = (to.params[0] && to.params[0].split('/-/')) || ['']; const branchId = baseSplit[0].slice(-1) === '/' ? baseSplit[0].slice(0, -1) : baseSplit[0]; if (branchId) { diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js index c5835cd3b06..2d74192e6b3 100644 --- a/app/assets/javascripts/ide/index.js +++ b/app/assets/javascripts/ide/index.js @@ -1,4 +1,5 @@ import Vue from 'vue'; +import { mapActions } from 'vuex'; import Translate from '~/vue_shared/translate'; import ide from './components/ide.vue'; import store from './stores'; @@ -17,11 +18,18 @@ export function initIde(el) { ide, }, created() { - this.$store.dispatch('setEmptyStateSvgs', { + this.setEmptyStateSvgs({ emptyStateSvgPath: el.dataset.emptyStateSvgPath, noChangesStateSvgPath: el.dataset.noChangesStateSvgPath, committedStateSvgPath: el.dataset.committedStateSvgPath, + pipelinesEmptyStateSvgPath: el.dataset.pipelinesEmptyStateSvgPath, }); + this.setLinks({ + ciHelpPagePath: el.dataset.ciHelpPagePath, + }); + }, + methods: { + ...mapActions(['setEmptyStateSvgs', 'setLinks']), }, render(createElement) { return createElement('ide'); diff --git a/app/assets/javascripts/ide/lib/common/model.js b/app/assets/javascripts/ide/lib/common/model.js index b1e43a1e38c..e5149b1f3ad 100644 --- a/app/assets/javascripts/ide/lib/common/model.js +++ b/app/assets/javascripts/ide/lib/common/model.js @@ -1,4 +1,3 @@ -/* global monaco */ import Disposable from './disposable'; import eventHub from '../../eventhub'; diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index 1a98b42761e..3dc365eaead 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -169,6 +169,12 @@ export const burstUnusedSeal = ({ state, commit }) => { } }; +export const setRightPane = ({ commit }, view) => { + commit(types.SET_RIGHT_PANE, view); +}; + +export const setLinks = ({ commit }, links) => commit(types.SET_LINKS, links); + export * from './actions/tree'; export * from './actions/file'; export * from './actions/project'; diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index 13aea91d8ba..74f9c112f5a 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -84,11 +84,11 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive }); }; -export const setFileMrChange = ({ state, commit }, { file, mrChange }) => { +export const setFileMrChange = ({ commit }, { file, mrChange }) => { commit(types.SET_FILE_MERGE_REQUEST_CHANGE, { file, mrChange }); }; -export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) => { +export const getRawFileData = ({ state, commit }, { path, baseSha }) => { const file = state.entries[path]; return new Promise((resolve, reject) => { service @@ -156,7 +156,7 @@ export const setEditorPosition = ({ getters, commit }, { editorRow, editorColumn } }; -export const setFileViewMode = ({ state, commit }, { file, viewMode }) => { +export const setFileViewMode = ({ commit }, { file, viewMode }) => { commit(types.SET_FILE_VIEWMODE, { file, viewMode }); }; diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js index da73034fd7d..5ec9bd661bb 100644 --- a/app/assets/javascripts/ide/stores/actions/merge_request.js +++ b/app/assets/javascripts/ide/stores/actions/merge_request.js @@ -3,7 +3,7 @@ import service from '../../services'; import * as types from '../mutation_types'; export const getMergeRequestData = ( - { commit, state, dispatch }, + { commit, state }, { projectId, mergeRequestId, force = false } = {}, ) => new Promise((resolve, reject) => { @@ -32,7 +32,7 @@ export const getMergeRequestData = ( }); export const getMergeRequestChanges = ( - { commit, state, dispatch }, + { commit, state }, { projectId, mergeRequestId, force = false } = {}, ) => new Promise((resolve, reject) => { @@ -58,7 +58,7 @@ export const getMergeRequestChanges = ( }); export const getMergeRequestVersions = ( - { commit, state, dispatch }, + { commit, state }, { projectId, mergeRequestId, force = false } = {}, ) => new Promise((resolve, reject) => { diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js index cece9154c82..46af47d2f81 100644 --- a/app/assets/javascripts/ide/stores/actions/project.js +++ b/app/assets/javascripts/ide/stores/actions/project.js @@ -1,16 +1,9 @@ -import Visibility from 'visibilityjs'; import flash from '~/flash'; import { __ } from '~/locale'; import service from '../../services'; import * as types from '../mutation_types'; -import Poll from '../../../lib/utils/poll'; -let eTagPoll; - -export const getProjectData = ( - { commit, state, dispatch }, - { namespace, projectId, force = false } = {}, -) => +export const getProjectData = ({ commit, state }, { namespace, projectId, force = false } = {}) => new Promise((resolve, reject) => { if (!state.projects[`${namespace}/${projectId}`] || force) { commit(types.TOGGLE_LOADING, { entry: state }); @@ -40,10 +33,7 @@ export const getProjectData = ( } }); -export const getBranchData = ( - { commit, state, dispatch }, - { projectId, branchId, force = false } = {}, -) => +export const getBranchData = ({ commit, state }, { projectId, branchId, force = false } = {}) => new Promise((resolve, reject) => { if ( typeof state.projects[`${projectId}`] === 'undefined' || @@ -78,7 +68,7 @@ export const getBranchData = ( } }); -export const refreshLastCommitData = ({ commit, state, dispatch }, { projectId, branchId } = {}) => +export const refreshLastCommitData = ({ commit }, { projectId, branchId } = {}) => service .getBranchData(projectId, branchId) .then(({ data }) => { @@ -91,61 +81,3 @@ export const refreshLastCommitData = ({ commit, state, dispatch }, { projectId, .catch(() => { flash(__('Error loading last commit.'), 'alert', document, null, false, true); }); - -export const pollSuccessCallBack = ({ commit, state, dispatch }, { data }) => { - if (data.pipelines && data.pipelines.length) { - const lastCommitHash = - state.projects[state.currentProjectId].branches[state.currentBranchId].commit.id; - const lastCommitPipeline = data.pipelines.find( - pipeline => pipeline.commit.id === lastCommitHash, - ); - commit(types.SET_LAST_COMMIT_PIPELINE, { - projectId: state.currentProjectId, - branchId: state.currentBranchId, - pipeline: lastCommitPipeline || {}, - }); - } - - return data; -}; - -export const pipelinePoll = ({ getters, dispatch }) => { - eTagPoll = new Poll({ - resource: service, - method: 'lastCommitPipelines', - data: { - getters, - }, - successCallback: ({ data }) => dispatch('pollSuccessCallBack', { data }), - errorCallback: () => { - flash( - __('Something went wrong while fetching the latest pipeline status.'), - 'alert', - document, - null, - false, - true, - ); - }, - }); - - if (!Visibility.hidden()) { - eTagPoll.makeRequest(); - } - - Visibility.change(() => { - if (!Visibility.hidden()) { - eTagPoll.restart(); - } else { - eTagPoll.stop(); - } - }); -}; - -export const stopPipelinePolling = () => { - eTagPoll.stop(); -}; - -export const restartPipelinePolling = () => { - eTagPoll.restart(); -}; diff --git a/app/assets/javascripts/ide/stores/actions/tree.js b/app/assets/javascripts/ide/stores/actions/tree.js index 6536be04f0a..cc5116413f7 100644 --- a/app/assets/javascripts/ide/stores/actions/tree.js +++ b/app/assets/javascripts/ide/stores/actions/tree.js @@ -5,7 +5,7 @@ import * as types from '../mutation_types'; import { findEntry } from '../utils'; import FilesDecoratorWorker from '../workers/files_decorator_worker'; -export const toggleTreeOpen = ({ commit, dispatch }, path) => { +export const toggleTreeOpen = ({ commit }, path) => { commit(types.TOGGLE_TREE_OPEN, path); }; @@ -23,7 +23,7 @@ export const handleTreeEntryAction = ({ commit, dispatch }, row) => { } }; -export const getLastCommitData = ({ state, commit, dispatch, getters }, tree = state) => { +export const getLastCommitData = ({ state, commit, dispatch }, tree = state) => { if (!tree || tree.lastCommitPath === null || !tree.lastCommitPath) return; service @@ -49,7 +49,7 @@ export const getLastCommitData = ({ state, commit, dispatch, getters }, tree = s .catch(() => flash('Error fetching log data.', 'alert', document, null, false, true)); }; -export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } = {}) => +export const getFiles = ({ state, commit }, { projectId, branchId } = {}) => new Promise((resolve, reject) => { if (!state.trees[`${projectId}/${branchId}`]) { const selectedProject = state.projects[projectId]; diff --git a/app/assets/javascripts/ide/stores/index.js b/app/assets/javascripts/ide/stores/index.js index 699710055e3..f8ce8a67ec0 100644 --- a/app/assets/javascripts/ide/stores/index.js +++ b/app/assets/javascripts/ide/stores/index.js @@ -6,16 +6,21 @@ import * as getters from './getters'; import mutations from './mutations'; import commitModule from './modules/commit'; import pipelines from './modules/pipelines'; +import mergeRequests from './modules/merge_requests'; Vue.use(Vuex); -export default new Vuex.Store({ - state: state(), - actions, - mutations, - getters, - modules: { - commit: commitModule, - pipelines, - }, -}); +export const createStore = () => + new Vuex.Store({ + state: state(), + actions, + mutations, + getters, + modules: { + commit: commitModule, + pipelines, + mergeRequests, + }, + }); + +export default createStore(); diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index cd25c3060f2..0a0db4033c8 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -31,9 +31,9 @@ export const setLastCommitMessage = ({ rootState, commit }, data) => { const currentProject = rootState.projects[rootState.currentProjectId]; const commitStats = data.stats ? sprintf(__('with %{additions} additions, %{deletions} deletions.'), { - additions: data.stats.additions, // eslint-disable-line indent - deletions: data.stats.deletions, // eslint-disable-line indent - }) // eslint-disable-line indent + additions: data.stats.additions, // eslint-disable-line indent-legacy + deletions: data.stats.deletions, // eslint-disable-line indent-legacy + }) // eslint-disable-line indent-legacy : ''; const commitMsg = sprintf( __('Your changes have been committed. Commit %{commitId} %{commitStats}'), @@ -74,10 +74,7 @@ export const checkCommitStatus = ({ rootState }) => ), ); -export const updateFilesAfterCommit = ( - { commit, dispatch, state, rootState, rootGetters }, - { data }, -) => { +export const updateFilesAfterCommit = ({ commit, dispatch, rootState }, { data }) => { const selectedProject = rootState.projects[rootState.currentProjectId]; const lastCommit = { commit_path: `${selectedProject.web_url}/commit/${data.id}`, diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js new file mode 100644 index 00000000000..d3050183bd3 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js @@ -0,0 +1,25 @@ +import { __ } from '../../../../locale'; +import Api from '../../../../api'; +import flash from '../../../../flash'; +import * as types from './mutation_types'; + +export const requestMergeRequests = ({ commit }) => commit(types.REQUEST_MERGE_REQUESTS); +export const receiveMergeRequestsError = ({ commit }) => { + flash(__('Error loading merge requests.')); + commit(types.RECEIVE_MERGE_REQUESTS_ERROR); +}; +export const receiveMergeRequestsSuccess = ({ commit }, data) => + commit(types.RECEIVE_MERGE_REQUESTS_SUCCESS, data); + +export const fetchMergeRequests = ({ dispatch, state: { scope, state } }, search = '') => { + dispatch('requestMergeRequests'); + dispatch('resetMergeRequests'); + + Api.mergeRequests({ scope, state, search }) + .then(({ data }) => dispatch('receiveMergeRequestsSuccess', data)) + .catch(() => dispatch('receiveMergeRequestsError')); +}; + +export const resetMergeRequests = ({ commit }) => commit(types.RESET_MERGE_REQUESTS); + +export default () => {}; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js b/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js new file mode 100644 index 00000000000..64b7763f257 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js @@ -0,0 +1,10 @@ +export const scopes = { + assignedToMe: 'assigned-to-me', + createdByMe: 'created-by-me', +}; + +export const states = { + opened: 'opened', + closed: 'closed', + merged: 'merged', +}; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/index.js b/app/assets/javascripts/ide/stores/modules/merge_requests/index.js new file mode 100644 index 00000000000..04e7e0f08f1 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/index.js @@ -0,0 +1,10 @@ +import state from './state'; +import * as actions from './actions'; +import mutations from './mutations'; + +export default { + namespaced: true, + state: state(), + actions, + mutations, +}; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/mutation_types.js b/app/assets/javascripts/ide/stores/modules/merge_requests/mutation_types.js new file mode 100644 index 00000000000..0badddcbae7 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/mutation_types.js @@ -0,0 +1,5 @@ +export const REQUEST_MERGE_REQUESTS = 'REQUEST_MERGE_REQUESTS'; +export const RECEIVE_MERGE_REQUESTS_ERROR = 'RECEIVE_MERGE_REQUESTS_ERROR'; +export const RECEIVE_MERGE_REQUESTS_SUCCESS = 'RECEIVE_MERGE_REQUESTS_SUCCESS'; + +export const RESET_MERGE_REQUESTS = 'RESET_MERGE_REQUESTS'; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js b/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js new file mode 100644 index 00000000000..98102a68e08 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js @@ -0,0 +1,26 @@ +/* eslint-disable no-param-reassign */ +import * as types from './mutation_types'; + +export default { + [types.REQUEST_MERGE_REQUESTS](state) { + state.isLoading = true; + }, + [types.RECEIVE_MERGE_REQUESTS_ERROR](state) { + state.isLoading = false; + }, + [types.RECEIVE_MERGE_REQUESTS_SUCCESS](state, data) { + state.isLoading = false; + state.mergeRequests = data.map(mergeRequest => ({ + id: mergeRequest.id, + iid: mergeRequest.iid, + title: mergeRequest.title, + projectId: mergeRequest.project_id, + projectPathWithNamespace: mergeRequest.web_url + .replace(`${gon.gitlab_url}/`, '') + .replace(`/merge_requests/${mergeRequest.iid}`, ''), + })); + }, + [types.RESET_MERGE_REQUESTS](state) { + state.mergeRequests = []; + }, +}; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/state.js b/app/assets/javascripts/ide/stores/modules/merge_requests/state.js new file mode 100644 index 00000000000..2947b686c1c --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/state.js @@ -0,0 +1,8 @@ +import { scopes, states } from './constants'; + +export default () => ({ + isLoading: false, + mergeRequests: [], + scope: scopes.assignedToMe, + state: states.opened, +}); diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js index 07f7b201f2e..1ebe487263b 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js @@ -1,49 +1,80 @@ +import Visibility from 'visibilityjs'; +import axios from 'axios'; import { __ } from '../../../../locale'; -import Api from '../../../../api'; import flash from '../../../../flash'; +import Poll from '../../../../lib/utils/poll'; +import service from '../../../services'; import * as types from './mutation_types'; +let eTagPoll; + +export const clearEtagPoll = () => { + eTagPoll = null; +}; +export const stopPipelinePolling = () => eTagPoll && eTagPoll.stop(); +export const restartPipelinePolling = () => eTagPoll && eTagPoll.restart(); + export const requestLatestPipeline = ({ commit }) => commit(types.REQUEST_LATEST_PIPELINE); -export const receiveLatestPipelineError = ({ commit }) => { +export const receiveLatestPipelineError = ({ commit, dispatch }) => { flash(__('There was an error loading latest pipeline')); commit(types.RECEIVE_LASTEST_PIPELINE_ERROR); + dispatch('stopPipelinePolling'); +}; +export const receiveLatestPipelineSuccess = ({ rootGetters, commit }, { pipelines }) => { + let lastCommitPipeline = false; + + if (pipelines && pipelines.length) { + const lastCommitHash = rootGetters.lastCommit && rootGetters.lastCommit.id; + lastCommitPipeline = pipelines.find(pipeline => pipeline.commit.id === lastCommitHash); + } + + commit(types.RECEIVE_LASTEST_PIPELINE_SUCCESS, lastCommitPipeline); }; -export const receiveLatestPipelineSuccess = ({ commit }, pipeline) => - commit(types.RECEIVE_LASTEST_PIPELINE_SUCCESS, pipeline); -export const fetchLatestPipeline = ({ dispatch, rootState }, sha) => { +export const fetchLatestPipeline = ({ dispatch, rootGetters }) => { + if (eTagPoll) return; + dispatch('requestLatestPipeline'); - return Api.pipelines(rootState.currentProjectId, { sha, per_page: '1' }) - .then(({ data }) => { - dispatch('receiveLatestPipelineSuccess', data.pop()); - }) - .catch(() => dispatch('receiveLatestPipelineError')); + eTagPoll = new Poll({ + resource: service, + method: 'lastCommitPipelines', + data: { getters: rootGetters }, + successCallback: ({ data }) => dispatch('receiveLatestPipelineSuccess', data), + errorCallback: () => dispatch('receiveLatestPipelineError'), + }); + + if (!Visibility.hidden()) { + eTagPoll.makeRequest(); + } + + Visibility.change(() => { + if (!Visibility.hidden()) { + eTagPoll.restart(); + } else { + eTagPoll.stop(); + } + }); }; -export const requestJobs = ({ commit }) => commit(types.REQUEST_JOBS); -export const receiveJobsError = ({ commit }) => { +export const requestJobs = ({ commit }, id) => commit(types.REQUEST_JOBS, id); +export const receiveJobsError = ({ commit }, id) => { flash(__('There was an error loading jobs')); - commit(types.RECEIVE_JOBS_ERROR); + commit(types.RECEIVE_JOBS_ERROR, id); }; -export const receiveJobsSuccess = ({ commit }, data) => commit(types.RECEIVE_JOBS_SUCCESS, data); +export const receiveJobsSuccess = ({ commit }, { id, data }) => + commit(types.RECEIVE_JOBS_SUCCESS, { id, data }); -export const fetchJobs = ({ dispatch, state, rootState }, page = '1') => { - dispatch('requestJobs'); +export const fetchJobs = ({ dispatch }, stage) => { + dispatch('requestJobs', stage.id); - Api.pipelineJobs(rootState.currentProjectId, state.latestPipeline.id, { - page, - }) - .then(({ data, headers }) => { - const nextPage = headers && headers['x-next-page']; - - dispatch('receiveJobsSuccess', data); - - if (nextPage) { - dispatch('fetchJobs', nextPage); - } - }) - .catch(() => dispatch('receiveJobsError')); + axios + .get(stage.dropdownPath) + .then(({ data }) => dispatch('receiveJobsSuccess', { id: stage.id, data })) + .catch(() => dispatch('receiveJobsError', stage.id)); }; +export const toggleStageCollapsed = ({ commit }, stageId) => + commit(types.TOGGLE_STAGE_COLLAPSE, stageId); + export default () => {}; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/constants.js b/app/assets/javascripts/ide/stores/modules/pipelines/constants.js new file mode 100644 index 00000000000..f5b96327e40 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pipelines/constants.js @@ -0,0 +1,4 @@ +// eslint-disable-next-line import/prefer-default-export +export const states = { + failed: 'failed', +}; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/getters.js b/app/assets/javascripts/ide/stores/modules/pipelines/getters.js index d6c91f5b64d..f545453806f 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/getters.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/getters.js @@ -1,7 +1,22 @@ +import { states } from './constants'; + export const hasLatestPipeline = state => !state.isLoadingPipeline && !!state.latestPipeline; -export const failedJobs = state => +export const pipelineFailed = state => + state.latestPipeline && state.latestPipeline.details.status.text === states.failed; + +export const failedStages = state => + state.stages.filter(stage => stage.status.text.toLowerCase() === states.failed).map(stage => ({ + ...stage, + jobs: stage.jobs.filter(job => job.status.text.toLowerCase() === states.failed), + })); + +export const failedJobsCount = state => state.stages.reduce( - (acc, stage) => acc.concat(stage.jobs.filter(job => job.status === 'failed')), - [], + (acc, stage) => acc + stage.jobs.filter(j => j.status.text === states.failed).length, + 0, ); + +export const jobsCount = state => state.stages.reduce((acc, stage) => acc + stage.jobs.length, 0); + +export default () => {}; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js b/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js index 6b5701670a6..3ddc8409c5b 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js @@ -5,3 +5,5 @@ export const RECEIVE_LASTEST_PIPELINE_SUCCESS = 'RECEIVE_LASTEST_PIPELINE_SUCCES export const REQUEST_JOBS = 'REQUEST_JOBS'; export const RECEIVE_JOBS_ERROR = 'RECEIVE_JOBS_ERROR'; export const RECEIVE_JOBS_SUCCESS = 'RECEIVE_JOBS_SUCCESS'; + +export const TOGGLE_STAGE_COLLAPSE = 'TOGGLE_STAGE_COLLAPSE'; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js b/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js index 2b16e57b386..745797e1ee5 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js @@ -1,5 +1,6 @@ /* eslint-disable no-param-reassign */ import * as types from './mutation_types'; +import { normalizeJob } from './utils'; export default { [types.REQUEST_LATEST_PIPELINE](state) { @@ -14,40 +15,52 @@ export default { if (pipeline) { state.latestPipeline = { id: pipeline.id, - status: pipeline.status, + path: pipeline.path, + commit: pipeline.commit, + details: { + status: pipeline.details.status, + }, + yamlError: pipeline.yaml_errors, }; + state.stages = pipeline.details.stages.map((stage, i) => { + const foundStage = state.stages.find(s => s.id === i); + return { + id: i, + dropdownPath: stage.dropdown_path, + name: stage.name, + status: stage.status, + isCollapsed: foundStage ? foundStage.isCollapsed : false, + isLoading: foundStage ? foundStage.isLoading : false, + jobs: foundStage ? foundStage.jobs : [], + }; + }); + } else { + state.latestPipeline = false; } }, - [types.REQUEST_JOBS](state) { - state.isLoadingJobs = true; + [types.REQUEST_JOBS](state, id) { + state.stages = state.stages.map(stage => ({ + ...stage, + isLoading: stage.id === id ? true : stage.isLoading, + })); }, - [types.RECEIVE_JOBS_ERROR](state) { - state.isLoadingJobs = false; + [types.RECEIVE_JOBS_ERROR](state, id) { + state.stages = state.stages.map(stage => ({ + ...stage, + isLoading: stage.id === id ? false : stage.isLoading, + })); }, - [types.RECEIVE_JOBS_SUCCESS](state, jobs) { - state.isLoadingJobs = false; - - state.stages = jobs.reduce((acc, job) => { - let stage = acc.find(s => s.title === job.stage); - - if (!stage) { - stage = { - title: job.stage, - jobs: [], - }; - - acc.push(stage); - } - - stage.jobs = stage.jobs.concat({ - id: job.id, - name: job.name, - status: job.status, - stage: job.stage, - duration: job.duration, - }); - - return acc; - }, state.stages); + [types.RECEIVE_JOBS_SUCCESS](state, { id, data }) { + state.stages = state.stages.map(stage => ({ + ...stage, + isLoading: stage.id === id ? false : stage.isLoading, + jobs: stage.id === id ? data.latest_statuses.map(normalizeJob) : stage.jobs, + })); + }, + [types.TOGGLE_STAGE_COLLAPSE](state, id) { + state.stages = state.stages.map(stage => ({ + ...stage, + isCollapsed: stage.id === id ? !stage.isCollapsed : stage.isCollapsed, + })); }, }; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/state.js b/app/assets/javascripts/ide/stores/modules/pipelines/state.js index 6f22542aaea..0f83b315fff 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/state.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/state.js @@ -1,5 +1,5 @@ export default () => ({ - isLoadingPipeline: false, + isLoadingPipeline: true, isLoadingJobs: false, latestPipeline: null, stages: [], diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/utils.js b/app/assets/javascripts/ide/stores/modules/pipelines/utils.js new file mode 100644 index 00000000000..9f4b0d7d726 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pipelines/utils.js @@ -0,0 +1,7 @@ +// eslint-disable-next-line import/prefer-default-export +export const normalizeJob = job => ({ + id: job.id, + name: job.name, + status: job.status, + path: job.build_path, +}); diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index 0a3f8d031c4..fbfb92105d6 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -6,6 +6,7 @@ export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED'; export const SET_RIGHT_PANEL_COLLAPSED = 'SET_RIGHT_PANEL_COLLAPSED'; export const SET_RESIZING_STATUS = 'SET_RESIZING_STATUS'; export const SET_EMPTY_STATE_SVGS = 'SET_EMPTY_STATE_SVGS'; +export const SET_LINKS = 'SET_LINKS'; // Project Mutation Types export const SET_PROJECT = 'SET_PROJECT'; @@ -23,7 +24,6 @@ export const SET_BRANCH = 'SET_BRANCH'; export const SET_BRANCH_COMMIT = 'SET_BRANCH_COMMIT'; export const SET_BRANCH_WORKING_REFERENCE = 'SET_BRANCH_WORKING_REFERENCE'; export const TOGGLE_BRANCH_OPEN = 'TOGGLE_BRANCH_OPEN'; -export const SET_LAST_COMMIT_PIPELINE = 'SET_LAST_COMMIT_PIPELINE'; // Tree mutation types export const SET_DIRECTORY_DATA = 'SET_DIRECTORY_DATA'; @@ -66,3 +66,5 @@ export const UPDATE_ACTIVITY_BAR_VIEW = 'UPDATE_ACTIVITY_BAR_VIEW'; export const UPDATE_TEMP_FLAG = 'UPDATE_TEMP_FLAG'; export const TOGGLE_FILE_FINDER = 'TOGGLE_FILE_FINDER'; export const BURST_UNUSED_SEAL = 'BURST_UNUSED_SEAL'; + +export const SET_RIGHT_PANE = 'SET_RIGHT_PANE'; diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index a257e2ef025..eeaa7cb0ec3 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -114,12 +114,13 @@ export default { }, [types.SET_EMPTY_STATE_SVGS]( state, - { emptyStateSvgPath, noChangesStateSvgPath, committedStateSvgPath }, + { emptyStateSvgPath, noChangesStateSvgPath, committedStateSvgPath, pipelinesEmptyStateSvgPath }, ) { Object.assign(state, { emptyStateSvgPath, noChangesStateSvgPath, committedStateSvgPath, + pipelinesEmptyStateSvgPath, }); }, [types.TOGGLE_FILE_FINDER](state, fileFindVisible) { @@ -148,6 +149,14 @@ export default { unusedSeal: false, }); }, + [types.SET_RIGHT_PANE](state, view) { + Object.assign(state, { + rightPane: state.rightPane === view ? null : view, + }); + }, + [types.SET_LINKS](state, links) { + Object.assign(state, { links }); + }, ...projectMutations, ...mergeRequestMutation, ...fileMutations, diff --git a/app/assets/javascripts/ide/stores/mutations/branch.js b/app/assets/javascripts/ide/stores/mutations/branch.js index f17ec4da308..e09f88878f4 100644 --- a/app/assets/javascripts/ide/stores/mutations/branch.js +++ b/app/assets/javascripts/ide/stores/mutations/branch.js @@ -14,10 +14,6 @@ export default { treeId: `${projectPath}/${branchName}`, active: true, workingReference: '', - commit: { - ...branch.commit, - pipeline: {}, - }, }, }, }); @@ -32,9 +28,4 @@ export default { commit, }); }, - [types.SET_LAST_COMMIT_PIPELINE](state, { projectId, branchId, pipeline }) { - Object.assign(state.projects[projectId].branches[branchId].commit, { - pipeline, - }); - }, }; diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js index e7411f16a4f..4aac4696075 100644 --- a/app/assets/javascripts/ide/stores/state.js +++ b/app/assets/javascripts/ide/stores/state.js @@ -23,4 +23,6 @@ export default () => ({ currentActivityView: activityBarViews.edit, unusedSeal: true, fileFindVisible: false, + rightPane: null, + links: {}, }); |