Merge branch 'master' into canon-tables

This commit is contained in:
Charles de Dreuille
2024-12-11 18:04:28 +00:00
26 changed files with 878 additions and 157 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-gitlab': patch
---
`restrictUsersToGroup` should use the entire group path when getting members
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': minor
---
Add pagination support to TechDocs Index Page and make it the default
+2
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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
+6 -3
View File
@@ -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
+11
View File
@@ -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
+4 -1
View File
@@ -164,7 +164,10 @@ const routes = (
/>
}
/>
<Route path="/docs" element={<TechDocsIndexPage />} />
<Route
path="/docs"
element={<TechDocsIndexPage pagination={{ mode: 'offset', limit: 20 }} />}
/>
<Route
path="/docs/:namespace/:kind/:name/*"
element={<TechDocsReaderPage />}
+1 -1
View File
@@ -6,4 +6,4 @@ metadata:
spec:
lifecycle: experimental
type: backstage-web-library
owner: maintainers
owner: design-system-maintainers
@@ -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
},
@@ -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<GitLabUser>(
options =>
this.gitLabClient.listSaaSUsers(
rootGroup,
groupPath,
options,
this.config.includeUsersWithoutSeat,
),
+2
View File
@@ -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<DocsTableRow>[];
actions?: TableProps<DocsTableRow>['actions'];
ownerPickerMode?: EntityOwnerPickerProps['mode'];
pagination?: EntityListPagination;
};
// @public @deprecated (undocumented)
@@ -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 (
<TechDocsPageWrapper>
<Content>
@@ -55,7 +61,7 @@ export const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => {
Discover documentation in your ecosystem.
</SupportButton>
</ContentHeader>
<EntityListProvider>
<EntityListProvider pagination={pagination}>
<CatalogFilterLayout>
<CatalogFilterLayout.Filters>
<TechDocsPicker />
@@ -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<EntityListContextProps<DefaultEntityFilters>>,
) => {
return (
<MockEntityListContextProvider value={value}>
{node}
</MockEntityListContextProvider>
);
};
it('should display all the items', async () => {
await renderInTestApp(
wrapInContext(<CursorPaginatedDocsTable data={data} columns={columns} />),
);
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(
<CursorPaginatedDocsTable
data={data}
columns={columns}
next={undefined}
/>,
),
);
expect(
screen.queryAllByRole('button', { name: 'Next Page' })[0],
).toBeDisabled();
const fn = jest.fn();
rerender(
wrapInContext(
<CursorPaginatedDocsTable data={data} columns={columns} next={fn} />,
),
);
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(
<CursorPaginatedDocsTable
data={data}
columns={columns}
prev={undefined}
/>,
),
);
expect(
screen.queryAllByRole('button', { name: 'Next Page' })[0],
).toBeDisabled();
const fn = jest.fn();
rerender(
wrapInContext(
<CursorPaginatedDocsTable data={data} columns={columns} prev={fn} />,
),
);
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(
<MockEntityListContextProvider
value={{
entities: data.map(e => e.entity),
totalItems: data.length,
filters: {
kind: new EntityKindFilter('techdocs'),
},
}}
>
<CursorPaginatedDocsTable
data={data}
columns={columns}
next={undefined}
title="My title"
/>
</MockEntityListContextProvider>,
);
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();
});
});
});
@@ -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<DocsTableRow>;
/**
* @internal
*/
export function CursorPaginatedDocsTable(props: PaginatedDocsTableProps) {
const {
actions,
columns,
data,
next,
prev,
title,
isLoading,
options,
...restProps
} = props;
return (
<Table
title={isLoading ? '' : title}
columns={columns}
data={data}
options={{
paginationPosition: 'both',
...options,
// These settings are configured to force server side pagination
pageSizeOptions: [],
showFirstLastPageButtons: false,
pageSize: Number.MAX_SAFE_INTEGER,
emptyRowsWhenPaging: false,
actionsColumnIndex: -1,
}}
onPageChange={page => {
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}
/>
);
}
@@ -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<DocsTableRow>;
};
const defaultColumns: TableColumn<DocsTableRow>[] = [
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<DocsTableRow>['actions'] = [
actionFactories.createCopyDocsUrlAction(copyToClipboard),
@@ -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 (
<CursorPaginatedDocsTable
columns={columns || defaultColumns}
isLoading={loading}
title={title}
actions={actions || defaultActions}
options={options}
data={documents}
next={pageInfo?.next}
prev={pageInfo?.prev}
/>
);
} else if (paginationMode === 'offset') {
return (
<OffsetPaginatedDocsTable
columns={columns || defaultColumns}
isLoading={loading}
title={title}
actions={actions || defaultActions}
options={options}
data={documents}
/>
);
}
if (error) {
return (
<WarningPanel
@@ -0,0 +1,111 @@
/*
* 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 } from '@testing-library/react';
import { DocsTableRow } from './types';
import { renderInTestApp } from '@backstage/test-utils';
import {
DefaultEntityFilters,
EntityListContextProps,
} from '@backstage/plugin-catalog-react';
import { MockEntityListContextProvider } from '@backstage/plugin-catalog-react/testUtils';
import { OffsetPaginatedDocsTable } from './OffsetPaginatedDocsTable';
describe('OffsetPaginatedDocsTable', () => {
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<EntityListContextProps<DefaultEntityFilters>>,
) => {
return (
<MockEntityListContextProvider value={value}>
{node}
</MockEntityListContextProvider>
);
};
it('should display all the items', async () => {
await renderInTestApp(
wrapInContext(
<OffsetPaginatedDocsTable data={data} columns={columns} />,
{
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(
<OffsetPaginatedDocsTable data={data} columns={columns} />,
{ 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);
});
});
@@ -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<DocsTableRow>) {
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 (
<Table<DocsTableRow>
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}
/>
);
}
@@ -85,3 +85,11 @@ export const columnFactories = {
};
},
};
export const defaultColumns: TableColumn<DocsTableRow>[] = [
columnFactories.createTitleColumn({ hidden: true }),
columnFactories.createNameColumn(),
columnFactories.createOwnerColumn(),
columnFactories.createKindColumn(),
columnFactories.createTypeColumn(),
];
@@ -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(', '),
},
};
});
}
@@ -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 = [
@@ -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}
</ContentHeader>
<div className={classes.panelContainer}>
<Panel data-testid="techdocs-custom-panel" entities={shownEntities} />
<EntityListProvider>
<Panel data-testid="techdocs-custom-panel" entities={shownEntities} />
</EntityListProvider>
</div>
</>
);
@@ -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<DocsTableRow>[];
actions?: TableProps<DocsTableRow>['actions'];
ownerPickerMode?: EntityOwnerPickerProps['mode'];
pagination?: EntityListPagination;
};
export const TechDocsIndexPage = (props: TechDocsIndexPageProps) => {
+267 -101
View File
@@ -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"