Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Hierarchical Tags #5969

Closed
kael-shipman opened this issue Apr 20, 2020 · 93 comments
Closed

Support Hierarchical Tags #5969

kael-shipman opened this issue Apr 20, 2020 · 93 comments

Comments

@kael-shipman
Copy link

kael-shipman commented Apr 20, 2020

Is your feature request related to a problem?

There is growing support in the OAS community for the idea of hierarchical tags (see OAI/OpenAPI-Specification#1367). The current consensus is that UIs like SwaggerUI can implement this with no change required in the OAS, and that this would be a much appreciated feature. I would like to implement it in SwaggerUI and would like help identifying the best way to do so.

Describe the solution you'd like

Tags such as Petstore|Mammals|Dogs should render as

## Petstore

### Mammals

#### Dogs

....

EDIT: Permanent Solution

I've implemented and published a plugin for this. Instructions for use are here. It works well as an ES module include in a webpack scenario OR as a global module via unpkg. There is also a PR out for this (here), but it is long stale and I doubt that Swagger will ever take interest in it. (The PR has now been closed without merging.)

@kael-shipman
Copy link
Author

I'm willing and able to implement this, even if just for my own fork of SwaggerUI, so regardless of whether this feature gets official approval or not, I'd love for someone to give me a hint at where to start.

@MarcusBondezan
Copy link

This would be great! The doc would be much more organized for the front end folks of my project.

@kael-shipman
Copy link
Author

Thanks for commenting! Good to know others find this desirable.

To the devs: I repeat my offer to implement this and PR it if you'll give me a push to start me in the right direction ;).

@effrafax
Copy link

Yes, would be great to have such a feature!

@SaiSrinivasM
Copy link

Yes, I am also looking for the same

@leandrofnunes
Copy link

It'd be awesome to have such feature available - as of now, I need to create composed tags which causes lots of duplicates.

@donaldduy-lb
Copy link

I would also love this feature!

@daveKoala
Copy link

I am also looking for the same thing.
My use case is, I have an existing API with 2 versions, about to start on the third, consumers add a field in the header asking for specified version. I think sub or hierarchical tags would make life so much easier for developers and readers of the docs. As i need to keep all versions in a single doc

Happy to be told that header accept version can be documented in a different manner

@mairead
Copy link

mairead commented Oct 5, 2020

We need this feature too. Our API serves several products but also we have utility endpoints, global endpoints and product specific endpoints. It would be really helpful to be able to add sub headings and also even a description to each sub heading so you could explain the purpose of the grouping

@arkanmgerges
Copy link

Yes it is a good feature

@jwpegram
Copy link

Any movement on this feature?

@mathis-m
Copy link
Contributor

@kael-shipman you could probably just override the component https://github.com/swagger-api/swagger-ui/blob/master/src/core/components/operation-tag.jsx using the plugin api. https://swagger.io/docs/open-source-tools/swagger-ui/customization/plugin-api/

then implement recursive rendering of the operation-tag within the render function of the component.

@kael-shipman
Copy link
Author

@mathis-m thanks for the specific tip and documentation! Very helpful. I'm a bit swamped at work right now, but I'll look into maybe building a plug-in for this when I get a chance.

@mathis-m
Copy link
Contributor

@kael-shipman for the plugin part I would use the wrapComponents plug point to conditional render either the hirachical operation tag component or the original component.

@kael-shipman
Copy link
Author

Hi to everyone following this. Any thoughts on styling? This is what it looks like so far:

Screenshot_2021-03-02_20-40-28

I tried left-justifying, too, but that made the hierarchy significantly less useful. Open to suggestions. If anyone's a whiz with this kind of stuff (css, react, etc.), feel free to PR my PR over at kael-shipman/swagger-ui-plugins@hierarchical-tags

@kael-shipman
Copy link
Author

kael-shipman commented Mar 3, 2021

Also, if anyone's really itchin' to get this going on their site, I just published the pre-release (v1.0.0-rc1) on github packages. You can get it by doing the following:

  1. Add @kael-shipman:registry=https://npm.pkg.github.com/kael-shipman to your package-local .npmrc file.
  2. Run npm install --save @kael-shipman/swagger-ui-plugin-hierarchical-tags
  3. Follow instructions in README.md

I believe that will work, but if it doesn't, I'd be happy to work through it with you.

EDIT: If you don't already have github authentication set up for npm, you have to do that as well:

  1. Create a github personal access token for your account (tutorial)
  2. Add //npm.pkg.github.com/:_authToken=YOUR-TOKEN to your user-specific .npmrc file (the one at ~/.npmrc, not the one in your package. If that file doesn't exist, then create it.) Make sure to put the value of your token in instead of the string YOUR-TOKEN.

@mathis-m
Copy link
Contributor

mathis-m commented Mar 3, 2021

@kael-shipman let's make this a PR against swagger-ui.
I can give you guidance, let's connect to get this going!

@dmrickey
Copy link

dmrickey commented Mar 3, 2021

Hi to everyone following this. Any thoughts on styling? This is what it looks like so far:

Screenshot_2021-03-02_20-40-28

I tried left-justifying, too, but that made the hierarchy significantly less useful. Open to suggestions. If anyone's a whiz with this kind of stuff (css, react, etc.), feel free to PR my PR over at kael-shipman/swagger-ui-plugins@hierarchical-tags

At least in the APIs I work with, this could still be very long. It'd be nice to have some kind of vertical gray line on the left to signify how deeply something is nested.

@mathis-m
Copy link
Contributor

mathis-m commented Mar 4, 2021

At least in the APIs I work with, this could still be very long. It'd be nice to have some kind of vertical gray line on the left to signify how deeply something is nested.

How about:
HierarchicalTags

@kael-shipman
Copy link
Author

Love it! That looks great!

@kael-shipman
Copy link
Author

@tim-lai, @mathis-m and I are working on a PR to swagger-ui to address this issue and we've run into some questions:

First, are you interested in this being part of swagger-ui? If not, we can stick to the plugin approach already mentioned above.

Second, if it seems acceptable for swagger-ui, what is your preferred architecture? I've implemented it as a backward-compatible core addition in this branch, but @mathis-m has suggested it may be more appropriate to build it as a core plugin, which he's started working on in this branch. I think either way is fine for us, but we'd like guidance before investing too much in one direction or the other.

@mathis-m
Copy link
Contributor

mathis-m commented Mar 6, 2021

In addition specification wise we are good to implement it.

Tagged operations may be handled differently by tools and libraries. For example, Swagger UI uses tags to group the displayed operations.

@JAdamCain
Copy link

I desperately need this functionality now. I'm a novice but willing to try it . Is it available as a plug-in I can just drop in. Corporate frowns on unofficial versions of major software but plug-ins are fair game!

@chesiren
Copy link

Hello @kael-shipman , i have a problem with your plugin and i would need your help to fix it:
When multiple subtags are named the same but are in different nested tags, clicking one will show/hide all the others ones as well.
How can i make it so they don't interact with each other without having to change their name?
You can see the problem in the petstore example included in your plugin package by clicking the view,create or delete tags
(or video bellow to show the problem)
https://user-images.githubusercontent.com/44122832/213244155-1886039c-ae14-4b76-9a0e-ceaf27147f46.mp4

@cocodee
Copy link

cocodee commented May 5, 2023

Are you still working on this?

@nop1984
Copy link

nop1984 commented May 6, 2023

Looking for that too

@kael-shipman
Copy link
Author

Hello @kael-shipman , i have a problem with your plugin and i would need your help to fix it: When multiple subtags are named the same but are in different nested tags, clicking one will show/hide all the others ones as well. How can i make it so they don't interact with each other without having to change their name? You can see the problem in the petstore example included in your plugin package by clicking the view,create or delete tags (or video bellow to show the problem) https://user-images.githubusercontent.com/44122832/213244155-1886039c-ae14-4b76-9a0e-ceaf27147f46.mp4

@chesiren sorry I missed this! I don't have time to mess with this right now, but I'm putting it on my to-do list and I'll see if I can get to it at some point. It's probably not a hugely difficult thing to fix. Will keep you posted.

@ChadBakkt
Copy link

we need this.

@Davidos533
Copy link

Yes we need this!

@geanruca
Copy link

We need this :D can I create a PR?

@mgrazianoc
Copy link

please merge this, we need it

@fabhed
Copy link

fabhed commented Aug 20, 2023

This would be a great feature to have merged!

@kael-shipman
Copy link
Author

kael-shipman commented Aug 27, 2023

From the description above:

I've implemented and published a plugin for this. Instructions for use are here. It works well as an ES module include in a webpack scenario OR as a global module via unpkg. There is also a PR out for this (here), but it is long stale and I doubt that Swagger will ever take interest in it. (The PR has now been closed without merging.)

@kael-shipman
Copy link
Author

kael-shipman commented Aug 27, 2023

Since the Swagger team decided (here) that this won't be a core feature, and since there is a published plugin for it here, I'm closing this issue as "completed".

@chrisnore94
Copy link

chrisnore94 commented Sep 4, 2023

An important question:

Why the plugin could not be become in a npm package (uploaded to the npm repos)? Do not you think it could be easier to install it by a simple "npm install" command and not having the need to use a .npmrc file in any project?

Thanks for advance. :)

