diff options
Diffstat (limited to 'app/assets/javascripts/groups/stores/groups_store.js')
-rw-r--r-- | app/assets/javascripts/groups/stores/groups_store.js | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/app/assets/javascripts/groups/stores/groups_store.js b/app/assets/javascripts/groups/stores/groups_store.js new file mode 100644 index 00000000000..6eab6083e8f --- /dev/null +++ b/app/assets/javascripts/groups/stores/groups_store.js @@ -0,0 +1,166 @@ +import Vue from 'vue'; + +export default class GroupsStore { + constructor() { + this.state = {}; + this.state.groups = {}; + this.state.pageInfo = {}; + } + + setGroups(rawGroups, parent) { + const parentGroup = parent; + const tree = this.buildTree(rawGroups, parentGroup); + + if (parentGroup) { + parentGroup.subGroups = tree; + } else { + this.state.groups = tree; + } + + return tree; + } + + // eslint-disable-next-line class-methods-use-this + resetGroups(parent) { + const parentGroup = parent; + parentGroup.subGroups = {}; + } + + storePagination(pagination = {}) { + let paginationInfo; + + if (Object.keys(pagination).length) { + const normalizedHeaders = gl.utils.normalizeHeaders(pagination); + paginationInfo = gl.utils.parseIntPagination(normalizedHeaders); + } else { + paginationInfo = pagination; + } + + this.state.pageInfo = paginationInfo; + } + + buildTree(rawGroups, parentGroup) { + const groups = this.decorateGroups(rawGroups); + const tree = {}; + const mappedGroups = {}; + const orphans = []; + + // Map groups to an object + groups.map((group) => { + mappedGroups[`id${group.id}`] = group; + mappedGroups[`id${group.id}`].subGroups = {}; + return group; + }); + + Object.keys(mappedGroups).map((key) => { + const currentGroup = mappedGroups[key]; + if (currentGroup.parentId) { + // If the group is not at the root level, add it to its parent array of subGroups. + const findParentGroup = mappedGroups[`id${currentGroup.parentId}`]; + if (findParentGroup) { + mappedGroups[`id${currentGroup.parentId}`].subGroups[`id${currentGroup.id}`] = currentGroup; + mappedGroups[`id${currentGroup.parentId}`].isOpen = true; // Expand group if it has subgroups + } else if (parentGroup && parentGroup.id === currentGroup.parentId) { + tree[`id${currentGroup.id}`] = currentGroup; + } else { + // No parent found. We save it for later processing + orphans.push(currentGroup); + + // Add to tree to preserve original order + tree[`id${currentGroup.id}`] = currentGroup; + } + } else { + // If the group is at the top level, add it to first level elements array. + tree[`id${currentGroup.id}`] = currentGroup; + } + + return key; + }); + + if (orphans.length) { + orphans.map((orphan) => { + let found = false; + const currentOrphan = orphan; + + Object.keys(tree).map((key) => { + const group = tree[key]; + + if ( + group && + currentOrphan.fullPath.lastIndexOf(group.fullPath) === 0 && + // Make sure the currently selected orphan is not the same as the group + // we are checking here otherwise it will end up in an infinite loop + currentOrphan.id !== group.id + ) { + group.subGroups[currentOrphan.id] = currentOrphan; + group.isOpen = true; + currentOrphan.isOrphan = true; + found = true; + + // Delete if group was put at the top level. If not the group will be displayed twice. + if (tree[`id${currentOrphan.id}`]) { + delete tree[`id${currentOrphan.id}`]; + } + } + + return key; + }); + + if (!found) { + currentOrphan.isOrphan = true; + + tree[`id${currentOrphan.id}`] = currentOrphan; + } + + return orphan; + }); + } + + return tree; + } + + decorateGroups(rawGroups) { + this.groups = rawGroups.map(this.decorateGroup); + return this.groups; + } + + // eslint-disable-next-line class-methods-use-this + decorateGroup(rawGroup) { + return { + id: rawGroup.id, + fullName: rawGroup.full_name, + fullPath: rawGroup.full_path, + avatarUrl: rawGroup.avatar_url, + name: rawGroup.name, + hasSubgroups: rawGroup.has_subgroups, + canEdit: rawGroup.can_edit, + description: rawGroup.description, + webUrl: rawGroup.web_url, + groupPath: rawGroup.group_path, + parentId: rawGroup.parent_id, + visibility: rawGroup.visibility, + leavePath: rawGroup.leave_path, + editPath: rawGroup.edit_path, + isOpen: false, + isOrphan: false, + numberProjects: rawGroup.number_projects_with_delimiter, + numberUsers: rawGroup.number_users_with_delimiter, + permissions: { + humanGroupAccess: rawGroup.permissions.human_group_access, + }, + subGroups: {}, + }; + } + + // eslint-disable-next-line class-methods-use-this + removeGroup(group, collection) { + Vue.delete(collection, `id${group.id}`); + } + + // eslint-disable-next-line class-methods-use-this + toggleSubGroups(toggleGroup) { + const group = toggleGroup; + group.isOpen = !group.isOpen; + return group; + } +} |