diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-30 12:09:39 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-30 12:09:39 +0300 |
commit | ada214dc52b53bd9eb3a79c279506f91c547f721 (patch) | |
tree | f4266ef83f9be3a62a0f8942911058758655929a /app/assets | |
parent | 27b43bd4d613cc7b8773ca0863b8d8f9b90f6d87 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
15 files changed, 202 insertions, 83 deletions
diff --git a/app/assets/javascripts/boards/constants.js b/app/assets/javascripts/boards/constants.js index 40f79a44b51..f577a168e75 100644 --- a/app/assets/javascripts/boards/constants.js +++ b/app/assets/javascripts/boards/constants.js @@ -1,3 +1,8 @@ +export const BoardType = { + project: 'project', + group: 'group', +}; + export const ListType = { assignee: 'assignee', milestone: 'milestone', @@ -11,5 +16,6 @@ export const ListType = { export const inactiveListId = 0; export default { + BoardType, ListType, }; diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index a12db7a5f1a..7c41182d554 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -16,10 +16,13 @@ import { getBoardsModalData, } from 'ee_else_ce/boards/ee_functions'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; import Flash from '~/flash'; import { __ } from '~/locale'; import './models/label'; import './models/assignee'; +import { BoardType } from './constants'; import FilteredSearchBoards from '~/boards/filtered_search_boards'; import eventHub from '~/boards/eventhub'; @@ -37,7 +40,16 @@ import { convertObjectPropsToCamelCase, parseBoolean, } from '~/lib/utils/common_utils'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import mountMultipleBoardsSwitcher from './mount_multiple_boards_switcher'; +import projectBoardQuery from './queries/project_board.query.graphql'; +import groupQuery from './queries/group_board.query.graphql'; + +Vue.use(VueApollo); + +const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), +}); let issueBoardsApp; @@ -79,18 +91,22 @@ export default () => { import('ee_component/boards/components/board_settings_sidebar.vue'), }, store, - data: { - state: boardsStore.state, - loading: true, - boardsEndpoint: $boardApp.dataset.boardsEndpoint, - recentBoardsEndpoint: $boardApp.dataset.recentBoardsEndpoint, - listsEndpoint: $boardApp.dataset.listsEndpoint, - boardId: $boardApp.dataset.boardId, - disabled: parseBoolean($boardApp.dataset.disabled), - issueLinkBase: $boardApp.dataset.issueLinkBase, - rootPath: $boardApp.dataset.rootPath, - bulkUpdatePath: $boardApp.dataset.bulkUpdatePath, - detailIssue: boardsStore.detail, + apolloProvider, + data() { + return { + state: boardsStore.state, + loading: 0, + boardsEndpoint: $boardApp.dataset.boardsEndpoint, + recentBoardsEndpoint: $boardApp.dataset.recentBoardsEndpoint, + listsEndpoint: $boardApp.dataset.listsEndpoint, + boardId: $boardApp.dataset.boardId, + disabled: parseBoolean($boardApp.dataset.disabled), + issueLinkBase: $boardApp.dataset.issueLinkBase, + rootPath: $boardApp.dataset.rootPath, + bulkUpdatePath: $boardApp.dataset.bulkUpdatePath, + detailIssue: boardsStore.detail, + parent: $boardApp.dataset.parent, + }; }, computed: { detailIssueVisible() { @@ -124,31 +140,56 @@ export default () => { this.filterManager.setup(); boardsStore.disabled = this.disabled; - boardsStore - .all() - .then(res => res.data) - .then(lists => { - lists.forEach(listObj => { - let { position } = listObj; - if (listObj.list_type === 'closed') { - position = Infinity; - } else if (listObj.list_type === 'backlog') { - position = -1; + + if (gon.features.graphqlBoardLists) { + this.$apollo.addSmartQuery('lists', { + query() { + return this.parent === BoardType.group ? groupQuery : projectBoardQuery; + }, + variables() { + return { + fullPath: this.state.endpoints.fullPath, + boardId: `gid://gitlab/Board/${this.boardId}`, + }; + }, + update(data) { + return this.getNodes(data); + }, + result({ data, error }) { + if (error) { + throw error; } - boardsStore.addList({ - ...listObj, - position, - }); - }); + const lists = this.getNodes(data); + + lists.forEach(list => + boardsStore.addList({ + ...list, + id: getIdFromGraphQLId(list.id), + }), + ); - boardsStore.addBlankState(); - setPromotionState(boardsStore); - this.loading = false; - }) - .catch(() => { - Flash(__('An error occurred while fetching the board lists. Please try again.')); + boardsStore.addBlankState(); + setPromotionState(boardsStore); + }, + error() { + Flash(__('An error occurred while fetching the board lists. Please try again.')); + }, }); + } else { + boardsStore + .all() + .then(res => res.data) + .then(lists => { + lists.forEach(list => boardsStore.addList(list)); + boardsStore.addBlankState(); + setPromotionState(boardsStore); + this.loading = false; + }) + .catch(() => { + Flash(__('An error occurred while fetching the board lists. Please try again.')); + }); + } }, methods: { updateTokens() { @@ -233,6 +274,9 @@ export default () => { }); } }, + getNodes(data) { + return data[this.parent]?.board?.lists.nodes; + }, }, }); diff --git a/app/assets/javascripts/boards/models/assignee.js b/app/assets/javascripts/boards/models/assignee.js index 5f5758583bb..1e822d06bfd 100644 --- a/app/assets/javascripts/boards/models/assignee.js +++ b/app/assets/javascripts/boards/models/assignee.js @@ -3,7 +3,7 @@ export default class ListAssignee { this.id = obj.id; this.name = obj.name; this.username = obj.username; - this.avatar = obj.avatar_url || obj.avatar || gon.default_avatar_url; + this.avatar = obj.avatarUrl || obj.avatar_url || obj.avatar || gon.default_avatar_url; this.path = obj.path; this.state = obj.state; this.webUrl = obj.web_url || obj.webUrl; diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js index af1a910149e..878f49cc6be 100644 --- a/app/assets/javascripts/boards/models/issue.js +++ b/app/assets/javascripts/boards/models/issue.js @@ -15,7 +15,7 @@ class ListIssue { this.labels = []; this.assignees = []; this.selected = false; - this.position = obj.relative_position || Infinity; + this.position = obj.position || obj.relative_position || Infinity; this.isFetching = { subscriptions: true, }; diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index cd46f8cd1a4..31c372b7a75 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -39,8 +39,8 @@ class List { this.id = obj.id; this._uid = this.guid(); this.position = obj.position; - this.title = obj.list_type === 'backlog' ? __('Open') : obj.title; - this.type = obj.list_type; + this.title = (obj.list_type || obj.listType) === 'backlog' ? __('Open') : obj.title; + this.type = obj.list_type || obj.listType; const typeInfo = this.getTypeInfo(this.type); this.preset = Boolean(typeInfo.isPreset); @@ -51,14 +51,12 @@ class List { this.loadingMore = false; this.issues = obj.issues || []; this.issuesSize = obj.issuesSize ? obj.issuesSize : 0; - this.maxIssueCount = Object.hasOwnProperty.call(obj, 'max_issue_count') - ? obj.max_issue_count - : 0; + this.maxIssueCount = obj.maxIssueCount || obj.max_issue_count || 0; if (obj.label) { this.label = new ListLabel(obj.label); - } else if (obj.user) { - this.assignee = new ListAssignee(obj.user); + } else if (obj.user || obj.assignee) { + this.assignee = new ListAssignee(obj.user || obj.assignee); this.title = this.assignee.name; } else if (IS_EE && obj.milestone) { this.milestone = new ListMilestone(obj.milestone); diff --git a/app/assets/javascripts/boards/queries/board_list.fragment.graphql b/app/assets/javascripts/boards/queries/board_list.fragment.graphql new file mode 100644 index 00000000000..bbf3314377e --- /dev/null +++ b/app/assets/javascripts/boards/queries/board_list.fragment.graphql @@ -0,0 +1,5 @@ +#import "./board_list_shared.fragment.graphql" + +fragment BoardListFragment on BoardList { + ...BoardListShared +} diff --git a/app/assets/javascripts/boards/queries/board_list_shared.fragment.graphql b/app/assets/javascripts/boards/queries/board_list_shared.fragment.graphql new file mode 100644 index 00000000000..6ba6c05d6d9 --- /dev/null +++ b/app/assets/javascripts/boards/queries/board_list_shared.fragment.graphql @@ -0,0 +1,15 @@ +fragment BoardListShared on BoardList { + id, + title, + position, + listType, + collapsed, + label { + id, + title, + color, + textColor, + description, + descriptionHtml + } +} diff --git a/app/assets/javascripts/boards/queries/group_board.query.graphql b/app/assets/javascripts/boards/queries/group_board.query.graphql new file mode 100644 index 00000000000..cb42cb3f73d --- /dev/null +++ b/app/assets/javascripts/boards/queries/group_board.query.graphql @@ -0,0 +1,13 @@ +#import "ee_else_ce/boards/queries/board_list.fragment.graphql" + +query GroupBoard($fullPath: ID!, $boardId: ID!) { + group(fullPath: $fullPath) { + board(id: $boardId) { + lists { + nodes { + ...BoardListFragment + } + } + } + } +} diff --git a/app/assets/javascripts/boards/queries/project_board.query.graphql b/app/assets/javascripts/boards/queries/project_board.query.graphql new file mode 100644 index 00000000000..4620a7e0fd5 --- /dev/null +++ b/app/assets/javascripts/boards/queries/project_board.query.graphql @@ -0,0 +1,13 @@ +#import "ee_else_ce/boards/queries/board_list.fragment.graphql" + +query ProjectBoard($fullPath: ID!, $boardId: ID!) { + project(fullPath: $fullPath) { + board(id: $boardId) { + lists { + nodes { + ...BoardListFragment + } + } + } + } +} diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index d20b99ecfaa..b8ae6396475 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -80,7 +80,15 @@ const boardsStore = { this.state.currentPage = page; }, addList(listObj) { - const list = new List(listObj); + const listType = listObj.listType || listObj.list_type; + let { position } = listObj; + if (listType === ListType.closed) { + position = Infinity; + } else if (listType === ListType.backlog) { + position = -1; + } + + const list = new List({ ...listObj, position }); this.state.lists = sortBy([...this.state.lists, list], 'position'); return list; }, diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue index 0cc6f3df2d7..0a5538237f9 100644 --- a/app/assets/javascripts/environments/components/environments_app.vue +++ b/app/assets/javascripts/environments/components/environments_app.vue @@ -1,6 +1,5 @@ <script> import { GlDeprecatedButton } from '@gitlab/ui'; -import envrionmentsAppMixin from 'ee_else_ce/environments/mixins/environments_app_mixin'; import Flash from '~/flash'; import { s__ } from '~/locale'; import emptyState from './empty_state.vue'; @@ -22,13 +21,18 @@ export default { DeleteEnvironmentModal, }, - mixins: [CIPaginationMixin, environmentsMixin, envrionmentsAppMixin], + mixins: [CIPaginationMixin, environmentsMixin], props: { endpoint: { type: String, required: true, }, + canaryDeploymentFeatureId: { + type: String, + required: false, + default: '', + }, canCreateEnvironment: { type: Boolean, required: true, @@ -41,6 +45,11 @@ export default { type: String, required: true, }, + helpCanaryDeploymentsPath: { + type: String, + required: false, + default: '', + }, helpPagePath: { type: String, required: true, @@ -50,17 +59,37 @@ export default { required: false, default: '', }, + lockPromotionSvgPath: { + type: String, + required: false, + default: '', + }, + showCanaryDeploymentCallout: { + type: Boolean, + required: false, + default: false, + }, + userCalloutsPath: { + type: String, + required: false, + default: '', + }, }, created() { eventHub.$on('toggleFolder', this.toggleFolder); + eventHub.$on('toggleDeployBoard', this.toggleDeployBoard); }, beforeDestroy() { eventHub.$off('toggleFolder'); + eventHub.$off('toggleDeployBoard'); }, methods: { + toggleDeployBoard(model) { + this.store.toggleDeployBoard(model.id); + }, toggleFolder(folder) { this.store.toggleFolder(folder); diff --git a/app/assets/javascripts/environments/mixins/environments_app_mixin.js b/app/assets/javascripts/environments/mixins/environments_app_mixin.js deleted file mode 100644 index fc805b9235a..00000000000 --- a/app/assets/javascripts/environments/mixins/environments_app_mixin.js +++ /dev/null @@ -1,32 +0,0 @@ -export default { - props: { - canaryDeploymentFeatureId: { - type: String, - required: false, - default: '', - }, - showCanaryDeploymentCallout: { - type: Boolean, - required: false, - default: false, - }, - userCalloutsPath: { - type: String, - required: false, - default: '', - }, - lockPromotionSvgPath: { - type: String, - required: false, - default: '', - }, - helpCanaryDeploymentsPath: { - type: String, - required: false, - default: '', - }, - }, - metods: { - toggleDeployBoard() {}, - }, -}; diff --git a/app/assets/javascripts/environments/stores/environments_store.js b/app/assets/javascripts/environments/stores/environments_store.js index 6b7c1ff627d..e07ec693948 100644 --- a/app/assets/javascripts/environments/stores/environments_store.js +++ b/app/assets/javascripts/environments/stores/environments_store.js @@ -133,6 +133,17 @@ export default class EnvironmentsStore { } /** + * Toggles deploy board visibility for the provided environment ID. + * Currently only works on EE. + * + * @param {Object} environment + * @return {Array} + */ + toggleDeployBoard() { + return this.state.environments; + } + + /** * Toggles folder open property for the given folder. * * @param {Object} folder diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue index 6efddec1172..e4edcc2448c 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue +++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue @@ -12,6 +12,7 @@ import { visibilityLevelDescriptions, featureAccessLevelMembers, featureAccessLevelEveryone, + featureAccessLevel, } from '../constants'; import { toggleHiddenClassBySelector } from '../external'; @@ -127,7 +128,7 @@ export default { wikiAccessLevel: 20, snippetsAccessLevel: 20, pagesAccessLevel: 20, - metricsAccessLevel: visibilityOptions.PRIVATE, + metricsDashboardAccessLevel: featureAccessLevel.PROJECT_MEMBERS, containerRegistryEnabled: true, lfsEnabled: true, requestAccessEnabled: true, @@ -174,6 +175,10 @@ export default { return options; }, + metricsOptionsDropdownEnabled() { + return this.featureAccessLevelOptions.length < 2; + }, + repositoryEnabled() { return this.repositoryAccessLevel > 0; }, @@ -211,6 +216,7 @@ export default { this.buildsAccessLevel = Math.min(10, this.buildsAccessLevel); this.wikiAccessLevel = Math.min(10, this.wikiAccessLevel); this.snippetsAccessLevel = Math.min(10, this.snippetsAccessLevel); + this.metricsDashboardAccessLevel = Math.min(10, this.metricsDashboardAccessLevel); if (this.pagesAccessLevel === 20) { // When from Internal->Private narrow access for only members this.pagesAccessLevel = 10; @@ -225,6 +231,7 @@ export default { if (this.wikiAccessLevel > 0) this.wikiAccessLevel = 20; if (this.snippetsAccessLevel > 0) this.snippetsAccessLevel = 20; if (this.pagesAccessLevel === 10) this.pagesAccessLevel = 20; + if (this.metricsDashboardAccessLevel === 10) this.metricsDashboardAccessLevel = 20; this.highlightChanges(); } }, @@ -485,17 +492,18 @@ export default { <div class="project-feature-controls"> <div class="select-wrapper"> <select - v-model="metricsAccessLevel" + v-model="metricsDashboardAccessLevel" + :disabled="metricsOptionsDropdownEnabled" name="project[project_feature_attributes][metrics_dashboard_access_level]" - class="form-control select-control" + class="form-control project-repo-select select-control" > <option - :value="visibilityOptions.PRIVATE" - :disabled="!visibilityAllowed(visibilityOptions.PRIVATE)" + :value="featureAccessLevelMembers[0]" + :disabled="!visibilityAllowed(visibilityOptions.INTERNAL)" >{{ featureAccessLevelMembers[1] }}</option > <option - :value="visibilityOptions.PUBLIC" + :value="featureAccessLevelEveryone[0]" :disabled="!visibilityAllowed(visibilityOptions.PUBLIC)" >{{ featureAccessLevelEveryone[1] }}</option > diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 320bd4adaaa..7f50c50145b 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -434,6 +434,7 @@ img.emoji { .append-bottom-20 { margin-bottom: 20px; } .append-bottom-default { margin-bottom: $gl-padding; } .prepend-bottom-32 { margin-bottom: 32px; } +.ml-10 { margin-left: 4.5rem; } .inline { display: inline-block; } .center { text-align: center; } .block { display: block; } |