@kael-shipman
Copy link
Author

That's a good point, and actually it's a documentation problem. The package has been hosted on npm for a while now and I just forgot to update the docs. I've now updated the docs (see the same link above), so you should be good to go.

@chrisnore94
Copy link

chrisnore94 commented Sep 8, 2023

Oh! Great thing! Another question: I know the plugin can be used on a client-side project, but, is it possible to use this plugin on any express project?

Example to use:

const express = require("express");
const app = express();

const HierarchicalTagsPlugin = require('swagger-ui-plugin-hierarchical-tags');
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger-output.json');

const swaggerOptions = {
  swaggerOptions: {
    plugins: [HierarchicalTagsPlugin]
  }
} 

// Swagger Documentation
app.use('/api/v1/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, swaggerOptions));

Could it be possible with your plugin? if not, are you planning to develop the plugin, so that it can be used with express?.

Thanks in advance. :)

@mathis-m
Copy link
Contributor

mathis-m commented Sep 8, 2023

That's a good point, and actually it's a documentation problem. The package has been hosted on npm for a while now and I just forgot to update the docs. I've now updated the docs (see the same link above), so you should be good to go.

@char0n would there be a option to create like an third party plugins page within the swagger documentation?

That would contribute to the overall position on market, cause it shows potential users or devs what can be done with the base product.

