swagger-ui
swagger-ui copied to clipboard
Add filter for operations and make filtering case insensitive
Feature request: add filter for operations and make it case insensitive
Check out the filter
parameter - https://github.com/swagger-api/swagger-ui#parameters.
It filters only in the tag
name not in the name or the description of the operations, and filtering is case sensitive.
Hi, will you add these features to the UI in the future?
Can't say, but it's not a high priority.
Ok, thanks for your response.
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 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
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 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....?
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 is the value passing to filter is true or it should be some string..??
@Falx Thanks it worked for me. Sorry forgot to mention.
hi @ben5Kuda can u say is there anything wrong in my above code...? not able to do the case Insensitive filter
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).
@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.
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.
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,
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 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"
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);
});
}
}
};
};