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"