I know that #5027 is there, but it is closed. Why not use the traffic that is there like on this PR, and take action, create a global entry point for swagger third party plugins.

@kael-shipman
Copy link
Author

Love this idea ☝️ ☝️

@kael-shipman
Copy link
Author

kael-shipman commented Dec 11, 2023

For anyone coming to this issue looking for a solution, please see "Permanent Solution" section in the issue description at the top of this page.

@akhateeb22
Copy link

Package not found in NPM!
Any idea ?!

@kael-shipman
Copy link
Author

Mm.... I just checked and here it is?

@akhateeb22
Copy link

Does it work on server side (nestjs) ?!

@kael-shipman
Copy link
Author

@akhateeb22 not sure exactly what use-case you're referring to. You can install it just like any other npm package, but of course it's a front-end package, so the code needs to make it to your front-end somehow. NestJS is a back-end microservice framework, so not sure what you're going for here.

@gulgulia17
Copy link

I started looking for something to add a tree view and found it. It's just amazing work!

@1nVitr0
Copy link

1nVitr0 commented Apr 12, 2024

Does it work on server side (nestjs) ?!

@akhateeb22 I presume you mean, how to include it in the Swagger module for nestjs? I have managed to include it, though it is quite "hacky":

// Include this in your bootstrap function in main.ts (or wherever you setup your nest app)

