MenuBuilder: Add support for sortOperationsAlphabetically and sortTagsAlphabetically (#1843)

* operations: Add support for sortOperationsAlphabetically

Already documented but is currently `NO-OP` and not implemented
`sortOperationsAlphabetically`.

Allows sorting operations in sidebar menu according to their `name`
configured which is by default `summary` from Swaggerspec

TLDR:
Following commit adds support for `sortOperationsAlphabetically` already
documented but not implemented here: https://redoc.ly/docs/api-reference-docs/guides/migration-guide-2-0/#automated-sorting

Signed-off-by: flouthoc <flouthoc.git@gmail.com>

* feat: move sort by prop to utils functions

* feat: add ability to sort tags

Co-authored-by: Oprysk <vyacheslav@redocly.com>
This commit is contained in:
flouthoc 2021-12-30 18:01:00 +05:30 committed by GitHub
parent c986f0ef1a
commit 831b207715
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 0 deletions

View File

@ -12,6 +12,7 @@ import {
SECURITY_DEFINITIONS_COMPONENT_NAME, SECURITY_DEFINITIONS_COMPONENT_NAME,
setSecuritySchemePrefix, setSecuritySchemePrefix,
JsonPointer, JsonPointer,
alphabeticallyByProp,
} from '../utils'; } from '../utils';
import { MarkdownRenderer } from './MarkdownRenderer'; import { MarkdownRenderer } from './MarkdownRenderer';
import { GroupModel, OperationModel } from './models'; import { GroupModel, OperationModel } from './models';
@ -130,9 +131,11 @@ export class MenuBuilder {
/** /**
* Returns array of OperationsGroup items for the tags of the group or for all tags * Returns array of OperationsGroup items for the tags of the group or for all tags
* @param parser
* @param tagsMap tags info returned from `getTagsWithOperations` * @param tagsMap tags info returned from `getTagsWithOperations`
* @param parent parent item * @param parent parent item
* @param group group which this tag belongs to. if not provided gets all tags * @param group group which this tag belongs to. if not provided gets all tags
* @param options normalized options
*/ */
static getTagsItems( static getTagsItems(
parser: OpenAPIParser, parser: OpenAPIParser,
@ -183,14 +186,21 @@ export class MenuBuilder {
res.push(item); res.push(item);
} }
if (options.sortTagsAlphabetically) {
res.sort(alphabeticallyByProp<GroupModel | OperationModel>('name'));
}
return res; return res;
} }
/** /**
* Returns array of Operation items for the tag * Returns array of Operation items for the tag
* @param parser
* @param parent parent OperationsGroup * @param parent parent OperationsGroup
* @param tag tag info returned from `getTagsWithOperations` * @param tag tag info returned from `getTagsWithOperations`
* @param depth items depth * @param depth items depth
* @param options - normalized options
*/ */
static getOperationsItems( static getOperationsItems(
parser: OpenAPIParser, parser: OpenAPIParser,
@ -209,6 +219,11 @@ export class MenuBuilder {
operation.depth = depth; operation.depth = depth;
res.push(operation); res.push(operation);
} }
if (options.sortOperationsAlphabetically) {
res.sort(alphabeticallyByProp<OperationModel>('name'));
}
return res; return res;
} }

View File

@ -18,6 +18,8 @@ export interface RedocRawOptions {
requiredPropsFirst?: boolean | string; requiredPropsFirst?: boolean | string;
sortPropsAlphabetically?: boolean | string; sortPropsAlphabetically?: boolean | string;
sortEnumValuesAlphabetically?: boolean | string; sortEnumValuesAlphabetically?: boolean | string;
sortOperationsAlphabetically?: boolean | string;
sortTagsAlphabetically?: boolean | string;
noAutoAuth?: boolean | string; noAutoAuth?: boolean | string;
nativeScrollbars?: boolean | string; nativeScrollbars?: boolean | string;
pathInMiddlePanel?: boolean | string; pathInMiddlePanel?: boolean | string;
@ -204,6 +206,8 @@ export class RedocNormalizedOptions {
requiredPropsFirst: boolean; requiredPropsFirst: boolean;
sortPropsAlphabetically: boolean; sortPropsAlphabetically: boolean;
sortEnumValuesAlphabetically: boolean; sortEnumValuesAlphabetically: boolean;
sortOperationsAlphabetically: boolean;
sortTagsAlphabetically: boolean;
noAutoAuth: boolean; noAutoAuth: boolean;
nativeScrollbars: boolean; nativeScrollbars: boolean;
pathInMiddlePanel: boolean; pathInMiddlePanel: boolean;
@ -264,6 +268,8 @@ export class RedocNormalizedOptions {
this.requiredPropsFirst = argValueToBoolean(raw.requiredPropsFirst); this.requiredPropsFirst = argValueToBoolean(raw.requiredPropsFirst);
this.sortPropsAlphabetically = argValueToBoolean(raw.sortPropsAlphabetically); this.sortPropsAlphabetically = argValueToBoolean(raw.sortPropsAlphabetically);
this.sortEnumValuesAlphabetically = argValueToBoolean(raw.sortEnumValuesAlphabetically); this.sortEnumValuesAlphabetically = argValueToBoolean(raw.sortEnumValuesAlphabetically);
this.sortOperationsAlphabetically = argValueToBoolean(raw.sortOperationsAlphabetically);
this.sortTagsAlphabetically = argValueToBoolean(raw.sortTagsAlphabetically);
this.noAutoAuth = argValueToBoolean(raw.noAutoAuth); this.noAutoAuth = argValueToBoolean(raw.noAutoAuth);
this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars); this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars);
this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel); this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel);

View File

@ -8,3 +8,4 @@ export * from './dom';
export * from './decorators'; export * from './decorators';
export * from './debug'; export * from './debug';
export * from './memoize'; export * from './memoize';
export * from './sort';

21
src/utils/sort.ts Normal file
View File

@ -0,0 +1,21 @@
/**
* Function that returns a comparator for sorting objects by some specific key alphabetically.
*
* @param {String} property key of the object to sort, if starts from `-` - reverse
*/
export function alphabeticallyByProp<T>(property: string): (a: T, b: T) => number {
let sortOrder = 1;
if (property[0] === '-') {
sortOrder = -1;
property = property.substr(1);
}
return (a: T, b: T) => {
if (sortOrder == -1) {
return b[property].localeCompare(a[property]);
} else {
return a[property].localeCompare(b[property]);
}
};
}