From 5ada359d0c0739c461ee2b7cd87817e32308133c Mon Sep 17 00:00:00 2001 From: b41ex Date: Mon, 8 Sep 2025 11:46:26 +0300 Subject: [PATCH 01/18] chore: set feature branch version for dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b629d2522..57add3799 100644 --- a/package.json +++ b/package.json @@ -29,12 +29,12 @@ "@mui/lab": "5.0.0-alpha.120", "@mui/material": "5.11.10", "@mui/private-theming": "5.11.9", - "@netcracker/qubership-apihub-api-diff": "2.2.0", - "@netcracker/qubership-apihub-api-doc-viewer": "2.1.4", - "@netcracker/qubership-apihub-api-processor": "4.1.2", + "@netcracker/qubership-apihub-api-diff": "feature-performance-optimization", + "@netcracker/qubership-apihub-api-doc-viewer": "feature-performance-optimization", + "@netcracker/qubership-apihub-api-processor": "feature-performance-optimization", "@netcracker/qubership-apihub-api-unifier": "2.3.0", "@netcracker/qubership-apihub-api-visitor": "1.0.10", - "@netcracker/qubership-apihub-apispec-view": "1.1.7", + "@netcracker/qubership-apihub-apispec-view": "feature-performance-optimization", "@netcracker/qubership-apihub-class-view": "1.0.3", "@netcracker/qubership-apihub-rest-playground": "1.1.2", "@otjs/plaintext": "0.2.2", From a752aeec166a9735459ce03e3d21c14b0eda33a5 Mon Sep 17 00:00:00 2001 From: CountRedClaw Date: Mon, 8 Sep 2025 14:19:48 +0500 Subject: [PATCH 02/18] refactor: remove operation.dataHash usages & add operation.documentId --- .../portal/server/mocks/packages/document-contents.ts | 4 ---- packages/portal/server/mocks/packages/operations.ts | 10 +--------- packages/portal/server/mocks/packages/types.ts | 5 +---- packages/shared/src/entities/operations.ts | 5 ++--- packages/shared/src/entities/version-changelog.ts | 4 +--- .../shared/src/stories/samples/operations-samples.ts | 4 ---- packages/shared/src/utils/packages-builder.ts | 2 +- 7 files changed, 6 insertions(+), 28 deletions(-) diff --git a/packages/portal/server/mocks/packages/document-contents.ts b/packages/portal/server/mocks/packages/document-contents.ts index 39f92ddd2..d44f89138 100644 --- a/packages/portal/server/mocks/packages/document-contents.ts +++ b/packages/portal/server/mocks/packages/document-contents.ts @@ -35,7 +35,6 @@ export const OPENAPI_SPEC: DocumentDto = { deprecated: true, apiKind: 'bwc', apiType: 'rest', - dataHash: 'sdfsdfsf242', metadata: { tags: ['RestControllerV1'], path: '/v1/pets', @@ -48,7 +47,6 @@ export const OPENAPI_SPEC: DocumentDto = { deprecated: false, apiKind: 'no-bwc', apiType: 'rest', - dataHash: 'sdfsdfsf243', metadata: { tags: ['RestControllerV3'], path: '/v3/fruit', @@ -60,7 +58,6 @@ export const OPENAPI_SPEC: DocumentDto = { title: 'Array Cars', apiKind: 'bwc', apiType: 'rest', - dataHash: 'sdfsdfsf244', metadata: { tags: ['RestControllerV5'], path: '/v5/cars/array', @@ -72,7 +69,6 @@ export const OPENAPI_SPEC: DocumentDto = { title: 'Get Cars 2', apiKind: 'bwc', apiType: 'rest', - dataHash: 'sdfsdfsf245', metadata: { tags: ['A', 'B'], path: '/v5/cars/array', diff --git a/packages/portal/server/mocks/packages/operations.ts b/packages/portal/server/mocks/packages/operations.ts index b3550101f..b3143c67c 100644 --- a/packages/portal/server/mocks/packages/operations.ts +++ b/packages/portal/server/mocks/packages/operations.ts @@ -144,7 +144,6 @@ export const OPERATIONS: Writeable = { deprecated: true, apiKind: 'bwc', apiType: 'rest', - dataHash: 'sdfsdfsf242', path: '/quoteManagement/v5/quote', tags: ['RestControllerV5'], method: 'get', @@ -157,7 +156,6 @@ export const OPERATIONS: Writeable = { deprecated: true, apiKind: 'bwc', apiType: 'rest', - dataHash: 'sdfsdfsf242', path: '/quoteManagement/v5/quote', tags: ['RestControllerV5'], method: 'patch', @@ -170,7 +168,6 @@ export const OPERATIONS: Writeable = { deprecated: false, apiKind: 'no-bwc', apiType: 'rest', - dataHash: 'sdfsdfsf243', tags: ['TMF'], path: '/quoteManagement/v3/pets', method: 'get', @@ -182,7 +179,6 @@ export const OPERATIONS: Writeable = { title: 'Array Quote', apiKind: 'bwc', apiType: 'rest', - dataHash: 'sdfsdfsf244', tags: ['RestControllerV5', 'TMF'], path: '/quoteManagement/v5/array', method: 'get', @@ -194,7 +190,6 @@ export const OPERATIONS: Writeable = { title: 'Get Pets2', apiKind: 'bwc', apiType: 'rest', - dataHash: 'sdfsdfsf245', tags: ['TMF', 'RestControllerV5'], path: '/quoteManagement/v5/array', method: 'post', @@ -206,7 +201,6 @@ export const OPERATIONS: Writeable = { data: graphQlOperationData, operationId: 'query-fulltextquotesearch', title: 'fullTextQuoteSearch', - dataHash: '3a2a746b578324e016ddbcdc4c3b462288fabc55', apiKind: 'bwc', apiType: 'graphql', type: 'query', @@ -218,7 +212,6 @@ export const OPERATIONS: Writeable = { data: graphQlOperationData, operationId: 'mutation-createorupdatesessioncontext', title: 'createOrUpdateSessionContext', - dataHash: '045efe99015262f164d740e00e0b110e8a110fbb', apiKind: 'bwc', apiType: 'graphql', type: 'mutation', @@ -230,7 +223,6 @@ export const OPERATIONS: Writeable = { data: graphQlOperationData, operationId: 'subscription-postwaspublished', title: 'postWasPublished', - dataHash: 'f202090d17c30e85b4170e23994746132c711891', apiKind: 'bwc', apiType: 'graphql', type: 'subscription', @@ -282,7 +274,7 @@ export const OPERATIONS: Writeable = { export const DEPRECATED_OPERATIONS: Writeable = { operations: OPERATIONS.operations.map((operation) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { data, dataHash, ...operationBaseProps } = operation + const { data, ...operationBaseProps } = operation return { deprecatedCount: operationBaseProps.deprecated ? '1' : '5', deprecatedInPreviousVersions: operationBaseProps.deprecated ? ['2022.1', '2021.4'] : undefined, diff --git a/packages/portal/server/mocks/packages/types.ts b/packages/portal/server/mocks/packages/types.ts index 01dba1f9f..3dd625dac 100644 --- a/packages/portal/server/mocks/packages/types.ts +++ b/packages/portal/server/mocks/packages/types.ts @@ -200,7 +200,6 @@ type OperationMetadata = Readonly<{ apiType: ApiType data?: object packageRef?: string - dataHash?: string deprecated?: boolean tags?: string[] }> @@ -228,7 +227,7 @@ export type DeprecatedItemDto = Readonly<{ }> export type DeprecatedItemsDto = ReadonlyArray -export type OperationWithDeprecatedDto = Omit & Readonly<{ +export type OperationWithDeprecatedDto = Omit & Readonly<{ deprecatedCount?: string deprecatedInfo?: object deprecatedItems?: DeprecatedItemsDto @@ -347,8 +346,6 @@ export type OperationChangesMetadata = Readonly<{ packageRef?: string previousVersionPackageRef?: string apiKind?: ApiKind - dataHash?: string - previousDataHash?: string tags?: readonly string[] }> diff --git a/packages/shared/src/entities/operations.ts b/packages/shared/src/entities/operations.ts index aa1e6ccc9..8fbfe2a68 100644 --- a/packages/shared/src/entities/operations.ts +++ b/packages/shared/src/entities/operations.ts @@ -37,13 +37,13 @@ export type OperationDto = RestOperationDto | GraphQlOperationDto export type OperationMetadataDto = Readonly<{ operationId: Key + documentId: Key title: string apiType: ApiType apiKind: ApiKind apiAudience: ApiAudience data?: object packageRef?: string - dataHash: string deprecated?: boolean tags?: Readonly customTags?: CustomTags @@ -69,7 +69,7 @@ export type OperationsWithDeprecationsDto = Readonly<{ operations: ReadonlyArray packages: PackagesRefs }> -export type OperationWithDeprecationsDto = Omit & Readonly<{ +export type OperationWithDeprecationsDto = Omit & Readonly<{ deprecatedCount?: string deprecatedInfo?: object deprecatedItems?: DeprecatedItemsDto @@ -114,7 +114,6 @@ export interface Operation { readonly title: string readonly apiKind: ApiKind readonly apiAudience: ApiAudience - readonly dataHash?: string readonly packageRef?: PackageRef readonly tags?: Readonly readonly customTags?: CustomTags diff --git a/packages/shared/src/entities/version-changelog.ts b/packages/shared/src/entities/version-changelog.ts index 877517587..2d50f68d7 100644 --- a/packages/shared/src/entities/version-changelog.ts +++ b/packages/shared/src/entities/version-changelog.ts @@ -57,7 +57,6 @@ export interface OperationInfoDto { readonly apiKind: ApiKind readonly apiAudience: ApiAudience readonly tags: string[] - readonly dataHash: string readonly packageRef?: string } @@ -100,7 +99,6 @@ export interface OperationInfo { readonly title: string readonly apiKind: ApiKind readonly apiAudience: ApiAudience - readonly dataHash: string readonly packageRef?: PackageRef } @@ -166,7 +164,7 @@ export const toOperationChange = ( packageRef: includePackageRefs ? toPackageRef(dto.previousOperation.packageRef, packagesRefs) : undefined, } : undefined, - action: calculateAction(dto.currentOperation?.dataHash, dto.previousOperation?.dataHash), + action: calculateAction(dto.currentOperation?.operationId, dto.previousOperation?.operationId), } } diff --git a/packages/shared/src/stories/samples/operations-samples.ts b/packages/shared/src/stories/samples/operations-samples.ts index ebc7cd2d7..8ab661a54 100644 --- a/packages/shared/src/stories/samples/operations-samples.ts +++ b/packages/shared/src/stories/samples/operations-samples.ts @@ -33,7 +33,6 @@ export const restDeprecatedOperations: OperationsWithDeprecations = [ }, 'apiAudience': 'unknown', 'title': '[Deprecated] Get list of changes in branch', - 'dataHash': 'bc2a54ac13185c9adb6c494dc691793fd0fb1322', 'deprecated': true, 'apiKind': 'bwc', 'apiType': 'rest', @@ -61,7 +60,6 @@ export const restDeprecatedOperations: OperationsWithDeprecations = [ }, 'apiAudience': 'unknown', 'title': 'Get project branch files by commit Id', - 'dataHash': 'f8fc078bf2730287acb648c7045139c40f2a045b', 'deprecated': true, 'apiKind': 'bwc', 'apiType': 'rest', @@ -90,7 +88,6 @@ export const restDeprecatedOperations: OperationsWithDeprecations = [ }, 'apiAudience': 'unknown', 'title': 'Publish project branch', - 'dataHash': '3cfe640496a9e342bfd857938481c1c09a212735', 'deprecated': true, 'apiKind': 'bwc', 'apiType': 'rest', @@ -119,7 +116,6 @@ export const restDeprecatedOperations: OperationsWithDeprecations = [ }, 'apiAudience': 'unknown', 'title': '[Draft] Get project version dependents', - 'dataHash': '43d0187d1ed8d7654e3deb35afd243dcd4638f72', 'deprecated': true, 'apiKind': 'bwc', 'apiType': 'rest', diff --git a/packages/shared/src/utils/packages-builder.ts b/packages/shared/src/utils/packages-builder.ts index 3ab721d3a..4a6c0f65c 100644 --- a/packages/shared/src/utils/packages-builder.ts +++ b/packages/shared/src/utils/packages-builder.ts @@ -276,8 +276,8 @@ export function toVersionOperation(value: OperationDto): ResolvedOperation { } return { operationId: value.operationId, + documentId: value.documentId, data: value.data!, - dataHash: value.dataHash, apiKind: value.apiKind as ApiKind, apiAudience: value.apiAudience as ApiAudience, deprecated: value.deprecated ?? false, From 562041cde54ad29ef6107b2e0b15a50249574d4d Mon Sep 17 00:00:00 2001 From: CountRedClaw Date: Tue, 9 Sep 2025 18:24:49 +0500 Subject: [PATCH 03/18] fix: add missing builder resolvers --- .../DocumentPreviewCard.tsx | 2 +- .../VersionDocumentsSubPage/FormatViewer.tsx | 2 +- .../package-version-builder-worker.ts | 4 + packages/shared/src/entities/documents.ts | 85 +++++++++++++++++++ packages/shared/src/entities/operations.ts | 8 +- .../documents}/usePublishedDocumentRaw.ts | 25 ++++-- .../shared/src/utils/builder-resolvers.ts | 46 ++++++++++ packages/shared/src/utils/packages-builder.ts | 23 +++++ 8 files changed, 182 insertions(+), 13 deletions(-) create mode 100644 packages/shared/src/entities/documents.ts rename packages/{portal/src/routes/root/PortalPage/VersionPage => shared/src/hooks/documents}/usePublishedDocumentRaw.ts (77%) diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/DocumentPreviewPage/DocumentPreviewCard.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/DocumentPreviewPage/DocumentPreviewCard.tsx index 834039856..aed6713c4 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/DocumentPreviewPage/DocumentPreviewCard.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/DocumentPreviewPage/DocumentPreviewCard.tsx @@ -19,8 +19,8 @@ import { memo } from 'react' import { useParams } from 'react-router-dom' import { Box } from '@mui/material' import { DocumentPreviewContentBody } from './DocumentPreviewContentBody' -import { usePublishedDocumentRaw } from '../usePublishedDocumentRaw' import { usePackageParamsWithRef } from '../../usePackageParamsWithRef' +import { usePublishedDocumentRaw } from '@netcracker/qubership-apihub-ui-shared/hooks/documents/usePublishedDocumentRaw' export const DocumentPreviewCard: FC = memo(() => { const { documentId } = useParams() diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/VersionDocumentsSubPage/FormatViewer.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/VersionDocumentsSubPage/FormatViewer.tsx index bf520b6db..0bb8851b0 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/VersionDocumentsSubPage/FormatViewer.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/VersionDocumentsSubPage/FormatViewer.tsx @@ -18,7 +18,6 @@ import type { FC } from 'react' import { memo } from 'react' import { useParams } from 'react-router-dom' import { Box } from '@mui/material' -import { usePublishedDocumentRaw } from '../usePublishedDocumentRaw' import { usePackageParamsWithRef } from '../../usePackageParamsWithRef' import { UnsupportedView } from './UnsupportedView' import { JsonSchemaViewer } from '@netcracker/qubership-apihub-ui-shared/components/JsonSchemaViewer' @@ -27,6 +26,7 @@ import { JSON_FILE_FORMAT, MD_FILE_FORMAT, YAML_FILE_FORMAT } from '@netcracker/ import { LoadingIndicator } from '@netcracker/qubership-apihub-ui-shared/components/LoadingIndicator' import { MarkdownViewer } from '@netcracker/qubership-apihub-ui-shared/components/SpecificationDialog/MarkdownViewer' import { isFastJsonSchema, toJsonSchema } from '@netcracker/qubership-apihub-ui-shared/utils/specifications' +import { usePublishedDocumentRaw } from '@netcracker/qubership-apihub-ui-shared/hooks/documents/usePublishedDocumentRaw' export type FormatViewerProps = { format: FileFormat diff --git a/packages/portal/src/routes/root/PortalPage/package-version-builder-worker.ts b/packages/portal/src/routes/root/PortalPage/package-version-builder-worker.ts index 7789ded89..9649aeb8e 100644 --- a/packages/portal/src/routes/root/PortalPage/package-version-builder-worker.ts +++ b/packages/portal/src/routes/root/PortalPage/package-version-builder-worker.ts @@ -18,7 +18,9 @@ import type { FileId, FileSourceMap, VersionsComparison } from '@netcracker/qube import { BUILD_TYPE, PackageVersionBuilder, VERSION_STATUS } from '@netcracker/qubership-apihub-api-processor' import { packageVersionResolver, + rawDocumentResolver, versionDeprecatedResolver, + versionDocumentsResolver, versionOperationsResolver, versionReferencesResolver, } from '@netcracker/qubership-apihub-ui-shared/utils/builder-resolvers' @@ -130,6 +132,8 @@ const worker: PackageVersionBuilderWorker = { versionReferencesResolver: await versionReferencesResolver(), versionOperationsResolver: await versionOperationsResolver(), versionDeprecatedResolver: await versionDeprecatedResolver(), + versionDocumentsResolver: await versionDocumentsResolver(), + rawDocumentResolver: await rawDocumentResolver(), }, }, fileSources) diff --git a/packages/shared/src/entities/documents.ts b/packages/shared/src/entities/documents.ts new file mode 100644 index 000000000..0837411d3 --- /dev/null +++ b/packages/shared/src/entities/documents.ts @@ -0,0 +1,85 @@ +/** + * Copyright 2024-2025 NetCracker Technology Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { FileKey, Key } from './keys' +import type { OperationDto, OperationsData, PackageRef, PackagesRefs } from './operations' +import type { SpecType } from '../utils/specs' + +export type DocumentsDto = Readonly<{ + documents: ReadonlyArray + packages: PackagesRefs +}> + +export type Documents = ReadonlyArray + +export type Document = Readonly<{ + key: Key + slug: Key + filename: string + title: string + type: SpecType + format: FileFormat + version?: string + labels?: Labels + description?: string + info?: Readonly + externalDocs?: Readonly + operations: OperationsData + packageRef?: PackageRef +}> + +export type DocumentDto = Readonly<{ + fileId: FileKey + slug: Key + filename: string + title: string + type: SpecType + format: FileFormat + version?: string + labels?: Labels + description?: string + info?: Readonly + externalDocs?: Readonly + operations?: ReadonlyArray + packages?: PackagesRefs // For operations + packageRef?: string // For dashboards +}> + +export type DocumentInfo = { + contact?: Readonly + license?: Readonly + termsOfService?: string +} + +export type DocLink = { + name?: string + url?: string +} + +export type ExternalDocsLink = Omit & { description?: string } + +export type Labels = string[] + +export const JSON_FILE_FORMAT = 'json' +export const YAML_FILE_FORMAT = 'yaml' +export const MD_FILE_FORMAT = 'md' +export const UNKNOWN_FILE_FORMAT = 'unknown' + +export type FileFormat = + | typeof JSON_FILE_FORMAT + | typeof YAML_FILE_FORMAT + | typeof MD_FILE_FORMAT + | typeof UNKNOWN_FILE_FORMAT diff --git a/packages/shared/src/entities/operations.ts b/packages/shared/src/entities/operations.ts index 8fbfe2a68..f68b50ba9 100644 --- a/packages/shared/src/entities/operations.ts +++ b/packages/shared/src/entities/operations.ts @@ -24,7 +24,7 @@ import type { FetchNextPageOptions, InfiniteQueryObserverResult } from '@tanstac import type { Key, VersionKey } from './keys' import type { ApiType } from './api-types' import { API_TYPE_REST } from './api-types' -import type { DeprecateItem } from '@netcracker/qubership-apihub-api-processor' +import type { DeprecateItem, ReferencedPackageKind } from '@netcracker/qubership-apihub-api-processor' import type { IsLoading } from '../utils/aliases' export const DEFAULT_API_TYPE: ApiType = API_TYPE_REST @@ -139,11 +139,11 @@ export type PackagesRefs = { } export type PackageRefDto = { refId: string - kind?: string - name?: string + kind: ReferencedPackageKind + name: string version: string notLatestRevision?: boolean - status?: VersionStatus + status: VersionStatus deletedAt?: string deletedBy?: string parentPackages?: ReadonlyArray diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/usePublishedDocumentRaw.ts b/packages/shared/src/hooks/documents/usePublishedDocumentRaw.ts similarity index 77% rename from packages/portal/src/routes/root/PortalPage/VersionPage/usePublishedDocumentRaw.ts rename to packages/shared/src/hooks/documents/usePublishedDocumentRaw.ts index c5c24a5f1..7a7089a73 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/usePublishedDocumentRaw.ts +++ b/packages/shared/src/hooks/documents/usePublishedDocumentRaw.ts @@ -16,12 +16,13 @@ import { useQuery } from '@tanstack/react-query' import { generatePath, useParams } from 'react-router-dom' -import { portalRequestText } from '@apihub/utils/requests' -import type { Key } from '@netcracker/qubership-apihub-ui-shared/entities/keys' -import type { FileContent } from '@apihub/entities/project-files' -import type { IsLoading } from '@netcracker/qubership-apihub-ui-shared/utils/aliases' -import { toFormattedJsonString } from '@netcracker/qubership-apihub-ui-shared/utils/strings' -import { getPackageRedirectDetails } from '@netcracker/qubership-apihub-ui-shared/utils/redirects' +import type { IsLoading } from '../../utils/aliases' +import { toFormattedJsonString } from '../../utils/strings' +import { getPackageRedirectDetails } from '../../utils/redirects' +import type { Key } from '../../entities/keys' +import { API_V2, requestBlob } from '../../utils/requests' + +export type FileContent = string const PUBLISHED_DOCUMENT_RAW_QUERY_KEY = 'published-document-raw-query-key' @@ -52,17 +53,27 @@ export async function getPublishedDocumentRaw( versionKey: Key, slug: Key, ): Promise { + const response = await getPublishedDocumentRawBlob(packageKey, versionKey, slug) + return response.text() +} + +export async function getPublishedDocumentRawBlob( + packageKey: Key, + versionKey: Key, + slug: Key, +): Promise { const packageId = encodeURIComponent(packageKey) const versionId = encodeURIComponent(versionKey) const fileId = encodeURIComponent(slug) const pathPattern = '/packages/:packageId/versions/:versionId/files/:fileId/raw' - return await portalRequestText( + return await requestBlob( generatePath(pathPattern, { packageId, versionId, fileId }), { method: 'get', }, { + basePath: API_V2, customRedirectHandler: (response) => getPackageRedirectDetails(response, pathPattern), }, ) diff --git a/packages/shared/src/utils/builder-resolvers.ts b/packages/shared/src/utils/builder-resolvers.ts index 80078716c..7212420fe 100644 --- a/packages/shared/src/utils/builder-resolvers.ts +++ b/packages/shared/src/utils/builder-resolvers.ts @@ -17,16 +17,21 @@ import { fetchDeprecatedItems, fetchOperations, + getDocuments, getPackageVersionContent, getVersionReferences, toVersionOperation, } from './packages-builder' import type { + RawDocumentResolver, + ResolvedVersionDocuments, VersionDeprecatedResolver, + VersionDocumentsResolver, VersionOperationsResolver, VersionReferencesResolver, VersionResolver, } from '@netcracker/qubership-apihub-api-processor' +import { getPublishedDocumentRawBlob } from '../hooks/documents/usePublishedDocumentRaw' export async function packageVersionResolver(): Promise { return async (packageId, version, includeOperations = false) => { @@ -90,3 +95,44 @@ export async function versionDeprecatedResolver(): Promise { + return async (version, packageId, apiType) => { + const EMPTY_DOCUMENTS_DTO = { documents: [], packages: {} } + const limit = 100 + const result: ResolvedVersionDocuments = { documents: [], packages: {} } + let page = 0 + let documentsCount = 0 + + try { + while (page === 0 || documentsCount === limit) { + const { documents, packages } = await getDocuments(packageId, version, apiType) ?? EMPTY_DOCUMENTS_DTO + result.documents = [...result.documents, ...documents] + result.packages = { ...result.packages, ...packages } + + page += 1 + documentsCount = documents.length + } + return result + } catch (error) { + console.error(error) + return EMPTY_DOCUMENTS_DTO + } + } +} + +export async function rawDocumentResolver(): Promise { + return async (version, packageId, slug) => { + try { + const response = await getPublishedDocumentRawBlob(packageId, version, slug) + + const data = await response.blob() + const filename = response.headers.get('content-disposition')!.split('filename=')[1].slice(1, -1) + const contentType = response.headers.get('content-type')! + return new File([data], filename, { type: contentType }) + } catch (error) { + console.error(error) + return null + } + } +} diff --git a/packages/shared/src/utils/packages-builder.ts b/packages/shared/src/utils/packages-builder.ts index 4a6c0f65c..4e945b1f7 100644 --- a/packages/shared/src/utils/packages-builder.ts +++ b/packages/shared/src/utils/packages-builder.ts @@ -32,6 +32,7 @@ import { getPackageRedirectDetails } from './redirects' import { API_V1, API_V2, API_V3, requestBlob, requestJson, requestVoid } from './requests' import { optionalSearchParams } from './search-params' import type { Key } from './types' +import type { DocumentsDto } from '../entities/documents' export async function getPackageVersionContent( packageKey: Key, @@ -317,3 +318,25 @@ export async function fetchExportTemplate( return [await data.text(), getFilename()] } + +export async function getDocuments( + packageKey: Key, + versionKey: Key, + apiType?: ApiType, + signal?: AbortSignal, +): Promise { + const packageId = encodeURIComponent(packageKey) + const versionId = encodeURIComponent(versionKey) + + const queryParams = optionalSearchParams({ apiType: { value: apiType } }) + const pathPattern = '/packages/:packageId/versions/:versionId/documents' + return await requestJson( + `${generatePath(pathPattern, { packageId, versionId })}?${queryParams}`, + { method: 'get' }, + { + basePath: API_V2, + customRedirectHandler: (response) => getPackageRedirectDetails(response, pathPattern), + }, + signal, + ) +} From d0a1d681c9694b21ed552489e7b36b5f702929ef Mon Sep 17 00:00:00 2001 From: CountRedClaw Date: Tue, 9 Sep 2025 19:20:18 +0500 Subject: [PATCH 04/18] refactor: use getDocuments and types from shared --- packages/portal/src/entities/documents.ts | 14 ++++---- packages/portal/src/entities/project-files.ts | 2 +- .../PortalPage/VersionPage/useDocuments.tsx | 29 ++--------------- packages/shared/src/entities/documents.ts | 32 ++----------------- .../src/entities/file-formats.ts | 0 5 files changed, 13 insertions(+), 64 deletions(-) rename packages/{portal => shared}/src/entities/file-formats.ts (100%) diff --git a/packages/portal/src/entities/documents.ts b/packages/portal/src/entities/documents.ts index bca584fe4..df2948f50 100644 --- a/packages/portal/src/entities/documents.ts +++ b/packages/portal/src/entities/documents.ts @@ -15,8 +15,6 @@ */ import type { FileKey, Key } from './keys' -import type { FileFormat } from './file-formats' -import { UNKNOWN_FILE_FORMAT } from './file-formats' import type { OperationData, OperationDto, @@ -28,20 +26,19 @@ import type { import { toPackageRef } from '@netcracker/qubership-apihub-ui-shared/entities/operations' import type { SpecType } from '@netcracker/qubership-apihub-ui-shared/utils/specs' import { UNKNOWN_SPEC_TYPE } from '@netcracker/qubership-apihub-ui-shared/utils/specs' +import type { FileFormat } from '@netcracker/qubership-apihub-ui-shared/utils/files' import { getFileFormat } from '@netcracker/qubership-apihub-ui-shared/utils/files' import type { MethodType } from '@netcracker/qubership-apihub-ui-shared/entities/method-types' import type { GraphQlOperationType } from '@netcracker/qubership-apihub-ui-shared/entities/graphql-operation-types' - -export type DocumentsDto = Readonly<{ - documents: ReadonlyArray - packages: PackagesRefs -}> +import { type DocumentsDto } from '@netcracker/qubership-apihub-ui-shared/entities/documents' +import { UNKNOWN_FILE_FORMAT } from '@netcracker/qubership-apihub-ui-shared/entities/file-formats' export type Documents = ReadonlyArray export type Document = Readonly<{ key: Key slug: Key + filename: string title: string type: SpecType format: FileFormat @@ -57,6 +54,7 @@ export type Document = Readonly<{ export type DocumentDto = Readonly<{ fileId: FileKey slug: Key + filename: string title: string type: SpecType format: FileFormat @@ -74,6 +72,7 @@ export function toDocument(value: DocumentDto, packagesRefs?: PackagesRefs): Doc return { key: value.fileId, slug: value.slug, + filename: value.filename, title: value.title, type: value.type, format: value.format ?? getFileFormat(value.fileId), @@ -100,6 +99,7 @@ export const EMPTY_DOC: Document = { key: '', title: '', slug: '', + filename: '', } export type RestMetaData = { diff --git a/packages/portal/src/entities/project-files.ts b/packages/portal/src/entities/project-files.ts index 581b9396c..910a80feb 100644 --- a/packages/portal/src/entities/project-files.ts +++ b/packages/portal/src/entities/project-files.ts @@ -15,9 +15,9 @@ */ import type { FileKey, Key } from './keys' -import type { FileFormat } from './file-formats' import type { SpecType } from '@netcracker/qubership-apihub-ui-shared/utils/specs' import type { ChangeStatus } from '@netcracker/qubership-apihub-ui-shared/entities/change-statuses' +import type { FileFormat } from '@netcracker/qubership-apihub-ui-shared/entities/file-formats' export type FileData = { content: FileContent diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/useDocuments.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/useDocuments.tsx index 3e968d925..cf4cb99f6 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/useDocuments.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/useDocuments.tsx @@ -16,15 +16,13 @@ import { useQuery } from '@tanstack/react-query' import { useVersionWithRevision } from '../../useVersionWithRevision' -import { generatePath } from 'react-router-dom' -import type { Documents, DocumentsDto } from '@apihub/entities/documents' +import type { Documents } from '@apihub/entities/documents' import { toDocuments } from '@apihub/entities/documents' import type { IsLoading } from '@netcracker/qubership-apihub-ui-shared/utils/aliases' import type { Key } from '@netcracker/qubership-apihub-ui-shared/entities/keys' -import { optionalSearchParams } from '@netcracker/qubership-apihub-ui-shared/utils/search-params' -import { portalRequestJson } from '@apihub/utils/requests' -import { getPackageRedirectDetails } from '@netcracker/qubership-apihub-ui-shared/utils/redirects' import type { ApiType } from '@netcracker/qubership-apihub-ui-shared/entities/api-types' +import type { DocumentsDto } from '@netcracker/qubership-apihub-ui-shared/entities/documents' +import { getDocuments } from '@netcracker/qubership-apihub-ui-shared/utils/packages-builder' const DOCUMENTS_QUERY_KEY = 'documents-query-key' @@ -60,24 +58,3 @@ export function useDocuments(options: Partial<{ isInitialLoading: isInitialLoading || isVersionInitialLoading, } } - -async function getDocuments( - packageKey: Key, - versionKey: Key, - apiType?: ApiType, - signal?: AbortSignal, -): Promise { - const packageId = encodeURIComponent(packageKey) - const versionId = encodeURIComponent(versionKey) - - const queryParams = optionalSearchParams({ apiType: { value: apiType } }) - const pathPattern = '/packages/:packageId/versions/:versionId/documents' - return await portalRequestJson( - `${generatePath(pathPattern, { packageId, versionId })}?${queryParams}`, - { method: 'get' }, - { - customRedirectHandler: (response) => getPackageRedirectDetails(response, pathPattern), - }, - signal, - ) -} diff --git a/packages/shared/src/entities/documents.ts b/packages/shared/src/entities/documents.ts index 0837411d3..1d20a2749 100644 --- a/packages/shared/src/entities/documents.ts +++ b/packages/shared/src/entities/documents.ts @@ -15,32 +15,15 @@ */ import type { FileKey, Key } from './keys' -import type { OperationDto, OperationsData, PackageRef, PackagesRefs } from './operations' +import type { OperationDto, PackagesRefs } from './operations' import type { SpecType } from '../utils/specs' +import type { FileFormat } from './file-formats' export type DocumentsDto = Readonly<{ documents: ReadonlyArray packages: PackagesRefs }> -export type Documents = ReadonlyArray - -export type Document = Readonly<{ - key: Key - slug: Key - filename: string - title: string - type: SpecType - format: FileFormat - version?: string - labels?: Labels - description?: string - info?: Readonly - externalDocs?: Readonly - operations: OperationsData - packageRef?: PackageRef -}> - export type DocumentDto = Readonly<{ fileId: FileKey slug: Key @@ -72,14 +55,3 @@ export type DocLink = { export type ExternalDocsLink = Omit & { description?: string } export type Labels = string[] - -export const JSON_FILE_FORMAT = 'json' -export const YAML_FILE_FORMAT = 'yaml' -export const MD_FILE_FORMAT = 'md' -export const UNKNOWN_FILE_FORMAT = 'unknown' - -export type FileFormat = - | typeof JSON_FILE_FORMAT - | typeof YAML_FILE_FORMAT - | typeof MD_FILE_FORMAT - | typeof UNKNOWN_FILE_FORMAT diff --git a/packages/portal/src/entities/file-formats.ts b/packages/shared/src/entities/file-formats.ts similarity index 100% rename from packages/portal/src/entities/file-formats.ts rename to packages/shared/src/entities/file-formats.ts From ddaea5ad34aa8d76496de3dcc3ac2875135785b4 Mon Sep 17 00:00:00 2001 From: CountRedClaw Date: Thu, 11 Sep 2025 17:45:21 +0500 Subject: [PATCH 05/18] fix: build --- packages/shared/src/entities/operations.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/shared/src/entities/operations.ts b/packages/shared/src/entities/operations.ts index f68b50ba9..c59d973ec 100644 --- a/packages/shared/src/entities/operations.ts +++ b/packages/shared/src/entities/operations.ts @@ -139,11 +139,11 @@ export type PackagesRefs = { } export type PackageRefDto = { refId: string - kind: ReferencedPackageKind - name: string + kind?: ReferencedPackageKind + name?: string version: string notLatestRevision?: boolean - status: VersionStatus + status?: VersionStatus deletedAt?: string deletedBy?: string parentPackages?: ReadonlyArray From a9e3886eb5d84e5822cebbb05e5b6880ede163f3 Mon Sep 17 00:00:00 2001 From: CountRedClaw Date: Thu, 11 Sep 2025 18:02:48 +0500 Subject: [PATCH 06/18] fix: build --- .../shared/src/utils/builder-resolvers.ts | 4 ++-- packages/shared/src/utils/packages-builder.ts | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/utils/builder-resolvers.ts b/packages/shared/src/utils/builder-resolvers.ts index 7212420fe..47941f2e6 100644 --- a/packages/shared/src/utils/builder-resolvers.ts +++ b/packages/shared/src/utils/builder-resolvers.ts @@ -17,8 +17,8 @@ import { fetchDeprecatedItems, fetchOperations, - getDocuments, getPackageVersionContent, + getResolvedVersionDocuments, getVersionReferences, toVersionOperation, } from './packages-builder' @@ -106,7 +106,7 @@ export async function versionDocumentsResolver(): Promise { + const packageId = encodeURIComponent(packageKey) + const versionId = encodeURIComponent(versionKey) + + const queryParams = optionalSearchParams({ apiType: { value: apiType } }) + const pathPattern = '/packages/:packageId/versions/:versionId/documents' + return await requestJson( + `${generatePath(pathPattern, { packageId, versionId })}?${queryParams}`, + { method: 'get' }, + { + basePath: API_V2, + customRedirectHandler: (response) => getPackageRedirectDetails(response, pathPattern), + }, + signal, + ) +} From 6d7e951b703f58a0f9eb969848e721dbe341100e Mon Sep 17 00:00:00 2001 From: CountRedClaw Date: Thu, 18 Sep 2025 17:49:43 +0500 Subject: [PATCH 07/18] fix: add missing resolvers --- .../package-version-builder-worker.ts | 4 ++ .../package-version-builder-worker.ts | 38 ++++++++----------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/packages/agents/src/routes/root/NamespacePage/ServicesPage/ServicesPageBody/package-version-builder-worker.ts b/packages/agents/src/routes/root/NamespacePage/ServicesPage/ServicesPageBody/package-version-builder-worker.ts index d8b08e665..b5fae1c0b 100644 --- a/packages/agents/src/routes/root/NamespacePage/ServicesPage/ServicesPageBody/package-version-builder-worker.ts +++ b/packages/agents/src/routes/root/NamespacePage/ServicesPage/ServicesPageBody/package-version-builder-worker.ts @@ -23,7 +23,9 @@ import { COMPLETE_PUBLISH_STATUS, ERROR_PUBLISH_STATUS } from '@apihub/entities/ import { BUILD_TYPE, PackageVersionBuilder } from '@netcracker/qubership-apihub-api-processor' import { packageVersionResolver, + rawDocumentResolver, versionDeprecatedResolver, + versionDocumentsResolver, versionOperationsResolver, versionReferencesResolver, } from '@netcracker/qubership-apihub-ui-shared/utils/builder-resolvers' @@ -77,6 +79,8 @@ const worker: PackageVersionBuilderWorker = { versionReferencesResolver: await versionReferencesResolver(), versionOperationsResolver: await versionOperationsResolver(), versionDeprecatedResolver: await versionDeprecatedResolver(), + versionDocumentsResolver: await versionDocumentsResolver(), + rawDocumentResolver: await rawDocumentResolver(), }, }) diff --git a/packages/portal/src/routes/root/PortalPage/package-version-builder-worker.ts b/packages/portal/src/routes/root/PortalPage/package-version-builder-worker.ts index 9649aeb8e..d35a8ec3d 100644 --- a/packages/portal/src/routes/root/PortalPage/package-version-builder-worker.ts +++ b/packages/portal/src/routes/root/PortalPage/package-version-builder-worker.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { FileId, FileSourceMap, VersionsComparison } from '@netcracker/qubership-apihub-api-processor' +import type { BuilderResolvers, FileId, FileSourceMap, VersionsComparison } from '@netcracker/qubership-apihub-api-processor' import { BUILD_TYPE, PackageVersionBuilder, VERSION_STATUS } from '@netcracker/qubership-apihub-api-processor' import { packageVersionResolver, @@ -61,15 +61,19 @@ export type PackageVersionBuilderWorker = { publishPackage: (options: PublishOptions) => Promise } +async function createCommonResolvers(): Promise { + return { + versionResolver: await packageVersionResolver(), + versionReferencesResolver: await versionReferencesResolver(), + versionOperationsResolver: await versionOperationsResolver(), + versionDeprecatedResolver: await versionDeprecatedResolver(), + versionDocumentsResolver: await versionDocumentsResolver(), + rawDocumentResolver: await rawDocumentResolver(), + } +} + const worker: PackageVersionBuilderWorker = { buildChangelogPackage: async ({ packageKey, versionKey, previousPackageKey, previousVersionKey }) => { - const builderResolvers = { - fileResolver: async () => null, - versionResolver: await packageVersionResolver(), - versionReferencesResolver: await versionReferencesResolver(), - versionOperationsResolver: await versionOperationsResolver(), - versionDeprecatedResolver: await versionDeprecatedResolver(), - } const builder = new PackageVersionBuilder( { packageId: packageKey, @@ -80,7 +84,7 @@ const worker: PackageVersionBuilderWorker = { buildType: BUILD_TYPE.CHANGELOG, }, { - resolvers: builderResolvers, + resolvers: await createCommonResolvers(), }, ) @@ -89,13 +93,6 @@ const worker: PackageVersionBuilderWorker = { return [builder.buildResult.comparisons, await builder.createVersionPackage({ type: 'blob' })] }, buildGroupChangelogPackage: async ({ packageKey, versionKey, currentGroup, previousGroup }) => { - const builderResolvers = { - fileResolver: async () => null, - versionResolver: await packageVersionResolver(), - versionReferencesResolver: await versionReferencesResolver(), - versionOperationsResolver: await versionOperationsResolver(), - versionDeprecatedResolver: await versionDeprecatedResolver(), - } const builder = new PackageVersionBuilder( { packageId: packageKey, @@ -106,7 +103,7 @@ const worker: PackageVersionBuilderWorker = { buildType: BUILD_TYPE.PREFIX_GROUPS_CHANGELOG, }, { - resolvers: builderResolvers, + resolvers: await createCommonResolvers(), }, ) @@ -128,12 +125,7 @@ const worker: PackageVersionBuilderWorker = { const builder = new PackageVersionBuilder(buildConfig, { resolvers: { fileResolver: async (fileId: FileId) => fileSources?.[fileId] ?? null, - versionResolver: await packageVersionResolver(), - versionReferencesResolver: await versionReferencesResolver(), - versionOperationsResolver: await versionOperationsResolver(), - versionDeprecatedResolver: await versionDeprecatedResolver(), - versionDocumentsResolver: await versionDocumentsResolver(), - rawDocumentResolver: await rawDocumentResolver(), + ...(await createCommonResolvers()), }, }, fileSources) From bbe0d317dab473c5f8b37699664f054818f032a5 Mon Sep 17 00:00:00 2001 From: b41ex Date: Sat, 20 Sep 2025 19:41:10 +0300 Subject: [PATCH 08/18] fix: merge problems --- .../VersionApiQualitySubPage/VersionApiQualityCard.tsx | 4 ++-- .../PortalPage/VersionPage/VersionApiQualitySubPage/types.ts | 2 +- .../VersionApiQualitySubPage/utilities/transformers.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/VersionApiQualityCard.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/VersionApiQualityCard.tsx index 03aaf46b0..9a7fecc13 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/VersionApiQualityCard.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/VersionApiQualityCard.tsx @@ -1,7 +1,7 @@ import { useValidationDetailsByDocument } from '@apihub/api-hooks/ApiQuality/useValidationDetailsByDocument' import { ValidationRulesettLink } from '@apihub/components/ApiQuality/ValidatationRulesetLink' import type { DocumentValidationSummary } from '@apihub/entities/api-quality/package-version-validation-summary' -import { JSON_FILE_FORMAT, YAML_FILE_FORMAT } from '@apihub/entities/file-formats' +import { JSON_FILE_FORMAT, YAML_FILE_FORMAT } from '@netcracker/qubership-apihub-ui-shared/entities/file-formats' import { transformIssuesToMarkers } from '@apihub/utils/api-quality/issues' import { Box, Typography } from '@mui/material' import { BodyCard } from '@netcracker/qubership-apihub-ui-shared/components/BodyCard' @@ -15,7 +15,7 @@ import type { FC, ReactNode } from 'react' import { memo, useCallback, useMemo, useState } from 'react' import { useParams } from 'react-router' import { ClientValidationStatuses, useApiQualityValidationSummary } from '../ApiQualityValidationSummaryProvider' -import { usePublishedDocumentRaw } from '../usePublishedDocumentRaw' +import { usePublishedDocumentRaw } from '@netcracker/qubership-apihub-ui-shared/hooks/documents/usePublishedDocumentRaw' import type { OriginalDocumentFileFormat } from './types' import { useTransformedRawDocumentByFormat } from './utilities/hooks' import { ValidatedDocumentSelector } from './ValidatedDocumentSelector' diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/types.ts b/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/types.ts index 41725a5f3..c336faaad 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/types.ts +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/types.ts @@ -1,4 +1,4 @@ -import type { FileFormat, MD_FILE_FORMAT, UNKNOWN_FILE_FORMAT } from '@apihub/entities/file-formats' +import type { FileFormat, MD_FILE_FORMAT, UNKNOWN_FILE_FORMAT } from '@netcracker/qubership-apihub-ui-shared/entities/file-formats' type ProhibitedFileFormat = | typeof MD_FILE_FORMAT | typeof UNKNOWN_FILE_FORMAT diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/utilities/transformers.ts b/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/utilities/transformers.ts index a3bef57ab..f670fb93c 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/utilities/transformers.ts +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/VersionApiQualitySubPage/utilities/transformers.ts @@ -1,4 +1,4 @@ -import { YAML_FILE_FORMAT, JSON_FILE_FORMAT } from '@apihub/entities/file-formats' +import { YAML_FILE_FORMAT, JSON_FILE_FORMAT } from '@netcracker/qubership-apihub-ui-shared/entities/file-formats' import type { SpecItemUri } from '@netcracker/qubership-apihub-ui-shared/utils/specifications' import { encodeKey } from '@netcracker/qubership-apihub-ui-shared/utils/specifications' import { safeParse } from '@stoplight/json' From 1e30478c93d647344ff21bb08a264f690f8f6a1c Mon Sep 17 00:00:00 2001 From: CountRedClaw Date: Thu, 25 Sep 2025 14:39:07 +0500 Subject: [PATCH 09/18] fix: remove hashList according to api change --- .../routes/root/PortalPage/VersionPage/useOperations.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/useOperations.ts b/packages/portal/src/routes/root/PortalPage/VersionPage/useOperations.ts index ace22fcaf..9ae7b8e53 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/useOperations.ts +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/useOperations.ts @@ -67,7 +67,6 @@ export function usePagedOperations(options?: Partial<{ versionKey: Key refPackageKey: PackageKey deprecated: DeprecatedQueryStatus - hashList: string[] ids: string[] includeData: boolean kind: ApiKind @@ -90,7 +89,6 @@ export function usePagedOperations(options?: Partial<{ tag, ids, includeData, - hashList, label, deprecated, kind, @@ -122,7 +120,6 @@ export function usePagedOperations(options?: Partial<{ versionKey: fullVersion!, refPackageKey: refPackageKey, deprecated: deprecated, - hashList: hashList, ids: ids, includeData: includeData, kind: kind, @@ -161,7 +158,6 @@ export function useOperations(options?: Partial<{ packageKey: Key versionKey: Key deprecated: DeprecatedQueryStatus - hashList: string[] ids: string[] includeData: boolean kind: ApiKind @@ -186,7 +182,6 @@ export function useOperations(options?: Partial<{ tag, ids, includeData, - hashList, label, deprecated, kind, @@ -218,7 +213,6 @@ export function useOperations(options?: Partial<{ packageKey: packageKey!, versionKey: fullVersion!, deprecated: deprecated, - hashList: hashList, ids: ids, includeData: includeData, kind: kind, @@ -260,7 +254,6 @@ export async function getOperations( versionKey: Key refPackageKey?: PackageKey deprecated?: DeprecatedQueryStatus - hashList?: string[] ids?: string[] includeData?: boolean kind?: ApiKind @@ -283,7 +276,6 @@ export async function getOperations( versionKey, refPackageKey, deprecated = ALL_DEPRECATED_QUERY_STATUS, - hashList, ids, includeData = false, kind = ALL_API_KIND, @@ -307,7 +299,6 @@ export async function getOperations( textFilter: { value: textFilter }, documentSlug: { value: documentId }, deprecated: { value: deprecated.toString() }, - hashList: { value: hashList ? encodeURIComponent(JSON.stringify(hashList)).toString() : '' }, ids: { value: ids ? encodeURIComponent(ids.join()).toString() : '' }, includeData: { value: includeData.toString() }, kind: { value: kind }, From 66b7475279e028a425b456455f14603d44a63c1b Mon Sep 17 00:00:00 2001 From: b41ex Date: Thu, 2 Oct 2025 20:22:17 +0300 Subject: [PATCH 10/18] chore: set feature branch version for dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 9bbe11c6a..f0738abfa 100644 --- a/package.json +++ b/package.json @@ -29,14 +29,14 @@ "@mui/lab": "5.0.0-alpha.120", "@mui/material": "5.11.10", "@mui/private-theming": "5.11.9", - "@netcracker/qubership-apihub-api-diff": "feature-performance-optimization", + "@netcracker/qubership-apihub-api-diff": "feature-move-prefix-from-server-to-path", "@netcracker/qubership-apihub-api-doc-viewer": "feature-performance-optimization", "@netcracker/qubership-apihub-api-processor": "feature-performance-optimization", - "@netcracker/qubership-apihub-api-unifier": "dev", - "@netcracker/qubership-apihub-api-visitor": "dev", + "@netcracker/qubership-apihub-api-unifier": "feature-performance-optimization", + "@netcracker/qubership-apihub-api-visitor": "feature-performance-optimization", "@netcracker/qubership-apihub-apispec-view": "feature-performance-optimization", "@netcracker/qubership-apihub-class-view": "1.0.3", - "@netcracker/qubership-apihub-rest-playground": "dev", + "@netcracker/qubership-apihub-rest-playground": "1.2.0", "@otjs/plaintext": "0.2.2", "@otjs/plaintext-editor": "0.2.2", "@stoplight/json": "3.21.7", From e78a8101ccc06362f7742a787be8619c515f380a Mon Sep 17 00:00:00 2001 From: b41ex Date: Fri, 3 Oct 2025 15:14:03 +0300 Subject: [PATCH 11/18] chore: fix linting errors --- lerna.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 20f8b786f..3c1a386ec 100644 --- a/lerna.json +++ b/lerna.json @@ -1,4 +1,4 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", "version": "3.1.1" -} \ No newline at end of file +} diff --git a/package.json b/package.json index 9b608ff01..f0738abfa 100644 --- a/package.json +++ b/package.json @@ -165,4 +165,4 @@ "engines": { "node": ">=18.0.0" } -} \ No newline at end of file +} From 60f458fae3e048d5b787b493cdb39cb58147d756 Mon Sep 17 00:00:00 2001 From: b41ex Date: Sat, 11 Oct 2025 19:27:20 +0300 Subject: [PATCH 12/18] fix: paths predicate for rest operation changes matches operation internal changes and OAS extension changes --- packages/portal/src/utils/operations.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/portal/src/utils/operations.ts b/packages/portal/src/utils/operations.ts index c2aa3f928..4bba8095c 100644 --- a/packages/portal/src/utils/operations.ts +++ b/packages/portal/src/utils/operations.ts @@ -23,7 +23,7 @@ import type { } from '@netcracker/qubership-apihub-ui-shared/entities/operations' import { DEFAULT_TAG, EMPTY_TAG } from '@netcracker/qubership-apihub-ui-shared/entities/operations' import { isEmpty } from '@netcracker/qubership-apihub-ui-shared/utils/arrays' -import { matchPaths, OPEN_API_PROPERTY_PATHS, PREDICATE_UNCLOSED_END } from '@netcracker/qubership-apihub-api-unifier' +import { matchPaths, OPEN_API_PROPERTY_PATHS, PREDICATE_NOT_OAS_EXTENSION } from '@netcracker/qubership-apihub-api-unifier' import { DiffAction } from '@netcracker/qubership-apihub-api-diff' export function groupOperationsByTags( @@ -108,7 +108,7 @@ export function isFullyAddedOperationChange(change: OperationChanges): boolean { } function isOperationChange(paths: JsonPath[]): boolean { //check - return !!matchPaths(paths, [[OPEN_API_PROPERTY_PATHS, PREDICATE_UNCLOSED_END]]) + return !!matchPaths(paths, [[OPEN_API_PROPERTY_PATHS, PREDICATE_NOT_OAS_EXTENSION, PREDICATE_NOT_OAS_EXTENSION]]) } // TODO: Remove JsonPath from shared or inline it with crawler From 771887e44eca84bd395b21fe87647332506c2618 Mon Sep 17 00:00:00 2001 From: b41ex Date: Sat, 11 Oct 2025 19:29:38 +0300 Subject: [PATCH 13/18] refactor: rename methods to emphasize they are valid for REST operations only --- .../GroupComparePage/GroupCompareContent.tsx | 5 ++--- packages/portal/src/utils/operations.ts | 16 ++++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/GroupComparePage/GroupCompareContent.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/GroupComparePage/GroupCompareContent.tsx index a1c87c30b..26aae17b7 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/GroupComparePage/GroupCompareContent.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/GroupComparePage/GroupCompareContent.tsx @@ -60,7 +60,7 @@ import { import { isEmpty, isNotEmpty } from '@netcracker/qubership-apihub-ui-shared/utils/arrays' import { LoadingIndicator } from '@netcracker/qubership-apihub-ui-shared/components/LoadingIndicator' import { CONTENT_PLACEHOLDER_AREA, Placeholder } from '@netcracker/qubership-apihub-ui-shared/components/Placeholder' -import { getActionForOperation } from '@apihub/utils/operations' +import { getActionForRestOperation } from '@apihub/utils/operations' import type { ChangeSeverity } from '@netcracker/qubership-apihub-ui-shared/entities/change-severities' import { ACTION_TYPE_COLOR_MAP, @@ -184,8 +184,7 @@ export const GroupCompareContent: FC = memo(({ groupCh const metadata = metadataObject as OperationChangesMetadata & Partial & Partial const previousMetadata = previousMetadataObject as OperationChangesMetadata & Partial & Partial - const { action } = diffs?.[0] ?? {} - const operationAction = getActionForOperation(change, REPLACE_ACTION_TYPE) + const operationAction = getActionForRestOperation(change, REPLACE_ACTION_TYPE) const severity = getMajorSeverity(changeSummary!) const isMetaDataPresent = !!( diff --git a/packages/portal/src/utils/operations.ts b/packages/portal/src/utils/operations.ts index 4bba8095c..f00753062 100644 --- a/packages/portal/src/utils/operations.ts +++ b/packages/portal/src/utils/operations.ts @@ -70,8 +70,8 @@ export function groupOperationPairsByTags( return operationPairsGroupedByTag } -export const getActionForOperation = (change: OperationChanges, actionType: string): string => { - return !isFullyAddedOrRemovedOperationChange(change) +export const getActionForRestOperation = (change: OperationChanges, actionType: string): string => { + return !isFullyAddedOrRemovedRestOperationChange(change) ? actionType : change?.diffs?.[0]?.action ?? '' } @@ -87,27 +87,27 @@ export function handleOperationTags(tags: readonly string[] | undefined): Set Date: Sat, 11 Oct 2025 19:31:59 +0300 Subject: [PATCH 14/18] fix: simplify properties population for prefix groups operation table based on new api-processor contract --- .../GroupComparePage/GroupCompareContent.tsx | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/GroupComparePage/GroupCompareContent.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/GroupComparePage/GroupCompareContent.tsx index 26aae17b7..030594b38 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/GroupComparePage/GroupCompareContent.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/GroupComparePage/GroupCompareContent.tsx @@ -64,9 +64,7 @@ import { getActionForRestOperation } from '@apihub/utils/operations' import type { ChangeSeverity } from '@netcracker/qubership-apihub-ui-shared/entities/change-severities' import { ACTION_TYPE_COLOR_MAP, - ADD_ACTION_TYPE, CHANGE_SEVERITIES, - REMOVE_ACTION_TYPE, REPLACE_ACTION_TYPE, } from '@netcracker/qubership-apihub-ui-shared/entities/change-severities' import { format } from '@netcracker/qubership-apihub-ui-shared/utils/strings' @@ -178,7 +176,6 @@ export const GroupCompareContent: FC = memo(({ groupCh changeSummary, metadata: metadataObject, previousMetadata: previousMetadataObject, - diffs, } = change const metadata = metadataObject as OperationChangesMetadata & Partial & Partial @@ -188,7 +185,10 @@ export const GroupCompareContent: FC = memo(({ groupCh const severity = getMajorSeverity(changeSummary!) const isMetaDataPresent = !!( - metadata?.title && metadata?.path && metadata?.method || + metadata?.title && metadata?.path && metadata?.method + ) + + const isPreviousMetaDataPresent = !!( previousMetadata?.title && previousMetadata?.path && previousMetadata?.method ) @@ -256,13 +256,12 @@ export const GroupCompareContent: FC = memo(({ groupCh }} /> @@ -276,8 +275,7 @@ export const GroupCompareContent: FC = memo(({ groupCh > Date: Sat, 11 Oct 2025 19:36:39 +0300 Subject: [PATCH 15/18] fix: simplify properties population based on new api-processor contract for prefix groups --- ...DifferentOperationGroupsComparisonPage.tsx | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx index 08674f6c3..644d5f4f3 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx @@ -199,24 +199,22 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { currentOperationKey: operationKey, }, operationAction) + //TODO: fix isLoading stuck in true if operation key is undefined const { data: originOperation, isLoading: isOriginOperationLoading } = useOperation({ packageKey: !isPackageFromDashboard ? originPackageKey : refPackageKey, - versionKey: !isPackageFromDashboard ? changedVersionKey : refComparisonSummary?.previousVersion, + versionKey: !isPackageFromDashboard ? originVersionKey : refComparisonSummary?.previousVersion, enabled: !!operationAction && actionForOriginalOperation.includes(operationAction) && !!restGroupingPrefix, apiType: apiType as ApiType, - operationKey: operationAction === DiffAction.rename - ? `${getFullGroupForOperation(restGroupingPrefix, previousGroup!)}-${operationKeyForOriginOperation}` - : operationKeyForOriginOperation, + operationKey: operationKeyForOriginOperation, }) + //TODO: fix isLoading stuck in true if operation key is undefined const { data: changedOperation, isLoading: isChangedOperationLoading } = useOperation({ - packageKey: !isPackageFromDashboard ? originPackageKey : refPackageKey, + packageKey: !isPackageFromDashboard ? changedPackageKey : refPackageKey, versionKey: !isPackageFromDashboard ? changedVersionKey : refComparisonSummary?.version, enabled: !!operationAction && actionForChangedOperation.includes(operationAction) && !!restGroupingPrefix, apiType: apiType as ApiType, - operationKey: operationAction === DiffAction.rename - ? `${getFullGroupForOperation(restGroupingPrefix, group!)}-${operationKeyForChangedOperation}` - : operationKeyForChangedOperation, + operationKey:operationKeyForChangedOperation, }) const areChangesAndOperationsLoading = isOriginOperationLoading && isChangedOperationLoading @@ -414,12 +412,5 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { const actionForOriginalOperation = ['remove', 'replace', 'rename'] const actionForChangedOperation = ['add', 'replace', 'rename'] - -export const getFullGroupForOperation = (restGroupingPrefix: string | undefined, group: string): string => { - if (!restGroupingPrefix) return group - - return convertToSlug(restGroupingPrefix.replace(/{group}/g, group)) -} - const httpMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] From 96b7f05321c1f59c87f0d0853ccc0ef0b6cb3afb Mon Sep 17 00:00:00 2001 From: b41ex Date: Sun, 12 Oct 2025 16:31:42 +0300 Subject: [PATCH 16/18] fix: process operation in the same way as in api-processor for prefix groups comparison, e.g. remove servers --- ...DifferentOperationGroupsComparisonPage.tsx | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx index 644d5f4f3..7576a8ea2 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx @@ -24,7 +24,7 @@ import { groupOperationPairsByTags, isFullyAddedOperationChange, isFullyRemovedO import type { ActionType } from '@netcracker/qubership-apihub-api-diff' import { DiffAction } from '@netcracker/qubership-apihub-api-diff' import type { OperationChanges } from '@netcracker/qubership-apihub-api-processor' -import { convertToSlug } from '@netcracker/qubership-apihub-api-processor' +import { createCopyWithPrefixGroupOperationsOnly, type RestOperationData } from '@netcracker/qubership-apihub-api-processor' import { PageLayout } from '@netcracker/qubership-apihub-ui-shared/components/PageLayout' import type { ApiType } from '@netcracker/qubership-apihub-ui-shared/entities/api-types' import type { @@ -189,7 +189,10 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { }) }, [changesSummary, isPackageFromDashboard, refPackageKey]) - const restGroupingPrefix = packageObj?.restGroupingPrefix + const groupPrefixTemplate = packageObj?.restGroupingPrefix + const currentGroupPrefix = getGroupPrefix(groupPrefixTemplate, group) + const previousGroupPrefix = getGroupPrefix(groupPrefixTemplate, previousGroup) + const { previousOperationKey: operationKeyForOriginOperation, @@ -203,7 +206,7 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { const { data: originOperation, isLoading: isOriginOperationLoading } = useOperation({ packageKey: !isPackageFromDashboard ? originPackageKey : refPackageKey, versionKey: !isPackageFromDashboard ? originVersionKey : refComparisonSummary?.previousVersion, - enabled: !!operationAction && actionForOriginalOperation.includes(operationAction) && !!restGroupingPrefix, + enabled: !!operationAction && actionForOriginalOperation.includes(operationAction) && !!groupPrefixTemplate, apiType: apiType as ApiType, operationKey: operationKeyForOriginOperation, }) @@ -212,11 +215,32 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { const { data: changedOperation, isLoading: isChangedOperationLoading } = useOperation({ packageKey: !isPackageFromDashboard ? changedPackageKey : refPackageKey, versionKey: !isPackageFromDashboard ? changedVersionKey : refComparisonSummary?.version, - enabled: !!operationAction && actionForChangedOperation.includes(operationAction) && !!restGroupingPrefix, + enabled: !!operationAction && actionForChangedOperation.includes(operationAction) && !!groupPrefixTemplate, apiType: apiType as ApiType, operationKey:operationKeyForChangedOperation, }) + // process operations in the same way they are processed in api-processor for prefix groups comparison + // particularly, remove servers from the operation data + const processedOriginOperation = useMemo( + () => ( + !!originOperation && !!originOperation.data + ? { + ...originOperation, + data: createCopyWithPrefixGroupOperationsOnly(originOperation.data as RestOperationData, previousGroupPrefix) } + : originOperation + ), + [originOperation, previousGroupPrefix], + ) + + const processedChangedOperation = useMemo( + () => ( + !!changedOperation && !!changedOperation.data + ? { ...changedOperation, data: createCopyWithPrefixGroupOperationsOnly(changedOperation.data as RestOperationData, currentGroupPrefix) } + : changedOperation), + [changedOperation, currentGroupPrefix], + ) + const areChangesAndOperationsLoading = isOriginOperationLoading && isChangedOperationLoading const operationPairsGroupedByTags: OperationPairsGroupedByTag = useMemo(() => { const filteredChanges: OperationChanges[] = compareGroups.data?.filter( @@ -351,8 +375,8 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { }, [apiType, areChangesAndOperationsLoading, changedPackageKey, changedVersionKey, filters, firstOperationPair, group, isCurrentOperationGrouped, navigateToFirstGroupOperation, previousGroup, selectedDocumentSlug]) const comparedOperationsPair: OptionalOperationPair = { - previousOperation: originOperation, - currentOperation: changedOperation, + previousOperation: processedOriginOperation, + currentOperation: processedChangedOperation, isLoading: isOriginOperationLoading || isChangedOperationLoading, } @@ -393,8 +417,8 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { } body={ { + if (!groupPrefixTemplate || !group) { + return '' + } + return groupPrefixTemplate.replace(/{group}/g, group) +} + From 42eab76112e9cfd18abfa0b34818ea4b8dccd24c Mon Sep 17 00:00:00 2001 From: b41ex Date: Mon, 13 Oct 2025 13:45:53 +0300 Subject: [PATCH 17/18] fix: Operation View not shown for added/removed operations when comparing operations in prefix groups due to changes in behavior of isLoading flag in React Query 4 --- .../DifferentOperationGroupsComparisonPage.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx index 7576a8ea2..5dc8b7358 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx @@ -202,8 +202,7 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { currentOperationKey: operationKey, }, operationAction) - //TODO: fix isLoading stuck in true if operation key is undefined - const { data: originOperation, isLoading: isOriginOperationLoading } = useOperation({ + const { data: originOperation, isInitialLoading: isOriginOperationLoading } = useOperation({ packageKey: !isPackageFromDashboard ? originPackageKey : refPackageKey, versionKey: !isPackageFromDashboard ? originVersionKey : refComparisonSummary?.previousVersion, enabled: !!operationAction && actionForOriginalOperation.includes(operationAction) && !!groupPrefixTemplate, @@ -211,8 +210,7 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { operationKey: operationKeyForOriginOperation, }) - //TODO: fix isLoading stuck in true if operation key is undefined - const { data: changedOperation, isLoading: isChangedOperationLoading } = useOperation({ + const { data: changedOperation, isInitialLoading: isChangedOperationLoading } = useOperation({ packageKey: !isPackageFromDashboard ? changedPackageKey : refPackageKey, versionKey: !isPackageFromDashboard ? changedVersionKey : refComparisonSummary?.version, enabled: !!operationAction && actionForChangedOperation.includes(operationAction) && !!groupPrefixTemplate, From e5a6bc70147f2b8b16a69b821d6db419bb20df2f Mon Sep 17 00:00:00 2001 From: b41ex Date: Mon, 13 Oct 2025 13:46:29 +0300 Subject: [PATCH 18/18] refactor: simplify condition to load data based on new contract for prefix groups in api-processor --- .../DifferentOperationGroupsComparisonPage.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx b/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx index 5dc8b7358..87f6fe776 100644 --- a/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx +++ b/packages/portal/src/routes/root/PortalPage/VersionPage/OperationsComparisonPage/DifferentOperationGroupsComparisonPage.tsx @@ -205,7 +205,6 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { const { data: originOperation, isInitialLoading: isOriginOperationLoading } = useOperation({ packageKey: !isPackageFromDashboard ? originPackageKey : refPackageKey, versionKey: !isPackageFromDashboard ? originVersionKey : refComparisonSummary?.previousVersion, - enabled: !!operationAction && actionForOriginalOperation.includes(operationAction) && !!groupPrefixTemplate, apiType: apiType as ApiType, operationKey: operationKeyForOriginOperation, }) @@ -213,7 +212,6 @@ export const DifferentOperationGroupsComparisonPage: FC = memo(() => { const { data: changedOperation, isInitialLoading: isChangedOperationLoading } = useOperation({ packageKey: !isPackageFromDashboard ? changedPackageKey : refPackageKey, versionKey: !isPackageFromDashboard ? changedVersionKey : refComparisonSummary?.version, - enabled: !!operationAction && actionForChangedOperation.includes(operationAction) && !!groupPrefixTemplate, apiType: apiType as ApiType, operationKey:operationKeyForChangedOperation, })