Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/api/projects_api.js7
-rw-r--r--app/assets/javascripts/groups/settings/components/group_settings_readme.vue147
-rw-r--r--app/assets/javascripts/groups/settings/constants.js4
-rw-r--r--app/assets/javascripts/groups/settings/init_group_settings_readme.js24
-rw-r--r--app/assets/javascripts/lib/utils/web_ide_navigator.js24
-rw-r--r--app/assets/javascripts/pages/groups/edit/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js2
-rw-r--r--app/assets/javascripts/repository/components/fork_info.vue46
-rw-r--r--app/assets/javascripts/repository/index.js6
-rw-r--r--app/assets/javascripts/super_sidebar/components/merge_request_menu.vue7
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_bar.vue9
-rw-r--r--app/assets/stylesheets/components/whats_new.scss14
12 files changed, 267 insertions, 26 deletions
diff --git a/app/assets/javascripts/api/projects_api.js b/app/assets/javascripts/api/projects_api.js
index 5a794dcd035..c72a913aacd 100644
--- a/app/assets/javascripts/api/projects_api.js
+++ b/app/assets/javascripts/api/projects_api.js
@@ -35,6 +35,13 @@ export function getProjects(query, options, callback = () => {}) {
});
}
+export function createProject(projectData) {
+ const url = buildApiUrl(PROJECTS_PATH);
+ return axios.post(url, projectData).then(({ data }) => {
+ return data;
+ });
+}
+
export function importProjectMembers(sourceId, targetId) {
const url = buildApiUrl(PROJECT_IMPORT_MEMBERS_PATH)
.replace(':id', sourceId)
diff --git a/app/assets/javascripts/groups/settings/components/group_settings_readme.vue b/app/assets/javascripts/groups/settings/components/group_settings_readme.vue
new file mode 100644
index 00000000000..123c7fc58f5
--- /dev/null
+++ b/app/assets/javascripts/groups/settings/components/group_settings_readme.vue
@@ -0,0 +1,147 @@
+<script>
+import { GlButton, GlModal, GlModalDirective, GlSprintf } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import { createProject } from '~/rest_api';
+import { createAlert } from '~/alert';
+import { openWebIDE } from '~/lib/utils/web_ide_navigator';
+import { README_MODAL_ID, GITLAB_README_PROJECT, README_FILE } from '../constants';
+
+export default {
+ name: 'GroupSettingsReadme',
+ i18n: {
+ readme: __('README'),
+ addReadme: __('Add README'),
+ cancel: __('Cancel'),
+ createProjectAndReadme: s__('Groups|Create and add README'),
+ creatingReadme: s__('Groups|Creating README'),
+ existingProjectNewReadme: s__('Groups|This will create a README.md for project %{path}.'),
+ newProjectAndReadme: s__('Groups|This will create a project %{path} and add a README.md.'),
+ errorCreatingProject: s__('Groups|There was an error creating the Group README.'),
+ },
+ components: {
+ GlButton,
+ GlModal,
+ GlSprintf,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ props: {
+ groupReadmePath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ readmeProjectPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ groupPath: {
+ type: String,
+ required: true,
+ },
+ groupId: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ creatingReadme: false,
+ };
+ },
+ computed: {
+ hasReadme() {
+ return this.groupReadmePath.length > 0;
+ },
+ hasReadmeProject() {
+ return this.readmeProjectPath.length > 0;
+ },
+ pathToReadmeProject() {
+ return this.hasReadmeProject
+ ? this.readmeProjectPath
+ : `${this.groupPath}/${GITLAB_README_PROJECT}`;
+ },
+ modalBody() {
+ return this.hasReadmeProject
+ ? this.$options.i18n.existingProjectNewReadme
+ : this.$options.i18n.newProjectAndReadme;
+ },
+ modalSubmitButtonText() {
+ return this.hasReadmeProject
+ ? this.$options.i18n.addReadme
+ : this.$options.i18n.createProjectAndReadme;
+ },
+ },
+ methods: {
+ hideModal() {
+ this.$refs.modal.hide();
+ },
+ createReadme() {
+ if (this.hasReadmeProject) {
+ openWebIDE(this.readmeProjectPath, README_FILE);
+ } else {
+ this.createProjectWithReadme();
+ }
+ },
+ createProjectWithReadme() {
+ this.creatingReadme = true;
+
+ const projectData = {
+ name: GITLAB_README_PROJECT,
+ namespace_id: this.groupId,
+ };
+
+ createProject(projectData)
+ .then(({ path_with_namespace: pathWithNamespace }) => {
+ openWebIDE(pathWithNamespace, README_FILE);
+ })
+ .catch(() => {
+ this.hideModal();
+ this.creatingReadme = false;
+ createAlert({ message: this.$options.i18n.errorCreatingProject });
+ });
+ },
+ },
+ README_MODAL_ID,
+};
+</script>
+
+<template>
+ <div>
+ <gl-button v-if="hasReadme" icon="doc-text" :href="groupReadmePath">{{
+ $options.i18n.readme
+ }}</gl-button>
+ <gl-button
+ v-else
+ v-gl-modal="$options.README_MODAL_ID"
+ variant="dashed"
+ icon="file-addition"
+ data-testid="group-settings-add-readme-button"
+ >{{ $options.i18n.addReadme }}</gl-button
+ >
+ <gl-modal ref="modal" :modal-id="$options.README_MODAL_ID" :title="$options.i18n.addReadme">
+ <div data-testid="group-settings-modal-readme-body">
+ <gl-sprintf :message="modalBody">
+ <template #path>
+ <code>{{ pathToReadmeProject }}</code>
+ </template>
+ </gl-sprintf>
+ </div>
+ <template #modal-footer>
+ <gl-button variant="default" @click="hideModal">{{ $options.i18n.cancel }}</gl-button>
+ <gl-button v-if="creatingReadme" variant="default" loading disabled>{{
+ $options.i18n.creatingReadme
+ }}</gl-button>
+ <gl-button
+ v-else
+ variant="confirm"
+ data-testid="group-settings-modal-create-readme-button"
+ @click="createReadme"
+ >{{ modalSubmitButtonText }}</gl-button
+ >
+ </template>
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/groups/settings/constants.js b/app/assets/javascripts/groups/settings/constants.js
index c91c2a20529..023ddf29b36 100644
--- a/app/assets/javascripts/groups/settings/constants.js
+++ b/app/assets/javascripts/groups/settings/constants.js
@@ -1,3 +1,7 @@
export const LEVEL_TYPES = {
GROUP: 'group',
};
+
+export const README_MODAL_ID = 'add_group_readme_modal';
+export const GITLAB_README_PROJECT = 'gitlab-profile';
+export const README_FILE = 'README.md';
diff --git a/app/assets/javascripts/groups/settings/init_group_settings_readme.js b/app/assets/javascripts/groups/settings/init_group_settings_readme.js
new file mode 100644
index 00000000000..d126228d854
--- /dev/null
+++ b/app/assets/javascripts/groups/settings/init_group_settings_readme.js
@@ -0,0 +1,24 @@
+import Vue from 'vue';
+import GroupSettingsReadme from './components/group_settings_readme.vue';
+
+export const initGroupSettingsReadme = () => {
+ const el = document.getElementById('js-group-settings-readme');
+
+ if (!el) return false;
+
+ const { groupReadmePath, readmeProjectPath, groupPath, groupId } = el.dataset;
+
+ return new Vue({
+ el,
+ render(createElement) {
+ return createElement(GroupSettingsReadme, {
+ props: {
+ groupReadmePath,
+ readmeProjectPath,
+ groupPath,
+ groupId,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/lib/utils/web_ide_navigator.js b/app/assets/javascripts/lib/utils/web_ide_navigator.js
new file mode 100644
index 00000000000..f0579b5886d
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/web_ide_navigator.js
@@ -0,0 +1,24 @@
+import { visitUrl, webIDEUrl } from '~/lib/utils/url_utility';
+
+/**
+ * Takes a project path and optional file path and branch
+ * and then redirects the user to the web IDE.
+ *
+ * @param {string} projectPath - Full path to project including namespace (ex. flightjs/Flight)
+ * @param {string} filePath - optional path to file to be edited, otherwise will open at base directory (ex. README.md)
+ * @param {string} branch - optional branch to open the IDE, defaults to 'main'
+ */
+
+export const openWebIDE = (projectPath, filePath, branch = 'main') => {
+ if (!projectPath) {
+ throw new TypeError('projectPath parameter is required');
+ }
+
+ const pathnameSegments = [projectPath, 'edit', branch, '-'];
+
+ if (filePath) {
+ pathnameSegments.push(filePath);
+ }
+
+ visitUrl(webIDEUrl(`/${pathnameSegments.join('/')}/`));
+};
diff --git a/app/assets/javascripts/pages/groups/edit/index.js b/app/assets/javascripts/pages/groups/edit/index.js
index dec06fe6f4d..721168f6140 100644
--- a/app/assets/javascripts/pages/groups/edit/index.js
+++ b/app/assets/javascripts/pages/groups/edit/index.js
@@ -9,6 +9,7 @@ import mountBadgeSettings from '~/pages/shared/mount_badge_settings';
import initSearchSettings from '~/search_settings';
import initSettingsPanels from '~/settings_panels';
import initConfirmDanger from '~/init_confirm_danger';
+import { initGroupSettingsReadme } from '~/groups/settings/init_group_settings_readme';
initFilePickers();
initConfirmDanger();
@@ -27,3 +28,5 @@ initProjectSelects();
initSearchSettings();
initCascadingSettingsLockPopovers();
+
+initGroupSettingsReadme();
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index dd39fb7c666..2f8c2a8e86f 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -102,6 +102,7 @@ const initForkInfo = () => {
sourceDefaultBranch,
aheadComparePath,
behindComparePath,
+ canUserCreateMrInFork,
} = forkEl.dataset;
return new Vue({
el: forkEl,
@@ -116,6 +117,7 @@ const initForkInfo = () => {
sourceDefaultBranch,
aheadComparePath,
behindComparePath,
+ canUserCreateMrInFork,
},
});
},
diff --git a/app/assets/javascripts/repository/components/fork_info.vue b/app/assets/javascripts/repository/components/fork_info.vue
index d84e197714e..a7795c8da0a 100644
--- a/app/assets/javascripts/repository/components/fork_info.vue
+++ b/app/assets/javascripts/repository/components/fork_info.vue
@@ -24,7 +24,8 @@ export const i18n = {
behindAhead: s__('ForksDivergence|%{messages} the upstream repository.'),
limitedVisibility: s__('ForksDivergence|Source project has a limited visibility.'),
error: s__('ForksDivergence|Failed to fetch fork details. Try again later.'),
- sync: s__('ForksDivergence|Update fork'),
+ updateFork: s__('ForksDivergence|Update fork'),
+ createMergeRequest: s__('ForksDivergence|Create merge request'),
};
export default {
@@ -103,6 +104,16 @@ export default {
required: false,
default: '',
},
+ createMrPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ canUserCreateMrInFork: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -173,12 +184,15 @@ export default {
hasBehindAheadMessage() {
return this.behindAheadMessage.length > 0;
},
- isSyncButtonAvailable() {
+ hasUpdateButton() {
return (
this.glFeatures.synchronizeFork &&
((this.sourceName && this.forkDetails && this.behind) || this.isUnknownDivergence)
);
},
+ hasCreateMrButton() {
+ return this.canUserCreateMrInFork && this.ahead && this.createMrPath;
+ },
forkDivergenceMessage() {
if (!this.forkDetails) {
return this.$options.i18n.limitedVisibility;
@@ -286,14 +300,26 @@ export default {
>
{{ $options.i18n.inaccessibleProject }}
</div>
- <gl-button
- v-if="isSyncButtonAvailable"
- :disabled="forkDetails.isSyncing"
- @click="checkIfSyncIsPossible"
- >
- <gl-loading-icon v-if="forkDetails.isSyncing" class="gl-display-inline" size="sm" />
- <span>{{ $options.i18n.sync }}</span>
- </gl-button>
+ <div class="gl-display-flex gl-xs-display-none!">
+ <gl-button
+ v-if="hasCreateMrButton"
+ class="gl-ml-4"
+ :href="createMrPath"
+ data-testid="create-mr-button"
+ >
+ <span>{{ $options.i18n.createMergeRequest }}</span>
+ </gl-button>
+ <gl-button
+ v-if="hasUpdateButton"
+ class="gl-ml-4"
+ :disabled="forkDetails.isSyncing"
+ data-testid="update-fork-button"
+ @click="checkIfSyncIsPossible"
+ >
+ <gl-loading-icon v-if="forkDetails.isSyncing" class="gl-display-inline" size="sm" />
+ <span>{{ $options.i18n.updateFork }}</span>
+ </gl-button>
+ </div>
<conflicts-modal
ref="modal"
:source-name="sourceName"
diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js
index 8dc67b97a60..b1217881bc3 100644
--- a/app/assets/javascripts/repository/index.js
+++ b/app/assets/javascripts/repository/index.js
@@ -74,8 +74,10 @@ export default function setupVueRepositoryList() {
sourceName,
sourcePath,
sourceDefaultBranch,
+ createMrPath,
aheadComparePath,
behindComparePath,
+ canUserCreateMrInFork,
} = forkEl.dataset;
return new Vue({
el: forkEl,
@@ -90,6 +92,8 @@ export default function setupVueRepositoryList() {
sourceDefaultBranch,
aheadComparePath,
behindComparePath,
+ createMrPath,
+ canUserCreateMrInFork,
},
});
},
@@ -153,8 +157,8 @@ export default function setupVueRepositoryList() {
initLastCommitApp();
initBlobControlsApp();
- initForkInfo();
initRefSwitcher();
+ initForkInfo();
router.afterEach(({ params: { path } }) => {
setTitle(path, ref, fullName);
diff --git a/app/assets/javascripts/super_sidebar/components/merge_request_menu.vue b/app/assets/javascripts/super_sidebar/components/merge_request_menu.vue
index 94fc6aedcc0..d37e863bed9 100644
--- a/app/assets/javascripts/super_sidebar/components/merge_request_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/merge_request_menu.vue
@@ -16,7 +16,12 @@ export default {
</script>
<template>
- <gl-disclosure-dropdown :items="items" placement="center">
+ <gl-disclosure-dropdown
+ :items="items"
+ placement="center"
+ @shown="$emit('shown')"
+ @hidden="$emit('hidden')"
+ >
<template #toggle>
<slot></slot>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue
index e03c587567e..498c082ddb2 100644
--- a/app/assets/javascripts/super_sidebar/components/user_bar.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue
@@ -56,6 +56,11 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ mrMenuShown: false,
+ };
+ },
methods: {
collapseSidebar() {
toggleSuperSidebarCollapsed(true, true, true);
@@ -144,9 +149,11 @@ export default {
<merge-request-menu
class="gl-flex-basis-third gl-display-block!"
:items="sidebarData.merge_request_menu"
+ @shown="mrMenuShown = true"
+ @hidden="mrMenuShown = false"
>
<counter
- v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.mergeRequests"
+ v-gl-tooltip:super-sidebar.hover.bottom="mrMenuShown ? '' : $options.i18n.mergeRequests"
class="gl-w-full"
icon="merge-request-open"
:count="sidebarData.total_merge_requests_count"
diff --git a/app/assets/stylesheets/components/whats_new.scss b/app/assets/stylesheets/components/whats_new.scss
index c1c68f64d86..35c619a2e2f 100644
--- a/app/assets/stylesheets/components/whats_new.scss
+++ b/app/assets/stylesheets/components/whats_new.scss
@@ -1,5 +1,5 @@
.whats-new-drawer {
- margin-top: $header-height;
+ margin-top: calc(#{$header-height} + #{$calc-application-bars-height});
@include gl-shadow-none;
overflow-y: hidden;
width: 500px;
@@ -35,18 +35,6 @@
}
}
-.with-performance-bar .whats-new-drawer {
- margin-top: calc(#{$performance-bar-height} + #{$header-height});
-}
-
-.with-system-header .whats-new-drawer {
- margin-top: calc(#{$system-header-height} + #{$header-height});
-}
-
-.with-performance-bar.with-system-header .whats-new-drawer {
- margin-top: calc(#{$performance-bar-height} + #{$system-header-height} + #{$header-height});
-}
-
.whats-new-item-title-link {
&:hover,
&:focus,