Skip to content

Commit e3985a8

Browse files
authored
Add Rehydrate, Enhancement for UI Tables and APIs (#2950)
* Add Rehydrate, Remove Resources Tab and RBAC Sidebar menu * Show Error to User, add Default Empty Body...
1 parent 9f5f22a commit e3985a8

42 files changed

Lines changed: 994 additions & 2032 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-dcm': minor
3+
'@red-hat-developer-hub/backstage-plugin-dcm-common': minor
4+
---
5+
6+
DCM UI and catalog client updates for the example app and published plugins.
7+
8+
**Example app (`packages/app`) — RBAC navigation**
9+
10+
- Removed the **RBAC** sidebar entry under Administration and the `/rbac` route.
11+
- Dropped the `@backstage-community/plugin-rbac` frontend dependency. The RBAC backend plugin may remain for permissions; only the menu and page were removed.
12+
13+
**`@red-hat-developer-hub/backstage-plugin-dcm` — Resources tab**
14+
15+
- Removed the **Resources** tab from the Data Center page and all **Placement / `resources`** proxy usage from the plugin.
16+
- Removed `placementApiRef`, `resources` route ref, and the `PlacementClient` integration from the plugin surface.
17+
18+
**`@red-hat-developer-hub/backstage-plugin-dcm-common` — placement API removed; catalog rehydrate**
19+
20+
- Removed the Placement API client, types, and tests tied to the internal `resources` API.
21+
- Added **`rehydrateCatalogItemInstance`** on `CatalogApi` / `CatalogClient`: `POST .../catalog-item-instances/{id}:rehydrate`.
22+
23+
**Catalog item instances UI**
24+
25+
- 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.

workspaces/dcm/packages/app/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
"lint": "backstage-cli package lint"
2020
},
2121
"dependencies": {
22-
"@backstage-community/plugin-rbac": "1.33.2",
2322
"@backstage/app-defaults": "^1.5.16",
2423
"@backstage/catalog-model": "^1.7.3",
2524
"@backstage/cli": "^0.35.2",

workspaces/dcm/packages/app/src/App.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ import { RequirePermission } from '@backstage/plugin-permission-react';
5252
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
5353
import { DcmPage } from '@red-hat-developer-hub/backstage-plugin-dcm';
5454
import { useRhdhTheme } from './hooks/useRhdhTheme';
55-
import { RbacPage } from '@backstage-community/plugin-rbac';
5655
import '@patternfly/patternfly/patternfly.css';
5756
import '@patternfly/patternfly/patternfly-charts.css';
5857

@@ -123,7 +122,6 @@ const routes = (
123122
<Route path="/settings" element={<UserSettingsPage />} />
124123
<Route path="/catalog-graph" element={<CatalogGraphPage />} />
125124
<Route path="/dcm/*" element={<DcmPage />} />
126-
<Route path="/rbac" element={<RbacPage />} />
127125
</FlatRoutes>
128126
);
129127

workspaces/dcm/packages/app/src/components/Root/Root.tsx

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import MenuIcon from '@material-ui/icons/Menu';
4141
import SearchIcon from '@material-ui/icons/Search';
4242
import SecurityIcon from '@material-ui/icons/Security';
4343
import StorageIcon from '@material-ui/icons/Storage';
44-
import VpnKeyIcon from '@material-ui/icons/VpnKey';
4544
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
4645
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
4746
import LogoFull from './LogoFull';
@@ -235,7 +234,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
235234
const location = useLocation();
236235
usePatternFlyTheme();
237236
const isDcmActive = location.pathname.startsWith('/dcm');
238-
const isRbacActive = location.pathname.startsWith('/rbac');
239237

240238
return (
241239
<SidebarPage>
@@ -274,16 +272,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
274272
isDcmActive ? classes.submenuItemActive : classes.inactiveItem
275273
}`}
276274
/>
277-
<SidebarItem
278-
icon={VpnKeyIcon}
279-
to="/rbac"
280-
text="RBAC"
281-
className={`${classes.submenuItem} ${
282-
isRbacActive
283-
? classes.submenuItemActive
284-
: classes.inactiveItem
285-
}`}
286-
/>
287275
</Box>
288276
</CollapsibleSubmenu>
289277
</SidebarGroup>

workspaces/dcm/plugins/dcm-common/report.api.md

Lines changed: 56 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ export interface CatalogApi {
3535
listCatalogItems(): Promise<CatalogItemList>;
3636
// (undocumented)
3737
listServiceTypes(): Promise<ServiceTypeList>;
38+
rehydrateCatalogItemInstance(
39+
catalogItemInstanceId: string,
40+
): Promise<CatalogItemInstance>;
3841
// (undocumented)
3942
updateCatalogItem(
4043
catalogItemId: string,
@@ -71,6 +74,10 @@ export class CatalogClient extends DcmBaseClient implements CatalogApi {
7174
// (undocumented)
7275
listServiceTypes(): Promise<ServiceTypeList>;
7376
// (undocumented)
77+
rehydrateCatalogItemInstance(
78+
catalogItemInstanceId: string,
79+
): Promise<CatalogItemInstance>;
80+
// (undocumented)
7481
protected readonly serviceName = 'Catalog';
7582
// (undocumented)
7683
updateCatalogItem(
@@ -264,46 +271,15 @@ export interface FieldConfigurationDependsOn {
264271
}
265272

266273
// @public
267-
export function parseDcmEntityStatus(raw: string): DcmEntityStatus | undefined;
268-
269-
// @public
270-
export interface PlacementApi {
271-
createResource(resource: Resource, id?: string): Promise<Resource>;
272-
deleteResource(resourceId: string): Promise<void>;
273-
getResource(resourceId: string): Promise<Resource>;
274-
listResources(options?: {
275-
provider?: string;
276-
maxPageSize?: number;
277-
pageToken?: string;
278-
}): Promise<ResourceList>;
279-
rehydrateResource(
280-
resourceId: string,
281-
request: RehydrateRequest,
282-
): Promise<Resource>;
274+
export interface ListServiceTypeInstancesParams {
275+
max_page_size?: number;
276+
page_token?: string;
277+
provider?: string;
278+
show_deleted?: boolean;
283279
}
284280

285281
// @public
286-
export class PlacementClient extends DcmBaseClient implements PlacementApi {
287-
// (undocumented)
288-
createResource(resource: Resource, id?: string): Promise<Resource>;
289-
// (undocumented)
290-
deleteResource(resourceId: string): Promise<void>;
291-
// (undocumented)
292-
getResource(resourceId: string): Promise<Resource>;
293-
// (undocumented)
294-
listResources(options?: {
295-
provider?: string;
296-
maxPageSize?: number;
297-
pageToken?: string;
298-
}): Promise<ResourceList>;
299-
// (undocumented)
300-
rehydrateResource(
301-
resourceId: string,
302-
request: RehydrateRequest,
303-
): Promise<Resource>;
304-
// (undocumented)
305-
protected readonly serviceName = 'Placement';
306-
}
282+
export function parseDcmEntityStatus(raw: string): DcmEntityStatus | undefined;
307283

308284
// @public
309285
export interface Policy {
@@ -449,24 +425,6 @@ export class ProvidersClient extends DcmBaseClient implements ProvidersApi {
449425
// @public
450426
export type ProviderStatus = 'registered' | 'updated';
451427

452-
// @public
453-
export interface RehydrateRequest {
454-
// (undocumented)
455-
new_resource_id: string;
456-
}
457-
458-
// @public
459-
export interface Resource {
460-
approval_status?: string;
461-
catalog_item_instance_id: string;
462-
create_time?: string;
463-
id?: string;
464-
path?: string;
465-
provider_name?: string;
466-
spec: Record<string, unknown>;
467-
update_time?: string;
468-
}
469-
470428
// @public
471429
export interface ResourceCapacity {
472430
// (undocumented)
@@ -480,11 +438,20 @@ export interface ResourceCapacity {
480438
}
481439

482440
// @public
483-
export interface ResourceList {
441+
export interface ResourcesApi {
442+
listServiceTypeInstances(
443+
params?: ListServiceTypeInstancesParams,
444+
): Promise<ServiceTypeInstanceList>;
445+
}
446+
447+
// @public
448+
export class ResourcesClient extends DcmBaseClient implements ResourcesApi {
484449
// (undocumented)
485-
next_page_token?: string;
450+
listServiceTypeInstances(
451+
params?: ListServiceTypeInstancesParams,
452+
): Promise<ServiceTypeInstanceList>;
486453
// (undocumented)
487-
resources: Resource[];
454+
protected readonly serviceName = 'Resources';
488455
}
489456

490457
// @public
@@ -506,6 +473,37 @@ export interface ServiceType {
506473
update_time?: string;
507474
}
508475

476+
// @public
477+
export interface ServiceTypeInstance {
478+
// (undocumented)
479+
create_time?: string;
480+
// (undocumented)
481+
delete_time?: string;
482+
deleted?: boolean;
483+
id: string;
484+
path?: string;
485+
provider_name?: string;
486+
spec?: ServiceTypeInstanceSpec;
487+
status?: string;
488+
// (undocumented)
489+
update_time?: string;
490+
}
491+
492+
// @public
493+
export interface ServiceTypeInstanceList {
494+
// (undocumented)
495+
instances?: ServiceTypeInstance[];
496+
// (undocumented)
497+
next_page_token?: string;
498+
}
499+
500+
// @public
501+
export interface ServiceTypeInstanceSpec {
502+
// (undocumented)
503+
[key: string]: unknown;
504+
service_type?: string;
505+
}
506+
509507
// @public
510508
export interface ServiceTypeList {
511509
// (undocumented)

workspaces/dcm/plugins/dcm-common/src/clients/CatalogApi.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,13 @@ export interface CatalogApi {
5252
createCatalogItemInstance(
5353
instance: CatalogItemInstance,
5454
): Promise<CatalogItemInstance>;
55+
/**
56+
* Triggers catalog item instance rehydrate (placement); may assign a new resource id.
57+
*
58+
* @public
59+
*/
60+
rehydrateCatalogItemInstance(
61+
catalogItemInstanceId: string,
62+
): Promise<CatalogItemInstance>;
5563
deleteCatalogItemInstance(catalogItemInstanceId: string): Promise<void>;
5664
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import type { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';
18+
import { CatalogClient } from './CatalogClient';
19+
import type { CatalogItemInstance } from '../types/catalog';
20+
21+
const BASE_URL = 'http://localhost/api/dcm';
22+
23+
const MOCK_INSTANCE: CatalogItemInstance = {
24+
api_version: 'v1alpha1',
25+
display_name: 'Test instance',
26+
uid: 'inst-1',
27+
spec: {
28+
catalog_item_id: 'ci-1',
29+
user_values: [],
30+
},
31+
resource_id: 'res-new',
32+
};
33+
34+
function makeClient(fetchFn: jest.Mock) {
35+
const discoveryApi: DiscoveryApi = {
36+
getBaseUrl: jest.fn().mockResolvedValue(BASE_URL),
37+
};
38+
const fetchApi: FetchApi = { fetch: fetchFn };
39+
return new CatalogClient({ discoveryApi, fetchApi });
40+
}
41+
42+
function okJson(data: unknown): Response {
43+
return {
44+
status: 200,
45+
ok: true,
46+
json: async () => data,
47+
} as unknown as Response;
48+
}
49+
50+
describe('CatalogClient', () => {
51+
it('rehydrateCatalogItemInstance calls POST catalog-item-instances/{id}:rehydrate', async () => {
52+
const fetchFn = jest.fn().mockResolvedValue(okJson(MOCK_INSTANCE));
53+
const client = makeClient(fetchFn);
54+
55+
const result = await client.rehydrateCatalogItemInstance('inst-1');
56+
57+
expect(result).toEqual(MOCK_INSTANCE);
58+
const [url, init] = fetchFn.mock.calls[0];
59+
expect(url).toBe(
60+
`${BASE_URL}/proxy/catalog-item-instances/inst-1:rehydrate`,
61+
);
62+
expect(init.method).toBe('POST');
63+
});
64+
});

workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ export class CatalogClient extends DcmBaseClient implements CatalogApi {
111111
});
112112
}
113113

114+
/**
115+
* @public
116+
*/
117+
async rehydrateCatalogItemInstance(
118+
catalogItemInstanceId: string,
119+
): Promise<CatalogItemInstance> {
120+
return this.fetch<CatalogItemInstance>(
121+
`catalog-item-instances/${catalogItemInstanceId}:rehydrate`,
122+
{ method: 'POST', body: '{}' },
123+
);
124+
}
125+
114126
async deleteCatalogItemInstance(
115127
catalogItemInstanceId: string,
116128
): Promise<void> {

workspaces/dcm/plugins/dcm-common/src/clients/PlacementApi.ts

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)