diff --git a/workspaces/dcm/.changeset/kind-ravens-rehydrate.md b/workspaces/dcm/.changeset/kind-ravens-rehydrate.md
new file mode 100644
index 00000000000..3818b4a8fb0
--- /dev/null
+++ b/workspaces/dcm/.changeset/kind-ravens-rehydrate.md
@@ -0,0 +1,25 @@
+---
+'@red-hat-developer-hub/backstage-plugin-dcm': minor
+'@red-hat-developer-hub/backstage-plugin-dcm-common': minor
+---
+
+DCM UI and catalog client updates for the example app and published plugins.
+
+**Example app (`packages/app`) — RBAC navigation**
+
+- Removed the **RBAC** sidebar entry under Administration and the `/rbac` route.
+- Dropped the `@backstage-community/plugin-rbac` frontend dependency. The RBAC backend plugin may remain for permissions; only the menu and page were removed.
+
+**`@red-hat-developer-hub/backstage-plugin-dcm` — Resources tab**
+
+- Removed the **Resources** tab from the Data Center page and all **Placement / `resources`** proxy usage from the plugin.
+- Removed `placementApiRef`, `resources` route ref, and the `PlacementClient` integration from the plugin surface.
+
+**`@red-hat-developer-hub/backstage-plugin-dcm-common` — placement API removed; catalog rehydrate**
+
+- Removed the Placement API client, types, and tests tied to the internal `resources` API.
+- Added **`rehydrateCatalogItemInstance`** on `CatalogApi` / `CatalogClient`: `POST .../catalog-item-instances/{id}:rehydrate`.
+
+**Catalog item instances UI**
+
+- Added a **Rehydrate** action (outlined button with refresh icon) on each instance row, success and error snackbars, and a unit test for the new client method.
diff --git a/workspaces/dcm/packages/app/package.json b/workspaces/dcm/packages/app/package.json
index 7723577751b..6afdd739d8c 100644
--- a/workspaces/dcm/packages/app/package.json
+++ b/workspaces/dcm/packages/app/package.json
@@ -19,7 +19,6 @@
"lint": "backstage-cli package lint"
},
"dependencies": {
- "@backstage-community/plugin-rbac": "1.33.2",
"@backstage/app-defaults": "^1.5.16",
"@backstage/catalog-model": "^1.7.3",
"@backstage/cli": "^0.35.2",
diff --git a/workspaces/dcm/packages/app/src/App.tsx b/workspaces/dcm/packages/app/src/App.tsx
index a94ac817203..0645c19004b 100644
--- a/workspaces/dcm/packages/app/src/App.tsx
+++ b/workspaces/dcm/packages/app/src/App.tsx
@@ -52,7 +52,6 @@ import { RequirePermission } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
import { DcmPage } from '@red-hat-developer-hub/backstage-plugin-dcm';
import { useRhdhTheme } from './hooks/useRhdhTheme';
-import { RbacPage } from '@backstage-community/plugin-rbac';
import '@patternfly/patternfly/patternfly.css';
import '@patternfly/patternfly/patternfly-charts.css';
@@ -123,7 +122,6 @@ const routes = (
} />
} />
} />
- } />
);
diff --git a/workspaces/dcm/packages/app/src/components/Root/Root.tsx b/workspaces/dcm/packages/app/src/components/Root/Root.tsx
index 04521b2b32a..33e668dd589 100644
--- a/workspaces/dcm/packages/app/src/components/Root/Root.tsx
+++ b/workspaces/dcm/packages/app/src/components/Root/Root.tsx
@@ -41,7 +41,6 @@ import MenuIcon from '@material-ui/icons/Menu';
import SearchIcon from '@material-ui/icons/Search';
import SecurityIcon from '@material-ui/icons/Security';
import StorageIcon from '@material-ui/icons/Storage';
-import VpnKeyIcon from '@material-ui/icons/VpnKey';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import LogoFull from './LogoFull';
@@ -235,7 +234,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
const location = useLocation();
usePatternFlyTheme();
const isDcmActive = location.pathname.startsWith('/dcm');
- const isRbacActive = location.pathname.startsWith('/rbac');
return (
@@ -274,16 +272,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
isDcmActive ? classes.submenuItemActive : classes.inactiveItem
}`}
/>
-
diff --git a/workspaces/dcm/plugins/dcm-common/report.api.md b/workspaces/dcm/plugins/dcm-common/report.api.md
index d1c1cbeff0d..15f4709dd78 100644
--- a/workspaces/dcm/plugins/dcm-common/report.api.md
+++ b/workspaces/dcm/plugins/dcm-common/report.api.md
@@ -35,6 +35,9 @@ export interface CatalogApi {
listCatalogItems(): Promise;
// (undocumented)
listServiceTypes(): Promise;
+ rehydrateCatalogItemInstance(
+ catalogItemInstanceId: string,
+ ): Promise;
// (undocumented)
updateCatalogItem(
catalogItemId: string,
@@ -71,6 +74,10 @@ export class CatalogClient extends DcmBaseClient implements CatalogApi {
// (undocumented)
listServiceTypes(): Promise;
// (undocumented)
+ rehydrateCatalogItemInstance(
+ catalogItemInstanceId: string,
+ ): Promise;
+ // (undocumented)
protected readonly serviceName = 'Catalog';
// (undocumented)
updateCatalogItem(
@@ -264,46 +271,15 @@ export interface FieldConfigurationDependsOn {
}
// @public
-export function parseDcmEntityStatus(raw: string): DcmEntityStatus | undefined;
-
-// @public
-export interface PlacementApi {
- createResource(resource: Resource, id?: string): Promise;
- deleteResource(resourceId: string): Promise;
- getResource(resourceId: string): Promise;
- listResources(options?: {
- provider?: string;
- maxPageSize?: number;
- pageToken?: string;
- }): Promise;
- rehydrateResource(
- resourceId: string,
- request: RehydrateRequest,
- ): Promise;
+export interface ListServiceTypeInstancesParams {
+ max_page_size?: number;
+ page_token?: string;
+ provider?: string;
+ show_deleted?: boolean;
}
// @public
-export class PlacementClient extends DcmBaseClient implements PlacementApi {
- // (undocumented)
- createResource(resource: Resource, id?: string): Promise;
- // (undocumented)
- deleteResource(resourceId: string): Promise;
- // (undocumented)
- getResource(resourceId: string): Promise;
- // (undocumented)
- listResources(options?: {
- provider?: string;
- maxPageSize?: number;
- pageToken?: string;
- }): Promise;
- // (undocumented)
- rehydrateResource(
- resourceId: string,
- request: RehydrateRequest,
- ): Promise;
- // (undocumented)
- protected readonly serviceName = 'Placement';
-}
+export function parseDcmEntityStatus(raw: string): DcmEntityStatus | undefined;
// @public
export interface Policy {
@@ -449,24 +425,6 @@ export class ProvidersClient extends DcmBaseClient implements ProvidersApi {
// @public
export type ProviderStatus = 'registered' | 'updated';
-// @public
-export interface RehydrateRequest {
- // (undocumented)
- new_resource_id: string;
-}
-
-// @public
-export interface Resource {
- approval_status?: string;
- catalog_item_instance_id: string;
- create_time?: string;
- id?: string;
- path?: string;
- provider_name?: string;
- spec: Record;
- update_time?: string;
-}
-
// @public
export interface ResourceCapacity {
// (undocumented)
@@ -480,11 +438,20 @@ export interface ResourceCapacity {
}
// @public
-export interface ResourceList {
+export interface ResourcesApi {
+ listServiceTypeInstances(
+ params?: ListServiceTypeInstancesParams,
+ ): Promise;
+}
+
+// @public
+export class ResourcesClient extends DcmBaseClient implements ResourcesApi {
// (undocumented)
- next_page_token?: string;
+ listServiceTypeInstances(
+ params?: ListServiceTypeInstancesParams,
+ ): Promise;
// (undocumented)
- resources: Resource[];
+ protected readonly serviceName = 'Resources';
}
// @public
@@ -506,6 +473,37 @@ export interface ServiceType {
update_time?: string;
}
+// @public
+export interface ServiceTypeInstance {
+ // (undocumented)
+ create_time?: string;
+ // (undocumented)
+ delete_time?: string;
+ deleted?: boolean;
+ id: string;
+ path?: string;
+ provider_name?: string;
+ spec?: ServiceTypeInstanceSpec;
+ status?: string;
+ // (undocumented)
+ update_time?: string;
+}
+
+// @public
+export interface ServiceTypeInstanceList {
+ // (undocumented)
+ instances?: ServiceTypeInstance[];
+ // (undocumented)
+ next_page_token?: string;
+}
+
+// @public
+export interface ServiceTypeInstanceSpec {
+ // (undocumented)
+ [key: string]: unknown;
+ service_type?: string;
+}
+
// @public
export interface ServiceTypeList {
// (undocumented)
diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/CatalogApi.ts b/workspaces/dcm/plugins/dcm-common/src/clients/CatalogApi.ts
index d08e2742238..a12fc771166 100644
--- a/workspaces/dcm/plugins/dcm-common/src/clients/CatalogApi.ts
+++ b/workspaces/dcm/plugins/dcm-common/src/clients/CatalogApi.ts
@@ -52,5 +52,13 @@ export interface CatalogApi {
createCatalogItemInstance(
instance: CatalogItemInstance,
): Promise;
+ /**
+ * Triggers catalog item instance rehydrate (placement); may assign a new resource id.
+ *
+ * @public
+ */
+ rehydrateCatalogItemInstance(
+ catalogItemInstanceId: string,
+ ): Promise;
deleteCatalogItemInstance(catalogItemInstanceId: string): Promise;
}
diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.test.ts b/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.test.ts
new file mode 100644
index 00000000000..50679fdc72b
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.test.ts
@@ -0,0 +1,64 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';
+import { CatalogClient } from './CatalogClient';
+import type { CatalogItemInstance } from '../types/catalog';
+
+const BASE_URL = 'http://localhost/api/dcm';
+
+const MOCK_INSTANCE: CatalogItemInstance = {
+ api_version: 'v1alpha1',
+ display_name: 'Test instance',
+ uid: 'inst-1',
+ spec: {
+ catalog_item_id: 'ci-1',
+ user_values: [],
+ },
+ resource_id: 'res-new',
+};
+
+function makeClient(fetchFn: jest.Mock) {
+ const discoveryApi: DiscoveryApi = {
+ getBaseUrl: jest.fn().mockResolvedValue(BASE_URL),
+ };
+ const fetchApi: FetchApi = { fetch: fetchFn };
+ return new CatalogClient({ discoveryApi, fetchApi });
+}
+
+function okJson(data: unknown): Response {
+ return {
+ status: 200,
+ ok: true,
+ json: async () => data,
+ } as unknown as Response;
+}
+
+describe('CatalogClient', () => {
+ it('rehydrateCatalogItemInstance calls POST catalog-item-instances/{id}:rehydrate', async () => {
+ const fetchFn = jest.fn().mockResolvedValue(okJson(MOCK_INSTANCE));
+ const client = makeClient(fetchFn);
+
+ const result = await client.rehydrateCatalogItemInstance('inst-1');
+
+ expect(result).toEqual(MOCK_INSTANCE);
+ const [url, init] = fetchFn.mock.calls[0];
+ expect(url).toBe(
+ `${BASE_URL}/proxy/catalog-item-instances/inst-1:rehydrate`,
+ );
+ expect(init.method).toBe('POST');
+ });
+});
diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts b/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts
index 4a7818f0c5a..6f7f651f6db 100644
--- a/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts
+++ b/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts
@@ -111,6 +111,18 @@ export class CatalogClient extends DcmBaseClient implements CatalogApi {
});
}
+ /**
+ * @public
+ */
+ async rehydrateCatalogItemInstance(
+ catalogItemInstanceId: string,
+ ): Promise {
+ return this.fetch(
+ `catalog-item-instances/${catalogItemInstanceId}:rehydrate`,
+ { method: 'POST', body: '{}' },
+ );
+ }
+
async deleteCatalogItemInstance(
catalogItemInstanceId: string,
): Promise {
diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/PlacementApi.ts b/workspaces/dcm/plugins/dcm-common/src/clients/PlacementApi.ts
deleted file mode 100644
index c1b8caa6129..00000000000
--- a/workspaces/dcm/plugins/dcm-common/src/clients/PlacementApi.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright Red Hat, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import type {
- Resource,
- ResourceList,
- RehydrateRequest,
-} from '../types/placement';
-
-/**
- * Interface for the DCM Placement Manager API client.
- *
- * @public
- */
-export interface PlacementApi {
- /** GET /resources — list all resources, optionally filtered by provider. */
- listResources(options?: {
- provider?: string;
- maxPageSize?: number;
- pageToken?: string;
- }): Promise;
-
- /** GET /resources/:resourceId — fetch a single resource. */
- getResource(resourceId: string): Promise;
-
- /**
- * POST /resources — create a new resource.
- * @param resource - The resource body (catalog_item_instance_id + spec).
- * @param id - Optional client-assigned resource ID (query param).
- */
- createResource(resource: Resource, id?: string): Promise;
-
- /** DELETE /resources/:resourceId — delete a resource. */
- deleteResource(resourceId: string): Promise;
-
- /** POST /resources/:resourceId:rehydrate — re-evaluate a resource against current policies. */
- rehydrateResource(
- resourceId: string,
- request: RehydrateRequest,
- ): Promise;
-}
diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/PlacementClient.test.ts b/workspaces/dcm/plugins/dcm-common/src/clients/PlacementClient.test.ts
deleted file mode 100644
index fed7d414af1..00000000000
--- a/workspaces/dcm/plugins/dcm-common/src/clients/PlacementClient.test.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright Red Hat, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';
-import { PlacementClient } from './PlacementClient';
-import type { Resource, RehydrateRequest } from '../types/placement';
-
-const BASE_URL = 'http://localhost/api/dcm';
-
-const MOCK_RESOURCE: Resource = {
- catalog_item_instance_id: 'instance-abc',
- spec: { memory: '4Gi' },
-};
-
-function makeClient(fetchFn: jest.Mock) {
- const discoveryApi: DiscoveryApi = {
- getBaseUrl: jest.fn().mockResolvedValue(BASE_URL),
- };
- const fetchApi: FetchApi = { fetch: fetchFn };
- return new PlacementClient({ discoveryApi, fetchApi });
-}
-
-function okJson(data: unknown): Response {
- return {
- status: 200,
- ok: true,
- json: async () => data,
- } as unknown as Response;
-}
-
-describe('PlacementClient', () => {
- it('listResources calls GET /resources without query params by default', async () => {
- const fetchFn = jest
- .fn()
- .mockResolvedValue(okJson({ resources: [MOCK_RESOURCE] }));
- const client = makeClient(fetchFn);
-
- await client.listResources();
-
- expect(fetchFn).toHaveBeenCalledWith(
- `${BASE_URL}/proxy/resources`,
- expect.any(Object),
- );
- });
-
- it('listResources appends query params when options are provided', async () => {
- const fetchFn = jest.fn().mockResolvedValue(okJson({ resources: [] }));
- const client = makeClient(fetchFn);
-
- await client.listResources({
- provider: 'prov-1',
- maxPageSize: 10,
- pageToken: 'tok',
- });
-
- const calledUrl = fetchFn.mock.calls[0][0] as string;
- expect(calledUrl).toContain('provider=prov-1');
- expect(calledUrl).toContain('max_page_size=10');
- expect(calledUrl).toContain('page_token=tok');
- });
-
- it('createResource calls POST /resources without id query param by default', async () => {
- const fetchFn = jest.fn().mockResolvedValue(okJson(MOCK_RESOURCE));
- const client = makeClient(fetchFn);
-
- await client.createResource(MOCK_RESOURCE);
-
- const [url, init] = fetchFn.mock.calls[0];
- expect(url).toBe(`${BASE_URL}/proxy/resources`);
- expect(init.method).toBe('POST');
- });
-
- it('createResource appends id query param when provided', async () => {
- const fetchFn = jest.fn().mockResolvedValue(okJson(MOCK_RESOURCE));
- const client = makeClient(fetchFn);
-
- await client.createResource(MOCK_RESOURCE, 'custom-id');
-
- const calledUrl = fetchFn.mock.calls[0][0] as string;
- expect(calledUrl).toContain('id=custom-id');
- });
-
- it('deleteResource calls DELETE /resources/{id} and returns undefined', async () => {
- const fetchFn = jest
- .fn()
- .mockResolvedValue({ status: 204, ok: true } as Response);
- const client = makeClient(fetchFn);
-
- const result = await client.deleteResource('res-1');
-
- expect(result).toBeUndefined();
- const [url, init] = fetchFn.mock.calls[0];
- expect(url).toBe(`${BASE_URL}/proxy/resources/res-1`);
- expect(init.method).toBe('DELETE');
- });
-
- it('rehydrateResource calls POST /resources/{id}:rehydrate', async () => {
- const rehydrateReq: RehydrateRequest = { new_resource_id: 'new-res-2' };
- const fetchFn = jest.fn().mockResolvedValue(okJson(MOCK_RESOURCE));
- const client = makeClient(fetchFn);
-
- await client.rehydrateResource('res-1', rehydrateReq);
-
- const [url, init] = fetchFn.mock.calls[0];
- expect(url).toBe(`${BASE_URL}/proxy/resources/res-1:rehydrate`);
- expect(init.method).toBe('POST');
- expect(JSON.parse(init.body)).toEqual(rehydrateReq);
- });
-});
diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/PlacementClient.ts b/workspaces/dcm/plugins/dcm-common/src/clients/PlacementClient.ts
deleted file mode 100644
index ccdae64cb5e..00000000000
--- a/workspaces/dcm/plugins/dcm-common/src/clients/PlacementClient.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright Red Hat, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import type {
- Resource,
- ResourceList,
- RehydrateRequest,
-} from '../types/placement';
-import type { PlacementApi } from './PlacementApi';
-import { DcmBaseClient } from './DcmBaseClient';
-
-/**
- * Calls the DCM Placement Manager API through the dcm-backend secure proxy.
- *
- * All requests are sent to `/api/dcm/proxy/` where the backend
- * strips the `/proxy` prefix and forwards to:
- * `{dcm.apiGatewayUrl}/api/v1alpha1/`
- *
- * @public
- */
-export class PlacementClient extends DcmBaseClient implements PlacementApi {
- protected readonly serviceName = 'Placement';
-
- async listResources(options?: {
- provider?: string;
- maxPageSize?: number;
- pageToken?: string;
- }): Promise {
- const params = new URLSearchParams();
- if (options?.provider) params.set('provider', options.provider);
- if (options?.maxPageSize)
- params.set('max_page_size', String(options.maxPageSize));
- if (options?.pageToken) params.set('page_token', options.pageToken);
- const qs = params.toString();
- const path = qs ? `resources?${qs}` : 'resources';
- return this.fetch(path);
- }
-
- async getResource(resourceId: string): Promise {
- return this.fetch(`resources/${resourceId}`);
- }
-
- async createResource(resource: Resource, id?: string): Promise {
- const qs = id ? `?id=${encodeURIComponent(id)}` : '';
- return this.fetch(`resources${qs}`, {
- method: 'POST',
- body: JSON.stringify(resource),
- });
- }
-
- async deleteResource(resourceId: string): Promise {
- return this.fetch(`resources/${resourceId}`, { method: 'DELETE' });
- }
-
- async rehydrateResource(
- resourceId: string,
- request: RehydrateRequest,
- ): Promise {
- return this.fetch(`resources/${resourceId}:rehydrate`, {
- method: 'POST',
- body: JSON.stringify(request),
- });
- }
-}
diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesApi.ts b/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesApi.ts
new file mode 100644
index 00000000000..166fbeef3fd
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesApi.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type {
+ ListServiceTypeInstancesParams,
+ ServiceTypeInstanceList,
+} from '../types/resources';
+
+/**
+ * Client interface for the DCM Resources (service-type-instances) API.
+ *
+ * @public
+ */
+export interface ResourcesApi {
+ /**
+ * Returns a paginated list of service type instances.
+ * Maps to `GET /service-type-instances`.
+ */
+ listServiceTypeInstances(
+ params?: ListServiceTypeInstancesParams,
+ ): Promise;
+}
diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesClient.ts b/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesClient.ts
new file mode 100644
index 00000000000..cb6becc0a20
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesClient.ts
@@ -0,0 +1,53 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * 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 { DcmBaseClient } from './DcmBaseClient';
+import type { ResourcesApi } from './ResourcesApi';
+import type {
+ ListServiceTypeInstancesParams,
+ ServiceTypeInstanceList,
+} from '../types/resources';
+
+/**
+ * Default implementation of {@link ResourcesApi}.
+ *
+ * Routes calls through the dcm-backend secure proxy to the
+ * `/service-type-instances` endpoint of the DCM API Gateway.
+ *
+ * @public
+ */
+export class ResourcesClient extends DcmBaseClient implements ResourcesApi {
+ protected readonly serviceName = 'Resources';
+
+ /** @public */
+ async listServiceTypeInstances(
+ params: ListServiceTypeInstancesParams = {},
+ ): Promise {
+ const query = new URLSearchParams();
+ if (params.provider !== undefined) query.set('provider', params.provider);
+ if (params.show_deleted !== undefined)
+ query.set('show_deleted', String(params.show_deleted));
+ if (params.max_page_size !== undefined)
+ query.set('max_page_size', String(params.max_page_size));
+ if (params.page_token !== undefined)
+ query.set('page_token', params.page_token);
+ const qs = query.toString();
+ const suffix = qs ? `?${qs}` : '';
+ return this.fetch(
+ `service-type-instances${suffix}`,
+ );
+ }
+}
diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/index.ts b/workspaces/dcm/plugins/dcm-common/src/clients/index.ts
index c037865014a..6165140e508 100644
--- a/workspaces/dcm/plugins/dcm-common/src/clients/index.ts
+++ b/workspaces/dcm/plugins/dcm-common/src/clients/index.ts
@@ -15,12 +15,12 @@
*/
export type { CatalogApi } from './CatalogApi';
-export type { PlacementApi } from './PlacementApi';
export type { PolicyManagerApi } from './PolicyManagerApi';
export type { ProvidersApi } from './ProvidersApi';
+export type { ResourcesApi } from './ResourcesApi';
export { DcmBaseClient } from './DcmBaseClient';
export { CatalogClient } from './CatalogClient';
-export { PlacementClient } from './PlacementClient';
export { PolicyManagerClient } from './PolicyManagerClient';
export { ProvidersClient } from './ProvidersClient';
+export { ResourcesClient } from './ResourcesClient';
diff --git a/workspaces/dcm/plugins/dcm-common/src/types/index.ts b/workspaces/dcm/plugins/dcm-common/src/types/index.ts
index dcd8b06ef08..b70f1518af3 100644
--- a/workspaces/dcm/plugins/dcm-common/src/types/index.ts
+++ b/workspaces/dcm/plugins/dcm-common/src/types/index.ts
@@ -16,6 +16,6 @@
export * from './catalog';
export * from './common';
-export * from './placement';
export * from './policy-manager';
export * from './providers';
+export * from './resources';
diff --git a/workspaces/dcm/plugins/dcm-common/src/types/placement.ts b/workspaces/dcm/plugins/dcm-common/src/types/placement.ts
deleted file mode 100644
index 2bd1f19ec10..00000000000
--- a/workspaces/dcm/plugins/dcm-common/src/types/placement.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright Red Hat, Inc.
- *
- * 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.
- */
-
-/**
- * Full resource representation.
- * Based on the Placement Management API schema (placement.yaml).
- * @public
- */
-export interface Resource {
- /** Unique identifier (readOnly, server-generated or client-provided via query param). */
- id?: string;
- /** Resource path identifier (readOnly). */
- path?: string;
- /** Name of the assigned Service Provider (readOnly). */
- provider_name?: string;
- /** The catalog item instance this resource was created from. */
- catalog_item_instance_id: string;
- /** Service specification JSON — must have at least one property. */
- spec: Record;
- /** Approval status returned by the Policy Engine (readOnly). */
- approval_status?: string;
- /** ISO 8601 creation timestamp (readOnly). */
- create_time?: string;
- /** ISO 8601 last-update timestamp (readOnly). */
- update_time?: string;
-}
-
-/**
- * Paginated list of resources.
- * @public
- */
-export interface ResourceList {
- resources: Resource[];
- next_page_token?: string;
-}
-
-/**
- * Request body for the rehydrate operation.
- * @public
- */
-export interface RehydrateRequest {
- new_resource_id: string;
-}
diff --git a/workspaces/dcm/plugins/dcm-common/src/types/resources.ts b/workspaces/dcm/plugins/dcm-common/src/types/resources.ts
new file mode 100644
index 00000000000..1c8b6dc8009
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-common/src/types/resources.ts
@@ -0,0 +1,65 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * 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.
+ */
+
+/**
+ * DCM Resources API types — derived from the service-type-instances OpenAPI spec.
+ *
+ * @public
+ */
+
+/** Spec payload of a {@link ServiceTypeInstance}. */
+export interface ServiceTypeInstanceSpec {
+ /** The service type this instance belongs to (e.g. "vm"). */
+ service_type?: string;
+ [key: string]: unknown;
+}
+
+/** A provisioned service type instance managed by DCM. */
+export interface ServiceTypeInstance {
+ /** Unique identifier (readOnly). */
+ id: string;
+ /** Resource path (readOnly). */
+ path?: string;
+ /** The provider that manages this instance. */
+ provider_name?: string;
+ /** Instance spec containing service_type and other provider-specific fields. */
+ spec?: ServiceTypeInstanceSpec;
+ /** Current lifecycle status. */
+ status?: string;
+ /** Whether this instance has been soft-deleted. */
+ deleted?: boolean;
+ create_time?: string;
+ update_time?: string;
+ delete_time?: string;
+}
+
+/** Paginated list of {@link ServiceTypeInstance} resources. */
+export interface ServiceTypeInstanceList {
+ instances?: ServiceTypeInstance[];
+ next_page_token?: string;
+}
+
+/** Query parameters accepted by the list endpoint. */
+export interface ListServiceTypeInstancesParams {
+ /** Filter by service provider name. */
+ provider?: string;
+ /** When true, soft-deleted instances are included alongside active ones. */
+ show_deleted?: boolean;
+ /** Maximum number of results per page (1–100, default 100). */
+ max_page_size?: number;
+ /** Opaque pagination token returned by a previous response. */
+ page_token?: string;
+}
diff --git a/workspaces/dcm/plugins/dcm/report.api.md b/workspaces/dcm/plugins/dcm/report.api.md
index 2d6497df25b..74134060c02 100644
--- a/workspaces/dcm/plugins/dcm/report.api.md
+++ b/workspaces/dcm/plugins/dcm/report.api.md
@@ -8,9 +8,9 @@ import { BackstagePlugin } from '@backstage/core-plugin-api';
import type { CatalogApi } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
import { JSX as JSX_2 } from 'react/jsx-runtime';
import { PathParams } from '@backstage/core-plugin-api';
-import type { PlacementApi } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
import type { PolicyManagerApi } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
import type { ProvidersApi } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
+import type { ResourcesApi } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
import { RouteRef } from '@backstage/core-plugin-api';
import { SubRouteRef } from '@backstage/core-plugin-api';
import { Theme } from '@material-ui/core/styles';
@@ -42,15 +42,15 @@ export const dcmPlugin: BackstagePlugin<
// @public
export function isDarkMode(theme: Theme): boolean;
-// @public
-export const placementApiRef: ApiRef;
-
// @public
export const policyManagerApiRef: ApiRef;
// @public
export const providersApiRef: ApiRef;
+// @public
+export const resourcesApiRef: ApiRef;
+
// @public
export const RhdhLogoFull: () => JSX_2.Element;
diff --git a/workspaces/dcm/plugins/dcm/src/apis.ts b/workspaces/dcm/plugins/dcm/src/apis.ts
index bf825d295df..eb11b6d43eb 100644
--- a/workspaces/dcm/plugins/dcm/src/apis.ts
+++ b/workspaces/dcm/plugins/dcm/src/apis.ts
@@ -17,9 +17,9 @@
import { createApiRef } from '@backstage/core-plugin-api';
import type {
CatalogApi,
- PlacementApi,
PolicyManagerApi,
ProvidersApi,
+ ResourcesApi,
} from '@red-hat-developer-hub/backstage-plugin-dcm-common';
/**
@@ -57,13 +57,12 @@ export const providersApiRef = createApiRef({
});
/**
- * Backstage API ref for the DCM Placement Manager service.
+ * Backstage API ref for the DCM Resources service.
*
- * Provides list, create, delete, and rehydrate operations for Resources
- * via the dcm-backend secure proxy.
+ * Provides read access to service type instances via the dcm-backend secure proxy.
*
* @public
*/
-export const placementApiRef = createApiRef({
- id: 'plugin.dcm.placement',
+export const resourcesApiRef = createApiRef({
+ id: 'plugin.dcm.resources',
});
diff --git a/workspaces/dcm/plugins/dcm/src/components/DcmCrudTabLayout.tsx b/workspaces/dcm/plugins/dcm/src/components/DcmCrudTabLayout.tsx
index 7b2815bf9c7..9ea2cb099b3 100644
--- a/workspaces/dcm/plugins/dcm/src/components/DcmCrudTabLayout.tsx
+++ b/workspaces/dcm/plugins/dcm/src/components/DcmCrudTabLayout.tsx
@@ -170,6 +170,8 @@ export function DcmCrudTabLayout({
sorting: true,
padding: 'default',
toolbar: false,
+ /** Avoid blank rows padding the table to `pageSize` when fewer rows exist. */
+ emptyRowsWhenPaging: false,
}}
totalCount={filtered.length}
page={page}
diff --git a/workspaces/dcm/plugins/dcm/src/components/DcmEntitiesTable.tsx b/workspaces/dcm/plugins/dcm/src/components/DcmEntitiesTable.tsx
index c7c3eb7928e..c7d098bf4e2 100644
--- a/workspaces/dcm/plugins/dcm/src/components/DcmEntitiesTable.tsx
+++ b/workspaces/dcm/plugins/dcm/src/components/DcmEntitiesTable.tsx
@@ -14,10 +14,13 @@
* limitations under the License.
*/
-import { useMemo, useState } from 'react';
-import { Link, TableColumn } from '@backstage/core-components';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import { InfoCard, Link, Table, TableColumn } from '@backstage/core-components';
import { Box, IconButton, Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
+import { usePersistedPageSize } from '../hooks/usePersistedPageSize';
+import { useDcmStyles } from './dcmStyles';
+import { DcmRequestHistoryFilter as DcmTableFilterField } from './DcmRequestHistoryTable';
import {
DCM_ENTITY_STATUS,
displayDcmEntityStatus,
@@ -185,3 +188,94 @@ export const DCM_ENTITY_TABLE_COLUMNS: TableColumn[] = [
/** Text filter used in entity detail tables (shared implementation with request history). */
export { DcmRequestHistoryFilter as DcmTableFilterField } from './DcmRequestHistoryTable';
+
+export type DcmEntitiesCardProps = Readonly<{
+ /** Rows already pre-filtered to the parent entity (environment or spec). */
+ allEntities: DcmEntityRow[];
+ /** localStorage key for persisting the chosen page size. */
+ storageKey: string;
+ /**
+ * When this value changes (e.g. navigating to a different environment) the
+ * current page resets to 0 so the user is not left on a non-existent page.
+ */
+ resetKey?: string | number;
+}>;
+
+/**
+ * Shared paginated entity table with filter and persistent page-size, used by
+ * both the environment-details and service-spec-details entity tabs.
+ */
+export function DcmEntitiesCard({
+ allEntities,
+ storageKey,
+ resetKey,
+}: DcmEntitiesCardProps) {
+ const classes = useDcmStyles();
+
+ const { filter, setFilter, filteredEntities, entityRowCount } =
+ useDcmEntityListState(allEntities);
+
+ const [page, setPage] = useState(0);
+ const [pageSize, setPageSize] = usePersistedPageSize(storageKey);
+
+ useEffect(() => {
+ setPage(0);
+ }, [filter, resetKey]);
+
+ const paginatedEntities = useMemo(() => {
+ const start = page * pageSize;
+ return filteredEntities.slice(start, start + pageSize);
+ }, [filteredEntities, page, pageSize]);
+
+ const handlePageChange = useCallback(
+ (newPage: number, newPageSize: number) => {
+ setPage(newPage);
+ setPageSize(newPageSize);
+ },
+ [setPageSize],
+ );
+
+ const handleRowsPerPageChange = useCallback(
+ (newPageSize: number) => {
+ setPageSize(newPageSize);
+ setPage(0);
+ },
+ [setPageSize],
+ );
+
+ return (
+
+ }
+ className={classes.tableCard}
+ >
+
+
+ data={paginatedEntities}
+ columns={DCM_ENTITY_TABLE_COLUMNS}
+ options={{
+ paging: true,
+ pageSize,
+ pageSizeOptions: [5, 10, 25, 50],
+ search: false,
+ sorting: true,
+ padding: 'default',
+ toolbar: false,
+ emptyRowsWhenPaging: false,
+ }}
+ totalCount={filteredEntities.length}
+ page={page}
+ onPageChange={handlePageChange}
+ onRowsPerPageChange={handleRowsPerPageChange}
+ localization={{ pagination: { labelRowsPerPage: 'rows' } }}
+ />
+
+
+ );
+}
diff --git a/workspaces/dcm/plugins/dcm/src/components/DcmRequestHistoryTable.tsx b/workspaces/dcm/plugins/dcm/src/components/DcmRequestHistoryTable.tsx
index 031900b2197..df415101284 100644
--- a/workspaces/dcm/plugins/dcm/src/components/DcmRequestHistoryTable.tsx
+++ b/workspaces/dcm/plugins/dcm/src/components/DcmRequestHistoryTable.tsx
@@ -21,6 +21,7 @@ import {
type Dispatch,
type SetStateAction,
} from 'react';
+import { usePersistedPageSize } from '../hooks/usePersistedPageSize';
import { InfoCard, Link, Table, TableColumn } from '@backstage/core-components';
import {
Box,
@@ -90,7 +91,7 @@ export function useDcmRequestHistoryListState(
) {
const [filter, setFilter] = useState('');
const [page, setPage] = useState(0);
- const [pageSize, setPageSize] = useState(5);
+ const [pageSize, setPageSize] = usePersistedPageSize('request-history');
const filteredHistory = useMemo(() => {
if (!filter.trim()) return allRows;
@@ -112,10 +113,13 @@ export function useDcmRequestHistoryListState(
const handlePageChange = useCallback((newPage: number) => {
setPage(newPage);
}, []);
- const handleRowsPerPageChange = useCallback((newPageSize: number) => {
- setPageSize(newPageSize);
- setPage(0);
- }, []);
+ const handleRowsPerPageChange = useCallback(
+ (newPageSize: number) => {
+ setPageSize(newPageSize);
+ setPage(0);
+ },
+ [setPageSize],
+ );
return {
filter,
@@ -284,6 +288,7 @@ export function DcmRequestHistoryTableCard(
sorting: true,
padding: 'default',
toolbar: false,
+ emptyRowsWhenPaging: false,
}}
totalCount={filteredHistory.length}
page={page}
diff --git a/workspaces/dcm/plugins/dcm/src/components/DcmSuccessSnackbar.tsx b/workspaces/dcm/plugins/dcm/src/components/DcmSuccessSnackbar.tsx
new file mode 100644
index 00000000000..53319f0013c
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm/src/components/DcmSuccessSnackbar.tsx
@@ -0,0 +1,52 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * 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 { Snackbar } from '@material-ui/core';
+import MuiAlert from '@material-ui/lab/Alert';
+
+export type DcmSuccessSnackbarProps = Readonly<{
+ /** The message to display, or null/undefined when hidden. */
+ message: string | null | undefined;
+ onClose: () => void;
+ autoHideDuration?: number;
+}>;
+
+/**
+ * Displays a transient success notification at the bottom-center of the screen.
+ */
+export function DcmSuccessSnackbar({
+ message,
+ onClose,
+ autoHideDuration = 6000,
+}: DcmSuccessSnackbarProps) {
+ return (
+
+
+ {message}
+
+
+ );
+}
diff --git a/workspaces/dcm/plugins/dcm/src/components/dcmTabListHelpers.tsx b/workspaces/dcm/plugins/dcm/src/components/dcmTabListHelpers.tsx
index 620b58e6411..753651515f0 100644
--- a/workspaces/dcm/plugins/dcm/src/components/dcmTabListHelpers.tsx
+++ b/workspaces/dcm/plugins/dcm/src/components/dcmTabListHelpers.tsx
@@ -15,7 +15,7 @@
*/
import type { Dispatch, SetStateAction } from 'react';
-import type { TableColumn } from '@backstage/core-components';
+import { InfoCard, Table, type TableColumn } from '@backstage/core-components';
import {
Box,
IconButton,
@@ -24,6 +24,7 @@ import {
Tooltip,
} from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
+import { useDcmStyles } from './dcmStyles';
import CloseIcon from '@material-ui/icons/Close';
import DeleteIcon from '@material-ui/icons/Delete';
import EditIcon from '@material-ui/icons/Edit';
@@ -99,6 +100,85 @@ function ActionsCell({ onEdit, onDelete }: ActionsCellProps) {
);
}
+export type DcmSearchTableCardProps = Readonly<{
+ title: string;
+ /** Already-paginated rows to render. */
+ data: T[];
+ columns: TableColumn[];
+ /** Total rows after filtering (drives the pagination footer). */
+ totalCount: number;
+ page: number;
+ pageSize: number;
+ setPage: Dispatch>;
+ setPageSize: Dispatch>;
+ search: string;
+ setSearch: Dispatch>;
+ pageSizeOptions?: number[];
+}>;
+
+/**
+ * Shared InfoCard + Table layout used by read-only data-center tabs (service
+ * types, resources, …). Handles the search action, pagination wiring, and
+ * all the standard table options so individual tabs only provide data & columns.
+ */
+export function DcmSearchTableCard({
+ title,
+ data,
+ columns,
+ totalCount,
+ page,
+ pageSize,
+ setPage,
+ setPageSize,
+ search,
+ setSearch,
+ pageSizeOptions = [5, 10, 25],
+}: DcmSearchTableCardProps) {
+ const classes = useDcmStyles();
+ return (
+
+ }
+ className={classes.dataCard}
+ titleTypographyProps={{ className: classes.cardTitle }}
+ >
+
+
+ data={data}
+ columns={columns}
+ options={{
+ paging: true,
+ pageSize,
+ pageSizeOptions,
+ search: false,
+ sorting: true,
+ padding: 'default',
+ toolbar: false,
+ emptyRowsWhenPaging: false,
+ }}
+ totalCount={totalCount}
+ page={page}
+ onPageChange={(p, ps) => {
+ setPage(p);
+ setPageSize(ps);
+ }}
+ onRowsPerPageChange={ps => {
+ setPageSize(ps);
+ setPage(0);
+ }}
+ localization={{ pagination: { labelRowsPerPage: 'rows' } }}
+ />
+
+
+ );
+}
+
export function createEditDeleteColumn(props: {
onEdit: (row: T) => void;
onDelete: (row: T) => void;
diff --git a/workspaces/dcm/plugins/dcm/src/hooks/useCrudTab.ts b/workspaces/dcm/plugins/dcm/src/hooks/useCrudTab.ts
index 062c032c978..d510d817abf 100644
--- a/workspaces/dcm/plugins/dcm/src/hooks/useCrudTab.ts
+++ b/workspaces/dcm/plugins/dcm/src/hooks/useCrudTab.ts
@@ -16,6 +16,7 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { extractApiError } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
+import { usePersistedPageSize } from './usePersistedPageSize';
// Module-level state-updater factories — defined outside the hook so they do
// not contribute to lexical function-nesting depth (typescript:S2004).
@@ -83,6 +84,12 @@ export interface UseCrudTabOptions> {
* Required when updateFn is provided.
*/
itemToForm?: (item: T) => F;
+ /**
+ * When provided, the selected page-size is persisted to `localStorage` under
+ * `dcm:pageSize:` so the user's preference survives refreshes.
+ * Each table should use a unique key (e.g. `'providers'`, `'policies'`).
+ */
+ storageKey?: string;
}
type TouchedMap = Partial>;
@@ -179,7 +186,9 @@ export function useCrudTab>(
// ── Search + pagination ──────────────────────────────────────────────────
const [search, setSearch] = useState('');
const [page, setPage] = useState(0);
- const [pageSize, setPageSize] = useState(5);
+ const [pageSize, setPageSize] = usePersistedPageSize(
+ options.storageKey ?? '',
+ );
// ── Create dialog ────────────────────────────────────────────────────────
const [createOpen, setCreateOpen] = useState(false);
@@ -251,15 +260,21 @@ export function useCrudTab>(
return filtered.slice(start, start + pageSize);
}, [filtered, page, pageSize]);
- const onPageChange = useCallback((p: number, ps: number) => {
- setPage(p);
- setPageSize(ps);
- }, []);
-
- const onRowsPerPageChange = useCallback((ps: number) => {
- setPageSize(ps);
- setPage(0);
- }, []);
+ const onPageChange = useCallback(
+ (p: number, ps: number) => {
+ setPage(p);
+ setPageSize(ps);
+ },
+ [setPageSize],
+ );
+
+ const onRowsPerPageChange = useCallback(
+ (ps: number) => {
+ setPageSize(ps);
+ setPage(0);
+ },
+ [setPageSize],
+ );
// ── Create ───────────────────────────────────────────────────────────────
const handleOpenCreate = useCallback(() => {
diff --git a/workspaces/dcm/plugins/dcm/src/hooks/usePersistedPageSize.ts b/workspaces/dcm/plugins/dcm/src/hooks/usePersistedPageSize.ts
new file mode 100644
index 00000000000..b8527f5a51e
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm/src/hooks/usePersistedPageSize.ts
@@ -0,0 +1,63 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * 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 { useEffect, useState } from 'react';
+
+const KEY_PREFIX = 'dcm:pageSize:';
+
+function readStored(key: string, defaultSize: number): number {
+ try {
+ const raw = localStorage.getItem(key);
+ if (raw !== null) {
+ const parsed = Number.parseInt(raw, 10);
+ if (!Number.isNaN(parsed) && parsed > 0) return parsed;
+ }
+ } catch {
+ // localStorage may be unavailable (e.g. private-browsing restrictions)
+ }
+ return defaultSize;
+}
+
+/**
+ * Behaves like `useState(defaultSize)` but persists the chosen page-size to
+ * `localStorage` under `dcm:pageSize:` so the user's preference
+ * survives page refreshes and navigation.
+ *
+ * When `storageKey` is an empty string no persistence is applied and the hook
+ * falls back to a plain in-memory default.
+ */
+export function usePersistedPageSize(
+ storageKey: string,
+ defaultSize = 5,
+): [number, React.Dispatch>] {
+ const fullKey = storageKey ? `${KEY_PREFIX}${storageKey}` : '';
+
+ const [pageSize, setPageSize] = useState(() =>
+ fullKey ? readStored(fullKey, defaultSize) : defaultSize,
+ );
+
+ useEffect(() => {
+ if (fullKey) {
+ try {
+ localStorage.setItem(fullKey, String(pageSize));
+ } catch {
+ // Ignore write failures silently
+ }
+ }
+ }, [fullKey, pageSize]);
+
+ return [pageSize, setPageSize];
+}
diff --git a/workspaces/dcm/plugins/dcm/src/index.ts b/workspaces/dcm/plugins/dcm/src/index.ts
index aef3b93c8af..0d6b83d6656 100644
--- a/workspaces/dcm/plugins/dcm/src/index.ts
+++ b/workspaces/dcm/plugins/dcm/src/index.ts
@@ -17,9 +17,9 @@ export { Router } from './Router';
export { dcmPlugin, DcmPage } from './plugin';
export {
catalogApiRef,
- placementApiRef,
policyManagerApiRef,
providersApiRef,
+ resourcesApiRef,
} from './apis';
export { isDarkMode, useIsDarkMode } from './components/dcmTheme';
export { RhdhLogoFull } from './components/RhdhLogoFull';
diff --git a/workspaces/dcm/plugins/dcm/src/pages/catalog-item-instances/CatalogItemInstancesTabContent.tsx b/workspaces/dcm/plugins/dcm/src/pages/catalog-item-instances/CatalogItemInstancesTabContent.tsx
index cf1448497d5..ff1c72c9e28 100644
--- a/workspaces/dcm/plugins/dcm/src/pages/catalog-item-instances/CatalogItemInstancesTabContent.tsx
+++ b/workspaces/dcm/plugins/dcm/src/pages/catalog-item-instances/CatalogItemInstancesTabContent.tsx
@@ -17,26 +17,20 @@
import { useCallback, useMemo, useState } from 'react';
import { TableColumn } from '@backstage/core-components';
import { useApi } from '@backstage/core-plugin-api';
-import { Chip, IconButton, Tooltip, Typography } from '@material-ui/core';
+import { Box, Chip, IconButton, Tooltip, Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
-
-const useStyles = makeStyles(() => ({
- catalogItemChip: {
- maxWidth: 180,
- },
- apiVersionChip: {
- maxWidth: 140,
- },
-}));
+import AutorenewIcon from '@material-ui/icons/Autorenew';
import DeleteIcon from '@material-ui/icons/Delete';
import type {
CatalogItem,
CatalogItemInstance,
} from '@red-hat-developer-hub/backstage-plugin-dcm-common';
+import { extractApiError } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
import { catalogApiRef } from '../../apis';
import { DcmCrudTabLayout } from '../../components/DcmCrudTabLayout';
import { DcmDeleteDialog } from '../../components/DcmDeleteDialog';
import { DcmErrorSnackbar } from '../../components/DcmErrorSnackbar';
+import { DcmSuccessSnackbar } from '../../components/DcmSuccessSnackbar';
import { DcmFormDialog } from '../../components/DcmFormDialog';
import { DcmFormDialogActions } from '../../components/DcmFormDialogActions';
import { DcmEmptyCell, TruncatedText } from '../../components/TruncatedText';
@@ -50,11 +44,33 @@ import {
} from './instanceFormTypes';
import type { InstanceForm } from './instanceFormTypes';
+const useStyles = makeStyles(() => ({
+ catalogItemChip: {
+ maxWidth: 180,
+ },
+ apiVersionChip: {
+ maxWidth: 140,
+ },
+ actionsCell: {
+ display: 'flex',
+ alignItems: 'center',
+ flexWrap: 'nowrap',
+ gap: 4,
+ },
+ /** Lets Tooltip wrap disabled IconButton (ref + layout) without raw ``. */
+ tooltipTrigger: {
+ display: 'inline-flex',
+ },
+}));
+
export function CatalogItemInstancesTabContent() {
const classes = useStyles();
const catalogApi = useApi(catalogApiRef);
const [catalogItems, setCatalogItems] = useState([]);
+ const [rehydratingId, setRehydratingId] = useState(null);
+ const [rehydrateError, setRehydrateError] = useState(null);
+ const [successMessage, setSuccessMessage] = useState(null);
const crud = useCrudTab({
loadFn: async () => {
@@ -77,9 +93,30 @@ export function CatalogItemInstancesTabContent() {
],
emptyForm: emptyInstanceForm,
isValid: isInstanceFormValid,
+ storageKey: 'catalog-item-instances',
});
- const { handleOpenDelete } = crud;
+ const { handleOpenDelete, setItems } = crud;
+
+ const handleRehydrate = useCallback(
+ async (inst: CatalogItemInstance) => {
+ const id = inst.uid ?? '';
+ if (!id) return;
+ setRehydratingId(id);
+ setRehydrateError(null);
+ setSuccessMessage(null);
+ try {
+ const updated = await catalogApi.rehydrateCatalogItemInstance(id);
+ setItems(prev => prev.map(row => (row.uid === id ? updated : row)));
+ setSuccessMessage('Catalog item instance rehydrated successfully.');
+ } catch (err) {
+ setRehydrateError(extractApiError(err));
+ } finally {
+ setRehydratingId(null);
+ }
+ },
+ [catalogApi, setItems],
+ );
const catalogItemName = useCallback(
(id: string) => {
@@ -159,21 +196,55 @@ export function CatalogItemInstancesTabContent() {
title: 'Actions',
field: 'actions',
sorting: false,
- width: '80px',
- render: inst => (
-
- handleOpenDelete(inst)}
- >
-
-
-
- ),
+ width: '120px',
+ render: inst => {
+ const busy = rehydratingId === inst.uid;
+ return (
+
+
+
+ handleRehydrate(inst)}
+ >
+
+
+
+
+
+
+ handleOpenDelete(inst)}
+ >
+
+
+
+
+
+ );
+ },
},
],
- [classes, handleOpenDelete, catalogItemName],
+ [
+ classes,
+ handleOpenDelete,
+ handleRehydrate,
+ catalogItemName,
+ rehydratingId,
+ ],
);
type ScalarTouched = Partial<
@@ -248,6 +319,16 @@ export function CatalogItemInstancesTabContent() {
error={crud.deleteError}
onClose={() => crud.setDeleteError(null)}
/>
+
+ setRehydrateError(null)}
+ />
+
+ setSuccessMessage(null)}
+ />
>
);
}
diff --git a/workspaces/dcm/plugins/dcm/src/pages/catalog-items/CatalogItemsTabContent.tsx b/workspaces/dcm/plugins/dcm/src/pages/catalog-items/CatalogItemsTabContent.tsx
index e1a43b82a7b..079313af729 100644
--- a/workspaces/dcm/plugins/dcm/src/pages/catalog-items/CatalogItemsTabContent.tsx
+++ b/workspaces/dcm/plugins/dcm/src/pages/catalog-items/CatalogItemsTabContent.tsx
@@ -123,6 +123,7 @@ export function CatalogItemsTabContent() {
emptyForm: emptyCatalogItemForm,
isValid: isCatalogItemFormValid,
itemToForm: catalogItemToForm,
+ storageKey: 'catalog-items',
});
const columns = useMemo[]>(
diff --git a/workspaces/dcm/plugins/dcm/src/pages/data-center/EnvironmentsTabContent.tsx b/workspaces/dcm/plugins/dcm/src/pages/data-center/EnvironmentsTabContent.tsx
index 8e441b057c5..4437a4b08b0 100644
--- a/workspaces/dcm/plugins/dcm/src/pages/data-center/EnvironmentsTabContent.tsx
+++ b/workspaces/dcm/plugins/dcm/src/pages/data-center/EnvironmentsTabContent.tsx
@@ -16,6 +16,7 @@
// Migrate to use useCrudTab + DcmCrudTabLayout when it is re-activated.
import { useMemo, useState, useCallback, useEffect } from 'react';
+import { usePersistedPageSize } from '../../hooks/usePersistedPageSize';
import {
Table,
TableColumn,
@@ -122,7 +123,7 @@ export function EnvironmentsTabContent() {
const [loading, setLoading] = useState(true);
const [search, setSearch] = useState('');
const [page, setPage] = useState(0);
- const [pageSize, setPageSize] = useState(5);
+ const [pageSize, setPageSize] = usePersistedPageSize('environments');
const [registerModalOpen, setRegisterModalOpen] = useState(false);
useEffect(() => {
@@ -282,13 +283,16 @@ export function EnvironmentsTabContent() {
setPage(newPage);
setPageSize(newPageSize);
},
- [],
+ [setPageSize],
);
- const handleRowsPerPageChange = useCallback((newPageSize: number) => {
- setPageSize(newPageSize);
- setPage(0);
- }, []);
+ const handleRowsPerPageChange = useCallback(
+ (newPageSize: number) => {
+ setPageSize(newPageSize);
+ setPage(0);
+ },
+ [setPageSize],
+ );
const { underlineLink } = classes;
@@ -407,6 +411,7 @@ export function EnvironmentsTabContent() {
sorting: true,
padding: 'default',
toolbar: false,
+ emptyRowsWhenPaging: false,
}}
totalCount={filteredEnvironments.length}
page={page}
diff --git a/workspaces/dcm/plugins/dcm/src/pages/environment-details/components/EntitiesTab.tsx b/workspaces/dcm/plugins/dcm/src/pages/environment-details/components/EntitiesTab.tsx
index c0ef09c4435..33080048ac9 100644
--- a/workspaces/dcm/plugins/dcm/src/pages/environment-details/components/EntitiesTab.tsx
+++ b/workspaces/dcm/plugins/dcm/src/pages/environment-details/components/EntitiesTab.tsx
@@ -14,94 +14,21 @@
* limitations under the License.
*/
-import { useCallback, useEffect, useMemo, useState } from 'react';
-import { InfoCard, Table } from '@backstage/core-components';
-import { Box } from '@material-ui/core';
-import {
- DCM_ENTITY_TABLE_COLUMNS,
- DcmTableFilterField,
- useDcmEntityListState,
-} from '../../../components/DcmEntitiesTable';
-import {
- MOCK_ENTITIES,
- type Environment,
- type EntityRow,
-} from '../../../data/environments';
-import { useDcmStyles } from '../../../components/dcmStyles';
+import { useMemo } from 'react';
+import { DcmEntitiesCard } from '../../../components/DcmEntitiesTable';
+import { MOCK_ENTITIES, type Environment } from '../../../data/environments';
export function EntitiesTab(props: Readonly<{ env: Environment }>) {
const { env } = props;
- const classes = useDcmStyles();
-
const allEntitiesForEnv = useMemo(
() => MOCK_ENTITIES.filter(e => e.envId === env.id),
[env.id],
);
-
- const { filter, setFilter, filteredEntities, entityRowCount } =
- useDcmEntityListState(allEntitiesForEnv);
-
- const [page, setPage] = useState(0);
- const [pageSize, setPageSize] = useState(5);
-
- useEffect(() => {
- setPage(0);
- }, [filter, env.id]);
-
- const paginatedEntities = useMemo(() => {
- const start = page * pageSize;
- return filteredEntities.slice(start, start + pageSize);
- }, [filteredEntities, page, pageSize]);
-
- const handlePageChange = useCallback(
- (newPage: number, newPageSize: number) => {
- setPage(newPage);
- setPageSize(newPageSize);
- },
- [],
- );
-
- const handleRowsPerPageChange = useCallback((newPageSize: number) => {
- setPageSize(newPageSize);
- setPage(0);
- }, []);
-
return (
-
- }
- className={classes.tableCard}
- >
-
-
- data={paginatedEntities}
- columns={DCM_ENTITY_TABLE_COLUMNS}
- options={{
- paging: true,
- pageSize,
- pageSizeOptions: [5, 10, 25, 50],
- search: false,
- sorting: true,
- padding: 'default',
- toolbar: false,
- }}
- totalCount={filteredEntities.length}
- page={page}
- onPageChange={handlePageChange}
- onRowsPerPageChange={handleRowsPerPageChange}
- localization={{
- pagination: {
- labelRowsPerPage: 'rows',
- },
- }}
- />
-
-
+
);
}
diff --git a/workspaces/dcm/plugins/dcm/src/pages/policies/PoliciesTabContent.tsx b/workspaces/dcm/plugins/dcm/src/pages/policies/PoliciesTabContent.tsx
index 7fd07d8e795..be7c67f1f1c 100644
--- a/workspaces/dcm/plugins/dcm/src/pages/policies/PoliciesTabContent.tsx
+++ b/workspaces/dcm/plugins/dcm/src/pages/policies/PoliciesTabContent.tsx
@@ -106,6 +106,7 @@ export function PoliciesTabContent() {
emptyForm: emptyPolicyForm,
isValid: isPolicyFormValid,
itemToForm: policyToForm,
+ storageKey: 'policies',
});
const { setItems, handleOpenEdit, handleOpenDelete } = crud;
@@ -209,7 +210,11 @@ export function PoliciesTabContent() {
title={isEnabled ? 'Disable policy' : 'Enable policy'}
placement="top"
>
-
+
{isToggling ? (
)}
-
+
[]>(
diff --git a/workspaces/dcm/plugins/dcm/src/pages/resources/ResourcesTabContent.tsx b/workspaces/dcm/plugins/dcm/src/pages/resources/ResourcesTabContent.tsx
index 6f337751dfa..264846322d1 100644
--- a/workspaces/dcm/plugins/dcm/src/pages/resources/ResourcesTabContent.tsx
+++ b/workspaces/dcm/plugins/dcm/src/pages/resources/ResourcesTabContent.tsx
@@ -14,248 +14,173 @@
* limitations under the License.
*/
-import { useMemo, useState } from 'react';
-import { TableColumn } from '@backstage/core-components';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import { TableColumn, Progress } from '@backstage/core-components';
import { useApi } from '@backstage/core-plugin-api';
-import { Box, Chip, IconButton, Tooltip, Typography } from '@material-ui/core';
-import { makeStyles } from '@material-ui/core/styles';
-
-const useStyles = makeStyles(() => ({
- nameCellBox: {
- minWidth: 0,
- },
-}));
-import DeleteIcon from '@material-ui/icons/Delete';
-import type {
- CatalogItemInstance,
- Resource,
-} from '@red-hat-developer-hub/backstage-plugin-dcm-common';
-import { catalogApiRef, placementApiRef } from '../../apis';
-import { DcmCrudTabLayout } from '../../components/DcmCrudTabLayout';
-import { DcmDeleteDialog } from '../../components/DcmDeleteDialog';
-import { DcmErrorSnackbar } from '../../components/DcmErrorSnackbar';
-import { DcmFormDialog } from '../../components/DcmFormDialog';
-import { DcmFormDialogActions } from '../../components/DcmFormDialogActions';
-import { DcmEmptyCell, TruncatedText } from '../../components/TruncatedText';
-import { useCrudTab } from '../../hooks/useCrudTab';
+import { Box, Button, Chip, Typography } from '@material-ui/core';
+import MuiAlert from '@material-ui/lab/Alert';
+import type { ServiceTypeInstance } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
+import { resourcesApiRef } from '../../apis';
+import { extractApiError } from '../../utils/extractApiError';
+import { DcmSearchTableCard } from '../../components/dcmTabListHelpers';
+import { useDcmStyles } from '../../components/dcmStyles';
import emptyIllustration from '../../assets/environments-empty-state.png';
-import { ResourceFormFields } from './components/ResourceFormFields';
-import {
- emptyResourceForm,
- formToResource,
- isResourceFormValid,
-} from './resourceFormTypes';
-import type { ResourceForm } from './resourceFormTypes';
+import { DcmDataCenterTabEmptyState } from '../../components/DcmDataCenterTabEmptyState';
+import { DcmEmptyCell, TruncatedText } from '../../components/TruncatedText';
+import { usePersistedPageSize } from '../../hooks/usePersistedPageSize';
export function ResourcesTabContent() {
- const classes = useStyles();
- const placementApi = useApi(placementApiRef);
- const catalogApi = useApi(catalogApiRef);
+ const classes = useDcmStyles();
+ const resourcesApi = useApi(resourcesApiRef);
- const [instances, setInstances] = useState([]);
+ const [instances, setInstances] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [loadError, setLoadError] = useState(null);
+ const [search, setSearch] = useState('');
+ const [page, setPage] = useState(0);
+ const [pageSize, setPageSize] = usePersistedPageSize('resources');
- const crud = useCrudTab({
- loadFn: async () => {
- const [resList, instList] = await Promise.all([
- placementApi.listResources(),
- catalogApi.listCatalogItemInstances(),
- ]);
- setInstances(instList.results ?? []);
- return resList.resources ?? [];
- },
- createFn: form => {
- const clientId = form.id.trim() || undefined;
- return placementApi.createResource(formToResource(form), clientId);
- },
- deleteFn: id => placementApi.deleteResource(id),
- getId: r => r.id ?? '',
- getSearchText: r => [
- r.id,
- r.catalog_item_instance_id,
- r.provider_name,
- r.approval_status,
- ],
- emptyForm: emptyResourceForm,
- isValid: isResourceFormValid,
- });
+ const load = useCallback(() => {
+ setLoading(true);
+ setLoadError(null);
+ resourcesApi
+ .listServiceTypeInstances()
+ .then(res => setInstances(res.instances ?? []))
+ .catch(err => setLoadError(extractApiError(err)))
+ .finally(() => setLoading(false));
+ }, [resourcesApi]);
- const instanceNameById = useMemo(() => {
- const map = new Map();
- instances.forEach(inst => {
- if (inst.uid) map.set(inst.uid, inst.display_name || inst.uid);
- });
- return map;
- }, [instances]);
+ useEffect(() => {
+ load();
+ }, [load]);
- const columns = useMemo[]>(
+ const filtered = useMemo(() => {
+ if (!search.trim()) return instances;
+ const q = search.toLowerCase();
+ return instances.filter(
+ inst =>
+ (inst.id ?? '').toLowerCase().includes(q) ||
+ (inst.spec?.service_type ?? '').toLowerCase().includes(q) ||
+ (inst.provider_name ?? '').toLowerCase().includes(q) ||
+ (inst.status ?? '').toLowerCase().includes(q),
+ );
+ }, [instances, search]);
+
+ const paginated = useMemo(() => {
+ const start = page * pageSize;
+ return filtered.slice(start, start + pageSize);
+ }, [filtered, page, pageSize]);
+
+ const columns = useMemo[]>(
() => [
{
- title: 'Resource ID',
+ title: 'ID',
field: 'id',
- render: r => (
-
- }
- />
- {r.path && (
- }
- />
- )}
-
- ),
- },
- {
- title: 'Catalog instance',
- field: 'catalog_item_instance_id',
- render: r => (
+ render: inst => (
}
/>
),
},
+ {
+ title: 'Service type',
+ field: 'spec.service_type',
+ render: inst =>
+ inst.spec?.service_type ? (
+
+ ) : (
+
+ ),
+ },
{
title: 'Provider',
field: 'provider_name',
- render: r => (
+ render: inst => (
}
/>
),
},
{
- title: 'Approval',
- field: 'approval_status',
- render: r =>
- r.approval_status ? (
-
+ title: 'Status',
+ field: 'status',
+ render: inst =>
+ inst.status ? (
+ {inst.status}
) : (
-
- —
-
+
),
},
{
title: 'Created',
field: 'create_time',
- render: r =>
- r.create_time ? (
+ render: inst =>
+ inst.create_time ? (
- {new Date(r.create_time).toLocaleDateString()}
+ {new Date(inst.create_time).toLocaleDateString()}
) : (
-
- —
-
+
),
},
- {
- title: 'Actions',
- field: 'actions',
- sorting: false,
- width: '80px',
- render: r => (
-
-
- crud.handleOpenDelete(r)}
- disabled={!r.id}
- >
-
-
-
-
- ),
- },
],
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [classes, crud.handleOpenDelete, instanceNameById],
+ [classes],
);
- return (
- <>
-
- items={crud.items}
- filtered={crud.filtered}
- paginated={crud.paginated}
- columns={columns}
- loading={crud.loading}
- loadError={crud.loadError}
- onRetry={crud.reload}
- search={crud.search}
- onSearchChange={crud.setSearch}
- page={crud.page}
- pageSize={crud.pageSize}
- onPageChange={crud.onPageChange}
- onRowsPerPageChange={crud.onRowsPerPageChange}
- emptyTitle="No resources provisioned"
- emptyDescription="Resources are created by the Placement Manager when a catalog item instance is submitted. Use the Create button to provision a new resource."
- primaryActionLabel="Create"
- onPrimaryAction={crud.handleOpenCreate}
- illustrationSrc={emptyIllustration}
- entityLabel="Resources"
- />
-
-
- }
- >
-
-
+ if (loading) return ;
-
+ if (loadError) {
+ return (
+
+
+ Retry
+
+ }
+ >
+ {loadError}
+
+
+ );
+ }
- crud.setDeleteError(null)}
- />
- >
+ return (
+
+ {instances.length === 0 ? (
+
+ ) : (
+
+ title={`Resources (${filtered.length})`}
+ data={paginated}
+ columns={columns}
+ totalCount={filtered.length}
+ page={page}
+ pageSize={pageSize}
+ setPage={setPage}
+ setPageSize={setPageSize}
+ search={search}
+ setSearch={setSearch}
+ />
+ )}
+
);
}
diff --git a/workspaces/dcm/plugins/dcm/src/pages/resources/components/ResourceFormFields.tsx b/workspaces/dcm/plugins/dcm/src/pages/resources/components/ResourceFormFields.tsx
deleted file mode 100644
index 8ad32f609c9..00000000000
--- a/workspaces/dcm/plugins/dcm/src/pages/resources/components/ResourceFormFields.tsx
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright Red Hat, Inc.
- *
- * 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 { useMemo, useRef } from 'react';
-import {
- Box,
- Button,
- FormControl,
- FormHelperText,
- InputLabel,
- MenuItem,
- OutlinedInput,
- Select,
- TextField,
- Tooltip,
-} from '@material-ui/core';
-import CloudUploadIcon from '@material-ui/icons/CloudUpload';
-import { makeStyles } from '@material-ui/core/styles';
-
-const useStyles = makeStyles(() => ({
- hiddenInput: {
- display: 'none',
- },
- monoInput: {
- fontFamily: 'monospace',
- fontSize: 13,
- },
-}));
-import type { CatalogItemInstance } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
-import { ResourceForm, validateResourceForm } from '../resourceFormTypes';
-
-type TouchedMap = Partial>;
-
-export type ResourceFormFieldsProps = Readonly<{
- form: ResourceForm;
- setForm: React.Dispatch>;
- touched: TouchedMap;
- setTouched: React.Dispatch>;
- instances: CatalogItemInstance[];
-}>;
-
-export function ResourceFormFields({
- form,
- setForm,
- touched,
- setTouched,
- instances,
-}: ResourceFormFieldsProps) {
- const classes = useStyles();
- const fileInputRef = useRef(null);
- const errors = useMemo(() => validateResourceForm(form), [form]);
-
- const set =
- (field: keyof ResourceForm) =>
- (e: React.ChangeEvent) => {
- setForm(prev => ({ ...prev, [field]: e.target.value }));
- setTouched(prev => ({ ...prev, [field]: true }));
- };
-
- const handleFileUpload = async (e: React.ChangeEvent) => {
- const file = e.target.files?.[0];
- if (!file) return;
- e.target.value = '';
- const text = await file.text();
- try {
- const parsed = JSON.parse(text);
- setForm(prev => ({ ...prev, spec: JSON.stringify(parsed, null, 2) }));
- } catch {
- setForm(prev => ({ ...prev, spec: text }));
- }
- setTouched(prev => ({ ...prev, spec: true }));
- };
-
- return (
-
-
- Catalog item instance *
-
- {touched.catalog_item_instance_id &&
- errors.catalog_item_instance_id && (
- {errors.catalog_item_instance_id}
- )}
-
-
- setTouched(prev => ({ ...prev, spec: true }))}
- fullWidth
- variant="outlined"
- multiline
- minRows={6}
- placeholder={'{\n "cpu": 2,\n "memory": "4Gi"\n}'}
- inputProps={{ className: classes.monoInput }}
- />
-
-
- }
- onClick={() => fileInputRef.current?.click()}
- >
- Upload Spec File
-
-
-
- setTouched(prev => ({ ...prev, id: true }))}
- fullWidth
- variant="outlined"
- size="small"
- placeholder="e.g. my-resource-01"
- />
-
- );
-}
diff --git a/workspaces/dcm/plugins/dcm/src/pages/resources/resourceFormTypes.test.ts b/workspaces/dcm/plugins/dcm/src/pages/resources/resourceFormTypes.test.ts
deleted file mode 100644
index 3acece96ad5..00000000000
--- a/workspaces/dcm/plugins/dcm/src/pages/resources/resourceFormTypes.test.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright Red Hat, Inc.
- *
- * 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 {
- emptyResourceForm,
- formToResource,
- isResourceFormValid,
- validateResourceForm,
-} from './resourceFormTypes';
-
-describe('validateResourceForm', () => {
- const valid = () => ({
- ...emptyResourceForm(),
- catalog_item_instance_id: 'inst-1',
- spec: '{"cpu":2}',
- });
-
- it('returns no errors for a valid form', () => {
- expect(validateResourceForm(valid())).toEqual({});
- });
-
- it('requires catalog_item_instance_id', () => {
- const errors = validateResourceForm({
- ...valid(),
- catalog_item_instance_id: '',
- });
- expect(errors.catalog_item_instance_id).toBeDefined();
- });
-
- it('requires spec to be valid non-empty JSON', () => {
- expect(validateResourceForm({ ...valid(), spec: '{}' }).spec).toBeDefined();
- expect(
- validateResourceForm({ ...valid(), spec: 'not-json' }).spec,
- ).toBeDefined();
- expect(
- validateResourceForm({ ...valid(), spec: '{"a":1}' }).spec,
- ).toBeUndefined();
- });
-
- it('validates the optional id pattern', () => {
- expect(
- validateResourceForm({ ...valid(), id: 'Valid-ID' }).id,
- ).toBeDefined();
- expect(
- validateResourceForm({ ...valid(), id: 'valid-id' }).id,
- ).toBeUndefined();
- expect(validateResourceForm({ ...valid(), id: '' }).id).toBeUndefined();
- });
-});
-
-describe('isResourceFormValid', () => {
- it('returns true for a valid form', () => {
- expect(
- isResourceFormValid({
- catalog_item_instance_id: 'inst-1',
- spec: '{"key":"value"}',
- id: '',
- }),
- ).toBe(true);
- });
-});
-
-describe('formToResource', () => {
- it('parses the spec JSON string into an object', () => {
- const resource = formToResource({
- catalog_item_instance_id: 'inst-1',
- spec: '{"cpu":4,"memory":"8Gi"}',
- id: '',
- });
- expect(resource.spec).toEqual({ cpu: 4, memory: '8Gi' });
- expect(resource.catalog_item_instance_id).toBe('inst-1');
- });
-});
diff --git a/workspaces/dcm/plugins/dcm/src/pages/resources/resourceFormTypes.ts b/workspaces/dcm/plugins/dcm/src/pages/resources/resourceFormTypes.ts
deleted file mode 100644
index 89a27b6212b..00000000000
--- a/workspaces/dcm/plugins/dcm/src/pages/resources/resourceFormTypes.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright Red Hat, Inc.
- *
- * 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 * as yup from 'yup';
-import type { Resource } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
-import { createYupValidator } from '../../utils/createYupValidator';
-
-export type ResourceForm = {
- catalog_item_instance_id: string;
- spec: string;
- /** Optional client-assigned ID (sent as a query parameter). */
- id: string;
-};
-
-const ID_PATTERN = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
-
-const resourceSchema = yup.object({
- catalog_item_instance_id: yup
- .string()
- .required('Catalog item instance is required'),
- spec: yup
- .string()
- .required('Spec is required')
- .test(
- 'valid-json',
- 'Must be valid JSON with at least one property',
- val => {
- try {
- const parsed = JSON.parse(val ?? '');
- return (
- typeof parsed === 'object' &&
- parsed !== null &&
- Object.keys(parsed).length > 0
- );
- } catch {
- return false;
- }
- },
- ),
- id: yup
- .string()
- .optional()
- .test(
- 'id-pattern',
- 'Must be 1\u201363 lowercase alphanumeric characters or hyphens, not starting or ending with a hyphen',
- val => !val || ID_PATTERN.test(val),
- ),
-});
-
-export const { validate: validateResourceForm, isValid: isResourceFormValid } =
- createYupValidator(resourceSchema);
-
-export function emptyResourceForm(): ResourceForm {
- return { catalog_item_instance_id: '', spec: '{}', id: '' };
-}
-
-export function formToResource(f: ResourceForm): Resource {
- return {
- catalog_item_instance_id: f.catalog_item_instance_id,
- spec: JSON.parse(f.spec) as Record,
- };
-}
diff --git a/workspaces/dcm/plugins/dcm/src/pages/service-spec-details/components/SpecEntitiesTab.tsx b/workspaces/dcm/plugins/dcm/src/pages/service-spec-details/components/SpecEntitiesTab.tsx
index 6eafb2be3dc..c1480c9861c 100644
--- a/workspaces/dcm/plugins/dcm/src/pages/service-spec-details/components/SpecEntitiesTab.tsx
+++ b/workspaces/dcm/plugins/dcm/src/pages/service-spec-details/components/SpecEntitiesTab.tsx
@@ -14,94 +14,24 @@
* limitations under the License.
*/
-import { useCallback, useEffect, useMemo, useState } from 'react';
-import { InfoCard, Table } from '@backstage/core-components';
-import { Box } from '@material-ui/core';
+import { useMemo } from 'react';
+import { DcmEntitiesCard } from '../../../components/DcmEntitiesTable';
import {
- DCM_ENTITY_TABLE_COLUMNS,
- DcmTableFilterField,
- useDcmEntityListState,
-} from '../../../components/DcmEntitiesTable';
-import type {
- ServiceSpec,
- ServiceSpecEntityRow,
+ MOCK_SERVICE_SPEC_ENTITIES,
+ type ServiceSpec,
} from '../../../data/service-specs';
-import { MOCK_SERVICE_SPEC_ENTITIES } from '../../../data/service-specs';
-import { useDcmStyles } from '../../../components/dcmStyles';
export function SpecEntitiesTab(props: Readonly<{ spec: ServiceSpec }>) {
const { spec } = props;
- const classes = useDcmStyles();
-
const allEntitiesForSpec = useMemo(
() => MOCK_SERVICE_SPEC_ENTITIES.filter(e => e.specId === spec.id),
[spec.id],
);
-
- const { filter, setFilter, filteredEntities, entityRowCount } =
- useDcmEntityListState(allEntitiesForSpec);
-
- const [page, setPage] = useState(0);
- const [pageSize, setPageSize] = useState(5);
-
- useEffect(() => {
- setPage(0);
- }, [filter, spec.id]);
-
- const paginatedEntities = useMemo(() => {
- const start = page * pageSize;
- return filteredEntities.slice(start, start + pageSize);
- }, [filteredEntities, page, pageSize]);
-
- const handlePageChange = useCallback(
- (newPage: number, newPageSize: number) => {
- setPage(newPage);
- setPageSize(newPageSize);
- },
- [],
- );
-
- const handleRowsPerPageChange = useCallback((newPageSize: number) => {
- setPageSize(newPageSize);
- setPage(0);
- }, []);
-
return (
-
- }
- className={classes.tableCard}
- >
-
-
- data={paginatedEntities}
- columns={DCM_ENTITY_TABLE_COLUMNS}
- options={{
- paging: true,
- pageSize,
- pageSizeOptions: [5, 10, 25, 50],
- search: false,
- sorting: true,
- padding: 'default',
- toolbar: false,
- }}
- totalCount={filteredEntities.length}
- page={page}
- onPageChange={handlePageChange}
- onRowsPerPageChange={handleRowsPerPageChange}
- localization={{
- pagination: {
- labelRowsPerPage: 'rows',
- },
- }}
- />
-
-
+
);
}
diff --git a/workspaces/dcm/plugins/dcm/src/pages/service-spec/ServiceSpecsTabContent.tsx b/workspaces/dcm/plugins/dcm/src/pages/service-spec/ServiceSpecsTabContent.tsx
index 6914a872dac..5e3a441c557 100644
--- a/workspaces/dcm/plugins/dcm/src/pages/service-spec/ServiceSpecsTabContent.tsx
+++ b/workspaces/dcm/plugins/dcm/src/pages/service-spec/ServiceSpecsTabContent.tsx
@@ -16,6 +16,7 @@
// Migrate to use useCrudTab + DcmCrudTabLayout when it is re-activated.
import { useMemo, useState, useCallback, useEffect } from 'react';
+import { usePersistedPageSize } from '../../hooks/usePersistedPageSize';
import {
Table,
TableColumn,
@@ -176,7 +177,7 @@ export const ServiceSpecsTabContent = () => {
const [loading, setLoading] = useState(true);
const [search, setSearch] = useState('');
const [page, setPage] = useState(0);
- const [pageSize, setPageSize] = useState(5);
+ const [pageSize, setPageSize] = usePersistedPageSize('service-specs');
const [createModalOpen, setCreateModalOpen] = useState(false);
useEffect(() => {
@@ -322,13 +323,16 @@ export const ServiceSpecsTabContent = () => {
setPage(newPage);
setPageSize(newPageSize);
},
- [],
+ [setPageSize],
);
- const handleRowsPerPageChange = useCallback((newPageSize: number) => {
- setPageSize(newPageSize);
- setPage(0);
- }, []);
+ const handleRowsPerPageChange = useCallback(
+ (newPageSize: number) => {
+ setPageSize(newPageSize);
+ setPage(0);
+ },
+ [setPageSize],
+ );
const { underlineLink } = classes;
@@ -470,6 +474,7 @@ export const ServiceSpecsTabContent = () => {
sorting: true,
padding: 'default',
toolbar: false,
+ emptyRowsWhenPaging: false,
}}
totalCount={filteredSpecs.length}
page={page}
diff --git a/workspaces/dcm/plugins/dcm/src/pages/service-types/ServiceTypesTabContent.tsx b/workspaces/dcm/plugins/dcm/src/pages/service-types/ServiceTypesTabContent.tsx
index 217903734cb..af53f548053 100644
--- a/workspaces/dcm/plugins/dcm/src/pages/service-types/ServiceTypesTabContent.tsx
+++ b/workspaces/dcm/plugins/dcm/src/pages/service-types/ServiceTypesTabContent.tsx
@@ -15,17 +15,13 @@
*/
import { useCallback, useEffect, useMemo, useState } from 'react';
-import {
- Table,
- TableColumn,
- InfoCard,
- Progress,
-} from '@backstage/core-components';
+import { usePersistedPageSize } from '../../hooks/usePersistedPageSize';
+import { TableColumn, Progress } from '@backstage/core-components';
import { useApi } from '@backstage/core-plugin-api';
import { Box, Chip, Typography } from '@material-ui/core';
import type { ServiceType } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
import { catalogApiRef } from '../../apis';
-import { DcmSearchCardAction } from '../../components/dcmTabListHelpers';
+import { DcmSearchTableCard } from '../../components/dcmTabListHelpers';
import { useDcmStyles } from '../../components/dcmStyles';
import emptyIllustration from '../../assets/environments-empty-state.png';
import { DcmDataCenterTabEmptyState } from '../../components/DcmDataCenterTabEmptyState';
@@ -41,7 +37,7 @@ export function ServiceTypesTabContent() {
const [loading, setLoading] = useState(true);
const [search, setSearch] = useState('');
const [page, setPage] = useState(0);
- const [pageSize, setPageSize] = useState(5);
+ const [pageSize, setPageSize] = usePersistedPageSize('service-types');
const load = useCallback(() => {
setLoading(true);
@@ -153,45 +149,18 @@ export function ServiceTypesTabContent() {
illustrationSrc={emptyIllustration}
/>
) : (
-
title={`Service types (${filtered.length})`}
- action={
-
- }
- className={classes.dataCard}
- titleTypographyProps={{ className: classes.cardTitle }}
- >
-
-
- data={paginated}
- columns={columns}
- options={{
- paging: true,
- pageSize,
- pageSizeOptions: [5, 10, 25],
- search: false,
- sorting: true,
- padding: 'default',
- toolbar: false,
- }}
- totalCount={filtered.length}
- page={page}
- onPageChange={(p, ps) => {
- setPage(p);
- setPageSize(ps);
- }}
- onRowsPerPageChange={ps => {
- setPageSize(ps);
- setPage(0);
- }}
- localization={{ pagination: { labelRowsPerPage: 'rows' } }}
- />
-
-
+ data={paginated}
+ columns={columns}
+ totalCount={filtered.length}
+ page={page}
+ pageSize={pageSize}
+ setPage={setPage}
+ setPageSize={setPageSize}
+ search={search}
+ setSearch={setSearch}
+ />
)}
);
diff --git a/workspaces/dcm/plugins/dcm/src/plugin.ts b/workspaces/dcm/plugins/dcm/src/plugin.ts
index e7bdc923921..56d913bf467 100644
--- a/workspaces/dcm/plugins/dcm/src/plugin.ts
+++ b/workspaces/dcm/plugins/dcm/src/plugin.ts
@@ -22,9 +22,9 @@ import {
} from '@backstage/core-plugin-api';
import {
CatalogClient,
- PlacementClient,
PolicyManagerClient,
ProvidersClient,
+ ResourcesClient,
} from '@red-hat-developer-hub/backstage-plugin-dcm-common';
import {
@@ -41,9 +41,9 @@ import {
} from './routes';
import {
catalogApiRef,
- placementApiRef,
policyManagerApiRef,
providersApiRef,
+ resourcesApiRef,
} from './apis';
/**
@@ -88,10 +88,10 @@ export const dcmPlugin = createPlugin({
},
}),
createApiFactory({
- api: placementApiRef,
+ api: resourcesApiRef,
deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },
factory({ discoveryApi, fetchApi }) {
- return new PlacementClient({ discoveryApi, fetchApi });
+ return new ResourcesClient({ discoveryApi, fetchApi });
},
}),
],
diff --git a/workspaces/dcm/yarn.lock b/workspaces/dcm/yarn.lock
index e3f339e55bf..344ff9b3779 100644
--- a/workspaces/dcm/yarn.lock
+++ b/workspaces/dcm/yarn.lock
@@ -1526,7 +1526,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.28.4, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
+"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.28.4, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.28.6
resolution: "@babel/runtime@npm:7.28.6"
checksum: 10/fbcd439cb74d4a681958eb064c509829e3f46d8a4bfaaf441baa81bb6733d1e680bccc676c813883d7741bcaada1d0d04b15aa320ef280b5734e2192b50decf9
@@ -1617,38 +1617,6 @@ __metadata:
languageName: node
linkType: hard
-"@backstage-community/plugin-rbac@npm:1.33.2":
- version: 1.33.2
- resolution: "@backstage-community/plugin-rbac@npm:1.33.2"
- dependencies:
- "@backstage-community/plugin-rbac-common": "npm:^1.12.2"
- "@backstage/catalog-model": "npm:^1.7.0"
- "@backstage/core-components": "npm:^0.15.1"
- "@backstage/core-plugin-api": "npm:^1.10.0"
- "@backstage/plugin-catalog": "npm:^1.24.0"
- "@backstage/plugin-catalog-common": "npm:^1.1.0"
- "@backstage/plugin-permission-common": "npm:^0.8.1"
- "@backstage/plugin-permission-react": "npm:^0.4.27"
- "@backstage/theme": "npm:^0.6.0"
- "@janus-idp/shared-react": "npm:^2.13.1"
- "@mui/icons-material": "npm:5.16.4"
- "@mui/material": "npm:^5.14.18"
- "@mui/styles": "npm:^6.1.7"
- "@rjsf/core": "npm:^5.21.2"
- "@rjsf/mui": "npm:^5.21.2"
- "@rjsf/utils": "npm:^5.21.2"
- "@rjsf/validator-ajv8": "npm:^5.21.2"
- autosuggest-highlight: "npm:^3.3.4"
- formik: "npm:^2.4.5"
- react-use: "npm:^17.4.0"
- yup: "npm:^1.3.2"
- peerDependencies:
- react: ^16.13.1 || ^17.0.0 || ^18.0.0
- react-router-dom: ^6.0.0
- checksum: 10/a5cede17430dc9f8160c08f3230e1112e26c50b8698e75a273741be81e504c3e9a375a5100860874d30cf59127b024626f0ec6033d72e7922ba7806f6b68a831
- languageName: node
- linkType: hard
-
"@backstage/app-defaults@npm:^1.5.16, @backstage/app-defaults@npm:^1.7.4":
version: 1.7.4
resolution: "@backstage/app-defaults@npm:1.7.4"
@@ -2505,112 +2473,6 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/core-components@npm:^0.15.1":
- version: 0.15.1
- resolution: "@backstage/core-components@npm:0.15.1"
- dependencies:
- "@backstage/config": "npm:^1.2.0"
- "@backstage/core-plugin-api": "npm:^1.10.0"
- "@backstage/errors": "npm:^1.2.4"
- "@backstage/theme": "npm:^0.6.0"
- "@backstage/version-bridge": "npm:^1.0.10"
- "@date-io/core": "npm:^1.3.13"
- "@material-table/core": "npm:^3.1.0"
- "@material-ui/core": "npm:^4.12.2"
- "@material-ui/icons": "npm:^4.9.1"
- "@material-ui/lab": "npm:4.0.0-alpha.61"
- "@react-hookz/web": "npm:^24.0.0"
- "@types/react-sparklines": "npm:^1.7.0"
- ansi-regex: "npm:^6.0.1"
- classnames: "npm:^2.2.6"
- d3-selection: "npm:^3.0.0"
- d3-shape: "npm:^3.0.0"
- d3-zoom: "npm:^3.0.0"
- dagre: "npm:^0.8.5"
- linkify-react: "npm:4.1.3"
- linkifyjs: "npm:4.1.3"
- lodash: "npm:^4.17.21"
- pluralize: "npm:^8.0.0"
- qs: "npm:^6.9.4"
- rc-progress: "npm:3.5.1"
- react-helmet: "npm:6.1.0"
- react-hook-form: "npm:^7.12.2"
- react-idle-timer: "npm:5.7.2"
- react-markdown: "npm:^8.0.0"
- react-sparklines: "npm:^1.7.0"
- react-syntax-highlighter: "npm:^15.4.5"
- react-use: "npm:^17.3.2"
- react-virtualized-auto-sizer: "npm:^1.0.11"
- react-window: "npm:^1.8.6"
- remark-gfm: "npm:^3.0.1"
- zen-observable: "npm:^0.10.0"
- zod: "npm:^3.22.4"
- peerDependencies:
- "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0
- react: ^16.13.1 || ^17.0.0 || ^18.0.0
- react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0
- react-router-dom: 6.0.0-beta.0 || ^6.3.0
- peerDependenciesMeta:
- "@types/react":
- optional: true
- checksum: 10/48c765a7219255b4f230af13b6ba3e78cf0b23f1642a8175b6fa2498b7655dec662ea356f92fbbd9d834b55f8923540f879c0529a0bff0772ebff676152a2275
- languageName: node
- linkType: hard
-
-"@backstage/core-components@npm:^0.16.3":
- version: 0.16.4
- resolution: "@backstage/core-components@npm:0.16.4"
- dependencies:
- "@backstage/config": "npm:^1.3.2"
- "@backstage/core-plugin-api": "npm:^1.10.4"
- "@backstage/errors": "npm:^1.2.7"
- "@backstage/theme": "npm:^0.6.4"
- "@backstage/version-bridge": "npm:^1.0.11"
- "@dagrejs/dagre": "npm:^1.1.4"
- "@date-io/core": "npm:^1.3.13"
- "@material-table/core": "npm:^3.1.0"
- "@material-ui/core": "npm:^4.12.2"
- "@material-ui/icons": "npm:^4.9.1"
- "@material-ui/lab": "npm:4.0.0-alpha.61"
- "@react-hookz/web": "npm:^24.0.0"
- "@testing-library/react": "npm:^16.0.0"
- "@types/react-sparklines": "npm:^1.7.0"
- ansi-regex: "npm:^6.0.1"
- classnames: "npm:^2.2.6"
- d3-selection: "npm:^3.0.0"
- d3-shape: "npm:^3.0.0"
- d3-zoom: "npm:^3.0.0"
- js-yaml: "npm:^4.1.0"
- linkify-react: "npm:4.1.3"
- linkifyjs: "npm:4.1.3"
- lodash: "npm:^4.17.21"
- pluralize: "npm:^8.0.0"
- qs: "npm:^6.9.4"
- rc-progress: "npm:3.5.1"
- react-helmet: "npm:6.1.0"
- react-hook-form: "npm:^7.12.2"
- react-idle-timer: "npm:5.7.2"
- react-markdown: "npm:^8.0.0"
- react-sparklines: "npm:^1.7.0"
- react-syntax-highlighter: "npm:^15.4.5"
- react-use: "npm:^17.3.2"
- react-virtualized-auto-sizer: "npm:^1.0.11"
- react-window: "npm:^1.8.6"
- remark-gfm: "npm:^3.0.1"
- zen-observable: "npm:^0.10.0"
- zod: "npm:^3.22.4"
- peerDependencies:
- "@types/react": ^17.0.0 || ^18.0.0
- react: ^17.0.0 || ^18.0.0
- react-dom: ^17.0.0 || ^18.0.0
- react-router-dom: ^6.3.0
- peerDependenciesMeta:
- "@types/react":
- optional: true
- checksum: 10/472f4a17edc740cec15041612068320114b0128d6917d6968db8b435c3f4c2f002be939978b29efb12ce32c3d660b28e9de051ac1104c14f4eae2b6129c5ab49
- languageName: node
- linkType: hard
-
"@backstage/core-components@npm:^0.17.1, @backstage/core-components@npm:^0.17.4, @backstage/core-components@npm:^0.17.5":
version: 0.17.5
resolution: "@backstage/core-components@npm:0.17.5"
@@ -2723,7 +2585,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/core-plugin-api@npm:^1.10.0, @backstage/core-plugin-api@npm:^1.10.3, @backstage/core-plugin-api@npm:^1.10.4, @backstage/core-plugin-api@npm:^1.10.6, @backstage/core-plugin-api@npm:^1.10.9, @backstage/core-plugin-api@npm:^1.11.0, @backstage/core-plugin-api@npm:^1.11.1, @backstage/core-plugin-api@npm:^1.12.1, @backstage/core-plugin-api@npm:^1.12.2":
+"@backstage/core-plugin-api@npm:^1.10.6, @backstage/core-plugin-api@npm:^1.10.9, @backstage/core-plugin-api@npm:^1.11.0, @backstage/core-plugin-api@npm:^1.11.1, @backstage/core-plugin-api@npm:^1.12.1, @backstage/core-plugin-api@npm:^1.12.2":
version: 1.12.2
resolution: "@backstage/core-plugin-api@npm:1.12.2"
dependencies:
@@ -3699,7 +3561,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/plugin-catalog-common@npm:^1.1.0, @backstage/plugin-catalog-common@npm:^1.1.3, @backstage/plugin-catalog-common@npm:^1.1.5, @backstage/plugin-catalog-common@npm:^1.1.7":
+"@backstage/plugin-catalog-common@npm:^1.1.3, @backstage/plugin-catalog-common@npm:^1.1.5, @backstage/plugin-catalog-common@npm:^1.1.7":
version: 1.1.7
resolution: "@backstage/plugin-catalog-common@npm:1.1.7"
dependencies:
@@ -3839,7 +3701,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/plugin-catalog@npm:^1.24.0, @backstage/plugin-catalog@npm:^1.26.1, @backstage/plugin-catalog@npm:^1.31.3":
+"@backstage/plugin-catalog@npm:^1.26.1, @backstage/plugin-catalog@npm:^1.31.3":
version: 1.32.2
resolution: "@backstage/plugin-catalog@npm:1.32.2"
dependencies:
@@ -3921,58 +3783,6 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/plugin-kubernetes-common@npm:^0.9.2, @backstage/plugin-kubernetes-common@npm:^0.9.9":
- version: 0.9.9
- resolution: "@backstage/plugin-kubernetes-common@npm:0.9.9"
- dependencies:
- "@backstage/catalog-model": "npm:^1.7.6"
- "@backstage/plugin-permission-common": "npm:^0.9.3"
- "@backstage/types": "npm:^1.2.2"
- "@kubernetes/client-node": "npm:1.4.0"
- kubernetes-models: "npm:^4.3.1"
- lodash: "npm:^4.17.21"
- luxon: "npm:^3.0.0"
- checksum: 10/30590e6cba4bfe792a5c06d651b5112ca4b6ef7d60dc4b278c8ab9fc057a805c5ff83a25a716e389486fc9141b200ea3a73559d92b34f1475c8544a7e5b7e3a3
- languageName: node
- linkType: hard
-
-"@backstage/plugin-kubernetes-react@npm:^0.5.3":
- version: 0.5.15
- resolution: "@backstage/plugin-kubernetes-react@npm:0.5.15"
- dependencies:
- "@backstage/catalog-model": "npm:^1.7.6"
- "@backstage/core-components": "npm:^0.18.5"
- "@backstage/core-plugin-api": "npm:^1.12.1"
- "@backstage/errors": "npm:^1.2.7"
- "@backstage/plugin-kubernetes-common": "npm:^0.9.9"
- "@backstage/types": "npm:^1.2.2"
- "@kubernetes-models/apimachinery": "npm:^2.0.0"
- "@kubernetes-models/base": "npm:^5.0.0"
- "@kubernetes/client-node": "npm:1.4.0"
- "@material-ui/core": "npm:^4.9.13"
- "@material-ui/icons": "npm:^4.11.3"
- "@material-ui/lab": "npm:^4.0.0-alpha.61"
- "@xterm/addon-attach": "npm:^0.11.0"
- "@xterm/addon-fit": "npm:^0.10.0"
- "@xterm/xterm": "npm:^5.5.0"
- cronstrue: "npm:^2.32.0"
- js-yaml: "npm:^4.1.0"
- kubernetes-models: "npm:^4.3.1"
- lodash: "npm:^4.17.21"
- luxon: "npm:^3.0.0"
- react-use: "npm:^17.4.0"
- peerDependencies:
- "@types/react": ^17.0.0 || ^18.0.0
- react: ^17.0.0 || ^18.0.0
- react-dom: ^17.0.0 || ^18.0.0
- react-router-dom: ^6.3.0
- peerDependenciesMeta:
- "@types/react":
- optional: true
- checksum: 10/aeda86a3f41bfd5e0d3a043e10b188e440078fe954e602e18b8a1d43b7da5168ab017545ce2de1217747ac7909ddce9f7acb27b243f4b00f7e5dfd24bc599c4b
- languageName: node
- linkType: hard
-
"@backstage/plugin-org@npm:^0.6.35":
version: 0.6.48
resolution: "@backstage/plugin-org@npm:0.6.48"
@@ -4110,7 +3920,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/plugin-permission-react@npm:^0.4.27, @backstage/plugin-permission-react@npm:^0.4.30, @backstage/plugin-permission-react@npm:^0.4.36, @backstage/plugin-permission-react@npm:^0.4.39":
+"@backstage/plugin-permission-react@npm:^0.4.30, @backstage/plugin-permission-react@npm:^0.4.36, @backstage/plugin-permission-react@npm:^0.4.39":
version: 0.4.39
resolution: "@backstage/plugin-permission-react@npm:0.4.39"
dependencies:
@@ -5045,7 +4855,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/theme@npm:^0.6.0, @backstage/theme@npm:^0.6.4, @backstage/theme@npm:^0.6.8":
+"@backstage/theme@npm:^0.6.8":
version: 0.6.8
resolution: "@backstage/theme@npm:0.6.8"
dependencies:
@@ -5113,7 +4923,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/version-bridge@npm:^1.0.10, @backstage/version-bridge@npm:^1.0.11":
+"@backstage/version-bridge@npm:^1.0.11":
version: 1.0.11
resolution: "@backstage/version-bridge@npm:1.0.11"
peerDependencies:
@@ -7021,31 +6831,6 @@ __metadata:
languageName: node
linkType: hard
-"@janus-idp/shared-react@npm:^2.13.1":
- version: 2.18.0
- resolution: "@janus-idp/shared-react@npm:2.18.0"
- dependencies:
- "@backstage/catalog-model": "npm:^1.7.3"
- "@backstage/core-components": "npm:^0.16.3"
- "@backstage/core-plugin-api": "npm:^1.10.3"
- "@backstage/plugin-kubernetes-common": "npm:^0.9.2"
- "@backstage/plugin-kubernetes-react": "npm:^0.5.3"
- "@kubernetes/client-node": "npm:1.0.0-rc7"
- "@material-ui/core": "npm:^4.12.4"
- "@mui/icons-material": "npm:5.15.17"
- "@mui/material": "npm:^5.15.17"
- classnames: "npm:^2.3.2"
- date-fns: "npm:^2.30.0"
- file-saver: "npm:^2.0.5"
- lodash: "npm:^4.17.21"
- mathjs: "npm:^11.11.2"
- react-use: "npm:^17.5.0"
- peerDependencies:
- react: ^16.13.1 || ^17.0.0 || ^18.0.0
- checksum: 10/1bbf14ac27c14483ea237ba6a6fb9f0b3e6f872d6af019e1e48e12e365e9a423f4b44b1007aeffc20082315d5b1294d136eabc14e09966f4f46b31ee116ef998
- languageName: node
- linkType: hard
-
"@jest/create-cache-key-function@npm:^30.0.0":
version: 30.2.0
resolution: "@jest/create-cache-key-function@npm:30.2.0"
@@ -7524,46 +7309,6 @@ __metadata:
languageName: node
linkType: hard
-"@kubernetes-models/apimachinery@npm:^2.0.0, @kubernetes-models/apimachinery@npm:^2.2.0":
- version: 2.2.0
- resolution: "@kubernetes-models/apimachinery@npm:2.2.0"
- dependencies:
- "@kubernetes-models/base": "npm:^5.0.1"
- "@kubernetes-models/validate": "npm:^4.0.0"
- "@swc/helpers": "npm:^0.5.8"
- checksum: 10/b266c6e82f570a048404a29255722e825a9b06eda27f70bd86dc0538afe8cd90861ce600f57c32b34a3e4eefd97fb93def6ab1143aa34e29f447f77474ac1cc6
- languageName: node
- linkType: hard
-
-"@kubernetes-models/base@npm:^5.0.0, @kubernetes-models/base@npm:^5.0.1":
- version: 5.0.1
- resolution: "@kubernetes-models/base@npm:5.0.1"
- dependencies:
- "@kubernetes-models/validate": "npm:^4.0.0"
- is-plain-object: "npm:^5.0.0"
- tslib: "npm:^2.4.0"
- checksum: 10/560de40c1c59cbfda18fac5191ebe096b0996b8cb6ec27898d8575b3249a9a7c1cd06950240b263b118ccdf54ee7ddffc4bb5936f0275a2e8fd6684d058eb345
- languageName: node
- linkType: hard
-
-"@kubernetes-models/validate@npm:^4.0.0":
- version: 4.0.0
- resolution: "@kubernetes-models/validate@npm:4.0.0"
- dependencies:
- ajv: "npm:^8.12.0"
- ajv-formats: "npm:^2.1.1"
- ajv-formats-draft2019: "npm:^1.6.1"
- ajv-i18n: "npm:^4.2.0"
- is-cidr: "npm:^4.0.0"
- re2-wasm: "npm:^1.0.2"
- tslib: "npm:^2.4.0"
- dependenciesMeta:
- re2-wasm:
- optional: true
- checksum: 10/948c86c1178710debd91756db9f92b3d1e5a706d1520d855b12bf9de378d8bab2e7c8f353ed1ec5271dff7175bb39202857216f0c047663e0809977bb34fde5d
- languageName: node
- linkType: hard
-
"@kubernetes/client-node@npm:0.20.0":
version: 0.20.0
resolution: "@kubernetes/client-node@npm:0.20.0"
@@ -7590,57 +7335,6 @@ __metadata:
languageName: node
linkType: hard
-"@kubernetes/client-node@npm:1.0.0-rc7":
- version: 1.0.0-rc7
- resolution: "@kubernetes/client-node@npm:1.0.0-rc7"
- dependencies:
- "@types/js-yaml": "npm:^4.0.1"
- "@types/node": "npm:^22.0.0"
- "@types/node-fetch": "npm:^2.6.9"
- "@types/stream-buffers": "npm:^3.0.3"
- "@types/tar": "npm:^6.1.1"
- "@types/ws": "npm:^8.5.4"
- form-data: "npm:^4.0.0"
- isomorphic-ws: "npm:^5.0.0"
- js-yaml: "npm:^4.1.0"
- jsonpath-plus: "npm:^10.0.0"
- node-fetch: "npm:^2.6.9"
- openid-client: "npm:^5.6.5"
- rfc4648: "npm:^1.3.0"
- stream-buffers: "npm:^3.0.2"
- tar: "npm:^7.0.0"
- tmp-promise: "npm:^3.0.2"
- tslib: "npm:^2.5.0"
- url-parse: "npm:^1.4.3"
- ws: "npm:^8.18.0"
- checksum: 10/dad4432c97d24410f3af293b64e3e261d3807d2e23d5b2e022e34d59b0fddd1e26087900695b13917941b40dda02dc6af3e04f08ffb3a6a28b1b23a8dc7543bb
- languageName: node
- linkType: hard
-
-"@kubernetes/client-node@npm:1.4.0":
- version: 1.4.0
- resolution: "@kubernetes/client-node@npm:1.4.0"
- dependencies:
- "@types/js-yaml": "npm:^4.0.1"
- "@types/node": "npm:^24.0.0"
- "@types/node-fetch": "npm:^2.6.13"
- "@types/stream-buffers": "npm:^3.0.3"
- form-data: "npm:^4.0.0"
- hpagent: "npm:^1.2.0"
- isomorphic-ws: "npm:^5.0.0"
- js-yaml: "npm:^4.1.0"
- jsonpath-plus: "npm:^10.3.0"
- node-fetch: "npm:^2.7.0"
- openid-client: "npm:^6.1.3"
- rfc4648: "npm:^1.3.0"
- socks-proxy-agent: "npm:^8.0.4"
- stream-buffers: "npm:^3.0.2"
- tar-fs: "npm:^3.0.9"
- ws: "npm:^8.18.2"
- checksum: 10/67237d327d44bc2b77dc68d44f03699e71ff85bc120b086565bab8446cf288a3da5132f7444bbfe971fbe1c1a544a1bc4c13bd7ffb7a745b3b810662017af8dd
- languageName: node
- linkType: hard
-
"@leichtgewicht/ip-codec@npm:^2.0.1":
version: 2.0.5
resolution: "@leichtgewicht/ip-codec@npm:2.0.5"
@@ -7765,7 +7459,7 @@ __metadata:
languageName: node
linkType: hard
-"@material-ui/icons@npm:^4.11.3, @material-ui/icons@npm:^4.9.1":
+"@material-ui/icons@npm:^4.9.1":
version: 4.11.3
resolution: "@material-ui/icons@npm:4.11.3"
dependencies:
@@ -8339,38 +8033,6 @@ __metadata:
languageName: node
linkType: hard
-"@mui/icons-material@npm:5.15.17":
- version: 5.15.17
- resolution: "@mui/icons-material@npm:5.15.17"
- dependencies:
- "@babel/runtime": "npm:^7.23.9"
- peerDependencies:
- "@mui/material": ^5.0.0
- "@types/react": ^17.0.0 || ^18.0.0
- react: ^17.0.0 || ^18.0.0
- peerDependenciesMeta:
- "@types/react":
- optional: true
- checksum: 10/fa7c33e1a47dbc85bf994e3b1c08dc0f504fd60a1b8bcee61c83c1b0fc126134eaff1b8acf894721c5ed8b4bbb48c4ba6b846e73a541314a72870990089c0426
- languageName: node
- linkType: hard
-
-"@mui/icons-material@npm:5.16.4":
- version: 5.16.4
- resolution: "@mui/icons-material@npm:5.16.4"
- dependencies:
- "@babel/runtime": "npm:^7.23.9"
- peerDependencies:
- "@mui/material": ^5.0.0
- "@types/react": ^17.0.0 || ^18.0.0
- react: ^17.0.0 || ^18.0.0
- peerDependenciesMeta:
- "@types/react":
- optional: true
- checksum: 10/6f163af896ad0c60d3c5c539d8a68b407c6bd1203184129a6b72d4b911ff8bc9a92448cfb6aaf5a23f46a810224e172321dfa37089f07a4d04dded4a87546d8e
- languageName: node
- linkType: hard
-
"@mui/icons-material@npm:^5.17.1":
version: 5.18.0
resolution: "@mui/icons-material@npm:5.18.0"
@@ -8387,7 +8049,7 @@ __metadata:
languageName: node
linkType: hard
-"@mui/material@npm:^5.12.2, @mui/material@npm:^5.14.18, @mui/material@npm:^5.15.17":
+"@mui/material@npm:^5.12.2":
version: 5.18.0
resolution: "@mui/material@npm:5.18.0"
dependencies:
@@ -8437,23 +8099,6 @@ __metadata:
languageName: node
linkType: hard
-"@mui/private-theming@npm:^6.4.9":
- version: 6.4.9
- resolution: "@mui/private-theming@npm:6.4.9"
- dependencies:
- "@babel/runtime": "npm:^7.26.0"
- "@mui/utils": "npm:^6.4.9"
- prop-types: "npm:^15.8.1"
- peerDependencies:
- "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
- react: ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- "@types/react":
- optional: true
- checksum: 10/d2e6b24001e82cb3a0c6115a54610ba0ee0abea64befe7fb5567fb8753fdc40b86eb77d399b1c014b1b8425c250f7bb3ee32171bb538f19bda5ce7a0d897a102
- languageName: node
- linkType: hard
-
"@mui/styled-engine@npm:^5.18.0":
version: 5.18.0
resolution: "@mui/styled-engine@npm:5.18.0"
@@ -8476,37 +8121,6 @@ __metadata:
languageName: node
linkType: hard
-"@mui/styles@npm:^6.1.7":
- version: 6.5.0
- resolution: "@mui/styles@npm:6.5.0"
- dependencies:
- "@babel/runtime": "npm:^7.26.0"
- "@emotion/hash": "npm:^0.9.2"
- "@mui/private-theming": "npm:^6.4.9"
- "@mui/types": "npm:~7.2.24"
- "@mui/utils": "npm:^6.4.9"
- clsx: "npm:^2.1.1"
- csstype: "npm:^3.1.3"
- hoist-non-react-statics: "npm:^3.3.2"
- jss: "npm:^10.10.0"
- jss-plugin-camel-case: "npm:^10.10.0"
- jss-plugin-default-unit: "npm:^10.10.0"
- jss-plugin-global: "npm:^10.10.0"
- jss-plugin-nested: "npm:^10.10.0"
- jss-plugin-props-sort: "npm:^10.10.0"
- jss-plugin-rule-value-function: "npm:^10.10.0"
- jss-plugin-vendor-prefixer: "npm:^10.10.0"
- prop-types: "npm:^15.8.1"
- peerDependencies:
- "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
- react: ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- "@types/react":
- optional: true
- checksum: 10/86fe34fa59498234e6b2801aae59c942410df9a7abbf502bc96d7a744d08cdbf5889654e04d9098a5ac87730ed9d532002ac78ec61c6c6ceed299ed77c1b692d
- languageName: node
- linkType: hard
-
"@mui/system@npm:^5.18.0":
version: 5.18.0
resolution: "@mui/system@npm:5.18.0"
@@ -8535,7 +8149,7 @@ __metadata:
languageName: node
linkType: hard
-"@mui/types@npm:~7.2.15, @mui/types@npm:~7.2.24":
+"@mui/types@npm:~7.2.15":
version: 7.2.24
resolution: "@mui/types@npm:7.2.24"
peerDependencies:
@@ -8567,26 +8181,6 @@ __metadata:
languageName: node
linkType: hard
-"@mui/utils@npm:^6.4.9":
- version: 6.4.9
- resolution: "@mui/utils@npm:6.4.9"
- dependencies:
- "@babel/runtime": "npm:^7.26.0"
- "@mui/types": "npm:~7.2.24"
- "@types/prop-types": "npm:^15.7.14"
- clsx: "npm:^2.1.1"
- prop-types: "npm:^15.8.1"
- react-is: "npm:^19.0.0"
- peerDependencies:
- "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
- react: ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- "@types/react":
- optional: true
- checksum: 10/4769956cc79283f9813d2984cd92b647528e4456eaea582c60b599d2db0a132ae4a10bf03ad28e8241463cd0ec2df1d56c0c4958f7c39d998241f93fc91c3ad4
- languageName: node
- linkType: hard
-
"@n1ru4l/push-pull-async-iterable-iterator@npm:^3.1.0":
version: 3.2.0
resolution: "@n1ru4l/push-pull-async-iterable-iterator@npm:3.2.0"
@@ -12096,7 +11690,7 @@ __metadata:
languageName: node
linkType: hard
-"@rjsf/core@npm:5.24.13, @rjsf/core@npm:^5.21.2":
+"@rjsf/core@npm:5.24.13":
version: 5.24.13
resolution: "@rjsf/core@npm:5.24.13"
dependencies:
@@ -12124,22 +11718,7 @@ __metadata:
languageName: node
linkType: hard
-"@rjsf/mui@npm:^5.21.2":
- version: 5.24.13
- resolution: "@rjsf/mui@npm:5.24.13"
- peerDependencies:
- "@emotion/react": ^11.7.0
- "@emotion/styled": ^11.6.0
- "@mui/icons-material": ^5.2.0 || ^6.0.0
- "@mui/material": ^5.2.2 || ^6.0.0
- "@rjsf/core": ^5.24.x
- "@rjsf/utils": ^5.24.x
- react: ">=17"
- checksum: 10/fedc93d4ce0bf2fe2d5b8ff3ef4857093d3d6fdb6983dd0728bbab9f7ddca9a28139c476aa948bae06a2f5d0d877bb75d56426c33ed2c6433a235e94f46d6a9a
- languageName: node
- linkType: hard
-
-"@rjsf/utils@npm:5.24.13, @rjsf/utils@npm:^5.21.2":
+"@rjsf/utils@npm:5.24.13":
version: 5.24.13
resolution: "@rjsf/utils@npm:5.24.13"
dependencies:
@@ -12154,7 +11733,7 @@ __metadata:
languageName: node
linkType: hard
-"@rjsf/validator-ajv8@npm:5.24.13, @rjsf/validator-ajv8@npm:^5.21.2":
+"@rjsf/validator-ajv8@npm:5.24.13":
version: 5.24.13
resolution: "@rjsf/validator-ajv8@npm:5.24.13"
dependencies:
@@ -14447,7 +14026,7 @@ __metadata:
languageName: node
linkType: hard
-"@swc/helpers@npm:^0.5.0, @swc/helpers@npm:^0.5.17, @swc/helpers@npm:^0.5.8":
+"@swc/helpers@npm:^0.5.0, @swc/helpers@npm:^0.5.17":
version: 0.5.18
resolution: "@swc/helpers@npm:0.5.18"
dependencies:
@@ -14959,7 +14538,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/hoist-non-react-statics@npm:^3.3.0, @types/hoist-non-react-statics@npm:^3.3.1":
+"@types/hoist-non-react-statics@npm:^3.3.0":
version: 3.3.7
resolution: "@types/hoist-non-react-statics@npm:3.3.7"
dependencies:
@@ -15156,16 +14735,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/node-fetch@npm:^2.6.13, @types/node-fetch@npm:^2.6.9":
- version: 2.6.13
- resolution: "@types/node-fetch@npm:2.6.13"
- dependencies:
- "@types/node": "npm:*"
- form-data: "npm:^4.0.4"
- checksum: 10/944d52214791ebba482ca1393a4f0d62b0dbac5f7343ff42c128b75d5356d8bcefd4df77771b55c1acd19d118e16e9bd5d2792819c51bc13402d1c87c0975435
- languageName: node
- linkType: hard
-
"@types/node-forge@npm:^1.3.0":
version: 1.3.14
resolution: "@types/node-forge@npm:1.3.14"
@@ -15209,24 +14778,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:^22.0.0":
- version: 22.19.11
- resolution: "@types/node@npm:22.19.11"
- dependencies:
- undici-types: "npm:~6.21.0"
- checksum: 10/bb899551432ce2bf3e1a175d58802f25dfb6a96e574ce1f0056d55d0ce48513961976ee3621215565142a8ad99a2464d9c384fa53ccba0650def031d218800f7
- languageName: node
- linkType: hard
-
-"@types/node@npm:^24.0.0":
- version: 24.10.13
- resolution: "@types/node@npm:24.10.13"
- dependencies:
- undici-types: "npm:~7.16.0"
- checksum: 10/c779d14cf17758a9d603e0c0978c8045bd070e259617ec16f4ddac419ec11aac0e0cf2bb013dab008fdbd2f46c39f82397884662bbdfabeb19bef0079679ea48
- languageName: node
- linkType: hard
-
"@types/oauth@npm:*":
version: 0.9.6
resolution: "@types/oauth@npm:0.9.6"
@@ -15287,7 +14838,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.12, @types/prop-types@npm:^15.7.14, @types/prop-types@npm:^15.7.3":
+"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.12, @types/prop-types@npm:^15.7.3":
version: 15.7.15
resolution: "@types/prop-types@npm:15.7.15"
checksum: 10/31aa2f59b28f24da6fb4f1d70807dae2aedfce090ec63eaf9ea01727a9533ef6eaf017de5bff99fbccad7d1c9e644f52c6c2ba30869465dd22b1a7221c29f356
@@ -15517,15 +15068,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/stream-buffers@npm:^3.0.3":
- version: 3.0.8
- resolution: "@types/stream-buffers@npm:3.0.8"
- dependencies:
- "@types/node": "npm:*"
- checksum: 10/2e269491769f3c529236cdd743a505d1dca52d14b3672714730d8940000d948bdf9468b2e54609b9d591d31e51e8e043eb44a830a6189bc727bd9dfc4dd70cdf
- languageName: node
- linkType: hard
-
"@types/styled-jsx@npm:^2.2.8":
version: 2.2.9
resolution: "@types/styled-jsx@npm:2.2.9"
@@ -15556,16 +15098,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/tar@npm:^6.1.1":
- version: 6.1.13
- resolution: "@types/tar@npm:6.1.13"
- dependencies:
- "@types/node": "npm:*"
- minipass: "npm:^4.0.0"
- checksum: 10/d325223cf90399fd03f366d0eabe2383e75e550b3e40a006d5f062d006b894a475cd7c0968d258a8eb8eae5df30b6e7f4607d493a474f89134bbff65362b77ed
- languageName: node
- linkType: hard
-
"@types/tern@npm:*":
version: 0.23.9
resolution: "@types/tern@npm:0.23.9"
@@ -15631,7 +15163,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/ws@npm:*, @types/ws@npm:^8.0.0, @types/ws@npm:^8.5.10, @types/ws@npm:^8.5.3, @types/ws@npm:^8.5.4":
+"@types/ws@npm:*, @types/ws@npm:^8.0.0, @types/ws@npm:^8.5.10, @types/ws@npm:^8.5.3":
version: 8.18.1
resolution: "@types/ws@npm:8.18.1"
dependencies:
@@ -16036,31 +15568,6 @@ __metadata:
languageName: node
linkType: hard
-"@xterm/addon-attach@npm:^0.11.0":
- version: 0.11.0
- resolution: "@xterm/addon-attach@npm:0.11.0"
- peerDependencies:
- "@xterm/xterm": ^5.0.0
- checksum: 10/f11e7ba68b8b1064ce545ecbf2beeaf3ebc94622fa3ca77e0ca0b8e8834964f634ee3897c031376abc7242ddfd305a40b10aa7b3e8056bfa59055967251523b5
- languageName: node
- linkType: hard
-
-"@xterm/addon-fit@npm:^0.10.0":
- version: 0.10.0
- resolution: "@xterm/addon-fit@npm:0.10.0"
- peerDependencies:
- "@xterm/xterm": ^5.0.0
- checksum: 10/8edfad561c0d0316c5883cbe2ce56109f105a2b2bf53b71d5f8c788e656a3205c1093a659dddcf4025a459e4b7ff8e07b6c6a19815c8711deeded560de5f1893
- languageName: node
- linkType: hard
-
-"@xterm/xterm@npm:^5.5.0":
- version: 5.5.0
- resolution: "@xterm/xterm@npm:5.5.0"
- checksum: 10/d4cdc402de81a83a3e0ef93f38072cb8f54abe4d65865f2e29b92cbc2593f86d052f6b993895c9e5dec97f47548f504e90bcea0aad6845917c09b03f2f3a4629
- languageName: node
- linkType: hard
-
"@yarnpkg/lockfile@npm:^1.1.0":
version: 1.1.0
resolution: "@yarnpkg/lockfile@npm:1.1.0"
@@ -16222,20 +15729,6 @@ __metadata:
languageName: node
linkType: hard
-"ajv-formats-draft2019@npm:^1.6.1":
- version: 1.6.1
- resolution: "ajv-formats-draft2019@npm:1.6.1"
- dependencies:
- punycode: "npm:^2.1.1"
- schemes: "npm:^1.4.0"
- smtp-address-parser: "npm:^1.0.3"
- uri-js: "npm:^4.4.1"
- peerDependencies:
- ajv: "*"
- checksum: 10/ecc9920a06eee23331873f4554e576d3593d2a1c9f42843571c6362858380f394419ec7a7a83af50fabf3913c43408f998d7261d601134d65ad6961165449a9f
- languageName: node
- linkType: hard
-
"ajv-formats@npm:^2.1.1, ajv-formats@npm:~2.1.0, ajv-formats@npm:~2.1.1":
version: 2.1.1
resolution: "ajv-formats@npm:2.1.1"
@@ -16264,15 +15757,6 @@ __metadata:
languageName: node
linkType: hard
-"ajv-i18n@npm:^4.2.0":
- version: 4.2.0
- resolution: "ajv-i18n@npm:4.2.0"
- peerDependencies:
- ajv: ^8.0.0-beta.0
- checksum: 10/c9e17fd87a6143583b415f0bb6e9c5d5cb4c013434bcee6ab1b5f6403a5090da78592e2cf2b21b1c224182402adbe2168ff08933c21d0bd6334085bd79bb01c9
- languageName: node
- linkType: hard
-
"ajv-keywords@npm:^3.4.1, ajv-keywords@npm:^3.5.2":
version: 3.5.2
resolution: "ajv-keywords@npm:3.5.2"
@@ -16461,7 +15945,6 @@ __metadata:
version: 0.0.0-use.local
resolution: "app@workspace:packages/app"
dependencies:
- "@backstage-community/plugin-rbac": "npm:1.33.2"
"@backstage/app-defaults": "npm:^1.5.16"
"@backstage/catalog-model": "npm:^1.7.3"
"@backstage/cli": "npm:^0.35.2"
@@ -16913,15 +16396,6 @@ __metadata:
languageName: node
linkType: hard
-"autosuggest-highlight@npm:^3.3.4":
- version: 3.3.4
- resolution: "autosuggest-highlight@npm:3.3.4"
- dependencies:
- remove-accents: "npm:^0.4.2"
- checksum: 10/4808b84f63baac7709e93fb2f73ed5b6638aa25af18ebc6236b4b11db9460c36a67d316270720d58d06a5f8fdf8c19b9308132263e305ddeb705a434562c5533
- languageName: node
- linkType: hard
-
"available-typed-arrays@npm:^1.0.7":
version: 1.0.7
resolution: "available-typed-arrays@npm:1.0.7"
@@ -18038,15 +17512,6 @@ __metadata:
languageName: node
linkType: hard
-"cidr-regex@npm:^3.1.1":
- version: 3.1.1
- resolution: "cidr-regex@npm:3.1.1"
- dependencies:
- ip-regex: "npm:^4.1.0"
- checksum: 10/ef9306d086928ee82b3f841b3bdab6e072230f3623a57cf19e06174946f2cbfeb70ca52bc106b127db27a628b9e84fb39284f5851003898ffdb957fe330478ee
- languageName: node
- linkType: hard
-
"cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3":
version: 1.0.7
resolution: "cipher-base@npm:1.0.7"
@@ -18058,7 +17523,7 @@ __metadata:
languageName: node
linkType: hard
-"classnames@npm:^2.2.6, classnames@npm:^2.3.1, classnames@npm:^2.3.2, classnames@npm:^2.5.1":
+"classnames@npm:^2.2.6, classnames@npm:^2.3.1, classnames@npm:^2.5.1":
version: 2.5.1
resolution: "classnames@npm:2.5.1"
checksum: 10/58eb394e8817021b153bb6e7d782cfb667e4ab390cb2e9dac2fc7c6b979d1cc2b2a733093955fc5c94aa79ef5c8c89f11ab77780894509be6afbb91dddd79d15
@@ -18441,13 +17906,6 @@ __metadata:
languageName: node
linkType: hard
-"complex.js@npm:^2.1.1":
- version: 2.4.3
- resolution: "complex.js@npm:2.4.3"
- checksum: 10/904a2b4a09a4cfd94d8636ceb95e15cc077dcdedd07c54e233308210fb38897338dde4e7113811e89c1cfe4c6e3ebcf11735ad5c901e27c6d7e3c132a3078e3c
- languageName: node
- linkType: hard
-
"component-emitter@npm:^1.3.0":
version: 1.3.1
resolution: "component-emitter@npm:1.3.1"
@@ -18942,15 +18400,6 @@ __metadata:
languageName: node
linkType: hard
-"cronstrue@npm:^2.32.0":
- version: 2.59.0
- resolution: "cronstrue@npm:2.59.0"
- bin:
- cronstrue: bin/cli.js
- checksum: 10/daa7a1ea7e4a40cdb533df754489142358ecdc23462ec57309fec61e539b84ae886d3ac4666a6133403f1b13a98834ca107a09f5f78d31e6cfac8625dd3422c3
- languageName: node
- linkType: hard
-
"cross-env@npm:^7.0.0":
version: 7.0.3
resolution: "cross-env@npm:7.0.3"
@@ -19346,16 +18795,6 @@ __metadata:
languageName: node
linkType: hard
-"dagre@npm:^0.8.5":
- version: 0.8.5
- resolution: "dagre@npm:0.8.5"
- dependencies:
- graphlib: "npm:^2.1.8"
- lodash: "npm:^4.17.15"
- checksum: 10/f39899e29e9090581d67177ef6e2dd3ca5d7f764fbf3de81758d879bba66fee6fd8802d41d0c5d3d9a0563b334e99e1454a8d6ab4ce17e8e4f50836a3a403fdd
- languageName: node
- linkType: hard
-
"damerau-levenshtein@npm:^1.0.8":
version: 1.0.8
resolution: "damerau-levenshtein@npm:1.0.8"
@@ -19436,7 +18875,7 @@ __metadata:
languageName: node
linkType: hard
-"date-fns@npm:^2.16.1, date-fns@npm:^2.30.0":
+"date-fns@npm:^2.16.1":
version: 2.30.0
resolution: "date-fns@npm:2.30.0"
dependencies:
@@ -19606,13 +19045,6 @@ __metadata:
languageName: node
linkType: hard
-"deepmerge@npm:^2.1.1":
- version: 2.2.1
- resolution: "deepmerge@npm:2.2.1"
- checksum: 10/a3da411cd3d471a8ae86ff7fd5e19abb648377b3f8c42a9e4c822406c2960a391cb829e4cca53819b73715e68f56b06f53c643ca7bba21cab569fecc9a723de1
- languageName: node
- linkType: hard
-
"deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.1, deepmerge@npm:~4.3.0":
version: 4.3.1
resolution: "deepmerge@npm:4.3.1"
@@ -20639,13 +20071,6 @@ __metadata:
languageName: node
linkType: hard
-"escape-latex@npm:^1.2.0":
- version: 1.2.0
- resolution: "escape-latex@npm:1.2.0"
- checksum: 10/73a787319f0965ecb8244bb38bf3a3cba872f0b9a5d3da8821140e9f39fe977045dc953a62b1a2bed4d12bfccbe75a7d8ec786412bf00739eaa2f627d0a8e0d6
- languageName: node
- linkType: hard
-
"escape-string-regexp@npm:^1.0.5":
version: 1.0.5
resolution: "escape-string-regexp@npm:1.0.5"
@@ -21487,13 +20912,6 @@ __metadata:
languageName: node
linkType: hard
-"file-saver@npm:^2.0.5":
- version: 2.0.5
- resolution: "file-saver@npm:2.0.5"
- checksum: 10/fbba443d9b682fec0be6676c048a7ac688b9bd33b105c02e8e1a1cb3e354ed441198dc1f15dcbc137fa044bea73f8a7549f2617e3a952fa7d96390356d54a7c3
- languageName: node
- linkType: hard
-
"file-type@npm:21.3.0":
version: 21.3.0
resolution: "file-type@npm:21.3.0"
@@ -21751,7 +21169,7 @@ __metadata:
languageName: node
linkType: hard
-"form-data@npm:^4.0.0, form-data@npm:^4.0.4, form-data@npm:^4.0.5":
+"form-data@npm:^4.0.0, form-data@npm:^4.0.5":
version: 4.0.5
resolution: "form-data@npm:4.0.5"
dependencies:
@@ -21824,24 +21242,6 @@ __metadata:
languageName: node
linkType: hard
-"formik@npm:^2.4.5":
- version: 2.4.9
- resolution: "formik@npm:2.4.9"
- dependencies:
- "@types/hoist-non-react-statics": "npm:^3.3.1"
- deepmerge: "npm:^2.1.1"
- hoist-non-react-statics: "npm:^3.3.0"
- lodash: "npm:^4.17.21"
- lodash-es: "npm:^4.17.21"
- react-fast-compare: "npm:^2.0.1"
- tiny-warning: "npm:^1.0.2"
- tslib: "npm:^2.0.0"
- peerDependencies:
- react: ">=16.8.0"
- checksum: 10/c7354bedce92ac13a8e8a59fa9bd05fe1743e0d10becf12a574ab98906a234eeb483ae9cb2a84956bd6b77aed3006e37c85203981e15547889f1a5862c5b06d0
- languageName: node
- linkType: hard
-
"formstream@npm:^1.1.1":
version: 1.5.2
resolution: "formstream@npm:1.5.2"
@@ -21861,13 +21261,6 @@ __metadata:
languageName: node
linkType: hard
-"fraction.js@npm:4.3.4":
- version: 4.3.4
- resolution: "fraction.js@npm:4.3.4"
- checksum: 10/3a1e6b268038ffdea625fab6a8d155d7ab644d35d0c99bc59084bfd29fbc714f3a38381b0627751ddb5f188bcde0b3f48c27e80eeb2ecd440825a7d2cd2bf9f1
- languageName: node
- linkType: hard
-
"framer-motion@npm:^6.5.1":
version: 6.5.1
resolution: "framer-motion@npm:6.5.1"
@@ -22542,15 +21935,6 @@ __metadata:
languageName: node
linkType: hard
-"graphlib@npm:^2.1.8":
- version: 2.1.8
- resolution: "graphlib@npm:2.1.8"
- dependencies:
- lodash: "npm:^4.17.15"
- checksum: 10/37cbd851d3c1fb99f3174750ccaa22305d23d11746e5df81a38ba3bf25c0ba29cd9658ba69a0159ea81d56c28e8e875033eeaaa7167d838419fae08d9cd2c62c
- languageName: node
- linkType: hard
-
"graphql-config@npm:^5.0.2":
version: 5.1.5
resolution: "graphql-config@npm:5.1.5"
@@ -23689,13 +23073,6 @@ __metadata:
languageName: node
linkType: hard
-"ip-regex@npm:^4.1.0":
- version: 4.3.0
- resolution: "ip-regex@npm:4.3.0"
- checksum: 10/7ff904b891221b1847f3fdf3dbb3e6a8660dc39bc283f79eb7ed88f5338e1a3d1104b779bc83759159be266249c59c2160e779ee39446d79d4ed0890dfd06f08
- languageName: node
- linkType: hard
-
"ipaddr.js@npm:1.9.1":
version: 1.9.1
resolution: "ipaddr.js@npm:1.9.1"
@@ -23827,15 +23204,6 @@ __metadata:
languageName: node
linkType: hard
-"is-cidr@npm:^4.0.0":
- version: 4.0.2
- resolution: "is-cidr@npm:4.0.2"
- dependencies:
- cidr-regex: "npm:^3.1.1"
- checksum: 10/ee6e670e655a835710a7fa15268b428adbf80267114a494ce1c2ca2b09e1ca0b629fe1375aae621d4c093b32930d5ff7c4ee6da97eae14e3836bc7b3a07b171f
- languageName: node
- linkType: hard
-
"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.1":
version: 2.16.1
resolution: "is-core-module@npm:2.16.1"
@@ -24477,13 +23845,6 @@ __metadata:
languageName: node
linkType: hard
-"javascript-natural-sort@npm:^0.7.1":
- version: 0.7.1
- resolution: "javascript-natural-sort@npm:0.7.1"
- checksum: 10/7bf6eab67871865d347f09a95aa770f9206c1ab0226bcda6fdd9edec340bf41111a7f82abac30556aa16a21cfa3b2b1ca4a362c8b73dd5ce15220e5d31f49d79
- languageName: node
- linkType: hard
-
"jest-css-modules@npm:^2.1.0":
version: 2.1.0
resolution: "jest-css-modules@npm:2.1.0"
@@ -24611,13 +23972,6 @@ __metadata:
languageName: node
linkType: hard
-"jose@npm:^6.1.3":
- version: 6.1.3
- resolution: "jose@npm:6.1.3"
- checksum: 10/9626c51e8c3792b505e954f3094698c182208617b62dfb27269230f31e57560b083985ed8128b8a9753aa92daf18d3a2341cc826d149503f14569abe87d42389
- languageName: node
- linkType: hard
-
"js-base64@npm:^3.6.0":
version: 3.7.8
resolution: "js-base64@npm:3.7.8"
@@ -24945,7 +24299,7 @@ __metadata:
languageName: node
linkType: hard
-"jsonpath-plus@npm:^10.0.0, jsonpath-plus@npm:^10.0.7, jsonpath-plus@npm:^10.3.0, jsonpath-plus@npm:^6.0.1 || ^10.1.0":
+"jsonpath-plus@npm:^10.0.7, jsonpath-plus@npm:^10.3.0, jsonpath-plus@npm:^6.0.1 || ^10.1.0":
version: 10.4.0
resolution: "jsonpath-plus@npm:10.4.0"
dependencies:
@@ -25021,7 +24375,7 @@ __metadata:
languageName: node
linkType: hard
-"jss-plugin-camel-case@npm:^10.10.0, jss-plugin-camel-case@npm:^10.5.1":
+"jss-plugin-camel-case@npm:^10.5.1":
version: 10.10.0
resolution: "jss-plugin-camel-case@npm:10.10.0"
dependencies:
@@ -25032,7 +24386,7 @@ __metadata:
languageName: node
linkType: hard
-"jss-plugin-default-unit@npm:^10.10.0, jss-plugin-default-unit@npm:^10.5.1":
+"jss-plugin-default-unit@npm:^10.5.1":
version: 10.10.0
resolution: "jss-plugin-default-unit@npm:10.10.0"
dependencies:
@@ -25042,7 +24396,7 @@ __metadata:
languageName: node
linkType: hard
-"jss-plugin-global@npm:^10.10.0, jss-plugin-global@npm:^10.5.1":
+"jss-plugin-global@npm:^10.5.1":
version: 10.10.0
resolution: "jss-plugin-global@npm:10.10.0"
dependencies:
@@ -25052,7 +24406,7 @@ __metadata:
languageName: node
linkType: hard
-"jss-plugin-nested@npm:^10.10.0, jss-plugin-nested@npm:^10.5.1":
+"jss-plugin-nested@npm:^10.5.1":
version: 10.10.0
resolution: "jss-plugin-nested@npm:10.10.0"
dependencies:
@@ -25063,7 +24417,7 @@ __metadata:
languageName: node
linkType: hard
-"jss-plugin-props-sort@npm:^10.10.0, jss-plugin-props-sort@npm:^10.5.1":
+"jss-plugin-props-sort@npm:^10.5.1":
version: 10.10.0
resolution: "jss-plugin-props-sort@npm:10.10.0"
dependencies:
@@ -25073,7 +24427,7 @@ __metadata:
languageName: node
linkType: hard
-"jss-plugin-rule-value-function@npm:^10.10.0, jss-plugin-rule-value-function@npm:^10.5.1":
+"jss-plugin-rule-value-function@npm:^10.5.1":
version: 10.10.0
resolution: "jss-plugin-rule-value-function@npm:10.10.0"
dependencies:
@@ -25084,7 +24438,7 @@ __metadata:
languageName: node
linkType: hard
-"jss-plugin-vendor-prefixer@npm:^10.10.0, jss-plugin-vendor-prefixer@npm:^10.5.1":
+"jss-plugin-vendor-prefixer@npm:^10.5.1":
version: 10.10.0
resolution: "jss-plugin-vendor-prefixer@npm:10.10.0"
dependencies:
@@ -25095,7 +24449,7 @@ __metadata:
languageName: node
linkType: hard
-"jss@npm:10.10.0, jss@npm:^10.10.0, jss@npm:^10.5.1, jss@npm:~10.10.0":
+"jss@npm:10.10.0, jss@npm:^10.5.1, jss@npm:~10.10.0":
version: 10.10.0
resolution: "jss@npm:10.10.0"
dependencies:
@@ -25330,18 +24684,6 @@ __metadata:
languageName: node
linkType: hard
-"kubernetes-models@npm:^4.3.1":
- version: 4.5.1
- resolution: "kubernetes-models@npm:4.5.1"
- dependencies:
- "@kubernetes-models/apimachinery": "npm:^2.2.0"
- "@kubernetes-models/base": "npm:^5.0.1"
- "@kubernetes-models/validate": "npm:^4.0.0"
- "@swc/helpers": "npm:^0.5.8"
- checksum: 10/65a7b2064dcfbc719a80da7fd24b44775f68423170eb7abef3d4946604acdb5c8a3b2c8fded1d7212e2725b10ccf13abc94adf3091dc8005e25cd5321577ae92
- languageName: node
- linkType: hard
-
"kuler@npm:^2.0.0":
version: 2.0.0
resolution: "kuler@npm:2.0.0"
@@ -25465,16 +24807,6 @@ __metadata:
languageName: node
linkType: hard
-"linkify-react@npm:4.1.3":
- version: 4.1.3
- resolution: "linkify-react@npm:4.1.3"
- peerDependencies:
- linkifyjs: ^4.0.0
- react: ">= 15.0.0"
- checksum: 10/e21dec51798783288c08979a74d0b8b6ee87315205d9a6ca36d8dc062c967577184791ab6456bb70f3635c2d156930040de9c278a3ca6dc940a45ea3b5d184c4
- languageName: node
- linkType: hard
-
"linkify-react@npm:4.3.2":
version: 4.3.2
resolution: "linkify-react@npm:4.3.2"
@@ -25485,13 +24817,6 @@ __metadata:
languageName: node
linkType: hard
-"linkifyjs@npm:4.1.3":
- version: 4.1.3
- resolution: "linkifyjs@npm:4.1.3"
- checksum: 10/7c17dac6a66fdea30e56b17d49d882a333833ec093993723738842b224c8cbd87bcddc6f51f2deac9529c868f162358d7acb0c44753b92832027ae761eceac1a
- languageName: node
- linkType: hard
-
"linkifyjs@npm:4.3.2":
version: 4.3.2
resolution: "linkifyjs@npm:4.3.2"
@@ -26092,25 +25417,6 @@ __metadata:
languageName: node
linkType: hard
-"mathjs@npm:^11.11.2":
- version: 11.12.0
- resolution: "mathjs@npm:11.12.0"
- dependencies:
- "@babel/runtime": "npm:^7.23.2"
- complex.js: "npm:^2.1.1"
- decimal.js: "npm:^10.4.3"
- escape-latex: "npm:^1.2.0"
- fraction.js: "npm:4.3.4"
- javascript-natural-sort: "npm:^0.7.1"
- seedrandom: "npm:^3.0.5"
- tiny-emitter: "npm:^2.1.0"
- typed-function: "npm:^4.1.1"
- bin:
- mathjs: bin/cli.js
- checksum: 10/d0a3ab35fb0a51be321709cdd49bd69de832c4f62ab578fc5761f94502411a016ddb3809020cf3d87e0c563d379c24f68a1b77aa14031e59965203956518d6ad
- languageName: node
- linkType: hard
-
"md5.js@npm:^1.3.4":
version: 1.3.5
resolution: "md5.js@npm:1.3.5"
@@ -27041,13 +26347,6 @@ __metadata:
languageName: node
linkType: hard
-"minipass@npm:^4.0.0":
- version: 4.2.8
- resolution: "minipass@npm:4.2.8"
- checksum: 10/e148eb6dcb85c980234cad889139ef8ddf9d5bdac534f4f0268446c8792dd4c74f4502479be48de3c1cce2f6450f6da4d0d4a86405a8a12be04c1c36b339569a
- languageName: node
- linkType: hard
-
"minipass@npm:^5.0.0":
version: 5.0.0
resolution: "minipass@npm:5.0.0"
@@ -27847,13 +27146,6 @@ __metadata:
languageName: node
linkType: hard
-"oauth4webapi@npm:^3.8.4":
- version: 3.8.5
- resolution: "oauth4webapi@npm:3.8.5"
- checksum: 10/5c39d4dbd95b795438e79444a1d710631b3f8311e8b8913150b385b5815857b32f617a49d4869a4476b2318f614adfbc9d19510360df198719973f6f69a2e75b
- languageName: node
- linkType: hard
-
"oauth@npm:0.10.x":
version: 0.10.2
resolution: "oauth@npm:0.10.2"
@@ -28163,7 +27455,7 @@ __metadata:
languageName: node
linkType: hard
-"openid-client@npm:^5.2.1, openid-client@npm:^5.3.0, openid-client@npm:^5.5.0, openid-client@npm:^5.6.5":
+"openid-client@npm:^5.2.1, openid-client@npm:^5.3.0, openid-client@npm:^5.5.0":
version: 5.7.1
resolution: "openid-client@npm:5.7.1"
dependencies:
@@ -28175,16 +27467,6 @@ __metadata:
languageName: node
linkType: hard
-"openid-client@npm:^6.1.3":
- version: 6.8.2
- resolution: "openid-client@npm:6.8.2"
- dependencies:
- jose: "npm:^6.1.3"
- oauth4webapi: "npm:^3.8.4"
- checksum: 10/5d30ff2419c4847d0037c43cf136dd7189b16399aaee98faaad5bcea105c4e1e4e43d2dac1141ea77049b446b50d1b26f2bb882f717b3e38a5f996645abfc1d0
- languageName: node
- linkType: hard
-
"oppa@npm:^0.4.0":
version: 0.4.0
resolution: "oppa@npm:0.4.0"
@@ -30254,13 +29536,6 @@ __metadata:
languageName: node
linkType: hard
-"re2-wasm@npm:^1.0.2":
- version: 1.0.2
- resolution: "re2-wasm@npm:1.0.2"
- checksum: 10/aabe66abb7ba8441bb9518b8d28c3b74b89105aa7f688ef912f7465aa1f52c2af7b1c492c768ad4bc0bbc6398127c3ac30353aeb093df3b21fbcb68bcb285c98
- languageName: node
- linkType: hard
-
"react-aria-components@npm:^1.13.0":
version: 1.15.1
resolution: "react-aria-components@npm:1.15.1"
@@ -30480,13 +29755,6 @@ __metadata:
languageName: node
linkType: hard
-"react-fast-compare@npm:^2.0.1":
- version: 2.0.4
- resolution: "react-fast-compare@npm:2.0.4"
- checksum: 10/e4e3218c0f5c29b88e9f184a12adb77b0a93a803dbd45cb98bbb754c8310dc74e6266c53dd70b90ba4d0939e0e1b8a182cb05d081bcab22507a0390fbcd768ac
- languageName: node
- linkType: hard
-
"react-fast-compare@npm:^3.1.1":
version: 3.2.2
resolution: "react-fast-compare@npm:3.2.2"
@@ -30882,7 +30150,7 @@ __metadata:
languageName: node
linkType: hard
-"react-use@npm:^17.2.4, react-use@npm:^17.3.2, react-use@npm:^17.4.0, react-use@npm:^17.5.0":
+"react-use@npm:^17.2.4, react-use@npm:^17.3.2":
version: 17.6.0
resolution: "react-use@npm:17.6.0"
dependencies:
@@ -31252,13 +30520,6 @@ __metadata:
languageName: node
linkType: hard
-"remove-accents@npm:^0.4.2":
- version: 0.4.4
- resolution: "remove-accents@npm:0.4.4"
- checksum: 10/13d1b4086d3926928117d3253ede78f1bb1084f8897c7a60043b392a47663d5b3abd008bc854dc225d6f762dd5a5845acf15add1b02826f1e11de37862bad024
- languageName: node
- linkType: hard
-
"remove-trailing-separator@npm:^1.0.1":
version: 1.1.0
resolution: "remove-trailing-separator@npm:1.1.0"
@@ -31945,15 +31206,6 @@ __metadata:
languageName: node
linkType: hard
-"schemes@npm:^1.4.0":
- version: 1.4.0
- resolution: "schemes@npm:1.4.0"
- dependencies:
- extend: "npm:^3.0.0"
- checksum: 10/4133cf55ee41c44756c6489721dc72326c1148c8bf0e26bb27cd4e19c9a3fdc1b47318a4bf0257f0261afe8bfaef4fbd6c860ffdeaa8ec7704fc39549d48314f
- languageName: node
- linkType: hard
-
"screenfull@npm:^5.1.0":
version: 5.2.0
resolution: "screenfull@npm:5.2.0"
@@ -31961,13 +31213,6 @@ __metadata:
languageName: node
linkType: hard
-"seedrandom@npm:^3.0.5":
- version: 3.0.5
- resolution: "seedrandom@npm:3.0.5"
- checksum: 10/acad5e516c04289f61c2fb9848f449b95f58362b75406b79ec51e101ec885293fc57e3675d2f39f49716336559d7190f7273415d185fead8cd27b171ebf7d8fb
- languageName: node
- linkType: hard
-
"select-case@npm:^1.0.0":
version: 1.0.0
resolution: "select-case@npm:1.0.0"
@@ -32373,15 +31618,6 @@ __metadata:
languageName: node
linkType: hard
-"smtp-address-parser@npm:^1.0.3":
- version: 1.1.0
- resolution: "smtp-address-parser@npm:1.1.0"
- dependencies:
- nearley: "npm:^2.20.1"
- checksum: 10/ff01b570da1a8faf96e817d38622b45db903033cc8b2c7874c679d7cb17b0cfef00d81260cdb5d886170c89f8d067d193cc36b6ff6c89ef2444da6a345d0b1e2
- languageName: node
- linkType: hard
-
"sockjs@npm:^0.3.24":
version: 0.3.24
resolution: "sockjs@npm:0.3.24"
@@ -32404,7 +31640,7 @@ __metadata:
languageName: node
linkType: hard
-"socks-proxy-agent@npm:^8.0.3, socks-proxy-agent@npm:^8.0.4, socks-proxy-agent@npm:^8.0.5":
+"socks-proxy-agent@npm:^8.0.3, socks-proxy-agent@npm:^8.0.5":
version: 8.0.5
resolution: "socks-proxy-agent@npm:8.0.5"
dependencies:
@@ -33394,7 +32630,7 @@ __metadata:
languageName: node
linkType: hard
-"tar-fs@npm:^3.0.9, tar-fs@npm:^3.1.1":
+"tar-fs@npm:^3.1.1":
version: 3.1.1
resolution: "tar-fs@npm:3.1.1"
dependencies:
@@ -33449,7 +32685,7 @@ __metadata:
languageName: node
linkType: hard
-"tar@npm:^7.0.0, tar@npm:^7.5.4":
+"tar@npm:^7.5.4":
version: 7.5.9
resolution: "tar@npm:7.5.9"
dependencies:
@@ -33652,13 +32888,6 @@ __metadata:
languageName: node
linkType: hard
-"tiny-emitter@npm:^2.1.0":
- version: 2.1.0
- resolution: "tiny-emitter@npm:2.1.0"
- checksum: 10/75633f4de4f47f43af56aff6162f25b87be7efc6f669fda256658f3c3f4a216f23dc0d13200c6fafaaf1b0c7142f0201352fb06aec0b77f68aea96be898f4516
- languageName: node
- linkType: hard
-
"tiny-invariant@npm:^1.0.6":
version: 1.3.3
resolution: "tiny-invariant@npm:1.3.3"
@@ -33701,16 +32930,7 @@ __metadata:
languageName: node
linkType: hard
-"tmp-promise@npm:^3.0.2":
- version: 3.0.3
- resolution: "tmp-promise@npm:3.0.3"
- dependencies:
- tmp: "npm:^0.2.0"
- checksum: 10/0ca65b4f233b1d2b01e17a7a62961d32923e4b27383a370bf4d8d52f1062d79c3250e6b6b706ec390e73c9c58c13dc130b3855eedc89c86c7d90beb28b8382e5
- languageName: node
- linkType: hard
-
-"tmp@npm:^0.2.0, tmp@npm:^0.2.5":
+"tmp@npm:^0.2.5":
version: 0.2.5
resolution: "tmp@npm:0.2.5"
checksum: 10/dd4b78b32385eab4899d3ae296007b34482b035b6d73e1201c4a9aede40860e90997a1452c65a2d21aee73d53e93cd167d741c3db4015d90e63b6d568a93d7ec
@@ -34209,13 +33429,6 @@ __metadata:
languageName: node
linkType: hard
-"typed-function@npm:^4.1.1":
- version: 4.2.2
- resolution: "typed-function@npm:4.2.2"
- checksum: 10/6d0eb312d2fa2c4b9af7a6cba5f3e9123e1e7c0b2521a7cd30a1140f862ffb94ad44353b2798a8c160fb40a9b341f7870d3c05589a7b54472514ff6f1b12e6ac
- languageName: node
- linkType: hard
-
"typed-rest-client@npm:2.1.0":
version: 2.1.0
resolution: "typed-rest-client@npm:2.1.0"
@@ -34776,7 +33989,7 @@ __metadata:
languageName: node
linkType: hard
-"url-parse@npm:^1.4.3, url-parse@npm:^1.5.10":
+"url-parse@npm:^1.5.10":
version: 1.5.10
resolution: "url-parse@npm:1.5.10"
dependencies:
@@ -35508,7 +34721,7 @@ __metadata:
languageName: node
linkType: hard
-"ws@npm:*, ws@npm:^8.11.0, ws@npm:^8.17.1, ws@npm:^8.18.0, ws@npm:^8.18.2, ws@npm:^8.18.3, ws@npm:^8.19.0, ws@npm:^8.8.0":
+"ws@npm:*, ws@npm:^8.11.0, ws@npm:^8.17.1, ws@npm:^8.18.0, ws@npm:^8.18.3, ws@npm:^8.19.0, ws@npm:^8.8.0":
version: 8.19.0
resolution: "ws@npm:8.19.0"
peerDependencies:
@@ -35816,7 +35029,7 @@ __metadata:
languageName: node
linkType: hard
-"yup@npm:^1.0.0, yup@npm:^1.3.2, yup@npm:^1.7.1":
+"yup@npm:^1.0.0, yup@npm:^1.7.1":
version: 1.7.1
resolution: "yup@npm:1.7.1"
dependencies: