Redocly / redoc

📘 OpenAPI/Swagger-generated API Reference Documentation
https://redocly.github.io/redoc/
MIT License
23.36k stars 2.29k forks source link

Feature Request and Implementation for Multi-Level Tag Grouping #2482

Open fakeyanss opened 8 months ago

fakeyanss commented 8 months ago

Dear Developer Team,

I encountered a need similar to issue #1489 during my use: the requirement for multi-level tag grouping. Currently, the three-tier structure provided by x-tagGroups (group - tag - operation) seems insufficient for our needs. Additionally, when I attempted to define a description for x-tagGroups, I discovered that it does not support the corresponding syntax.

With complex service systems and a large number of APIs, a three-tier sidebar can easily become overly lengthy. When dealing with complex businesses, maintaining a structured relationship is more conducive to understanding and managing APIs than simply flattening all relationships.

I’ve read the code related to the sidebar logic in the redoc project and attempted to modify the MenuBuilder class on my own to implement the nested tag feature, without limiting the number of nesting levels. Theoretically, as long as the page width allows, an unlimited number of nesting levels is possible.

I noticed in the MenuBuilder.ts#GroupModel class that a parent property has already been defined to represent parent-child relationships, which made my modification work relatively straightforward. I’m curious to know if the developer team originally planned to support multi-level tagging.

export class GroupModel implements IMenuItem {
...
  parent?: GroupModel;
...

To achieve multi-level tagging, I’ve established a naming convention within my team, using slashes / to separate multiple tag names (such as tag_name1/tag_name2/tag_name3).

An multi-level tag example like this:

tags:
  - name: pet
    description: Everything about your Pets
  - name: pet/pet1111111
    x-displayName: pet1111111
  - name: pet/pet2222222
    x-displayName: pet2222222
  - name: pet/pet2222222/pet21111111
    x-displayName: pet21111111

Then, I rewrote the MenuBuilder.ts#getTagsItems method to properly handle tags with slashes and nest them under their respective parent tags.

      const slashCount = tag.name.split('/').length - 1;
      if (slashCount > 0) {
        const rootTagname = tag.name.substring(0, tag.name.indexOf('/'));
        const rootItem = resMap[rootTagname];
        let parentItem;
        const parentTagNames = tag.name.split('/');
        for (let i = 0; i < slashCount; i++) {
          if (i == 0) {
            parentItem = rootItem;
          } else {
            parentItem = <GroupModel>(
              parentItem.items.filter(it => it.name === parentTagNames[i])[0]
            );
          }
        }
        item.parent = parentItem;
        parentItem.items.push(item);
        // reset depthes for items
        for (const it of parentItem.items) {
          it.depth = parentItem.depth + 1;
        }
        for (const it of item.items) {
          it.depth = item.depth + 1;
        }
      } else {
        res.push(item);
        resMap[tag.name] = item;
      }

Additionally, I adjusted the CSS definition in styled.elements.ts#menuItemDepth so that different levels of tag items can calculate their left padding based on their depth.


export const menuItemDepth = {
  0: css`
    opacity: 0.7;
    text-transform: ${({ theme }) => theme.sidebar.groupItems.textTransform};
    font-size: 0.8em;
    padding-bottom: 0;
    cursor: default;
  `,
  1: css`
    font-size: 0.929em;
    text-transform: ${({ theme }) => theme.sidebar.level1Items.textTransform};
  `,
  2: css`
    padding-left: ${20 + 10}px;
  `,
  3: css`
    padding-left: ${20 + 10 * 2}px;
  `,
  4: css`
    padding-left: ${20 + 10 * 3}px;
  `,
  5: css`
    padding-left: ${20 + 10 * 4}px;
  `,
  6: css`
    padding-left: ${20 + 10 * 5}px;
  `,
  7: css`
    padding-left: ${20 + 10 * 6}px;
  `,
  8: css`
    padding-left: ${20 + 10 * 7}px;
  `,
  9: css`
    padding-left: ${20 + 10 * 8}px;
  `,
  10: css`
    padding-left: ${20 + 10 * 9}px;
  `,
};

Although I am a backend developer with just a basic understanding of JS, my modifications may not be the most elegant. However, I’m curious to know if there is a plan by the development team to support the functionality of multi-level tag nesting? If interested in the modifications I’ve made, I’d be happy to submit a PR for your assessment.

Thank you for your hard work, looking forward to your reply.

Attachment:

image
Orest-Yastremskyy commented 8 months ago

Hi @fakeyanss,

Thank you for taking the time to share this idea with us.

I have added it to our list of ideas so that our Product Team can evaluate how it fits our roadmap.

As soon as we have news regarding this, we will be sure to let you know.

cleverly87 commented 8 months ago

Love this idea - just even having that one additional level would make such a difference to it

fakeyanss commented 8 months ago

I’m glad that nested tags will be supported by developers. If anyone else wants to experience this feature, you can rely on my fork implementation, with the npm scope package being @fakeyanss/redocly-cli.