swagger-ui icon indicating copy to clipboard operation
swagger-ui copied to clipboard

Add filter for operations and make filtering case insensitive

Open ocdevops opened this issue 7 years ago • 20 comments

Feature request: add filter for operations and make it case insensitive

ocdevops avatar Nov 07 '17 18:11 ocdevops

Check out the filter parameter - https://github.com/swagger-api/swagger-ui#parameters.

webron avatar Nov 07 '17 19:11 webron

It filters only in the tag name not in the name or the description of the operations, and filtering is case sensitive.

ocdevops avatar Nov 07 '17 19:11 ocdevops

Hi, will you add these features to the UI in the future?

ocdevops avatar Nov 21 '17 16:11 ocdevops

Can't say, but it's not a high priority.

webron avatar Nov 21 '17 16:11 webron

Ok, thanks for your response.

ocdevops avatar Nov 21 '17 16:11 ocdevops

A bit late, but for those who want at least case insensitive tag search. Just add this plugin:

const CaseInsensitiveFilterPlugin = function (system) {
    return {
        fn: {
            opsFilter: (taggedOps, phrase) => {
                return taggedOps.filter((tagObj, tag) => tag.toLowerCase().indexOf(phrase.toLowerCase()) !== -1);
            }
        }
    }
};

In your Swagger configuration object, add your new plugin, like so:

{
    ...,
    plugins: [
        CaseInsensitiveFilterPlugin
    ],
    ...
}

Now you've overwritten the default filter function, with a new case insensitive one.

Falx avatar Aug 13 '18 10:08 Falx

@Falx when i inject my own custom index page i do not see the search bar anymore even though i have EnableFilter() option. Is there a way to add the plugin by injecting it as JavaScript or what am i missing. I am using SwashBuckleCore

ben5Kuda avatar Sep 06 '18 21:09 ben5Kuda

Sorry, I don't really understand your problem. I just added the plugin following the Configuration docs at https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/#plugin-system

The only custom part is the plugin itself which only overwrites the standard used opsFilter with a new version that used .toLowerCase() to check equality.

It is in javascript..

Falx avatar Sep 07 '18 10:09 Falx

@Falx i've added ur plugin in index.html. but cant perform the case insensitive search.

<script>
window.onload = function() {
  
  // Build a system
const CaseInsensitiveFilterPlugin = function (system) {
    return {
        fn: {
            opsFilter: (taggedOps, phrase) => {
                return taggedOps.filter((tagObj, tag) => tag.toLowerCase().indexOf(phrase.toLowerCase()) !== -1);
            }
        }
    }
};

  const ui = SwaggerUIBundle({
    url: "xxxxx.json",
    dom_id: '#swagger-ui',
    deepLinking: true,
    filter: true,
    presets: [
      SwaggerUIBundle.presets.apis,
      SwaggerUIStandalonePreset
    ],
    plugins: [
      SwaggerUIBundle.plugins.DownloadUrl,
     CaseInsensitiveFilterPlugin
    ],
    layout: "StandaloneLayout"
  })

  window.ui = ui
}
</script>

can u specify where i'm doing wrong....?

kranthi0099 avatar Jan 21 '19 09:01 kranthi0099

Honestly, this looks right to me.. Only difference I can spot, is that I don't include the SwaggerUIStandalonePreset. That's it really.. I also don't use the layout: "StandaloneLayout", but I did customize the layout, so that's normal.

Falx avatar Jan 21 '19 11:01 Falx

@Falx is the value passing to filter is true or it should be some string..??

kranthi0099 avatar Jan 22 '19 05:01 kranthi0099

@Falx Thanks it worked for me. Sorry forgot to mention.

ben5Kuda avatar Jan 22 '19 06:01 ben5Kuda

hi @ben5Kuda can u say is there anything wrong in my above code...? not able to do the case Insensitive filter

kranthi0099 avatar Jan 22 '19 06:01 kranthi0099

is the value passing to filter is true or it should be some string..??

Just true, like you did, should be fine (that's what's in my code too).

Falx avatar Jan 22 '19 06:01 Falx

@krekam I used your code as is, and could not replicate your issue. I was able to get the case insensitive filter to work. if it still isn't working my guess is you are using the default index.html page and not the custom one.

ben5Kuda avatar Jan 22 '19 07:01 ben5Kuda

Chiming in here - if anyone would like to port @Falx's case-insensitive plugin into a pull request, we'd be happy to accept the change into the core project.

shockey avatar Jan 24 '19 18:01 shockey

Hi guys,

Maybe I reach late to the conversation but I'm thinking that the main problem is produced by swagger-ui. The swagger-ui are using the tags to group the operations, from my point of view this is not correct because tags are used to filter to. I'm thinking that the best approach can be generate a property to group the methods and maintain the tags for filtering. With this way we can tag every path with any information like operation name, some word, http method , whatever..

Regards,

hocklo avatar Aug 07 '19 16:08 hocklo

Hi,

I have figured out a way to filter operations based on path, summary (title) and description. Here is the code:

const AdvancedFilterPlugin = function (system) {
  return {
    fn: {
      opsFilter: function (taggedOps, phrase) {
        phrase = phrase.toLowerCase()
        var normalTaggedOps = JSON.parse(JSON.stringify(taggedOps));
        for (tagObj in normalTaggedOps) {
          var operations = normalTaggedOps[tagObj].operations;
          var i = operations.length;
          while (i--) {
            var operation = operations[i].operation;
            var parameters = "";
            var responses = "";
            var requestBody = "";
            if(typeof operation.parameters !== 'undefined'){
              parameters = JSON.stringify(operation.parameters).toLowerCase();
            }
            if(typeof operation.responses !== 'undefined'){
              responses = JSON.stringify(operation.responses).toLowerCase();
            }
            if(typeof operation.requestBody !== 'undefined'){
              requestBody=JSON.stringify(operation.requestBody).toLowerCase();
            }
            if ((operations[i].path.toLowerCase().indexOf(phrase) === -1)
              && (operation.summary.toLowerCase().indexOf(phrase) === -1)
              && (operation.description.toLowerCase().indexOf(phrase) === -1)
              && (parameters.indexOf(phrase) === -1)
              && (responses.indexOf(phrase) === -1)
              && (requestBody.indexOf(phrase) === -1)
            ) {
              operations.splice(i, 1);
            }
          }
          if (operations.length == 0 ) {
            delete normalTaggedOps[tagObj];
          }
          else {
            normalTaggedOps[tagObj].operations = operations;
          }
        }
        return system.Im.fromJS(normalTaggedOps);
      }
    }
  };
};

In your Swagger configuration object, add your new plugin, like so mentioned in https://github.com/swagger-api/swagger-ui/issues/3876#issuecomment-412476501

manoj-apare avatar Jun 28 '20 05:06 manoj-apare

@manoj-apare nice, you have just to add a check if operation.summary and operation.description aren't undefined and maybe alter the textbox placeholder that says "Filter by tag"

MithrilMan avatar Nov 30 '20 19:11 MithrilMan

I ran into the issue that the tags were out of order when using system.Im.fromJS like @manoj-apare

Below is a variation on this that worked for me.

const AdvancedFilterPlugin = function (system) {
    return {
        fn: {
            opsFilter: function (taggedOps, phrase) {
                phrase = phrase.toLowerCase()
                //first filter out all actions that don't meet the search criteria
                var filteredActions = taggedOps.map((tagObj) => {
                    tagObj._root.entries[1][1] = tagObj._root.entries[1][1].filter((operationObj) => {
                        var op = JSON.parse(JSON.stringify(operationObj));
                        var summary = "";
                        var description = "";
                        if (typeof op.operation.summary !== 'undefined') {
                            summary = JSON.stringify(op.operation.summary).toLowerCase();
                        }
                        if (typeof op.operation.description !== 'undefined') {
                            description = JSON.stringify(op.operation.description).toLowerCase();
                        }
                        if ((op.path.toLowerCase().indexOf(phrase) === -1)
                            && (summary.indexOf(phrase) === -1)
                            && (description.indexOf(phrase) === -1)
                        ) {
                            return false;
                        } else {
                            return true;
                        }
                    });
                    return tagObj;
                });
                //then filter any Tags with no actions remaining
                return filteredActions.filter((tagObj) => {
                    return (tagObj._root.entries[1][1].size > 0);
                });
            }
        }
    };
};

ConorDMurphy avatar Jan 11 '24 18:01 ConorDMurphy