diff --git a/.changeset/blue-dragons-shout.md b/.changeset/blue-dragons-shout.md new file mode 100644 index 0000000000..762234a72b --- /dev/null +++ b/.changeset/blue-dragons-shout.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +`restrictUsersToGroup` should use the entire group path when getting members diff --git a/.changeset/curly-beans-brake.md b/.changeset/curly-beans-brake.md new file mode 100644 index 0000000000..4afb11578d --- /dev/null +++ b/.changeset/curly-beans-brake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': minor +--- + +Add pagination support to TechDocs Index Page and make it the default diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c7326c5f4e..b31cca1080 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -12,10 +12,12 @@ yarn.lock @backstage/maintainers @backst /docs @backstage/maintainers @backstage/documentation-maintainers /docs/assets/search @backstage/search-maintainers /docs/features/search @backstage/search-maintainers +/docs/dls @backstage/design-system-maintainers /docs/features/techdocs @backstage/techdocs-maintainers /docs/plugins/integrating-search-into-plugins.md @backstage/search-maintainers /packages/cli/src/commands/onboard @backstage/sharks /packages/backend-openapi-utils @backstage/maintainers @backstage/reviewers @backstage/openapi-tooling-maintainers +/packages/canon @backstage/design-system-maintainers /packages/techdocs-cli @backstage/techdocs-maintainers /packages/techdocs-cli-embedded-app @backstage/techdocs-maintainers /plugins/api-docs @backstage/maintainers @backstage/reviewers @backstage/sda-se-reviewers diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 49f199cc57..a40c5a0653 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 with: sarif_file: results.sarif diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index fdcf23c21c..6300b1ca4d 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -58,6 +58,6 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} NODE_OPTIONS: --max-old-space-size=7168 - name: Upload Snyk report - uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 with: sarif_file: snyk.sarif diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml index c8a7d032ac..cb40f28f54 100644 --- a/.github/workflows/verify_codeql.yml +++ b/.github/workflows/verify_codeql.yml @@ -55,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + uses: github/codeql-action/init@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -66,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + uses: github/codeql-action/autobuild@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -80,4 +80,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 + uses: github/codeql-action/analyze@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index bffb57e691..5ddd88b92d 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -49,13 +49,16 @@ jobs: run: yarn install --immutable working-directory: storybook + # Only for verification, the canon one is what we upload to Chromatic - run: yarn build-storybook + - run: yarn --cwd packages/canon build-storybook + - uses: chromaui/action@0efa3230f403b7848d5d65c6ce140b617fb68380 # v11 with: token: ${{ secrets.GITHUB_TOKEN }} # projectToken intentionally shared to allow collaborators to run Chromatic on forks # https://www.chromatic.com/docs/custom-ci-provider#run-chromatic-on-external-forks-of-open-source-projects - projectToken: 9tzak77m9nj - workingDir: storybook - storybookBuildDir: dist + projectToken: chpt_dab72dc0f97d55b + workingDir: packages/canon + storybookBuildDir: storybook-static diff --git a/OWNERS.md b/OWNERS.md index 58672a20da..0932d3386b 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -30,6 +30,17 @@ Scope: The catalog plugin and catalog model | Patrik Oldsberg | Spotify | Cubic Belugas | [Rugvip](https://github.com/Rugvip) | `Rugvip#0019` | | Vincenzo Scamporlino | Spotify | Cubic Belugas | [vinzscam](http://github.com/vinzscam) | `vinzscam#6944` | +### Design System + +Team: @backstage/design-system-maintainers + +Scope: The Backstage design system, component library, as well as surrounding tooling such as Storybook. + +| Name | Organization | Team | GitHub | Discord | +| ------------------- | ------------ | ------------- | --------------------------------------------- | ------------- | +| Charles de Dreuille | Spotify | | [cdedreuille](https://github.com/cdedreuille) | `cdedreuille` | +| Patrik Oldsberg | Spotify | Cubic Belugas | [Rugvip](https://github.com/Rugvip) | `Rugvip` | + ### Home Team: @backstage/home-maintainers diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index ccf06b17bd..7e914bdc9b 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -164,7 +164,10 @@ const routes = ( /> } /> - } /> + } + /> } diff --git a/packages/canon/catalog-info.yaml b/packages/canon/catalog-info.yaml index 37aa7b1caf..8369c314b3 100644 --- a/packages/canon/catalog-info.yaml +++ b/packages/canon/catalog-info.yaml @@ -6,4 +6,4 @@ metadata: spec: lifecycle: experimental type: backstage-web-library - owner: maintainers + owner: design-system-maintainers diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts index a4fb3ba391..041aa5b835 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts @@ -83,7 +83,7 @@ const httpHandlers = [ }), rest.get( - `${apiBaseUrlSaas}/groups/subgroup1/members/all`, + `${apiBaseUrlSaas}/groups/group1%2Fsubgroup1/members/all`, (_req, res, ctx) => { return res(ctx.json(subgroup_saas_users_response)); // To-DO change }, diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index eb10dd2274..1fbd2a2a13 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -400,14 +400,14 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { groups.push(await this.gitLabClient.getGroupByPath(this.config.group)); // adds the parent group for #26554 const rootGroupSplit = this.config.group.split('/'); - const rootGroup = this.config.restrictUsersToGroup - ? rootGroupSplit[rootGroupSplit.length - 1] + const groupPath = this.config.restrictUsersToGroup + ? this.config.group : rootGroupSplit[0]; users = paginated( options => this.gitLabClient.listSaaSUsers( - rootGroup, + groupPath, options, this.config.includeUsersWithoutSeat, ), diff --git a/plugins/techdocs/report.api.md b/plugins/techdocs/report.api.md index 2cc3934f62..c577de5eac 100644 --- a/plugins/techdocs/report.api.md +++ b/plugins/techdocs/report.api.md @@ -12,6 +12,7 @@ import { Config } from '@backstage/config'; import { CSSProperties } from '@material-ui/styles/withStyles'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; +import { EntityListPagination } from '@backstage/plugin-catalog-react'; import { EntityOwnerPickerProps } from '@backstage/plugin-catalog-react'; import { FetchApi } from '@backstage/core-plugin-api'; import { IdentityApi } from '@backstage/core-plugin-api'; @@ -309,6 +310,7 @@ export type TechDocsIndexPageProps = { columns?: TableColumn[]; actions?: TableProps['actions']; ownerPickerMode?: EntityOwnerPickerProps['mode']; + pagination?: EntityListPagination; }; // @public @deprecated (undocumented) diff --git a/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx b/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx index 2fbd5bb50a..f9757f29cc 100644 --- a/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx +++ b/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx @@ -46,7 +46,13 @@ export type DefaultTechDocsHomeProps = TechDocsIndexPageProps; * @public */ export const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => { - const { initialFilter = 'owned', columns, actions, ownerPickerMode } = props; + const { + initialFilter = 'owned', + columns, + actions, + ownerPickerMode, + pagination, + } = props; return ( @@ -55,7 +61,7 @@ export const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => { Discover documentation in your ecosystem. - + diff --git a/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.test.tsx b/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.test.tsx new file mode 100644 index 0000000000..d7ab3827e1 --- /dev/null +++ b/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.test.tsx @@ -0,0 +1,168 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 React, { ReactNode } from 'react'; +import { fireEvent, screen, waitFor } from '@testing-library/react'; +import { CursorPaginatedDocsTable } from './CursorPaginatedDocsTable'; +import { DocsTableRow } from './types'; +import { renderInTestApp } from '@backstage/test-utils'; +import { + DefaultEntityFilters, + EntityKindFilter, + EntityListContextProps, +} from '@backstage/plugin-catalog-react'; +import { MockEntityListContextProvider } from '@backstage/plugin-catalog-react/testUtils'; + +describe('CursorPaginatedDocsTable', () => { + const data = new Array(100).fill(0).map((_, index) => { + const name = `techdocs-${index}`; + return { + entity: { + apiVersion: '1', + kind: 'TestKind', + metadata: { + name, + }, + }, + resolved: { + docsUrl: 'https://example.com', + ownedByRelationsTitle: 'owned', + ownedByRelations: [], + }, + } as DocsTableRow; + }); + + const columns = [ + { + title: 'Title', + field: 'entity.metadata.name', + searchable: true, + }, + ]; + + const wrapInContext = ( + node: ReactNode, + value?: Partial>, + ) => { + return ( + + {node} + + ); + }; + + it('should display all the items', async () => { + await renderInTestApp( + wrapInContext(), + ); + + for (const item of data) { + expect(screen.queryByText(item.entity.metadata.name)).toBeInTheDocument(); + } + }); + + it('should display and invoke the next button', async () => { + const { rerender } = await renderInTestApp( + wrapInContext( + , + ), + ); + + expect( + screen.queryAllByRole('button', { name: 'Next Page' })[0], + ).toBeDisabled(); + + const fn = jest.fn(); + + rerender( + wrapInContext( + , + ), + ); + + const nextButton = screen.queryAllByRole('button', { + name: 'Next Page', + })[0]; + expect(nextButton).toBeEnabled(); + + fireEvent.click(nextButton); + expect(fn).toHaveBeenCalled(); + }); + + it('should display and invoke the prev button', async () => { + const { rerender } = await renderInTestApp( + wrapInContext( + , + ), + ); + + expect( + screen.queryAllByRole('button', { name: 'Next Page' })[0], + ).toBeDisabled(); + + const fn = jest.fn(); + + rerender( + wrapInContext( + , + ), + ); + + const prevButton = screen.queryAllByRole('button', { + name: 'Previous Page', + })[0]; + expect(prevButton).toBeEnabled(); + + fireEvent.click(prevButton); + expect(fn).toHaveBeenCalled(); + }); + + it('should display entity names when loading has finished and no error occurred', async () => { + await renderInTestApp( + e.entity), + totalItems: data.length, + filters: { + kind: new EntityKindFilter('techdocs'), + }, + }} + > + + , + ); + + expect(screen.getByText(/techdocs-0/)).toBeInTheDocument(); + expect(screen.getByText(/techdocs-50/)).toBeInTheDocument(); + expect(screen.getByText(/techdocs-99/)).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText(/My title/)).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.tsx b/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.tsx new file mode 100644 index 0000000000..48a1ecddce --- /dev/null +++ b/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.tsx @@ -0,0 +1,75 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 React from 'react'; + +import { Table, TableProps } from '@backstage/core-components'; +import { DocsTableRow } from './types'; + +type PaginatedDocsTableProps = { + prev?(): void; + next?(): void; +} & TableProps; + +/** + * @internal + */ + +export function CursorPaginatedDocsTable(props: PaginatedDocsTableProps) { + const { + actions, + columns, + data, + next, + prev, + title, + isLoading, + options, + ...restProps + } = props; + + return ( + { + if (page > 0) { + next?.(); + } else { + prev?.(); + } + }} + /* this will enable the prev button accordingly */ + page={prev ? 1 : 0} + /* this will enable the next button accordingly */ + totalCount={next ? Number.MAX_VALUE : Number.MAX_SAFE_INTEGER} + localization={{ pagination: { labelDisplayedRows: '' } }} + isLoading={isLoading} + {...restProps} + /> + ); +} diff --git a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx index b1537affdb..29dbb3fd4f 100644 --- a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx +++ b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx @@ -18,11 +18,7 @@ import React from 'react'; import useCopyToClipboard from 'react-use/esm/useCopyToClipboard'; import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; -import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; -import { - getEntityRelations, - humanizeEntityRef, -} from '@backstage/plugin-catalog-react'; +import { Entity } from '@backstage/catalog-model'; import { rootDocsRouteRef } from '../../../routes'; import { EmptyState, @@ -33,9 +29,9 @@ import { TableProps, } from '@backstage/core-components'; import { actionFactories } from './actions'; -import { columnFactories } from './columns'; -import { toLowerMaybe } from '../../../helpers'; +import { columnFactories, defaultColumns } from './columns'; import { DocsTableRow } from './types'; +import { entitiesToDocsMapper } from './helpers'; /** * Props for {@link DocsTable}. @@ -51,14 +47,6 @@ export type DocsTableProps = { options?: TableOptions; }; -const defaultColumns: TableColumn[] = [ - columnFactories.createTitleColumn({ hidden: true }), - columnFactories.createNameColumn(), - columnFactories.createOwnerColumn(), - columnFactories.createKindColumn(), - columnFactories.createTypeColumn(), -]; - /** * Component which renders a table documents * @@ -71,26 +59,11 @@ export const DocsTable = (props: DocsTableProps) => { const config = useApi(configApiRef); if (!entities) return null; - const documents = entities.map(entity => { - const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); - return { - entity, - resolved: { - docsUrl: getRouteToReaderPageFor({ - namespace: toLowerMaybe( - entity.metadata.namespace ?? 'default', - config, - ), - kind: toLowerMaybe(entity.kind, config), - name: toLowerMaybe(entity.metadata.name, config), - }), - ownedByRelations, - ownedByRelationsTitle: ownedByRelations - .map(r => humanizeEntityRef(r, { defaultKind: 'group' })) - .join(', '), - }, - }; - }); + const documents = entitiesToDocsMapper( + entities, + getRouteToReaderPageFor, + config, + ); const defaultActions: TableProps['actions'] = [ actionFactories.createCopyDocsUrlAction(copyToClipboard), diff --git a/plugins/techdocs/src/home/components/Tables/EntityListDocsTable.tsx b/plugins/techdocs/src/home/components/Tables/EntityListDocsTable.tsx index 563bec4d22..08702d2fde 100644 --- a/plugins/techdocs/src/home/components/Tables/EntityListDocsTable.tsx +++ b/plugins/techdocs/src/home/components/Tables/EntityListDocsTable.tsx @@ -24,14 +24,19 @@ import { TableProps, WarningPanel, } from '@backstage/core-components'; +import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; import { useEntityList, useStarredEntities, } from '@backstage/plugin-catalog-react'; import { DocsTable } from './DocsTable'; +import { OffsetPaginatedDocsTable } from './OffsetPaginatedDocsTable'; +import { CursorPaginatedDocsTable } from './CursorPaginatedDocsTable'; import { actionFactories } from './actions'; -import { columnFactories } from './columns'; +import { columnFactories, defaultColumns } from './columns'; import { DocsTableRow } from './types'; +import { rootDocsRouteRef } from '../../../routes'; +import { entitiesToDocsMapper } from './helpers'; /** * Props for {@link EntityListDocsTable}. @@ -51,9 +56,12 @@ export type EntityListDocsTableProps = { */ export const EntityListDocsTable = (props: EntityListDocsTableProps) => { const { columns, actions, options } = props; - const { loading, error, entities, filters } = useEntityList(); + const { loading, error, entities, filters, paginationMode, pageInfo } = + useEntityList(); const { isStarredEntity, toggleStarredEntity } = useStarredEntities(); const [, copyToClipboard] = useCopyToClipboard(); + const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef); + const config = useApi(configApiRef); const title = capitalize(filters.user?.value ?? 'all'); @@ -65,6 +73,38 @@ export const EntityListDocsTable = (props: EntityListDocsTableProps) => { ), ]; + const documents = entitiesToDocsMapper( + entities, + getRouteToReaderPageFor, + config, + ); + + if (paginationMode === 'cursor') { + return ( + + ); + } else if (paginationMode === 'offset') { + return ( + + ); + } + if (error) { return ( { + const data = new Array(100).fill(0).map((_, index) => { + const name = `tectdocs-${index}`; + return { + entity: { + apiVersion: '1', + kind: 'TestKind', + metadata: { + name, + }, + }, + resolved: { + docsUrl: 'https://example.com', + ownedByRelationsTitle: 'owned', + ownedByRelations: [], + }, + } as DocsTableRow; + }); + + const columns = [ + { + title: 'Title', + field: 'entity.metadata.name', + searchable: true, + }, + ]; + + const wrapInContext = ( + node: ReactNode, + value?: Partial>, + ) => { + return ( + + {node} + + ); + }; + + it('should display all the items', async () => { + await renderInTestApp( + wrapInContext( + , + { + setOffset: jest.fn(), + limit: Number.MAX_SAFE_INTEGER, + offset: 0, + totalItems: data.length, + }, + ), + ); + + for (const item of data) { + expect(screen.queryByText(item.entity.metadata.name)).toBeInTheDocument(); + } + }); + + it('should display and invoke the next and previous buttons', async () => { + const offsetFn = jest.fn(); + + await renderInTestApp( + wrapInContext( + , + { setOffset: offsetFn, limit: 10, totalItems: data.length, offset: 0 }, + ), + ); + + expect(offsetFn).toHaveBeenNthCalledWith(1, 0); + const nextButton = screen.queryAllByRole('button', { + name: 'Next Page', + })[0]; + expect(nextButton).toBeEnabled(); + + fireEvent.click(nextButton); + expect(offsetFn).toHaveBeenNthCalledWith(2, 10); + + const prevButton = screen.queryAllByRole('button', { + name: 'Previous Page', + })[0]; + expect(prevButton).toBeEnabled(); + + fireEvent.click(prevButton); + expect(offsetFn).toHaveBeenNthCalledWith(3, 0); + }); +}); diff --git a/plugins/techdocs/src/home/components/Tables/OffsetPaginatedDocsTable.tsx b/plugins/techdocs/src/home/components/Tables/OffsetPaginatedDocsTable.tsx new file mode 100644 index 0000000000..9f4572117d --- /dev/null +++ b/plugins/techdocs/src/home/components/Tables/OffsetPaginatedDocsTable.tsx @@ -0,0 +1,75 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 React, { useEffect } from 'react'; + +import { Table, TableProps } from '@backstage/core-components'; +import { DocsTableRow } from './types'; +import { + EntityTextFilter, + useEntityList, +} from '@backstage/plugin-catalog-react'; + +/** + * @internal + */ +export function OffsetPaginatedDocsTable(props: TableProps) { + const { actions, columns, data, isLoading, options } = props; + const { updateFilters, setLimit, setOffset, limit, totalItems, offset } = + useEntityList(); + const [page, setPage] = React.useState( + offset && limit ? Math.floor(offset / limit) : 0, + ); + + useEffect(() => { + if (totalItems && page * limit >= totalItems) { + setOffset!(Math.max(0, totalItems - limit)); + } else { + setOffset!(Math.max(0, page * limit)); + } + }, [setOffset, page, limit, totalItems]); + + return ( + + columns={columns} + data={data} + options={{ + paginationPosition: 'both', + pageSizeOptions: [5, 10, 20, 50, 100], + pageSize: limit, + emptyRowsWhenPaging: false, + actionsColumnIndex: -1, + ...options, + }} + actions={actions} + onSearchChange={(searchText: string) => + updateFilters({ + text: searchText ? new EntityTextFilter(searchText) : undefined, + }) + } + page={page} + onPageChange={newPage => { + setPage(newPage); + }} + onRowsPerPageChange={pageSize => { + setLimit(pageSize); + }} + totalCount={totalItems} + localization={{ pagination: { labelDisplayedRows: '' } }} + isLoading={isLoading} + /> + ); +} diff --git a/plugins/techdocs/src/home/components/Tables/columns.tsx b/plugins/techdocs/src/home/components/Tables/columns.tsx index ef22f6d288..9947e1de9e 100644 --- a/plugins/techdocs/src/home/components/Tables/columns.tsx +++ b/plugins/techdocs/src/home/components/Tables/columns.tsx @@ -85,3 +85,11 @@ export const columnFactories = { }; }, }; + +export const defaultColumns: TableColumn[] = [ + columnFactories.createTitleColumn({ hidden: true }), + columnFactories.createNameColumn(), + columnFactories.createOwnerColumn(), + columnFactories.createKindColumn(), + columnFactories.createTypeColumn(), +]; diff --git a/plugins/techdocs/src/home/components/Tables/helpers.ts b/plugins/techdocs/src/home/components/Tables/helpers.ts new file mode 100644 index 0000000000..4c6383c35e --- /dev/null +++ b/plugins/techdocs/src/home/components/Tables/helpers.ts @@ -0,0 +1,56 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 { RELATION_OWNED_BY, Entity } from '@backstage/catalog-model'; +import { + getEntityRelations, + humanizeEntityRef, +} from '@backstage/plugin-catalog-react'; +import { toLowerMaybe } from '../../../helpers'; +import { ConfigApi, RouteFunc } from '@backstage/core-plugin-api'; + +type getRouteFunc = RouteFunc<{ + namespace: string; + kind: string; + name: string; +}>; + +export function entitiesToDocsMapper( + entities: Entity[], + getRouteToReaderPageFor: getRouteFunc, + config: ConfigApi, +) { + return entities.map(entity => { + const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); + return { + entity, + resolved: { + docsUrl: getRouteToReaderPageFor({ + namespace: toLowerMaybe( + entity.metadata.namespace ?? 'default', + config, + ), + kind: toLowerMaybe(entity.kind, config), + name: toLowerMaybe(entity.metadata.name, config), + }), + ownedByRelations, + ownedByRelationsTitle: ownedByRelations + .map(r => humanizeEntityRef(r, { defaultKind: 'group' })) + .join(', '), + }, + }; + }); +} diff --git a/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx b/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx index 409d68a593..585248c6c9 100644 --- a/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx +++ b/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx @@ -14,7 +14,11 @@ * limitations under the License. */ -import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { + catalogApiRef, + starredEntitiesApiRef, + MockStarredEntitiesApi, +} from '@backstage/plugin-catalog-react'; import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; import { screen } from '@testing-library/react'; @@ -37,7 +41,10 @@ const mockCatalogApi = catalogApiMock({ }); describe('TechDocsCustomHome', () => { - const apiRegistry = TestApiRegistry.from([catalogApiRef, mockCatalogApi]); + const apiRegistry = TestApiRegistry.from( + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, new MockStarredEntitiesApi()], + ); it('should render a TechDocs home page', async () => { const tabsConfig = [ diff --git a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx index 56d086acfc..d89bc5ee1b 100644 --- a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx +++ b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx @@ -23,6 +23,7 @@ import { catalogApiRef, CatalogApi, useEntityOwnership, + EntityListProvider, } from '@backstage/plugin-catalog-react'; import { Entity } from '@backstage/catalog-model'; import { DocsTable } from './Tables'; @@ -127,7 +128,9 @@ const CustomPanel = ({ ) : null}
- + + +
); diff --git a/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx b/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx index adbb68d3e9..cc89d22c08 100644 --- a/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx +++ b/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx @@ -18,6 +18,7 @@ import React from 'react'; import { useOutlet } from 'react-router-dom'; import { TableColumn, TableProps } from '@backstage/core-components'; import { + EntityListPagination, EntityOwnerPickerProps, UserListFilterKind, } from '@backstage/plugin-catalog-react'; @@ -34,6 +35,7 @@ export type TechDocsIndexPageProps = { columns?: TableColumn[]; actions?: TableProps['actions']; ownerPickerMode?: EntityOwnerPickerProps['mode']; + pagination?: EntityListPagination; }; export const TechDocsIndexPage = (props: TechDocsIndexPageProps) => { diff --git a/yarn.lock b/yarn.lock index 1e28a7a65d..098bb4c173 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9443,10 +9443,12 @@ __metadata: languageName: node linkType: hard -"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.1, @codemirror/state@npm:^6.4.0": - version: 6.4.0 - resolution: "@codemirror/state@npm:6.4.0" - checksum: c5236fe5786f1b85d17273a5c17fa8aeb063658c1404ab18caeb6e7591663ec96b65d453ab8162f75839c3801b04cd55ba4bc48f44cb61ebfeeee383f89553c7 +"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.1, @codemirror/state@npm:^6.5.0": + version: 6.5.0 + resolution: "@codemirror/state@npm:6.5.0" + dependencies: + "@marijn/find-cluster-break": ^1.0.0 + checksum: f7fbed072cc67bf250f7d231668a00b988748cacaaa2ce3ea74ff13c7c392db76000e7d517933521cc6ad9dc3651c7b6d33accab3e3d4b9816cd3c5714661a84 languageName: node linkType: hard @@ -9463,13 +9465,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.23.0": - version: 6.35.2 - resolution: "@codemirror/view@npm:6.35.2" + version: 6.35.3 + resolution: "@codemirror/view@npm:6.35.3" dependencies: - "@codemirror/state": ^6.4.0 + "@codemirror/state": ^6.5.0 style-mod: ^4.1.0 w3c-keyname: ^2.2.4 - checksum: 18cc95a38fe451758fda93927873334584714ab9e2f1f8a823c5be00b90576f3f755ce01c399bf861c24449c0cb735b2bb0c6ea8ebda7030f93d7b8fe414e88b + checksum: 09c2685c9345b23ea69d28f323f29d6e73a269e9ffa29ffbf6443c139b2c97fd1a87eced1c59553a3416a08aed3246e30dd5eb70d516159ac352ae422ff4394d languageName: node linkType: hard @@ -11790,6 +11792,13 @@ __metadata: languageName: node linkType: hard +"@marijn/find-cluster-break@npm:^1.0.0": + version: 1.0.2 + resolution: "@marijn/find-cluster-break@npm:1.0.2" + checksum: 0d836de25e04d58325813401ef3c2d34caf040da985a5935fcbc9d84e7b47a21bdb15f57d70c2bf0960bd29ed3dbbb1afd00cdd0fc4fafbee7fd0ffe7d508ae1 + languageName: node + linkType: hard + "@material-table/core@npm:^3.1.0": version: 3.2.5 resolution: "@material-table/core@npm:3.2.5" @@ -12525,8 +12534,8 @@ __metadata: linkType: hard "@mui/styles@npm:^5.14.18": - version: 5.16.9 - resolution: "@mui/styles@npm:5.16.9" + version: 5.16.10 + resolution: "@mui/styles@npm:5.16.10" dependencies: "@babel/runtime": ^7.23.9 "@emotion/hash": ^0.9.1 @@ -12551,7 +12560,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 8167e70518b7328a4f9d0ae51f46fc9ea5b023cf934e3007b307a0e871ac818771a7634d4a57b4486d456b067fd9aba967eb119f1e803d7c2cf241a3c167cdc9 + checksum: 7e85e030993f9e2d93f2f32c4c6f65febd882c8f8d324a1d9476845c8bf8e26fce588fb1336caeb7eea19453454eead92ee8493caa36fed5ce51089899c8ca1b languageName: node linkType: hard @@ -12776,6 +12785,19 @@ __metadata: languageName: node linkType: hard +"@npmcli/agent@npm:^3.0.0": + version: 3.0.0 + resolution: "@npmcli/agent@npm:3.0.0" + dependencies: + agent-base: ^7.1.0 + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.1 + lru-cache: ^10.0.1 + socks-proxy-agent: ^8.0.3 + checksum: e8fc25d536250ed3e669813b36e8c6d805628b472353c57afd8c4fde0fcfcf3dda4ffe22f7af8c9070812ec2e7a03fb41d7151547cef3508efe661a5a3add20f + languageName: node + linkType: hard + "@npmcli/arborist@npm:^4.0.4": version: 4.3.1 resolution: "@npmcli/arborist@npm:4.3.1" @@ -12847,6 +12869,15 @@ __metadata: languageName: node linkType: hard +"@npmcli/fs@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/fs@npm:4.0.0" + dependencies: + semver: ^7.3.5 + checksum: 68951c589e9a4328698a35fd82fe71909a257d6f2ede0434d236fa55634f0fbcad9bb8755553ce5849bd25ee6f019f4d435921ac715c853582c4a7f5983c8d4a + languageName: node + linkType: hard + "@npmcli/git@npm:^2.1.0": version: 2.1.0 resolution: "@npmcli/git@npm:2.1.0" @@ -15093,13 +15124,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.49.0 - resolution: "@playwright/test@npm:1.49.0" + version: 1.49.1 + resolution: "@playwright/test@npm:1.49.1" dependencies: - playwright: 1.49.0 + playwright: 1.49.1 bin: playwright: cli.js - checksum: f8477aa61d59fd22c6161c48221ab246340dc37bbe2804e1a7d1be8cbd0fd861747fcb7ca559f4bc7328226ff2c90ccb7efa588a7d7d7829f3e57902b28fe39a + checksum: cdbd16df3d773dc8e522d79b4b961e25c2e1b1d4f3ec45eb711078ab5d11bca47caafe833e2be2f923328fbd012405a9ee31d9b449d184077598546a36847e69 languageName: node linkType: hard @@ -16313,8 +16344,8 @@ __metadata: linkType: hard "@rspack/dev-server@npm:^1.0.9": - version: 1.0.9 - resolution: "@rspack/dev-server@npm:1.0.9" + version: 1.0.10 + resolution: "@rspack/dev-server@npm:1.0.10" dependencies: chokidar: ^3.6.0 connect-history-api-fallback: ^2.0.0 @@ -16327,7 +16358,7 @@ __metadata: ws: ^8.16.0 peerDependencies: "@rspack/core": "*" - checksum: 46b6ad1e8f52a44c178042b6b9306fe54ad28ab24b86015f118d03a69628b04bf9563201686e0738b8c06ee8c5dedbc0bb4d6705c7f2d7d3959f2a449ff95cd6 + checksum: 0df53d1a655e5eb95c3a84b8ef34bcab6d32f8c7b23ba080f9691aa15edeee6dd79236c3942c1d55834ff9ae9f427b6e5f58cbf5e10aae015979f3d171bd65ef languageName: node linkType: hard @@ -16339,17 +16370,17 @@ __metadata: linkType: hard "@rspack/plugin-react-refresh@npm:^1.0.0": - version: 1.0.0 - resolution: "@rspack/plugin-react-refresh@npm:1.0.0" + version: 1.0.1 + resolution: "@rspack/plugin-react-refresh@npm:1.0.1" dependencies: - error-stack-parser: ^2.0.6 - html-entities: ^2.1.0 + error-stack-parser: ^2.1.4 + html-entities: ^2.5.2 peerDependencies: react-refresh: ">=0.10.0 <1.0.0" peerDependenciesMeta: react-refresh: optional: true - checksum: 88212e66da7e51d99228c7d77b683ef020ba2f70ea7ed546158167eaa4d6e3fa228da2f7d660c3f7a74ad69a47bc98c67a2d11e4a403f3e1ff8523cded67c6c0 + checksum: 876e75b28cbafa0b405cc68768cb9fd4e394531e5c8e1515dc20fb4bd72e1bef23cb055475fc286f5d215f16ab38e4c571731c38398a85e5066b8fbee86449b0 languageName: node linkType: hard @@ -20398,11 +20429,11 @@ __metadata: linkType: hard "@types/react-dom@npm:^18": - version: 18.3.3 - resolution: "@types/react-dom@npm:18.3.3" + version: 18.3.5 + resolution: "@types/react-dom@npm:18.3.5" peerDependencies: "@types/react": ^18.0.0 - checksum: d9d78c5541a223d696ead4ae5fd7e20334723b2c0ee9f7455f96c9fdb95aeb876dd5b29519fa2c6686e5000624290c5d0dbd2f1005e478172e07a42343857e8d + checksum: 95c757684f71e761515c5a11299e5feec550c72bb52975487f360e6f0d359b26454c26eaf2ce45dd22748205aa9b2c2fe0abe7005ebcbd233a7615283ac39a7d languageName: node linkType: hard @@ -20500,12 +20531,12 @@ __metadata: linkType: hard "@types/react@npm:^18": - version: 18.3.14 - resolution: "@types/react@npm:18.3.14" + version: 18.3.16 + resolution: "@types/react@npm:18.3.16" dependencies: "@types/prop-types": "*" csstype: ^3.0.2 - checksum: 40e2112301d784106bdc713e3eb925c8c710e676a3a31ef65c76ca7df8529cdde3dda2db6e0f6f1878253a79bc6cf87a461aa114bd8364f453bdd2be52c175e5 + checksum: 467c2a325870580b88b4e3bf439749b51b27cb13f52408653cb8c3e7e1b7eff86ada87e384b1aa4d34aa6027c187ca27df00bea77140fda524d726992f5b93ef languageName: node linkType: hard @@ -22688,12 +22719,10 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": - version: 7.1.1 - resolution: "agent-base@npm:7.1.1" - dependencies: - debug: ^4.3.4 - checksum: 51c158769c5c051482f9ca2e6e1ec085ac72b5a418a9b31b4e82fe6c0a6699adb94c1c42d246699a587b3335215037091c79e0de512c516f73b6ea844202f037 +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.3 + resolution: "agent-base@npm:7.1.3" + checksum: 87bb7ee54f5ecf0ccbfcba0b07473885c43ecd76cb29a8db17d6137a19d9f9cd443a2a7c5fd8a3f24d58ad8145f9eb49116344a66b107e1aeab82cf2383f4753 languageName: node linkType: hard @@ -24586,6 +24615,26 @@ __metadata: languageName: node linkType: hard +"cacache@npm:^19.0.1": + version: 19.0.1 + resolution: "cacache@npm:19.0.1" + dependencies: + "@npmcli/fs": ^4.0.0 + fs-minipass: ^3.0.0 + glob: ^10.2.2 + lru-cache: ^10.0.1 + minipass: ^7.0.3 + minipass-collect: ^2.0.1 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + p-map: ^7.0.2 + ssri: ^12.0.0 + tar: ^7.4.3 + unique-filename: ^4.0.0 + checksum: e95684717de6881b4cdaa949fa7574e3171946421cd8291769dd3d2417dbf7abf4aa557d1f968cca83dcbc95bed2a281072b09abfc977c942413146ef7ed4525 + languageName: node + linkType: hard + "cache-content-type@npm:^1.0.0": version: 1.0.1 resolution: "cache-content-type@npm:1.0.1" @@ -26806,15 +26855,15 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:~4.3.6": - version: 4.3.7 - resolution: "debug@npm:4.3.7" +"debug@npm:4, debug@npm:^4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:~4.4.0": + version: 4.4.0 + resolution: "debug@npm:4.4.0" dependencies: ms: ^2.1.3 peerDependenciesMeta: supports-color: optional: true - checksum: 822d74e209cd910ef0802d261b150314bbcf36c582ccdbb3e70f0894823c17e49a50d3e66d96b633524263975ca16b6a833f3e3b7e030c157169a5fabac63160 + checksum: fb42df878dd0e22816fc56e1fdca9da73caa85212fbe40c868b1295a6878f9101ae684f4eeef516c13acfc700f5ea07f1136954f43d4cd2d477a811144136479 languageName: node linkType: hard @@ -27895,12 +27944,12 @@ __metadata: languageName: node linkType: hard -"error-stack-parser@npm:^2.0.6": - version: 2.0.6 - resolution: "error-stack-parser@npm:2.0.6" +"error-stack-parser@npm:^2.0.6, error-stack-parser@npm:^2.1.4": + version: 2.1.4 + resolution: "error-stack-parser@npm:2.1.4" dependencies: - stackframe: ^1.1.1 - checksum: bd8e048fcb1c0c74ab201271fec3b39c097a7c24bdef1718828d053c0584da5d7ad845253b5e4773803ee8e7450b23b0920e60a3b60dd403c1568c843058cb12 + stackframe: ^1.3.4 + checksum: 3b916d2d14c6682f287c8bfa28e14672f47eafe832701080e420e7cdbaebb2c50293868256a95706ac2330fe078cf5664713158b49bc30d7a5f2ac229ded0e18 languageName: node linkType: hard @@ -33865,11 +33914,11 @@ __metadata: linkType: hard "jest-when@npm:^3.1.0": - version: 3.6.0 - resolution: "jest-when@npm:3.6.0" + version: 3.7.0 + resolution: "jest-when@npm:3.7.0" peerDependencies: jest: ">= 25" - checksum: ed32ed84e5802bb6fec98966cdf862ce59677551be33d3795e6ac7a6207acf467ed559573d671c8d94c59f7fc0780cf358d2d165d81cdc7d9611250d975ee024 + checksum: d805e2af8e76bf172e33dfde5280590fbc3510427a2d671d3a36df1c90c1bb68ebfee2ea4c87132e265973c7092d3ad20efb69398bd70141f7abef8815d5ad00 languageName: node linkType: hard @@ -34771,8 +34820,8 @@ __metadata: linkType: hard "knip@npm:^5.0.0": - version: 5.38.2 - resolution: "knip@npm:5.38.2" + version: 5.39.4 + resolution: "knip@npm:5.39.4" dependencies: "@nodelib/fs.walk": 1.2.8 "@snyk/github-codeowners": 1.1.0 @@ -34796,7 +34845,7 @@ __metadata: bin: knip: bin/knip.js knip-bun: bin/knip-bun.js - checksum: dd2b9dd20f1e940e07057f60d04c39da12130e3c2246bc600500af3fe7fa8251ef170d63cd492e4b70bd946beef44ef797afe103b6805b355430ea4057d7cba3 + checksum: 0a67865d11e015e324097616caec95f2bec15081daf1a969efcabd0f183020a6c6460326d2ea8cfc1c60b3ecf285710420c328c3ff4093018aec1d077b5815d7 languageName: node linkType: hard @@ -35018,10 +35067,10 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:~3.1.2": - version: 3.1.2 - resolution: "lilconfig@npm:3.1.2" - checksum: 4e8b83ddd1d0ad722600994e6ba5d858ddca14f0587aa6b9c8185e17548149b5e13d4d583d811e9e9323157fa8c6a527e827739794c7502b59243c58e210b8c3 +"lilconfig@npm:~3.1.3": + version: 3.1.3 + resolution: "lilconfig@npm:3.1.3" + checksum: 644eb10830350f9cdc88610f71a921f510574ed02424b57b0b3abb66ea725d7a082559552524a842f4e0272c196b88dfe1ff7d35ffcc6f45736777185cd67c9a languageName: node linkType: hard @@ -35068,22 +35117,22 @@ __metadata: linkType: hard "lint-staged@npm:^15.0.0": - version: 15.2.10 - resolution: "lint-staged@npm:15.2.10" + version: 15.2.11 + resolution: "lint-staged@npm:15.2.11" dependencies: chalk: ~5.3.0 commander: ~12.1.0 - debug: ~4.3.6 + debug: ~4.4.0 execa: ~8.0.1 - lilconfig: ~3.1.2 - listr2: ~8.2.4 + lilconfig: ~3.1.3 + listr2: ~8.2.5 micromatch: ~4.0.8 pidtree: ~0.6.0 string-argv: ~0.3.2 - yaml: ~2.5.0 + yaml: ~2.6.1 bin: lint-staged: bin/lint-staged.js - checksum: 7ab255b848478ca47c6b94aad0e7a3cfe5ba48ae1fb353cfa86635741333b83b1fd793d7cac6d44bf0388ad087d7e0250c7ec0a8ebece63fbcf7a8d175279809 + checksum: 9668e67791fd73aa91cf9268641a5b41191b4221ac9e4d34b51bb10088a082548aa5984d9b38066c3832e41f5a01bbb36aa41d9a8c96bbc775301cb5c9071e13 languageName: node linkType: hard @@ -35094,9 +35143,9 @@ __metadata: languageName: node linkType: hard -"listr2@npm:~8.2.4": - version: 8.2.4 - resolution: "listr2@npm:8.2.4" +"listr2@npm:~8.2.5": + version: 8.2.5 + resolution: "listr2@npm:8.2.5" dependencies: cli-truncate: ^4.0.0 colorette: ^2.0.20 @@ -35104,7 +35153,7 @@ __metadata: log-update: ^6.1.0 rfdc: ^1.4.1 wrap-ansi: ^9.0.0 - checksum: b1cdcae653ff967a9b28637e346df2d6614165b4ad1e9e36b1403bc972550c51f57ec0e6d307dc3921ceea0601e244e848ab79457c6d570ab1f088b577a63d90 + checksum: 0ca2387b067eb11bbe91863f36903f3a5a040790422a499cc1a15806d8497979e7d1990bd129061c0510906b2971eaa97a74a9635e3ec5abd5830c9749b655b9 languageName: node linkType: hard @@ -35737,6 +35786,25 @@ __metadata: languageName: node linkType: hard +"make-fetch-happen@npm:^14.0.3": + version: 14.0.3 + resolution: "make-fetch-happen@npm:14.0.3" + dependencies: + "@npmcli/agent": ^3.0.0 + cacache: ^19.0.1 + http-cache-semantics: ^4.1.1 + minipass: ^7.0.2 + minipass-fetch: ^4.0.0 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + negotiator: ^1.0.0 + proc-log: ^5.0.0 + promise-retry: ^2.0.1 + ssri: ^12.0.0 + checksum: 6fb2fee6da3d98f1953b03d315826b5c5a4ea1f908481afc113782d8027e19f080c85ae998454de4e5f27a681d3ec58d57278f0868d4e0b736f51d396b661691 + languageName: node + linkType: hard + "make-fetch-happen@npm:^9.1.0": version: 9.1.0 resolution: "make-fetch-happen@npm:9.1.0" @@ -36816,6 +36884,15 @@ __metadata: languageName: node linkType: hard +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: ^7.0.3 + checksum: b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 + languageName: node + linkType: hard + "minipass-fetch@npm:^1.3.2, minipass-fetch@npm:^1.4.1": version: 1.4.1 resolution: "minipass-fetch@npm:1.4.1" @@ -36861,6 +36938,21 @@ __metadata: languageName: node linkType: hard +"minipass-fetch@npm:^4.0.0": + version: 4.0.0 + resolution: "minipass-fetch@npm:4.0.0" + dependencies: + encoding: ^0.1.13 + minipass: ^7.0.3 + minipass-sized: ^1.0.3 + minizlib: ^3.0.1 + dependenciesMeta: + encoding: + optional: true + checksum: 7d59a31011ab9e4d1af6562dd4c4440e425b2baf4c5edbdd2e22fb25a88629e1cdceca39953ff209da504a46021df520f18fd9a519f36efae4750ff724ddadea + languageName: node + linkType: hard + "minipass-flush@npm:^1.0.5": version: 1.0.5 resolution: "minipass-flush@npm:1.0.5" @@ -37446,6 +37538,13 @@ __metadata: languageName: node linkType: hard +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 20ebfe79b2d2e7cf9cbc8239a72662b584f71164096e6e8896c8325055497c96f6b80cd22c258e8a2f2aa382a787795ec3ee8b37b422a302c7d4381b0d5ecfbb + languageName: node + linkType: hard + "neo-async@npm:^2.5.0, neo-async@npm:^2.6.2": version: 2.6.2 resolution: "neo-async@npm:2.6.2" @@ -37609,9 +37708,9 @@ __metadata: languageName: node linkType: hard -"node-gyp@npm:^10.0.0, node-gyp@npm:latest": - version: 10.2.0 - resolution: "node-gyp@npm:10.2.0" +"node-gyp@npm:^10.0.0": + version: 10.3.1 + resolution: "node-gyp@npm:10.3.1" dependencies: env-paths: ^2.2.0 exponential-backoff: ^3.1.1 @@ -37625,7 +37724,7 @@ __metadata: which: ^4.0.0 bin: node-gyp: bin/node-gyp.js - checksum: 0233759d8c19765f7fdc259a35eb046ad86c3d09e22f7384613ae2b89647dd27fcf833fdf5293d9335041e91f9b1c539494225959cdb312a5c8080b7534b926f + checksum: 91b0690ab504fe051ad66863226dc5ecac72b8471f85e8428e4d5ca3217d3a2adfffae48cd555e8d009a4164689fff558b88d2bc9bfd246452a3336ab308cf99 languageName: node linkType: hard @@ -37649,6 +37748,26 @@ __metadata: languageName: node linkType: hard +"node-gyp@npm:latest": + version: 11.0.0 + resolution: "node-gyp@npm:11.0.0" + dependencies: + env-paths: ^2.2.0 + exponential-backoff: ^3.1.1 + glob: ^10.3.10 + graceful-fs: ^4.2.6 + make-fetch-happen: ^14.0.3 + nopt: ^8.0.0 + proc-log: ^5.0.0 + semver: ^7.3.5 + tar: ^7.4.3 + which: ^5.0.0 + bin: + node-gyp: bin/node-gyp.js + checksum: d7d5055ccc88177f721c7cd4f8f9440c29a0eb40e7b79dba89ef882ec957975dfc1dcb8225e79ab32481a02016eb13bbc051a913ea88d482d3cbdf2131156af4 + languageName: node + linkType: hard + "node-html-markdown@npm:^1.3.0": version: 1.3.0 resolution: "node-html-markdown@npm:1.3.0" @@ -37724,8 +37843,8 @@ __metadata: linkType: hard "node-mocks-http@npm:^1.0.0": - version: 1.16.1 - resolution: "node-mocks-http@npm:1.16.1" + version: 1.16.2 + resolution: "node-mocks-http@npm:1.16.2" dependencies: accepts: ^1.3.7 content-disposition: ^0.5.3 @@ -37745,7 +37864,7 @@ __metadata: optional: true "@types/node": optional: true - checksum: 198030725eac236062eb3547a7d5cec2d6f2d44bf05efab0ea621e90f671d6966dca2873faaea9bcbb5dde92a222aff0610a01d453c2f76b0bc5dbdf4bd8057a + checksum: 9d148c49947e2161dbfd55204f07352f3fd976a41dfe355a97bd932cb8d4dbf584be4058fc78b121a9d83f0b86397e00a591e87afa9a1ecfb0335608ef1ace96 languageName: node linkType: hard @@ -37868,6 +37987,17 @@ __metadata: languageName: node linkType: hard +"nopt@npm:^8.0.0": + version: 8.0.0 + resolution: "nopt@npm:8.0.0" + dependencies: + abbrev: ^2.0.0 + bin: + nopt: bin/nopt.js + checksum: 2cfc65e7ee38af2e04aea98f054753b0230011c0eeca4ecf131bd7d25984cbbf6f214586e0ae5dfcc2e830bc0bffa5a7fb28ea8d0b306ffd4ae8ea2d814c1ab3 + languageName: node + linkType: hard + "nopt@npm:~1.0.10": version: 1.0.10 resolution: "nopt@npm:1.0.10" @@ -39644,27 +39774,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.49.0": - version: 1.49.0 - resolution: "playwright-core@npm:1.49.0" +"playwright-core@npm:1.49.1": + version: 1.49.1 + resolution: "playwright-core@npm:1.49.1" bin: playwright-core: cli.js - checksum: d8423ad0cab2e672856529bf6b98b406e7e605da098b847b9b54ee8ebd8d716ed8880a9afff4b38f0a2e3f59b95661c74589116ce3ff2b5e0ae3561507086c94 + checksum: a940f4b10ff1de033b4b8594b5104b02849a892d9adda0d42330a872cd3d8d287ffd2b01fc33f33ccd34f8904bb8ae8220b878b62e899f3d9bcd1b0945ab45c7 languageName: node linkType: hard -"playwright@npm:1.49.0": - version: 1.49.0 - resolution: "playwright@npm:1.49.0" +"playwright@npm:1.49.1": + version: 1.49.1 + resolution: "playwright@npm:1.49.1" dependencies: fsevents: 2.3.2 - playwright-core: 1.49.0 + playwright-core: 1.49.1 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: f1bfb2fff65cad2ce996edab74ec231dfd21aeb5961554b765ce1eaec27efb87eaba37b00e91ecd27727b82861e5d8c230abe4960e93f6ada8be5ad1020df306 + checksum: c136d42d625e32614f90e5228a165dc8be48c5bfb52aca9210c6ff04161a409dbe42fe5ae4f05a2653f6a1b836876a04d3b0f24bcbbc053d1509c1d605b7c8d5 languageName: node linkType: hard @@ -40395,6 +40525,13 @@ __metadata: languageName: node linkType: hard +"proc-log@npm:^5.0.0": + version: 5.0.0 + resolution: "proc-log@npm:5.0.0" + checksum: c78b26ecef6d5cce4a7489a1e9923d7b4b1679028c8654aef0463b27f4a90b0946cd598f55799da602895c52feb085ec76381d007ab8dcceebd40b89c2f9dfe0 + languageName: node + linkType: hard + "process-nextick-args@npm:^2.0.0, process-nextick-args@npm:~2.0.0": version: 2.0.1 resolution: "process-nextick-args@npm:2.0.1" @@ -43624,14 +43761,14 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^8.0.1, socks-proxy-agent@npm:^8.0.2, socks-proxy-agent@npm:^8.0.4": - version: 8.0.4 - resolution: "socks-proxy-agent@npm:8.0.4" +"socks-proxy-agent@npm:^8.0.1, socks-proxy-agent@npm:^8.0.2, socks-proxy-agent@npm:^8.0.3, socks-proxy-agent@npm:^8.0.4": + version: 8.0.5 + resolution: "socks-proxy-agent@npm:8.0.5" dependencies: - agent-base: ^7.1.1 + agent-base: ^7.1.2 debug: ^4.3.4 socks: ^2.8.3 - checksum: b2ec5051d85fe49072f9a250c427e0e9571fd09d5db133819192d078fd291276e1f0f50f6dbc04329b207738b1071314cee8bdbb4b12e27de42dbcf1d4233c67 + checksum: b4fbcdb7ad2d6eec445926e255a1fb95c975db0020543fbac8dfa6c47aecc6b3b619b7fb9c60a3f82c9b2969912a5e7e174a056ae4d98cb5322f3524d6036e1d languageName: node linkType: hard @@ -43933,6 +44070,15 @@ __metadata: languageName: node linkType: hard +"ssri@npm:^12.0.0": + version: 12.0.0 + resolution: "ssri@npm:12.0.0" + dependencies: + minipass: ^7.0.3 + checksum: ef4b6b0ae47b4a69896f5f1c4375f953b9435388c053c36d27998bc3d73e046969ccde61ab659e679142971a0b08e50478a1228f62edb994105b280f17900c98 + languageName: node + linkType: hard + "ssri@npm:^6.0.1": version: 6.0.2 resolution: "ssri@npm:6.0.2" @@ -43992,10 +44138,10 @@ __metadata: languageName: node linkType: hard -"stackframe@npm:^1.1.1": - version: 1.1.1 - resolution: "stackframe@npm:1.1.1" - checksum: 6031b30cc070972be6b12f4f4109e62150912ddbc8d6d2bc1707387bfa74b69ec298aa1211b9bf8dc4cf4f5245a5cdb72dda4b7c0467ea0cce2d10e4f10ffe3a +"stackframe@npm:^1.1.1, stackframe@npm:^1.3.4": + version: 1.3.4 + resolution: "stackframe@npm:1.3.4" + checksum: bae1596873595c4610993fa84f86a3387d67586401c1816ea048c0196800c0646c4d2da98c2ee80557fd9eff05877efe33b91ba6cd052658ed96ddc85d19067d languageName: node linkType: hard @@ -44949,7 +45095,7 @@ __metadata: languageName: node linkType: hard -"tar@npm:^7.0.0": +"tar@npm:^7.0.0, tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" dependencies: @@ -46273,6 +46419,15 @@ __metadata: languageName: node linkType: hard +"unique-filename@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-filename@npm:4.0.0" + dependencies: + unique-slug: ^5.0.0 + checksum: 6a62094fcac286b9ec39edbd1f8f64ff92383baa430af303dfed1ffda5e47a08a6b316408554abfddd9730c78b6106bef4ca4d02c1231a735ddd56ced77573df + languageName: node + linkType: hard + "unique-slug@npm:^2.0.0": version: 2.0.2 resolution: "unique-slug@npm:2.0.2" @@ -46291,6 +46446,15 @@ __metadata: languageName: node linkType: hard +"unique-slug@npm:^5.0.0": + version: 5.0.0 + resolution: "unique-slug@npm:5.0.0" + dependencies: + imurmurhash: ^0.1.4 + checksum: 222d0322bc7bbf6e45c08967863212398313ef73423f4125e075f893a02405a5ffdbaaf150f7dd1e99f8861348a486dd079186d27c5f2c60e465b7dcbb1d3e5b + languageName: node + linkType: hard + "unique-string@npm:^2.0.0": version: 2.0.0 resolution: "unique-string@npm:2.0.0" @@ -47601,6 +47765,17 @@ __metadata: languageName: node linkType: hard +"which@npm:^5.0.0": + version: 5.0.0 + resolution: "which@npm:5.0.0" + dependencies: + isexe: ^3.1.1 + bin: + node-which: bin/which.js + checksum: 6ec99e89ba32c7e748b8a3144e64bfc74aa63e2b2eacbb61a0060ad0b961eb1a632b08fb1de067ed59b002cec3e21de18299216ebf2325ef0f78e0f121e14e90 + languageName: node + linkType: hard + "wide-align@npm:^1.1.2": version: 1.1.5 resolution: "wide-align@npm:1.1.5" @@ -47990,7 +48165,7 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.0.0, yaml@npm:^2.0.0-10, yaml@npm:^2.1.1, yaml@npm:^2.2.1, yaml@npm:^2.2.2, yaml@npm:^2.3.2, yaml@npm:^2.3.3, yaml@npm:^2.3.4": +"yaml@npm:^2.0.0, yaml@npm:^2.0.0-10, yaml@npm:^2.1.1, yaml@npm:^2.2.1, yaml@npm:^2.2.2, yaml@npm:^2.3.2, yaml@npm:^2.3.3, yaml@npm:^2.3.4, yaml@npm:~2.6.1": version: 2.6.1 resolution: "yaml@npm:2.6.1" bin: @@ -47999,15 +48174,6 @@ __metadata: languageName: node linkType: hard -"yaml@npm:~2.5.0": - version: 2.5.1 - resolution: "yaml@npm:2.5.1" - bin: - yaml: bin.mjs - checksum: 31275223863fbd0b47ba9d2b248fbdf085db8d899e4ca43fff8a3a009497c5741084da6871d11f40e555d61360951c4c910b98216c1325d2c94753c0036d8172 - languageName: node - linkType: hard - "yargs-parser@npm:^20.2.2": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9"