Skip to content

Vue Shared - New component `nested_groups_projects_list.vue`

What / Why

We are aiming to create a more consistent experience across all Group Lists in GitLab. We have created a shared groups_list.vue that is intended to be the SSoT for all singular group lists in GitLab.

Additionally, we would like to add a similar SSoT component for tree like lists that utilize a tree like structure. This component could be called nested_groups_projects_list.vue. There is an existing Vue component that does tree few on Groups/Subgroups found in group_folder.vue

This is a good starting point, but ideally we could create a new, more flexible, component that could support a tree of Groups and Projects to meet the upcoming requirements of &13790 (closed).

Implementation Plan

Pulled from @peterhegman comments below

Directory

.
├── groups_list/
│   ├── groups_list_item.vue
│   └── groups_list.vue
├── projects_list/
│   ├── projects_list_item.vue
│   └── projects_list.vue
└── nested_groups_projects_list/
    ├── list_item.vue
    └── nested_groups_projects_list.vue

Nested data structure

This is the simplified structure the API returns. I removed everything that wasn't relevant to this example. As the user dives into each subgroup items are added to the children array

[
  {
    "id": 205,
    "type": "group",
    "parent_id": 31,
    "subgroup_count": 1,
    "project_count": 1,
    "children": [
      {
        "id": 224,
        "type": "group",
        "parent_id": 205,
        "subgroup_count": 0,
        "project_count": 0,
        "children": []
      },
      {
        "id": 45,
        "type": "project",
      }
    ]
  },
  {
    "id": 6,
    "type": "project",
  }
]

nested_groups_projects_list/list_item.vue logic

Docs:

<script>
export default {
  props: {
    item: {
      type: Object,
      required: true
    }
  },
  beforeCreate: function () {
    this.$options.components.ListItem = require('./list_item.vue').default
  },
  computed: {
    itemComponent() {
      return this.item.type === 'project' ? ProjectsListItem : GroupsListItem;
    }
  }
}
<script>

<template>
  <component :is="itemComponent">
    <ul v-if="item.children.length">
      <list-item v-for="childItem in item.children" :item="childItem" />
    </ul>
  </component>
<template>

nested_groups_projects_list/nested_groups_projects_list.vue logic

<script>
export default {
  props: {
    items: {
      type: Array,
      required: true
    }
  },
}
<script>

<template>
  <ul>
    <list-item v-for="item in items" :item="item" />
  </ul>
<template>

The above code is untested but I think it should at least be close to working.

Edited by Peter Hegman