Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions workspaces/dcm/.changeset/kind-ravens-rehydrate.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 0 additions & 1 deletion workspaces/dcm/packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 0 additions & 2 deletions workspaces/dcm/packages/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -123,7 +122,6 @@ const routes = (
<Route path="/settings" element={<UserSettingsPage />} />
<Route path="/catalog-graph" element={<CatalogGraphPage />} />
<Route path="/dcm/*" element={<DcmPage />} />
<Route path="/rbac" element={<RbacPage />} />
</FlatRoutes>
);

Expand Down
12 changes: 0 additions & 12 deletions workspaces/dcm/packages/app/src/components/Root/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 (
<SidebarPage>
Expand Down Expand Up @@ -274,16 +272,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
isDcmActive ? classes.submenuItemActive : classes.inactiveItem
}`}
/>
<SidebarItem
icon={VpnKeyIcon}
to="/rbac"
text="RBAC"
className={`${classes.submenuItem} ${
isRbacActive
? classes.submenuItemActive
: classes.inactiveItem
}`}
/>
</Box>
</CollapsibleSubmenu>
</SidebarGroup>
Expand Down
114 changes: 56 additions & 58 deletions workspaces/dcm/plugins/dcm-common/report.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export interface CatalogApi {
listCatalogItems(): Promise<CatalogItemList>;
// (undocumented)
listServiceTypes(): Promise<ServiceTypeList>;
rehydrateCatalogItemInstance(
catalogItemInstanceId: string,
): Promise<CatalogItemInstance>;
// (undocumented)
updateCatalogItem(
catalogItemId: string,
Expand Down Expand Up @@ -71,6 +74,10 @@ export class CatalogClient extends DcmBaseClient implements CatalogApi {
// (undocumented)
listServiceTypes(): Promise<ServiceTypeList>;
// (undocumented)
rehydrateCatalogItemInstance(
catalogItemInstanceId: string,
): Promise<CatalogItemInstance>;
// (undocumented)
protected readonly serviceName = 'Catalog';
// (undocumented)
updateCatalogItem(
Expand Down Expand Up @@ -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<Resource>;
deleteResource(resourceId: string): Promise<void>;
getResource(resourceId: string): Promise<Resource>;
listResources(options?: {
provider?: string;
maxPageSize?: number;
pageToken?: string;
}): Promise<ResourceList>;
rehydrateResource(
resourceId: string,
request: RehydrateRequest,
): Promise<Resource>;
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<Resource>;
// (undocumented)
deleteResource(resourceId: string): Promise<void>;
// (undocumented)
getResource(resourceId: string): Promise<Resource>;
// (undocumented)
listResources(options?: {
provider?: string;
maxPageSize?: number;
pageToken?: string;
}): Promise<ResourceList>;
// (undocumented)
rehydrateResource(
resourceId: string,
request: RehydrateRequest,
): Promise<Resource>;
// (undocumented)
protected readonly serviceName = 'Placement';
}
export function parseDcmEntityStatus(raw: string): DcmEntityStatus | undefined;

// @public
export interface Policy {
Expand Down Expand Up @@ -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<string, unknown>;
update_time?: string;
}

// @public
export interface ResourceCapacity {
// (undocumented)
Expand All @@ -480,11 +438,20 @@ export interface ResourceCapacity {
}

// @public
export interface ResourceList {
export interface ResourcesApi {
listServiceTypeInstances(
params?: ListServiceTypeInstancesParams,
): Promise<ServiceTypeInstanceList>;
}

// @public
export class ResourcesClient extends DcmBaseClient implements ResourcesApi {
// (undocumented)
next_page_token?: string;
listServiceTypeInstances(
params?: ListServiceTypeInstancesParams,
): Promise<ServiceTypeInstanceList>;
// (undocumented)
resources: Resource[];
protected readonly serviceName = 'Resources';
}

// @public
Expand All @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions workspaces/dcm/plugins/dcm-common/src/clients/CatalogApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,13 @@ export interface CatalogApi {
createCatalogItemInstance(
instance: CatalogItemInstance,
): Promise<CatalogItemInstance>;
/**
* Triggers catalog item instance rehydrate (placement); may assign a new resource id.
*
* @public
*/
rehydrateCatalogItemInstance(
catalogItemInstanceId: string,
): Promise<CatalogItemInstance>;
deleteCatalogItemInstance(catalogItemInstanceId: string): Promise<void>;
}
Original file line number Diff line number Diff line change
@@ -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');
});
});
12 changes: 12 additions & 0 deletions workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ export class CatalogClient extends DcmBaseClient implements CatalogApi {
});
}

/**
* @public
*/
async rehydrateCatalogItemInstance(
catalogItemInstanceId: string,
): Promise<CatalogItemInstance> {
return this.fetch<CatalogItemInstance>(
`catalog-item-instances/${catalogItemInstanceId}:rehydrate`,
{ method: 'POST', body: '{}' },
);
}

async deleteCatalogItemInstance(
catalogItemInstanceId: string,
): Promise<void> {
Expand Down
54 changes: 0 additions & 54 deletions workspaces/dcm/plugins/dcm-common/src/clients/PlacementApi.ts

This file was deleted.

Loading
Loading