Small fixes, update docs and readme

This commit is contained in:
Maksymilian Fryc 2017-08-17 13:33:13 +02:00
parent 5fff1c5002
commit 43527b197d
7 changed files with 272 additions and 214 deletions

View File

@ -130,6 +130,7 @@ ReDoc makes use of the following [vendor extensions](http://swagger.io/specifica
* [`x-displayName`](docs/redoc-vendor-extensions.md#x-displayname) - specify human-friendly names for the menu categories
* [`x-tagGroups`](docs/redoc-vendor-extensions.md#x-tagGroups) - group tags by categories in the side menu
* [`x-servers`](docs/redoc-vendor-extensions.md#x-servers) - ability to specify different servers for API (backported from OpenAPI 3.0)
* [`x-sort-order`](docs/redoc-vendor-extensions.md#x-sort-order) - specify custom sorting for endpoints
### `<redoc>` tag attributes
* `spec-url` - relative or absolute url to your spec file;

View File

@ -243,3 +243,40 @@ PayPalPayment:
In the example above the names of definitions (`PayPalPayment`) are named differently than
names in the payload (`paypal`) which is not supported by default `discriminator`.
### Sort endpoints vendor extensions
#### x-sort-order
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-sort-order | int | specifies sorting order |
###### Usage in ReDoc
By using `x-sort-order` you can override default alphabetical sorting and arrange elements in any way you want.
Add `x-sort-order` with number from 0 to number of elements in group - 1 (e.g. for 3 items, the scope is 0-2).
Endpoints with lower `x-sort-order` number come first in a group.
###### x-sort-order example
```
/store/inventory:
get:
tags:
- store
summary: Return pet inventories by status
x-sort-order: 1
description: Returns a map of status codes to quantities
/store/order:
post:
tags:
- store
summary: Place an order for a pet
x-sort-order: 0
description: Places an order for a pet
```
In this example "Place an order for a pet" endpoint will come before "Return pet inventories by status"
(because of the `x-sort-order` property).

View File

@ -0,0 +1,188 @@
export let fixedMenuItemsList =
[
{
name: "Pagination",
id: "section/Pagination",
items: []
},
{
name: "JSONP",
id: "section/JSONP",
items: []
},
{
name: "Authentication",
id: "section/Authentication",
items: []
},
{
name: "pet",
id: "tag/pet",
items: [
{
name: "Deletes a pet",
id: "/paths/~1pet~1{petId}/delete",
metadata: {operation: "delete"}
},
{
name: "Find pet by ID",
id: "/paths/~1pet~1{petId}/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by status",
id: "/paths/~1pet~1findByStatus/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by tags",
id: "/paths/~1pet~1findByTags/get",
metadata: {operation: "get"}
},
{
name: "Add a new pet to the store",
id: "/paths/~1pet/post",
metadata: {operation: "post"}
},
{
name: "Updates a pet in the store with form data",
id: "/paths/~1pet~1{petId}/post",
metadata: {operation: "post"}
},
{
name: "uploads an image",
id: "/paths/~1pet~1{petId}~1uploadImage/post",
metadata: {operation: "post"}
},
{
name: "Update an existing pet",
id: "/paths/~1pet/put",
metadata: {operation: "put"}
}
]
},
{
name: "store",
id: "tag/store",
items: [
{
name: "Delete purchase order by ID",
id: "/paths/~1store~1order~1{orderId}/delete",
metadata: {operation: "delete"}
},
{
name: "Find purchase order by ID",
id: "/paths/~1store~1order~1{orderId}/get",
metadata: {operation: "get"}
},
{
name: "Returns pet inventories by status",
id: "/paths/~1store~1inventory/get",
metadata: {operation: "get"}
},
{
name: "Place an order for a pet",
id: "/paths/~1store~1order/post",
metadata: {operation: "post"}
}
]
},
{
name: "user",
id: "tag/user",
items: [
{
name: "Delete user",
id: "/paths/~1user~1{username}/delete",
metadata: {operation: "delete"}
},
{
name: "Get user by user name",
id: "/paths/~1user~1{username}/get",
metadata: {operation: "get"}
},
{
name: "Logs out current logged in user session",
id: "/paths/~1user~1logout/get",
metadata: {operation: "get"}
},
{
name: "Logs user into the system",
id: "/paths/~1user~1login/get",
metadata: {operation: "get"}
},
{
name: "Create user",
id: "/paths/~1user/post",
metadata: {operation: "post"}
},
{
name: "Creates list of users with given input array",
id: "/paths/~1user~1createWithArray/post",
metadata: {operation: "post"}
},
{
name: "Creates list of users with given input array",
id: "/paths/~1user~1createWithList/post",
metadata: {operation: "post"}
},
{
name: "Updated user",
id: "/paths/~1user~1{username}/put",
metadata: {operation: "put"}
}
]
},
{
name: "Pagination",
id: "tag/Pagination",
items: [
{
name: "Finds Pets by status",
id: "/paths/~1pet~1findByStatus/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by tags",
id: "/paths/~1pet~1findByTags/get",
metadata: {operation: "get"}
}
]
},
{
name: "JSONP",
id: "tag/JSONP",
items: [
{
name: "Find pet by ID",
id: "/paths/~1pet~1{petId}/get",
metadata: {operation: "get"}
},
{
name: "Find purchase order by ID",
id: "/paths/~1store~1order~1{orderId}/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by status",
id: "/paths/~1pet~1findByStatus/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by tags",
id: "/paths/~1pet~1findByTags/get",
metadata: {operation: "get"}
},
{
name: "Get user by user name",
id: "/paths/~1user~1{username}/get",
metadata: {operation: "post"}
},
{
name: "Returns pet inventories by status",
id: "/paths/~1store~1inventory/get",
metadata: {operation: "post"}
}
]
}
];

View File

@ -3,7 +3,8 @@
import { getChildDebugElement } from '../../../tests/helpers';
import { Component } from '@angular/core';
import { OptionsService, MenuItem } from '../../services/index';
import { compareEndpoints, menuItemsList } from './sort';
import { endpointComparator } from './sort';
import { fixedMenuItemsList } from './fixed-array';
import {
inject,
@ -66,12 +67,14 @@ describe('Redoc components', () => {
});
it('should confirm that component is sorted', () => {
for(var i=0;i<menuItemsList.length;i++) {
if(menuItemsList[i].items !== null){
for(var j=0;j<menuItemsList[i].items.length;j++){
component.menuItems[i].items[j].name.should.be.equal(menuItemsList[i].items[j].name);
}
let firstMenuItemsListLength = fixedMenuItemsList.length;
for(var firstMenuItemIndex = 0; firstMenuItemIndex < firstMenuItemsListLength; firstMenuItemIndex++) {
if(fixedMenuItemsList[firstMenuItemIndex].items !== null) {
let secondMenuItemsListLength = fixedMenuItemsList[firstMenuItemIndex].items.length;
for(var secondMenuItemIndex = 0; secondMenuItemIndex < secondMenuItemsListLength; secondMenuItemIndex++) {
component.menuItems[firstMenuItemIndex].items[secondMenuItemIndex].name.should.be.equal(fixedMenuItemsList[firstMenuItemIndex].items[secondMenuItemIndex].name);
}
}
}
});

View File

@ -15,7 +15,7 @@ import { trigger, state, animate, transition, style } from '@angular/core';
import { ScrollService, MenuService, OptionsService, MenuItem } from '../../services/';
import { PerfectScrollbar } from '../../shared/components';
import { BrowserDomAdapter as DOM } from '../../utils/browser-adapter';
import { compareEndpoints, menuItemsList } from './sort';
import { endpointComparator } from './sort';
const global = window;
@ -114,14 +114,18 @@ export class SideMenu implements OnInit, OnDestroy {
init() {
this.menuItems = this.menuService.items;
let firstMenuItemsLength = this.menuItems.length;
for(var i=0;i<this.menuItems.length;i++){
if(this.menuItems[i].items !== null){
for(var j=0;j<this.menuItems[i].items.length;j++){
if(this.menuItems[i].items[j].items == null)
this.menuItems[i].items.sort(compareEndpoints);
else
this.menuItems[i].items[j].items.sort(compareEndpoints);
for(var firstMenuItemIndex = 0; firstMenuItemIndex < firstMenuItemsLength; firstMenuItemIndex++) {
if(this.menuItems[firstMenuItemIndex].items !== null) {
let secondMenuItemsLength = this.menuItems[firstMenuItemIndex].items.length;
for(var secondMenuItemIndex = 0; secondMenuItemIndex < secondMenuItemsLength; secondMenuItemIndex++) {
if(this.menuItems[firstMenuItemIndex].items[secondMenuItemIndex].items == null) {
this.menuItems[firstMenuItemIndex].items.sort(endpointComparator);
}
else{
this.menuItems[firstMenuItemIndex].items[secondMenuItemIndex].items.sort(endpointComparator);
}
}
}
}

View File

@ -1,204 +1,23 @@
export const compareEndpoints = (a,b) => {
export const endpointComparator = (a, b) => {
let sortOrderComparisonResult: number;
if(a.metadata.sortOrder != null && b.metadata.sortOrder != null)
sortOrderComparisonResult = a.metadata.sortOrder.localeCompare(b.metadata.sortOrder);
let operationComparisonResult: number;
if(a.metadata.operation != null && b.metadata.operation != null)
operationComparisonResult = a.metadata.operation.localeCompare(b.metadata.operation);
let nameComparisonResult: number = a.name.localeCompare(b.name);
if(sortOrderComparisonResult != null && sortOrderComparisonResult !== 0)
return sortOrderComparisonResult;
else if(operationComparisonResult != null && operationComparisonResult !== 0)
return operationComparisonResult;
else
return nameComparisonResult;
}
export let menuItemsList =
[
{
name: "Pagination",
id: "section/Pagination",
items: []
},
{
name: "JSONP",
id: "section/JSONP",
items: []
},
{
name: "Authentication",
id: "section/Authentication",
items: []
},
{
name: "pet",
id: "tag/pet",
items: [
{
name: "Deletes a pet",
id: "/paths/~1pet~1{petId}/delete",
metadata: {operation: "delete"}
},
{
name: "Find pet by ID",
id: "/paths/~1pet~1{petId}/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by status",
id: "/paths/~1pet~1findByStatus/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by tags",
id: "/paths/~1pet~1findByTags/get",
metadata: {operation: "get"}
},
{
name: "Add a new pet to the store",
id: "/paths/~1pet/post",
metadata: {operation: "post"}
},
{
name: "Updates a pet in the store with form data",
id: "/paths/~1pet~1{petId}/post",
metadata: {operation: "post"}
},
{
name: "uploads an image",
id: "/paths/~1pet~1{petId}~1uploadImage/post",
metadata: {operation: "post"}
},
{
name: "Update an existing pet",
id: "/paths/~1pet/put",
metadata: {operation: "put"}
}
]
},
{
name: "store",
id: "tag/store",
items: [
{
name: "Delete purchase order by ID",
id: "/paths/~1store~1order~1{orderId}/delete",
metadata: {operation: "delete"}
},
{
name: "Find purchase order by ID",
id: "/paths/~1store~1order~1{orderId}/get",
metadata: {operation: "get"}
},
{
name: "Returns pet inventories by status",
id: "/paths/~1store~1inventory/get",
metadata: {operation: "get"}
},
{
name: "Place an order for a pet",
id: "/paths/~1store~1order/post",
metadata: {operation: "post"}
}
]
},
{
name: "user",
id: "tag/user",
items: [
{
name: "Delete user",
id: "/paths/~1user~1{username}/delete",
metadata: {operation: "delete"}
},
{
name: "Get user by user name",
id: "/paths/~1user~1{username}/get",
metadata: {operation: "get"}
},
{
name: "Logs out current logged in user session",
id: "/paths/~1user~1logout/get",
metadata: {operation: "get"}
},
{
name: "Logs user into the system",
id: "/paths/~1user~1login/get",
metadata: {operation: "get"}
},
{
name: "Create user",
id: "/paths/~1user/post",
metadata: {operation: "post"}
},
{
name: "Creates list of users with given input array",
id: "/paths/~1user~1createWithArray/post",
metadata: {operation: "post"}
},
{
name: "Creates list of users with given input array",
id: "/paths/~1user~1createWithList/post",
metadata: {operation: "post"}
},
{
name: "Updated user",
id: "/paths/~1user~1{username}/put",
metadata: {operation: "put"}
}
]
},
{
name: "Pagination",
id: "tag/Pagination",
items: [
{
name: "Finds Pets by status",
id: "/paths/~1pet~1findByStatus/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by tags",
id: "/paths/~1pet~1findByTags/get",
metadata: {operation: "get"}
}
]
},
{
name: "JSONP",
id: "tag/JSONP",
items: [
{
name: "Find pet by ID",
id: "/paths/~1pet~1{petId}/get",
metadata: {operation: "get"}
},
{
name: "Find purchase order by ID",
id: "/paths/~1store~1order~1{orderId}/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by status",
id: "/paths/~1pet~1findByStatus/get",
metadata: {operation: "get"}
},
{
name: "Finds Pets by tags",
id: "/paths/~1pet~1findByTags/get",
metadata: {operation: "get"}
},
{
name: "Get user by user name",
id: "/paths/~1user~1{username}/get",
metadata: {operation: "post"}
},
{
name: "Returns pet inventories by status",
id: "/paths/~1store~1inventory/get",
metadata: {operation: "post"}
}
]
if(a.metadata.sortOrder != null && b.metadata.sortOrder != null) {
sortOrderComparisonResult = a.metadata.sortOrder.localeCompare(b.metadata.sortOrder);
}
];
if(a.metadata.operation != null && b.metadata.operation != null) {
operationComparisonResult = a.metadata.operation.localeCompare(b.metadata.operation);
}
if(sortOrderComparisonResult != null && sortOrderComparisonResult !== 0) {
return sortOrderComparisonResult;
}
else if(operationComparisonResult != null && operationComparisonResult !== 0) {
return operationComparisonResult;
}
else {
return nameComparisonResult;
}
}

View File

@ -334,7 +334,13 @@ export class MenuService {
for (let operationInfo of tag.operations) {
let xSortOrder;
let orderInfo = operationInfo['x-sort-order'];
if(orderInfo>=0 && orderInfo<tag.operations.length && Number.isInteger(orderInfo)) xSortOrder = operationInfo['x-sort-order'];
if(orderInfo != null) {
if(orderInfo >= 0 && orderInfo < tag.operations.length && Number.isInteger(orderInfo)) {
xSortOrder = operationInfo['x-sort-order'];
}
}
let subItem = {
name: SchemaHelper.operationSummary(operationInfo),
id: operationInfo._pointer,