summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/environments/components/container.vue1
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue18
-rw-r--r--app/assets/javascripts/environments/components/environment_external_url.vue14
-rw-r--r--app/assets/javascripts/environments/components/environment_monitoring.vue15
-rw-r--r--app/assets/javascripts/environments/components/environment_rollback.vue3
-rw-r--r--app/assets/javascripts/environments/components/environment_terminal_button.vue18
-rw-r--r--app/assets/javascripts/ide/components/changed_file_icon.vue10
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue22
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list_item.vue2
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/success_message.vue39
-rw-r--r--app/assets/javascripts/ide/components/repo_commit_section.vue33
-rw-r--r--app/assets/javascripts/ide/components/repo_file.vue89
-rw-r--r--app/assets/javascripts/ide/stores/actions.js6
-rw-r--r--app/assets/javascripts/ide/stores/actions/file.js4
-rw-r--r--app/assets/javascripts/ide/stores/getters.js17
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/actions.js4
-rw-r--r--app/assets/javascripts/ide/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/ide/stores/mutations.js5
-rw-r--r--app/assets/javascripts/ide/stores/state.js1
-rw-r--r--app/assets/javascripts/ide/stores/utils.js10
-rw-r--r--app/assets/javascripts/lib/utils/text_utility.js6
-rw-r--r--app/assets/javascripts/sidebar/components/participants/participants.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue8
-rw-r--r--app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue22
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.js15
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue18
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue4
-rw-r--r--app/assets/stylesheets/pages/boards.scss2
-rw-r--r--app/assets/stylesheets/pages/diff.scss6
-rw-r--r--app/assets/stylesheets/pages/repo.scss33
-rw-r--r--app/models/ci/build_trace_chunk.rb9
-rw-r--r--app/models/identity.rb8
-rw-r--r--app/models/merge_request.rb2
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--app/workers/all_queues.yml2
-rw-r--r--app/workers/build_trace_chunk_flush_to_db_worker.rb12
-rw-r--r--app/workers/ci/build_trace_chunk_flush_worker.rb13
37 files changed, 339 insertions, 139 deletions
diff --git a/app/assets/javascripts/environments/components/container.vue b/app/assets/javascripts/environments/components/container.vue
index dbee81fa320..6bd7c6b49cb 100644
--- a/app/assets/javascripts/environments/components/container.vue
+++ b/app/assets/javascripts/environments/components/container.vue
@@ -43,6 +43,7 @@
<div class="environments-container">
<loading-icon
+ class="prepend-top-default"
label="Loading environments"
v-if="isLoading"
size="3"
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index 16bd2f5feb3..ab9e22037d0 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -1,5 +1,5 @@
<script>
- import playIconSvg from 'icons/_icon_play.svg';
+ import Icon from '~/vue_shared/components/icon.vue';
import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tooltip from '../../vue_shared/directives/tooltip';
@@ -8,9 +8,9 @@
directives: {
tooltip,
},
-
components: {
loadingIcon,
+ Icon,
},
props: {
actions: {
@@ -19,20 +19,16 @@
default: () => [],
},
},
-
data() {
return {
- playIconSvg,
isLoading: false,
};
},
-
computed: {
title() {
return 'Deploy to...';
},
},
-
methods: {
onClickAction(endpoint) {
this.isLoading = true;
@@ -65,7 +61,10 @@
:disabled="isLoading"
>
<span>
- <span v-html="playIconSvg"></span>
+ <icon
+ name="play"
+ :size="12"
+ />
<i
class="fa fa-caret-down"
aria-hidden="true"
@@ -86,7 +85,10 @@
:class="{ disabled: isActionDisabled(action) }"
:disabled="isActionDisabled(action)"
>
- <span v-html="playIconSvg"></span>
+ <icon
+ name="play"
+ :size="12"
+ />
<span>
{{ action.name }}
</span>
diff --git a/app/assets/javascripts/environments/components/environment_external_url.vue b/app/assets/javascripts/environments/components/environment_external_url.vue
index c9a68cface6..ea6f1168c68 100644
--- a/app/assets/javascripts/environments/components/environment_external_url.vue
+++ b/app/assets/javascripts/environments/components/environment_external_url.vue
@@ -1,4 +1,5 @@
<script>
+ import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '../../vue_shared/directives/tooltip';
import { s__ } from '../../locale';
@@ -6,6 +7,9 @@
* Renders the external url link in environments table.
*/
export default {
+ components: {
+ Icon,
+ },
directives: {
tooltip,
},
@@ -15,7 +19,6 @@
required: true,
},
},
-
computed: {
title() {
return s__('Environments|Open');
@@ -34,10 +37,9 @@
:aria-label="title"
:href="externalUrl"
>
- <i
- class="fa fa-external-link"
- aria-hidden="true"
- >
- </i>
+ <icon
+ name="external-link"
+ :size="12"
+ />
</a>
</template>
diff --git a/app/assets/javascripts/environments/components/environment_monitoring.vue b/app/assets/javascripts/environments/components/environment_monitoring.vue
index 081537cf218..deada134b27 100644
--- a/app/assets/javascripts/environments/components/environment_monitoring.vue
+++ b/app/assets/javascripts/environments/components/environment_monitoring.vue
@@ -2,20 +2,22 @@
/**
* Renders the Monitoring (Metrics) link in environments table.
*/
+ import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '../../vue_shared/directives/tooltip';
export default {
+ components: {
+ Icon,
+ },
directives: {
tooltip,
},
-
props: {
monitoringUrl: {
type: String,
required: true,
},
},
-
computed: {
title() {
return 'Monitoring';
@@ -33,10 +35,9 @@
:title="title"
:aria-label="title"
>
- <i
- class="fa fa-area-chart"
- aria-hidden="true"
- >
- </i>
+ <icon
+ name="chart"
+ :size="12"
+ />
</a>
</template>
diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue
index 605a88e997e..c822fb1574c 100644
--- a/app/assets/javascripts/environments/components/environment_rollback.vue
+++ b/app/assets/javascripts/environments/components/environment_rollback.vue
@@ -12,7 +12,6 @@
components: {
loadingIcon,
},
-
props: {
retryUrl: {
type: String,
@@ -24,13 +23,11 @@
default: true,
},
},
-
data() {
return {
isLoading: false,
};
},
-
methods: {
onClick() {
this.isLoading = true;
diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.vue b/app/assets/javascripts/environments/components/environment_terminal_button.vue
index 407d5333c0e..e8469d088ef 100644
--- a/app/assets/javascripts/environments/components/environment_terminal_button.vue
+++ b/app/assets/javascripts/environments/components/environment_terminal_button.vue
@@ -3,14 +3,16 @@
* Renders a terminal button to open a web terminal.
* Used in environments table.
*/
- import terminalIconSvg from 'icons/_icon_terminal.svg';
+ import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '../../vue_shared/directives/tooltip';
export default {
+ components: {
+ Icon,
+ },
directives: {
tooltip,
},
-
props: {
terminalPath: {
type: String,
@@ -18,13 +20,6 @@
default: '',
},
},
-
- data() {
- return {
- terminalIconSvg,
- };
- },
-
computed: {
title() {
return 'Terminal';
@@ -40,7 +35,10 @@
:title="title"
:aria-label="title"
:href="terminalPath"
- v-html="terminalIconSvg"
>
+ <icon
+ name="terminal"
+ :size="12"
+ />
</a>
</template>
diff --git a/app/assets/javascripts/ide/components/changed_file_icon.vue b/app/assets/javascripts/ide/components/changed_file_icon.vue
index fdbc14a4b8f..1cec84706fc 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} prepend-left-5 pull-left`;
+ return `multi-${this.changedIcon} pull-left`;
},
tooltipTitle() {
if (!this.showTooltip) return undefined;
@@ -79,13 +79,7 @@ export default {
class="ide-file-changed-icon"
>
<icon
- v-if="file.staged && showStagedIcon"
- :name="stagedIcon"
- :size="12"
- :css-classes="changedIconClass"
- />
- <icon
- v-if="file.changed || file.tempFile || (file.staged && !showStagedIcon)"
+ v-if="file.changed || file.tempFile || file.staged"
:name="changedIcon"
:size="12"
:css-classes="changedIconClass"
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue b/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue
index 6424b93ce54..1f6bbca13b5 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue
@@ -15,17 +15,10 @@ export default {
type: String,
required: true,
},
- committedStateSvgPath: {
- type: String,
- required: true,
- },
},
computed: {
- ...mapState(['lastCommitMsg', 'rightPanelCollapsed']),
+ ...mapState(['lastCommitMsg', 'rightPanelCollapsed', 'changedFiles', 'stagedFiles']),
...mapGetters(['collapseButtonIcon', 'collapseButtonTooltip']),
- statusSvg() {
- return this.lastCommitMsg ? this.committedStateSvgPath : this.noChangesStateSvgPath;
- },
},
methods: {
...mapActions(['toggleRightPanelCollapsed']),
@@ -35,6 +28,7 @@ export default {
<template>
<div
+ v-if="!lastCommitMsg"
class="multi-file-commit-panel-section ide-commit-empty-state js-empty-state"
>
<header
@@ -64,12 +58,11 @@ export default {
v-if="!rightPanelCollapsed"
>
<div class="svg-content svg-80">
- <img :src="statusSvg" />
+ <img :src="noChangesStateSvgPath" />
</div>
<div class="append-right-default prepend-left-default">
<div
class="text-content text-center"
- v-if="!lastCommitMsg"
>
<h4>
{{ __('No changes') }}
@@ -78,15 +71,6 @@ export default {
{{ __('Edit files in the editor and commit changes here') }}
</p>
</div>
- <div
- class="text-content text-center"
- v-else
- >
- <h4>
- {{ __('All changes are committed') }}
- </h4>
- <p v-html="lastCommitMsg"></p>
- </div>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
index ad4713c40d5..872302840e2 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
@@ -36,7 +36,7 @@ export default {
return this.file.tempFile ? `file-addition${prefix}` : `file-modified${prefix}`;
},
iconClass() {
- return `multi-file-${this.file.tempFile ? 'additions' : 'modified'} append-right-8`;
+ return `multi-file-${this.file.tempFile ? 'addition' : 'modified'} append-right-8`;
},
},
methods: {
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue
new file mode 100644
index 00000000000..628a17eddca
--- /dev/null
+++ b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue
@@ -0,0 +1,39 @@
+<script>
+import { mapState } from 'vuex';
+
+export default {
+ props: {
+ committedStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapState(['lastCommitMsg']),
+ },
+};
+</script>
+
+<template>
+ <div
+ class="multi-file-commit-panel-success-message"
+ aria-live="assertive"
+ >
+ <div class="svg-content svg-80">
+ <img
+ :src="committedStateSvgPath"
+ alt=""
+ />
+ </div>
+ <div class="append-right-default prepend-left-default">
+ <div
+ class="text-content text-center"
+ >
+ <h4>
+ {{ __('All changes are committed') }}
+ </h4>
+ <p v-html="lastCommitMsg"></p>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ide/components/repo_commit_section.vue b/app/assets/javascripts/ide/components/repo_commit_section.vue
index 877d1b5e026..fa929381744 100644
--- a/app/assets/javascripts/ide/components/repo_commit_section.vue
+++ b/app/assets/javascripts/ide/components/repo_commit_section.vue
@@ -7,6 +7,7 @@ import LoadingButton from '~/vue_shared/components/loading_button.vue';
import CommitFilesList from './commit_sidebar/list.vue';
import EmptyState from './commit_sidebar/empty_state.vue';
import CommitMessageField from './commit_sidebar/message_field.vue';
+import SuccessMessage from './commit_sidebar/success_message.vue';
import * as consts from '../stores/modules/commit/constants';
import Actions from './commit_sidebar/actions.vue';
@@ -16,6 +17,7 @@ export default {
Icon,
CommitFilesList,
EmptyState,
+ SuccessMessage,
Actions,
LoadingButton,
CommitMessageField,
@@ -34,9 +36,15 @@ export default {
},
},
computed: {
- ...mapState(['changedFiles', 'stagedFiles', 'rightPanelCollapsed']),
+ showStageUnstageArea() {
+ return !!(this.someUncommitedChanges || this.lastCommitMsg || !this.unusedSeal);
+ },
+ someUncommitedChanges() {
+ return !!(this.changedFiles.length || this.stagedFiles.length);
+ },
+ ...mapState(['changedFiles', 'stagedFiles', 'rightPanelCollapsed', 'lastCommitMsg', 'unusedSeal']),
...mapState('commit', ['commitMessage', 'submitCommitLoading']),
- ...mapGetters('commit', ['commitButtonDisabled', 'discardDraftButtonDisabled', 'branchName']),
+ ...mapGetters('commit', ['commitButtonDisabled', 'discardDraftButtonDisabled']),
},
methods: {
...mapActions('commit', [
@@ -69,7 +77,7 @@ export default {
</template>
</deprecated-modal>
<template
- v-if="changedFiles.length || stagedFiles.length"
+ v-if="showStageUnstageArea"
>
<commit-files-list
icon-name="unstaged"
@@ -89,11 +97,23 @@ export default {
:show-toggle="false"
:staged-list="true"
/>
+ </template>
+ <empty-state
+ v-if="unusedSeal"
+ :no-changes-state-svg-path="noChangesStateSvgPath"
+ />
+ <div
+ class="multi-file-commit-panel-bottom"
+ >
<form
class="form-horizontal multi-file-commit-form"
@submit.prevent.stop="commitChanges"
v-if="!rightPanelCollapsed"
>
+ <success-message
+ v-if="lastCommitMsg && !someUncommitedChanges"
+ :committed-state-svg-path="committedStateSvgPath"
+ />
<commit-message-field
:text="commitMessage"
@input="updateCommitMessage"
@@ -117,11 +137,6 @@ export default {
</button>
</div>
</form>
- </template>
- <empty-state
- v-else
- :no-changes-state-svg-path="noChangesStateSvgPath"
- :committed-state-svg-path="committedStateSvgPath"
- />
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/repo_file.vue b/app/assets/javascripts/ide/components/repo_file.vue
index e86db2da4a6..89c5ce70dd3 100644
--- a/app/assets/javascripts/ide/components/repo_file.vue
+++ b/app/assets/javascripts/ide/components/repo_file.vue
@@ -1,22 +1,29 @@
<script>
-import { mapActions } from 'vuex';
-import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
-import fileIcon from '~/vue_shared/components/file_icon.vue';
+import { mapActions, mapGetters } from 'vuex';
+import { n__, __, sprintf } from '~/locale';
+import tooltip from '~/vue_shared/directives/tooltip';
+import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
+import Icon from '~/vue_shared/components/icon.vue';
+import FileIcon from '~/vue_shared/components/file_icon.vue';
import router from '../ide_router';
-import newDropdown from './new_dropdown/index.vue';
-import fileStatusIcon from './repo_file_status_icon.vue';
-import changedFileIcon from './changed_file_icon.vue';
-import mrFileIcon from './mr_file_icon.vue';
+import NewDropdown from './new_dropdown/index.vue';
+import FileStatusIcon from './repo_file_status_icon.vue';
+import ChangedFileIcon from './changed_file_icon.vue';
+import MrFileIcon from './mr_file_icon.vue';
export default {
name: 'RepoFile',
+ directives: {
+ tooltip,
+ },
components: {
- skeletonLoadingContainer,
- newDropdown,
- fileStatusIcon,
- fileIcon,
- changedFileIcon,
- mrFileIcon,
+ SkeletonLoadingContainer,
+ NewDropdown,
+ FileStatusIcon,
+ FileIcon,
+ ChangedFileIcon,
+ MrFileIcon,
+ Icon,
},
props: {
file: {
@@ -29,6 +36,34 @@ export default {
},
},
computed: {
+ ...mapGetters([
+ 'getChangesInFolder',
+ 'getUnstagedFilesCountForPath',
+ 'getStagedFilesCountForPath',
+ ]),
+ folderUnstagedCount() {
+ return this.getUnstagedFilesCountForPath(this.file.path);
+ },
+ folderStagedCount() {
+ return this.getStagedFilesCountForPath(this.file.path);
+ },
+ changesCount() {
+ return this.getChangesInFolder(this.file.path);
+ },
+ folderChangesTooltip() {
+ if (this.changesCount === 0) return undefined;
+
+ if (this.folderUnstagedCount > 0 && this.folderStagedCount === 0) {
+ return n__('%d unstaged change', '%d unstaged changes', this.folderUnstagedCount);
+ } else if (this.folderUnstagedCount === 0 && this.folderStagedCount > 0) {
+ return n__('%d staged change', '%d staged changes', this.folderStagedCount);
+ }
+
+ return sprintf(__('%{unstaged} unstaged and %{staged} staged changes'), {
+ unstaged: this.folderUnstagedCount,
+ staged: this.folderStagedCount,
+ });
+ },
isTree() {
return this.file.type === 'tree';
},
@@ -48,10 +83,19 @@ export default {
'is-open': this.file.opened,
};
},
+ showTreeChangesCount() {
+ return this.isTree && this.changesCount > 0 && !this.file.opened;
+ },
+ showChangedFileIcon() {
+ return this.file.changed || this.file.tempFile || this.file.staged;
+ },
},
updated() {
if (this.file.type === 'blob' && this.file.active) {
- this.$el.scrollIntoView();
+ this.$el.scrollIntoView({
+ behavior: 'smooth',
+ block: 'nearest',
+ });
}
},
methods: {
@@ -101,8 +145,23 @@ export default {
<mr-file-icon
v-if="file.mrChange"
/>
+ <span
+ v-if="showTreeChangesCount"
+ class="ide-tree-changes"
+ >
+ {{ changesCount }}
+ <icon
+ v-tooltip
+ :title="folderChangesTooltip"
+ data-container="body"
+ data-placement="right"
+ name="file-modified"
+ :size="12"
+ css-classes="prepend-left-5 multi-file-modified"
+ />
+ </span>
<changed-file-icon
- v-if="file.changed || file.tempFile || file.staged"
+ v-else-if="showChangedFileIcon"
:file="file"
:show-tooltip="true"
:show-staged-icon="true"
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index 4c8c997e376..7358dd9ef92 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -149,6 +149,12 @@ export const updateTempFlagForEntry = ({ commit, dispatch, state }, { file, temp
export const toggleFileFinder = ({ commit }, fileFindVisible) =>
commit(types.TOGGLE_FILE_FINDER, fileFindVisible);
+export const burstUnusedSeal = ({ state, commit }) => {
+ if (state.unusedSeal) {
+ commit(types.BURST_UNUSED_SEAL);
+ }
+};
+
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 fcdb3b753b2..861830badee 100644
--- a/app/assets/javascripts/ide/stores/actions/file.js
+++ b/app/assets/javascripts/ide/stores/actions/file.js
@@ -117,7 +117,7 @@ export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) =
});
};
-export const changeFileContent = ({ state, commit }, { path, content }) => {
+export const changeFileContent = ({ commit, dispatch, state }, { path, content }) => {
const file = state.entries[path];
commit(types.UPDATE_FILE_CONTENT, { path, content });
@@ -128,6 +128,8 @@ export const changeFileContent = ({ state, commit }, { path, content }) => {
} else if (!file.changed && indexOfChangedFile !== -1) {
commit(types.REMOVE_FILE_FROM_CHANGED, path);
}
+
+ dispatch('burstUnusedSeal', {}, { root: true });
};
export const setFileLanguage = ({ getters, commit }, { fileLanguage }) => {
diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js
index ec1ea155aee..a93d29fd865 100644
--- a/app/assets/javascripts/ide/stores/getters.js
+++ b/app/assets/javascripts/ide/stores/getters.js
@@ -1,4 +1,5 @@
import { __ } from '~/locale';
+import { getChangesCountForFiles, filePathMatches } from './utils';
export const activeFile = state => state.openFiles.find(file => file.active) || null;
@@ -55,7 +56,23 @@ export const allBlobs = state =>
}, [])
.sort((a, b) => b.lastOpenedAt - a.lastOpenedAt);
+export const getChangedFile = state => path => state.changedFiles.find(f => f.path === path);
export const getStagedFile = state => path => state.stagedFiles.find(f => f.path === path);
+export const getChangesInFolder = state => path => {
+ const changedFilesCount = state.changedFiles.filter(f => filePathMatches(f, path)).length;
+ const stagedFilesCount = state.stagedFiles.filter(
+ f => filePathMatches(f, path) && !getChangedFile(state)(f.path),
+ ).length;
+
+ return changedFilesCount + stagedFilesCount;
+};
+
+export const getUnstagedFilesCountForPath = state => path =>
+ getChangesCountForFiles(state.changedFiles, path);
+
+export const getStagedFilesCountForPath = state => path =>
+ getChangesCountForFiles(state.stagedFiles, path);
+
// 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 349ff68f1e3..4fbc97d053e 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js
@@ -182,6 +182,10 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState }) =
}
commit(rootTypes.CLEAR_STAGED_CHANGES, null, { root: true });
+
+ setTimeout(() => {
+ commit(rootTypes.SET_LAST_COMMIT_MSG, '', { root: true });
+ }, 5000);
})
.then(() => dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH));
})
diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js
index f5c12db6db0..87b39379338 100644
--- a/app/assets/javascripts/ide/stores/mutation_types.js
+++ b/app/assets/javascripts/ide/stores/mutation_types.js
@@ -61,3 +61,4 @@ export const REMOVE_PENDING_TAB = 'REMOVE_PENDING_TAB';
export const UPDATE_TEMP_FLAG = 'UPDATE_TEMP_FLAG';
export const TOGGLE_FILE_FINDER = 'TOGGLE_FILE_FINDER';
+export const BURST_UNUSED_SEAL = 'BURST_UNUSED_SEAL';
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index 0c1d720df09..539a07116b3 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -128,6 +128,11 @@ export default {
}),
});
},
+ [types.BURST_UNUSED_SEAL](state) {
+ Object.assign(state, {
+ unusedSeal: false,
+ });
+ },
...projectMutations,
...mergeRequestMutation,
...fileMutations,
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 3470bb9aec0..0976d278559 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -18,5 +18,6 @@ export default () => ({
entries: {},
viewer: 'editor',
delayViewerUpdated: false,
+ unusedSeal: true,
fileFindVisible: false,
});
diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js
index 59185f8f0ad..bc79ff4a542 100644
--- a/app/assets/javascripts/ide/stores/utils.js
+++ b/app/assets/javascripts/ide/stores/utils.js
@@ -33,7 +33,6 @@ export const dataStructure = () => ({
raw: '',
content: '',
parentTreeUrl: '',
- parentPath: '',
renderError: false,
base64: false,
editorRow: 1,
@@ -43,6 +42,7 @@ export const dataStructure = () => ({
viewMode: 'edit',
previewMode: null,
size: 0,
+ parentPath: null,
lastOpenedAt: 0,
});
@@ -83,7 +83,6 @@ export const decorateData = entity => {
opened,
active,
parentTreeUrl,
- parentPath,
changed,
renderError,
content,
@@ -91,6 +90,7 @@ export const decorateData = entity => {
previewMode,
file_lock,
html,
+ parentPath,
};
};
@@ -137,3 +137,9 @@ export const sortTree = sortedTree =>
}),
)
.sort(sortTreesByTypeAndName);
+
+export const filePathMatches = (f, path) =>
+ f.path.replace(new RegExp(`${f.name}$`), '').indexOf(`${path}/`) === 0;
+
+export const getChangesCountForFiles = (files, path) =>
+ files.filter(f => filePathMatches(f, path)).length;
diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js
index b54ecd2d543..5e786ee6935 100644
--- a/app/assets/javascripts/lib/utils/text_utility.js
+++ b/app/assets/javascripts/lib/utils/text_utility.js
@@ -74,7 +74,11 @@ export function capitalizeFirstCharacter(text) {
* @param {*} replace
* @returns {String}
*/
-export const stripHtml = (string, replace = '') => string.replace(/<[^>]*>/g, replace);
+export const stripHtml = (string, replace = '') => {
+ if (!string) return string;
+
+ return string.replace(/<[^>]*>/g, replace);
+};
/**
* Converts snake_case string to camelCase
diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue
index 6d95153af28..8f9e6761d20 100644
--- a/app/assets/javascripts/sidebar/components/participants/participants.vue
+++ b/app/assets/javascripts/sidebar/components/participants/participants.vue
@@ -70,6 +70,9 @@
toggleMoreParticipants() {
this.isShowingMoreParticipants = !this.isShowingMoreParticipants;
},
+ onClickCollapsedIcon() {
+ this.$emit('toggleSidebar');
+ },
},
};
</script>
@@ -82,6 +85,7 @@
data-container="body"
data-placement="left"
:title="participantLabel"
+ @click="onClickCollapsedIcon"
>
<i
class="fa fa-users"
diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue
index 3e8cc7a6630..385717e7c1e 100644
--- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue
+++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue
@@ -1,6 +1,5 @@
<script>
import Store from '../../stores/sidebar_store';
-import eventHub from '../../event_hub';
import Flash from '../../../flash';
import { __ } from '../../../locale';
import subscriptions from './subscriptions.vue';
@@ -20,12 +19,6 @@ export default {
store: new Store(),
};
},
- created() {
- eventHub.$on('toggleSubscription', this.onToggleSubscription);
- },
- beforeDestroy() {
- eventHub.$off('toggleSubscription', this.onToggleSubscription);
- },
methods: {
onToggleSubscription() {
this.mediator.toggleSubscription()
@@ -42,6 +35,7 @@ export default {
<subscriptions
:loading="store.isFetching.subscriptions"
:subscribed="store.subscribed"
+ @toggleSubscription="onToggleSubscription"
/>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue
index d69d100a26c..f0df759ef7a 100644
--- a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue
+++ b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue
@@ -47,8 +47,25 @@
},
},
methods: {
+ /**
+ * We need to emit this event on both component & eventHub
+ * for 2 dependencies;
+ *
+ * 1. eventHub: This component is used in Issue Boards sidebar
+ * where component template is part of HAML
+ * and event listeners are tied to app's eventHub.
+ * 2. Component: This compone is also used in Epics in EE
+ * where listeners are tied to component event.
+ */
toggleSubscription() {
+ // App's eventHub event emission.
eventHub.$emit('toggleSubscription', this.id);
+
+ // Component event emission.
+ this.$emit('toggleSubscription', this.id);
+ },
+ onClickCollapsedIcon() {
+ this.$emit('toggleSidebar');
},
},
};
@@ -56,7 +73,10 @@
<template>
<div>
- <div class="sidebar-collapsed-icon">
+ <div
+ class="sidebar-collapsed-icon"
+ @click="onClickCollapsedIcon"
+ >
<span
v-tooltip
:title="notificationTooltip"
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.js b/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.js
deleted file mode 100644
index bf987562647..00000000000
--- a/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.js
+++ /dev/null
@@ -1,15 +0,0 @@
-export default {
- name: 'time-tracking-spent-only-pane',
- props: {
- timeSpentHumanReadable: {
- type: String,
- required: true,
- },
- },
- template: `
- <div class="time-tracking-spend-only-pane">
- <span class="bold">Spent:</span>
- {{ timeSpentHumanReadable }}
- </div>
- `,
-};
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue
new file mode 100644
index 00000000000..59cd99f8f14
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue
@@ -0,0 +1,18 @@
+<script>
+export default {
+ name: 'TimeTrackingSpentOnlyPane',
+ props: {
+ timeSpentHumanReadable: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="time-tracking-spend-only-pane">
+ <span class="bold">Spent:</span>
+ {{ timeSpentHumanReadable }}
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
index 9c003aa9f8a..8f5d0bee107 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
@@ -1,7 +1,7 @@
<script>
import TimeTrackingHelpState from './help_state.vue';
import TimeTrackingCollapsedState from './collapsed_state.vue';
-import timeTrackingSpentOnlyPane from './spent_only_pane';
+import TimeTrackingSpentOnlyPane from './spent_only_pane.vue';
import TimeTrackingNoTrackingPane from './no_tracking_pane.vue';
import TimeTrackingEstimateOnlyPane from './estimate_only_pane.vue';
import TimeTrackingComparisonPane from './comparison_pane.vue';
@@ -13,7 +13,7 @@ export default {
components: {
TimeTrackingCollapsedState,
TimeTrackingEstimateOnlyPane,
- 'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane,
+ TimeTrackingSpentOnlyPane,
TimeTrackingNoTrackingPane,
TimeTrackingComparisonPane,
TimeTrackingHelpState,
diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss
index 318d3ddaece..681242f8d85 100644
--- a/app/assets/stylesheets/pages/boards.scss
+++ b/app/assets/stylesheets/pages/boards.scss
@@ -317,6 +317,7 @@
a {
color: $gl-text-color;
word-wrap: break-word;
+ word-break: break-word;
margin-right: 2px;
}
}
@@ -462,6 +463,7 @@
.issuable-header-text {
padding-right: 35px;
+ word-break: break-word;
> strong {
font-weight: $gl-font-weight-bold;
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 11052be40a8..70ce5de6a6c 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -44,6 +44,12 @@
}
}
+ .note-text {
+ table {
+ font-family: $font-family-sans-serif;
+ }
+ }
+
table {
width: 100%;
font-family: $monospace_font;
diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss
index 6342042374f..e74606e864f 100644
--- a/app/assets/stylesheets/pages/repo.scss
+++ b/app/assets/stylesheets/pages/repo.scss
@@ -549,6 +549,7 @@
margin-bottom: 0;
border-bottom: 1px solid $white-dark;
padding: $gl-btn-padding 0;
+ min-height: 56px;
}
.multi-file-commit-panel-header-title {
@@ -602,14 +603,14 @@
}
}
-.multi-file-additions,
-.multi-file-additions-solid {
- fill: $green-500;
+.multi-file-addition,
+.multi-file-addition-solid {
+ color: $green-500;
}
.multi-file-modified,
.multi-file-modified-solid {
- fill: $orange-500;
+ color: $orange-500;
}
.multi-file-commit-list-collapsed {
@@ -673,6 +674,24 @@
}
}
+.multi-file-commit-panel-bottom {
+ position: relative;
+
+ .multi-file-commit-panel-success-message {
+ position: absolute;
+ top: 1px;
+ left: 3px;
+ bottom: 0;
+ right: 0;
+ z-index: 10;
+ background: $gray-light;
+ overflow: auto;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ }
+}
+
.dirty-diff {
// !important need to override monaco inline style
width: 4px !important;
@@ -972,6 +991,12 @@
resize: none;
}
+.ide-tree-changes {
+ display: flex;
+ align-items: center;
+ font-size: 12px;
+}
+
.ide-new-modal-label {
line-height: 34px;
}
diff --git a/app/models/ci/build_trace_chunk.rb b/app/models/ci/build_trace_chunk.rb
index 406b4f91ce7..2d21604325d 100644
--- a/app/models/ci/build_trace_chunk.rb
+++ b/app/models/ci/build_trace_chunk.rb
@@ -59,11 +59,14 @@ module Ci
end
def truncate(offset = 0)
- self.append("", offset) if offset < size
+ raise ArgumentError, 'Offset is out of range' if offset > size || offset < 0
+ return if offset == size # Skip the following process as it doesn't affect anything
+
+ self.append("", offset)
end
def append(new_data, offset)
- raise ArgumentError, 'Offset is out of range' if offset > data.bytesize || offset < 0
+ raise ArgumentError, 'Offset is out of range' if offset > size || offset < 0
raise ArgumentError, 'Chunk size overflow' if CHUNK_SIZE < (offset + new_data.bytesize)
set_data(data.byteslice(0, offset) + new_data)
@@ -130,7 +133,7 @@ module Ci
def schedule_to_db
return if db?
- BuildTraceChunkFlushToDbWorker.perform_async(id)
+ Ci::BuildTraceChunkFlushWorker.perform_async(id)
end
def fullfilled?
diff --git a/app/models/identity.rb b/app/models/identity.rb
index 1011b9f1109..3fd0c5e751d 100644
--- a/app/models/identity.rb
+++ b/app/models/identity.rb
@@ -1,12 +1,16 @@
class Identity < ActiveRecord::Base
+ def self.uniqueness_scope
+ :provider
+ end
+
include Sortable
include CaseSensitivity
belongs_to :user
validates :provider, presence: true
- validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider, case_sensitive: false }
- validates :user_id, uniqueness: { scope: :provider }
+ validates :extern_uid, allow_blank: true, uniqueness: { scope: uniqueness_scope, case_sensitive: false }
+ validates :user_id, uniqueness: { scope: uniqueness_scope }
before_save :ensure_normalized_extern_uid, if: :extern_uid_changed?
after_destroy :clear_user_synced_attributes, if: :user_synced_attributes_metadata_from_provider?
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 8f964a488aa..63c6ada86e1 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -323,7 +323,7 @@ class MergeRequest < ActiveRecord::Base
# updates `merge_jid` with the MergeWorker#jid.
# This helps tracking enqueued and ongoing merge jobs.
def merge_async(user_id, params)
- jid = MergeWorker.perform_async(id, user_id, params)
+ jid = MergeWorker.perform_async(id, user_id, params.to_h)
update_column(:merge_jid, jid)
end
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 4bf01ecb48c..d35ddf3eb39 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -35,7 +35,7 @@
= link_to avatar_icon_for_user(@user, 400), target: '_blank', rel: 'noopener noreferrer' do
= image_tag avatar_icon_for_user(@user, 90), class: "avatar s90", alt: ''
- .user-info
+ .user-info.prepend-left-default.append-right-default
.cover-title
= @user.name
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 0d30971dfd2..dc628bb7f50 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -66,7 +66,7 @@
- pipeline_processing:pipeline_update
- pipeline_processing:stage_update
- pipeline_processing:update_head_pipeline_for_merge_request
-- pipeline_processing:build_trace_chunk_flush_to_db
+- pipeline_processing:ci_build_trace_chunk_flush
- repository_check:repository_check_clear
- repository_check:repository_check_single_repository
diff --git a/app/workers/build_trace_chunk_flush_to_db_worker.rb b/app/workers/build_trace_chunk_flush_to_db_worker.rb
deleted file mode 100644
index 495118f7c14..00000000000
--- a/app/workers/build_trace_chunk_flush_to_db_worker.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class BuildTraceChunkFlushToDbWorker
- include ApplicationWorker
- include PipelineQueue
-
- queue_namespace :pipeline_processing
-
- def perform(build_trace_chunk_id)
- Ci::BuildTraceChunk.find_by(id: build_trace_chunk_id).try do |build_trace_chunk|
- build_trace_chunk.use_database!
- end
- end
-end
diff --git a/app/workers/ci/build_trace_chunk_flush_worker.rb b/app/workers/ci/build_trace_chunk_flush_worker.rb
new file mode 100644
index 00000000000..b8f8be29c7b
--- /dev/null
+++ b/app/workers/ci/build_trace_chunk_flush_worker.rb
@@ -0,0 +1,13 @@
+module Ci
+ class BuildTraceChunkFlushWorker
+ include ApplicationWorker
+
+ queue_namespace :pipeline_processing
+
+ def perform(build_trace_chunk_id)
+ ::Ci::BuildTraceChunk.find_by(id: build_trace_chunk_id).try do |build_trace_chunk|
+ build_trace_chunk.use_database!
+ end
+ end
+ end
+end