const swaggerConfig = new DocumentBuilder()
    .setTitle('Hierarchical Tags')
    .build();
const document = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup('api', app, document, {
    swaggerOptions: {
        plugins: [
            (...args: any[]) => (window as any).HierarchicalTagsPlugin(...args),
           // This is added by nestjs by default and would be overridden if not included
            (...args: any[]) => (window as any).SwaggerUIBundle.plugins.DownloadUrl(...args),
        ],
        hierarchicalTagSeparator: '/', // This must be a string, as RegExp will not survive being json encoded
    },
    customJs: ['https://unpkg.com/swagger-ui-plugin-hierarchical-tags'],
});

The SwaggerUIBundle.plugins.DownloadUrl plugin is sourced from the js template of the @nestjs/swagger init template. I haven't checked what it does, but I'm sure it's used for something.

The encapsulation of the plugins into functions is necessary, because this get's used client-side and functions are the only properties that are passed on as-is (see @nestjs/swagger/swagger-ui/helpers.ts).

Also hierarchicalTagSeparator MUST be a string, as RegExp cannot be JSON encoded. This does limit the separator to a single character, but that didn't bother me.

It's definitely not an ideal solution as it plays with the internal functioning of @nestjs/swagger and may break at any time.

@cse210001015
Copy link

Does it work on server side (nestjs) ?!

@akhateeb22 I presume you mean, how to include it in the Swagger module for nestjs? I have managed to include it, though it is quite "hacky":

// Include this in your bootstrap function in main.ts (or wherever you setup your nest app)

const swaggerConfig = new DocumentBuilder()
    .setTitle('Hierarchical Tags')
    .build();
const document = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup('api', app, document, {
    swaggerOptions: {
        plugins: [
            (...args: any[]) => (window as any).HierarchicalTagsPlugin(...args),
           // This is added by nestjs by default and would be overridden if not included
            (...args: any[]) => (window as any).SwaggerUIBundle.plugins.DownloadUrl(...args),
        ],
        hierarchicalTagSeparator: '/', // This must be a string, as RegExp will not survive being json encoded
    },
    customJs: ['https://unpkg.com/swagger-ui-plugin-hierarchical-tags'],
});

The SwaggerUIBundle.plugins.DownloadUrl plugin is sourced from the js template of the @nestjs/swagger init template. I haven't checked what it does, but I'm sure it's used for something.

The encapsulation of the plugins into functions is necessary, because this get's used client-side and functions are the only properties that are passed on as-is (see @nestjs/swagger/swagger-ui/helpers.ts).

Also hierarchicalTagSeparator MUST be a string, as RegExp cannot be JSON encoded. This does limit the separator to a single character, but that didn't bother me.

It's definitely not an ideal solution as it plays with the internal functioning of @nestjs/swagger and may break at any time.

how did you get the window variable?

@1nVitr0
Copy link

1nVitr0 commented Apr 22, 2024

how did you get the window variable?

@cse210001015 Yeah, that's the hacky bit. Unless @nestjs/swaggerhas changed their code or you're using an older version, functions inside the plugin section are compiled as-is into the client code for the swagger route. That's why I used window as any, the windowglobal is non-existing in the context of your main.ts file, but it will be on the client the swagger docs are served to.

The encapsulation of the plugins into functions is necessary, because this get's used client-side and functions are the only properties that are passed on as-is (see @nestjs/swagger/swagger-ui/helpers.ts).

I haven't tried this with SSR, but I'm fairly sure it should still be executed client-side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests