From 413d83d819d583309e6185605f8222d64e29d2f0 Mon Sep 17 00:00:00 2001 From: Viktor Vorona Date: Tue, 2 Jan 2024 14:11:30 +0100 Subject: [PATCH] SONAR-21057 Support internal parameters --- .../src/main/js/api/mocks/data/web-api.ts | 52 +++++- .../src/main/js/apps/web-api-v2/WebApiApp.tsx | 100 ++++++----- .../web-api-v2/__tests__/WebApiApp-it.tsx | 43 ++++- .../components/ApiFilterContext.tsx | 30 ++++ .../web-api-v2/components/ApiInformation.tsx | 14 +- .../web-api-v2/components/ApiParameters.tsx | 168 ++++++++++-------- .../components/ApiRequestParameters.tsx | 126 +++++++------ .../apps/web-api-v2/components/ApiSidebar.tsx | 29 +-- .../web-api-v2/components/RestMethodPill.tsx | 56 ++++++ .../src/main/js/apps/web-api-v2/types.ts | 4 + .../src/main/js/apps/web-api-v2/utils.ts | 17 -- .../resources/org/sonar/l10n/core.properties | 2 + 12 files changed, 422 insertions(+), 219 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/web-api-v2/components/ApiFilterContext.tsx create mode 100644 server/sonar-web/src/main/js/apps/web-api-v2/components/RestMethodPill.tsx diff --git a/server/sonar-web/src/main/js/api/mocks/data/web-api.ts b/server/sonar-web/src/main/js/api/mocks/data/web-api.ts index 7cf57325fbb..e6aeb205ecf 100644 --- a/server/sonar-web/src/main/js/api/mocks/data/web-api.ts +++ b/server/sonar-web/src/main/js/api/mocks/data/web-api.ts @@ -18,8 +18,9 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { OpenAPIV3 } from 'openapi-types'; +import { InternalExtension } from '../../../apps/web-api-v2/types'; -export const openApiTestData: OpenAPIV3.Document<{ 'x-internal'?: 'true' }> = { +export const openApiTestData: OpenAPIV3.Document = { openapi: '3.0.2', info: { title: 'Swagger Petstore - OpenAPI 3.0', @@ -397,6 +398,55 @@ export const openApiTestData: OpenAPIV3.Document<{ 'x-internal'?: 'true' }> = { }, }, }, + '/test': { + get: { + summary: 'Test internal query params', + description: 'For tests only', + parameters: [ + { + name: 'visible', + in: 'query', + description: 'parameter visible to anyone', + schema: { type: 'integer', format: 'int64' }, + }, + { + name: 'hidden', + in: 'query', + description: 'parameter is internal', + schema: { type: 'integer', format: 'int64' }, + 'x-internal': 'true', + } as OpenAPIV3.ParameterObject & InternalExtension, + ], + responses: { + default: { + description: 'successful operation', + }, + }, + }, + post: { + summary: 'Test internal query params', + description: 'For tests only', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + visible: { type: 'string' }, + hidden: { type: 'string', 'x-internal': 'true' } as OpenAPIV3.SchemaObject & + InternalExtension, + }, + }, + }, + }, + }, + responses: { + default: { + description: 'successful operation', + }, + }, + }, + }, '/user': { post: { tags: ['user'], diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/WebApiApp.tsx b/server/sonar-web/src/main/js/apps/web-api-v2/WebApiApp.tsx index b217d97e1d4..df1ff1ff3df 100644 --- a/server/sonar-web/src/main/js/apps/web-api-v2/WebApiApp.tsx +++ b/server/sonar-web/src/main/js/apps/web-api-v2/WebApiApp.tsx @@ -20,16 +20,18 @@ import styled from '@emotion/styled'; import { LargeCenteredLayout, PageContentFontWrapper, Spinner, Title } from 'design-system'; import { omit } from 'lodash'; -import React, { useMemo } from 'react'; +import React, { useMemo, useState } from 'react'; import { Helmet } from 'react-helmet-async'; import { useLocation } from 'react-router-dom'; import { translate } from '../../helpers/l10n'; import { useOpenAPI } from '../../queries/web-api'; +import ApiFilterContext from './components/ApiFilterContext'; import ApiInformation from './components/ApiInformation'; import ApiSidebar from './components/ApiSidebar'; import { URL_DIVIDER, dereferenceSchema } from './utils'; export default function WebApiApp() { + const [showInternal, setShowInternal] = useState(false); const { data, isLoading } = useOpenAPI(); const location = useLocation(); const activeApi = location.hash.replace('#', '').split(URL_DIVIDER); @@ -53,51 +55,61 @@ export default function WebApiApp() { activeApi.length > 1 && apis.find((api) => api.name === activeApi[0] && api.method === activeApi[1]); + const contextValue = useMemo( + () => ({ + showInternal, + setShowInternal, + }), + [showInternal], + ); + return ( - - - - - {data && ( -
- -
- ({ - method, - name, - info, - }))} - /> -
-
-
- - {!activeData && ( - <> - {translate('about')} -

{data.info.description}

- - )} - {data && activeData && ( - + + + + + {data && ( +
+ +
+ ({ + method, + name, + info, + }))} /> - )} - -
-
- )} -
-
-
+ + +
+ + {!activeData && ( + <> + {translate('about')} +

{data.info.description}

+ + )} + {data && activeData && ( + + )} +
+
+ + )} + + + + ); } diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/__tests__/WebApiApp-it.tsx b/server/sonar-web/src/main/js/apps/web-api-v2/__tests__/WebApiApp-it.tsx index 708698d5f6c..f0ff8841196 100644 --- a/server/sonar-web/src/main/js/apps/web-api-v2/__tests__/WebApiApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/web-api-v2/__tests__/WebApiApp-it.tsx @@ -31,10 +31,13 @@ const ui = { search: byRole('searchbox'), title: byRole('link', { name: 'Swagger Petstore - OpenAPI 3.0 1.0.17' }), searchClear: byRole('button', { name: 'clear' }), - showInternal: byRole('checkbox', { name: 'api_documentation.show_internal' }), + showInternal: byRole('checkbox', { name: 'api_documentation.show_internal_v2' }), apiScopePet: byRole('button', { name: 'pet' }), apiScopeStore: byRole('button', { name: 'store' }), apiScopeUser: byRole('button', { name: 'user' }), + apiScopeTest: byRole('button', { name: 'test' }), + publicButton: byRole('button', { name: /visible/ }), + internalButton: byRole('button', { name: /hidden/ }), apiSidebarItem: byTestId('js-subnavigation-item'), requestBody: byText('api_documentation.v2.request_subheader.request_body'), queryParameter: byRole('list', { name: 'api_documentation.v2.request_subheader.query' }).byRole( @@ -86,7 +89,7 @@ it('should search apis', async () => { expect(ui.apiSidebarItem.getAll().length).toBeGreaterThan(3); }); -it('should show internal', async () => { +it('should show internal endpoints', async () => { const user = userEvent.setup(); renderWebApiApp(); expect(await ui.apiScopeStore.find()).toBeInTheDocument(); @@ -99,9 +102,41 @@ it('should show internal', async () => { .getAll() .find((el) => el.textContent?.includes('internal')); expect(internalItem).toBeInTheDocument(); - await user.click(internalItem!); + await user.click(internalItem as HTMLElement); - expect(await screen.findByText('/api/v3/store/inventory')).toHaveTextContent(/internal/); + expect(await byRole('heading', { name: /\/api\/v3\/store\/inventory/ }).find()).toHaveTextContent( + /internal/, + ); +}); + +it('should show internal parameters', async () => { + const user = userEvent.setup(); + renderWebApiApp(); + expect(await ui.apiScopeTest.find()).toBeInTheDocument(); + await user.click(ui.apiScopeTest.get()); + expect(ui.apiSidebarItem.getAll()).toHaveLength(2); + + await user.click( + ui.apiSidebarItem.getAll().find((el) => el.textContent?.includes('GET')) as HTMLElement, + ); + expect(await ui.publicButton.find()).toBeInTheDocument(); + expect(ui.internalButton.query()).not.toBeInTheDocument(); + await user.click(ui.showInternal.get()); + expect(ui.publicButton.get()).toBeInTheDocument(); + expect(ui.publicButton.get()).not.toHaveTextContent('internal'); + expect(ui.internalButton.get()).toBeInTheDocument(); + expect(ui.internalButton.get()).toHaveTextContent('internal'); + + await user.click( + ui.apiSidebarItem.getAll().find((el) => el.textContent?.includes('POST')) as HTMLElement, + ); + expect(ui.publicButton.get()).toBeInTheDocument(); + expect(ui.publicButton.get()).not.toHaveTextContent('internal'); + expect(ui.internalButton.get()).toBeInTheDocument(); + expect(ui.internalButton.get()).toHaveTextContent('internal'); + await user.click(ui.showInternal.get()); + expect(await ui.publicButton.find()).toBeInTheDocument(); + expect(ui.internalButton.query()).not.toBeInTheDocument(); }); it('should navigate between apis', async () => { diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiFilterContext.tsx b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiFilterContext.tsx new file mode 100644 index 00000000000..5c669dc0213 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiFilterContext.tsx @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { Dispatch, SetStateAction, createContext } from 'react'; + +const ApiFilterContext = createContext<{ + showInternal: boolean; + setShowInternal: Dispatch>; +}>({ + showInternal: false, + setShowInternal: () => {}, +}); + +export default ApiFilterContext; diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiInformation.tsx b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiInformation.tsx index f1446b8da2f..d6da453d68e 100644 --- a/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiInformation.tsx +++ b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiInformation.tsx @@ -17,18 +17,18 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import classNames from 'classnames'; import { Badge, SubHeading, Title } from 'design-system'; import { OpenAPIV3 } from 'openapi-types'; import React from 'react'; import { translate } from '../../../helpers/l10n'; -import { ExcludeReferences } from '../types'; -import { getApiEndpointKey, getMethodClassName } from '../utils'; +import { ExcludeReferences, InternalExtension } from '../types'; +import { getApiEndpointKey } from '../utils'; import ApiParameters from './ApiParameters'; import ApiResponses from './ApiResponses'; +import RestMethodPill from './RestMethodPill'; interface Props { - data: ExcludeReferences>; + data: ExcludeReferences>; apiUrl: string; name: string; method: string; @@ -39,10 +39,8 @@ export default function ApiInformation({ name, data, method, apiUrl }: Readonly< <> {data.summary && {data.summary}} - - {method} - - {apiUrl.replace(/.*(?=\/api)/, '') + name} + + {apiUrl.replace(/.*(?=\/api)/, '') + name} {data['x-internal'] && ( {translate('internal')} diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiParameters.tsx b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiParameters.tsx index 113ddc8999f..e0b3657da16 100644 --- a/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiParameters.tsx +++ b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiParameters.tsx @@ -20,11 +20,12 @@ import { Accordion, Badge, SubHeading, SubTitle, TextMuted } from 'design-system'; import { groupBy } from 'lodash'; import { OpenAPIV3 } from 'openapi-types'; -import React from 'react'; +import React, { useContext } from 'react'; import { FormattedMessage } from 'react-intl'; import { translate } from '../../../helpers/l10n'; -import { ExcludeReferences } from '../types'; +import { ExcludeReferences, InternalExtension } from '../types'; import { mapOpenAPISchema } from '../utils'; +import ApiFilterContext from './ApiFilterContext'; import ApiRequestBodyParameters from './ApiRequestParameters'; import ApiResponseSchema from './ApiResponseSchema'; @@ -32,8 +33,9 @@ interface Props { data: ExcludeReferences; } -export default function ApiParameters({ data }: Props) { +export default function ApiParameters({ data }: Readonly) { const [openParameters, setOpenParameters] = React.useState([]); + const { showInternal } = useContext(ApiFilterContext); const toggleParameter = (name: string) => { if (openParameters.includes(name)) { @@ -54,85 +56,97 @@ export default function ApiParameters({ data }: Props) { return ( <> {translate('api_documentation.v2.parameter_header')} - {Object.entries(groupBy(data.parameters, (p) => p.in)).map(([group, parameters]) => ( -
- - {translate(`api_documentation.v2.request_subheader.${group}`)} - -
    - {parameters.map((parameter) => { - return ( - - {parameter.name}{' '} - {parameter.schema && ( + {Object.entries(groupBy(data.parameters, (p) => p.in)).map( + ([group, parameters]: [ + string, + ExcludeReferences>, + ]) => ( +
    + + {translate(`api_documentation.v2.request_subheader.${group}`)} + +
      + {parameters + .filter((parameter) => showInternal || !parameter['x-internal']) + .map((parameter) => { + return ( + + {parameter.name}{' '} + {parameter.schema && ( + + )} + {parameter.required && ( + {translate('required')} + )} + {parameter.deprecated && ( + + {translate('deprecated')} + + )} + {parameter['x-internal'] && ( + + {translate('internal')} + + )} +
    + } + data={parameter.name} + onClick={toggleParameter} + open={openParameters.includes(parameter.name)} + > +
    {parameter.description}
    + {parameter.schema?.enum && ( +
    + + {parameter.schema.enum.join(', ')} +
    + ), + }} + /> +
+ )} + {parameter.schema?.maximum && ( )} - {parameter.required && ( - {translate('required')} + {typeof parameter.schema?.minimum === 'number' && ( + )} - {parameter.deprecated && ( - - {translate('deprecated')} - + {parameter.example !== undefined && ( + )} - - } - data={parameter.name} - onClick={toggleParameter} - open={openParameters.includes(parameter.name)} - > -
{parameter.description}
- {parameter.schema?.enum && ( -
- - {parameter.schema.enum.join(', ')} -
- ), - }} - /> - - )} - {parameter.schema?.maximum && ( - - )} - {typeof parameter.schema?.minimum === 'number' && ( - - )} - {parameter.example !== undefined && ( - - )} - {parameter.schema?.default !== undefined && ( - - )} - - ); - })} - - - ))} + {parameter.schema?.default !== undefined && ( + + )} + + ); + })} + + + ), + )} {!requestBody && !data.parameters?.length && } {requestBody && (
diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiRequestParameters.tsx b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiRequestParameters.tsx index b1b78e9cbba..42bc04e3ce8 100644 --- a/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiRequestParameters.tsx +++ b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiRequestParameters.tsx @@ -20,17 +20,19 @@ import { Accordion, Badge, TextMuted } from 'design-system'; import { isEmpty } from 'lodash'; import { OpenAPIV3 } from 'openapi-types'; -import React from 'react'; +import React, { useContext } from 'react'; import { FormattedMessage } from 'react-intl'; import { translate } from '../../../helpers/l10n'; -import { ExcludeReferences } from '../types'; +import { ExcludeReferences, InternalExtension } from '../types'; +import ApiFilterContext from './ApiFilterContext'; interface Props { - content?: Exclude['content'], undefined>; + content?: ExcludeReferences['content']; } export default function ApiRequestBodyParameters({ content }: Readonly) { const [openParameters, setOpenParameters] = React.useState([]); + const { showInternal } = useContext(ApiFilterContext); const toggleParameter = (parameter: string) => { if (openParameters.includes(parameter)) { @@ -63,60 +65,72 @@ export default function ApiRequestBodyParameters({ content }: Readonly) { return (
    - {orderedKeys.map((key) => { - return ( - - {key}{' '} - {schema.required?.includes(key) && ( - {translate('required')} - )} - {parameters[key].deprecated && ( - - {translate('deprecated')} - - )} -
- } - data={key} - onClick={() => toggleParameter(key)} - open={openParameters.includes(key)} - > -
{parameters[key].description}
- {parameters[key].enum && ( -
- {parameters[key].enum?.join(', ')}, - }} + {orderedKeys + .filter((key) => showInternal || !(parameters[key] as InternalExtension)['x-internal']) + .map((key) => { + return ( + + {key}{' '} + {schema.required?.includes(key) && ( + {translate('required')} + )} + {parameters[key].deprecated && ( + + {translate('deprecated')} + + )} + {parameters[key].deprecated && ( + + {translate('deprecated')} + + )} + {(parameters[key] as InternalExtension)['x-internal'] && ( + + {translate('internal')} + + )} +
+ } + data={key} + onClick={() => toggleParameter(key)} + open={openParameters.includes(key)} + > +
{parameters[key].description}
+ {parameters[key].enum && ( +
+ {parameters[key].enum?.join(', ')}, + }} + /> +
+ )} + {parameters[key].maxLength && ( + - - )} - {parameters[key].maxLength && ( - - )} - {typeof parameters[key].minLength === 'number' && ( - - )} - {parameters[key].default !== undefined && ( - - )} - - ); - })} + )} + {typeof parameters[key].minLength === 'number' && ( + + )} + {parameters[key].default !== undefined && ( + + )} + + ); + })} ); } diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiSidebar.tsx b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiSidebar.tsx index 86fca9b65ab..e8ef17258c1 100644 --- a/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiSidebar.tsx +++ b/server/sonar-web/src/main/js/apps/web-api-v2/components/ApiSidebar.tsx @@ -17,7 +17,6 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import classNames from 'classnames'; import { Badge, BasicSeparator, @@ -31,17 +30,20 @@ import { } from 'design-system'; import { sortBy } from 'lodash'; import { OpenAPIV3 } from 'openapi-types'; -import React, { Fragment, useMemo, useState } from 'react'; +import React, { Fragment, useContext, useMemo, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import HelpTooltip from '../../../components/controls/HelpTooltip'; import { translate } from '../../../helpers/l10n'; import { Dict } from '../../../types/types'; -import { URL_DIVIDER, getApiEndpointKey, getMethodClassName } from '../utils'; +import { InternalExtension } from '../types'; +import { URL_DIVIDER, getApiEndpointKey } from '../utils'; +import ApiFilterContext from './ApiFilterContext'; +import RestMethodPill from './RestMethodPill'; interface Api { name: string; method: string; - info: OpenAPIV3.OperationObject<{ 'x-internal'?: 'true' }>; + info: OpenAPIV3.OperationObject; } interface Props { docInfo: OpenAPIV3.InfoObject; @@ -57,9 +59,9 @@ const METHOD_ORDER: Dict = { export default function ApiSidebar({ apisList, docInfo }: Readonly) { const [search, setSearch] = useState(''); - const [showInternal, setShowInternal] = useState(false); const navigate = useNavigate(); const location = useLocation(); + const { showInternal, setShowInternal } = useContext(ApiFilterContext); const activeApi = location.hash.replace('#', '').split(URL_DIVIDER); const handleApiClick = (value: string) => { @@ -106,9 +108,12 @@ export default function ApiSidebar({ apisList, docInfo }: Readonly) {
setShowInternal((prev) => !prev)}> - {translate('api_documentation.show_internal')} + {translate('api_documentation.show_internal_v2')} - +
@@ -141,11 +146,11 @@ export default function ApiSidebar({ apisList, docInfo }: Readonly) { onClick={handleApiClick} value={getApiEndpointKey(name, method)} > -
- - {method.toUpperCase()} - -
{info.summary ?? name}
+
+
+ +
{info.summary ?? name}
+
{(info['x-internal'] || info.deprecated) && (
diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/components/RestMethodPill.tsx b/server/sonar-web/src/main/js/apps/web-api-v2/components/RestMethodPill.tsx new file mode 100644 index 00000000000..8387e0adf73 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/web-api-v2/components/RestMethodPill.tsx @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import classNames from 'classnames'; +import { Badge } from 'design-system'; +import React from 'react'; + +interface Props { + method: string; +} + +export default function RestMethodPill({ method }: Readonly) { + const getMethodClassName = (): string => { + switch (method.toLowerCase()) { + case 'get': + return 'sw-bg-green-200'; + case 'delete': + return 'sw-bg-red-200'; + case 'post': + return 'sw-bg-blue-200'; + case 'put': + return 'sw-bg-purple-200'; + case 'patch': + return 'sw-bg-yellow-200'; + default: + return 'sw-bg-gray-200'; + } + }; + + return ( + + {method.toUpperCase()} + + ); +} diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/types.ts b/server/sonar-web/src/main/js/apps/web-api-v2/types.ts index 22e1e34dd7c..30d2f6cb2b7 100644 --- a/server/sonar-web/src/main/js/apps/web-api-v2/types.ts +++ b/server/sonar-web/src/main/js/apps/web-api-v2/types.ts @@ -34,3 +34,7 @@ export type DereferenceRecursive = T extends object [K in keyof T]: DereferenceRecursive; } : T; + +export interface InternalExtension { + 'x-internal'?: 'true'; +} diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/utils.ts b/server/sonar-web/src/main/js/apps/web-api-v2/utils.ts index da52b8c33c8..7e8826d05f9 100644 --- a/server/sonar-web/src/main/js/apps/web-api-v2/utils.ts +++ b/server/sonar-web/src/main/js/apps/web-api-v2/utils.ts @@ -72,23 +72,6 @@ export const dereferenceSchema = ( return dereferenceRecursive(document) as ExcludeReferences; }; -export const getMethodClassName = (method: string): string => { - switch (method.toLowerCase()) { - case 'get': - return 'sw-bg-green-200'; - case 'delete': - return 'sw-bg-red-200'; - case 'post': - return 'sw-bg-blue-200'; - case 'put': - return 'sw-bg-purple-200'; - case 'patch': - return 'sw-bg-yellow-200'; - default: - return 'sw-bg-gray-200'; - } -}; - export const getResponseCodeClassName = (code: string): string => { switch (code[0]) { case '1': diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index f2f4cbb63d0..5864c0816f1 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -4018,10 +4018,12 @@ overview.activity.variations.first_analysis=First analysis: #------------------------------------------------------------------------------ api_documentation.deprecation_tooltip=An API deprecated in version X.Y will be dropped in version (X+1).0. Example: an API deprecated in 4.1 is supported in 4.X (4.2, 4.3, etc.) and will be dropped in version 5.0. api_documentation.internal_tooltip=Use at your own risk; internal services are subject to change or removal without notice. +api_documentation.internal_tooltip_v2=Use at your own risk. Shows/hides the internal endpoints, parameters, and other details used for internal services. These are subject to change or removal without notice. api_documentation.page=Web API api_documentation.page.v2=Web API v2 api_documentation.show_deprecated=Show Deprecated API api_documentation.show_internal=Show Internal API +api_documentation.show_internal_v2=Show Internal api_documentation.possible_values=Possible values api_documentation.default_values=Default value api_documentation.example_values=Example value -- 2.39.5