Skip to content
This repository was archived by the owner on Feb 20, 2024. It is now read-only.

Commit 1c0d3f8

Browse files
Merge pull request #27 from solace-iot-team/feature-bg-apps
Feature bg apps
2 parents 5caa45f + cab8145 commit 1c0d3f8

File tree

78 files changed

+2326
-6652
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+2326
-6652
lines changed

ReleaseNotes.md

+17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22

33
Solace Async API Management.
44

5+
## Version 0.1.7
6+
* [API-M Admin & Developer Portal](https://github.com/solace-iot-team/async-apim/tree/main/apim-portal): 0.1.7
7+
* [API-M Server OpenAPI](https://github.com/solace-iot-team/async-apim/blob/main/apim-server/server/common/api.yml): 0.1.0
8+
* [API-M Server](https://github.com/solace-iot-team/async-apim/tree/main/apim-server): 0.1.0
9+
* [API-M Connector OpenAPI](https://github.com/solace-iot-team/platform-api): 0.7.11
10+
11+
#### API-M Admin & Developer Portal
12+
**New Features:**
13+
* **Developer Portal:Business Group Apps**
14+
- new feature, create and manage business group apps as well
15+
16+
**Enhancements:**
17+
* **Developer Portal:My Apps & Business Group Apps**
18+
- improved fetch time of list
19+
* **Admin Portal:Business Groups**
20+
- added business group apps to list of assets and fixed delete protection for group with assets
21+
522
## Version 0.1.6
623
* [API-M Admin & Developer Portal](https://github.com/solace-iot-team/async-apim/tree/main/apim-portal): 0.1.6
724
* [API-M Server OpenAPI](https://github.com/solace-iot-team/async-apim/blob/main/apim-server/server/common/api.yml): 0.1.0

apim-portal/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "async-apim-portal",
3-
"version": "0.1.6",
3+
"version": "0.1.7",
44
"description": "Solace Async API Management Portal",
55
"repository": {
66
"type": "git",

apim-portal/src/App.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import { DeveloperPortalHomePage } from "./developer-portal/pages/DeveloperPorta
1414
import { DeveloperPortalAppRoutes } from "./developer-portal/DeveloperPortalAppRoutes";
1515
import { DeveloperPortalSideBar } from "./developer-portal/components/DeveloperPortalSideBar";
1616
// * Public Developer Portal *
17-
import { PublicDeveloperPortalAppRoutes } from "./developer-portal/PublicDeveloperPortalAppRoutes";
18-
import { PublicDeveloperPortalSideBar } from "./developer-portal/components/PublicDeveloperPortalSideBar";
17+
// import { PublicDeveloperPortalAppRoutes } from "./developer-portal/PublicDeveloperPortalAppRoutes";
18+
// import { PublicDeveloperPortalSideBar } from "./developer-portal/components/PublicDeveloperPortalSideBar";
1919

2020
import {
2121
EUIDeveloperToolsResourcePaths,
@@ -158,9 +158,9 @@ const App: React.FC = () => {
158158
{ isDebug && userContext && displayStateInfo() }
159159
<div className="ap-app-grid">
160160
<div className="ap-app-grid-left">
161-
{showPublicDeveloperPortal &&
161+
{/* {showPublicDeveloperPortal &&
162162
<PublicDeveloperPortalSideBar />
163-
}
163+
} */}
164164
{showDeveloperPortal &&
165165
<DeveloperPortalSideBar onSwitchToAdminPortal={onSwitchToAdminPortal} />
166166
}
@@ -188,7 +188,7 @@ const App: React.FC = () => {
188188
{ showAdminPortal && AdminPortalAppRoutes() }
189189

190190
{/* Public Developer Portal */}
191-
{ showPublicDeveloperPortal && PublicDeveloperPortalAppRoutes() }
191+
{/* { showPublicDeveloperPortal && PublicDeveloperPortalAppRoutes() } */}
192192

193193
{/* Developer Portal */}
194194
{ showDeveloperPortal && DeveloperPortalAppRoutes() }

apim-portal/src/admin-portal/components/ManageApps/ListApps.tsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { Loading } from "../../../components/Loading/Loading";
2626
import APDisplayUtils from "../../../displayServices/APDisplayUtils";
2727
import APEntityIdsService, { TAPEntityIdList } from "../../../utils/APEntityIdsService";
2828
import APRbacDisplayService from "../../../displayServices/APRbacDisplayService";
29+
import { Config } from "../../../Config";
2930

3031
import '../../../components/APComponents.css';
3132
import "./ManageApps.css";
@@ -260,7 +261,7 @@ export const ListApps: React.FC<IListAppsProps> = (props: IListAppsProps) => {
260261
const ownerIdField = APAdminPortalAppsDisplayService.nameOf_ApAppMeta('appOwnerId');
261262
const ownerTypeField = APAdminPortalAppsDisplayService.nameOf_ApAppMeta('apAppOwnerType');
262263
const appTypeField = APAdminPortalAppsDisplayService.nameOf_ApAppMeta('apAppType');
263-
// const develStatusField = APAdminPortalAppsDisplayService.nameOf<TManagedObject>('apAppStatus');
264+
const develAppStatusField = 'connectorAppListItem.status';
264265

265266
return (
266267
<div className="card">
@@ -291,7 +292,9 @@ export const ListApps: React.FC<IListAppsProps> = (props: IListAppsProps) => {
291292
<Column header="Owner Id" body={ownerIdBodyTemplate} field={ownerIdField} sortable />
292293
<Column header="Owner Type" body={ownerTypeBodyTemplate} field={ownerTypeField} sortable style={{ width: '9em' }}/>
293294
<Column header="Status" field={statusField} sortable style={{ width: "13em"}} />
294-
{/* <Column header="DEVEL:Status" field={develStatusField} sortable style={{ width: "13em"}} /> */}
295+
{Config.getUseDevelTools() &&
296+
<Column header="DEVEL:App Status" field={develAppStatusField} style={{ width: "15%"}} sortable />
297+
}
295298
</DataTable>
296299
</div>
297300
);

apim-portal/src/admin-portal/components/ManageApps/ManageAccess/EditApiProducts.tsx

+19-14
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,21 @@ export const EditApiProducts: React.FC<IEditApiProductsProps> = (props: IEditApi
4242

4343

4444
const hasApiProductListChanged = (): boolean => {
45-
const funcName = 'hasApiProductListChanged';
46-
const logName = `${ComponentName}.${funcName}()`;
47-
if(managedObject === undefined) throw new Error(`${logName}: managedObject === undefined`);
48-
// compare original with managedObject
49-
let hasChanged: boolean = false;
50-
managedObject.forEach( (moElem: TManagedObjectElement) => {
51-
const currentAppApiProductDisplay: TAPDeveloperPortalAppApiProductDisplay | undefined = props.apAdminPortalAppDisplay.apAppApiProductDisplayList.find( (x) => {
52-
return x.apEntityId.id === moElem.apEntityId.id;
53-
});
54-
if(currentAppApiProductDisplay === undefined) throw new Error(`${logName}: currentAppApiProductDisplay === undefined`);
55-
if(moElem.apApp_ApiProduct_Status !== currentAppApiProductDisplay.apApp_ApiProduct_Status) hasChanged = true;
56-
});
57-
return hasChanged;
45+
// set to true to always enable save, seems easier to manage externally produced apps that are not approved
46+
return true;
47+
// const funcName = 'hasApiProductListChanged';
48+
// const logName = `${ComponentName}.${funcName}()`;
49+
// if(managedObject === undefined) throw new Error(`${logName}: managedObject === undefined`);
50+
// // compare original with managedObject
51+
// let hasChanged: boolean = false;
52+
// managedObject.forEach( (moElem: TManagedObjectElement) => {
53+
// const currentAppApiProductDisplay: TAPDeveloperPortalAppApiProductDisplay | undefined = props.apAdminPortalAppDisplay.apAppApiProductDisplayList.find( (x) => {
54+
// return x.apEntityId.id === moElem.apEntityId.id;
55+
// });
56+
// if(currentAppApiProductDisplay === undefined) throw new Error(`${logName}: currentAppApiProductDisplay === undefined`);
57+
// if(moElem.apApp_ApiProduct_Status !== currentAppApiProductDisplay.apApp_ApiProduct_Status) hasChanged = true;
58+
// });
59+
// return hasChanged;
5860
}
5961

6062
const get_OriginalManagedObjectElement = (moElem: TManagedObjectElement): TManagedObjectElement => {
@@ -169,9 +171,12 @@ export const EditApiProducts: React.FC<IEditApiProductsProps> = (props: IEditApi
169171
);
170172
}
171173
const managedObjectFormFooterRightToolbarTemplate = () => {
174+
const isSaveDisabled: boolean = !hasApiProductListChanged();
172175
return (
173176
<React.Fragment>
174-
<Button key={ComponentName+'Save'} form={FormId} type="submit" label="Save" icon="pi pi-save" className="p-button-text p-button-plain p-button-outlined" disabled={!hasApiProductListChanged()} />
177+
<Button key={ComponentName+'Save'} form={FormId} type="submit" label="Save" icon="pi pi-save" className="p-button-text p-button-plain p-button-outlined"
178+
disabled={isSaveDisabled}
179+
/>
175180
</React.Fragment>
176181
);
177182
}

apim-portal/src/admin-portal/components/ManageBusinessGroups/ListAsTreeTableBusinessGroups.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ export const ListAsTreeTableBusinessGroups: React.FC<IListAsTreeTableBusinessGro
138138
</div>
139139
);
140140
}
141+
if(node.data.apBusinessGroupAssetReference.apBusinessGroupAppReferenceEntityIdList.length > 0) {
142+
jsxElementList.push(
143+
<div>
144+
Business Group Apps: {node.data.apBusinessGroupAssetReference.apBusinessGroupAppReferenceEntityIdList.length}
145+
</div>
146+
);
147+
}
141148
if(jsxElementList.length === 0) {
142149
jsxElementList.push(
143150
<div>None.</div>

apim-portal/src/admin-portal/components/ManageBusinessGroups/ViewBusinessGroup.tsx

+55-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { APComponentHeader } from "../../../components/APComponentHeader/APCompo
77
import { ApiCallState, TApiCallState } from "../../../utils/ApiCallState";
88
import { ApiCallStatusError } from "../../../components/ApiCallStatusError/ApiCallStatusError";
99
import { E_CALL_STATE_ACTIONS } from "./ManageBusinessGroupsCommon";
10-
import APBusinessGroupsDisplayService, { TAPBusinessGroupDisplay } from "../../../displayServices/APBusinessGroupsDisplayService";
10+
import APBusinessGroupsDisplayService, { TAPBusinessGroupAssetReference, TAPBusinessGroupDisplay } from "../../../displayServices/APBusinessGroupsDisplayService";
1111
import APEntityIdsService, { TAPEntityId, TAPEntityIdList } from "../../../utils/APEntityIdsService";
1212
import { APSClientOpenApi } from "../../../utils/APSClientOpenApi";
1313
import APDisplayUtils from "../../../displayServices/APDisplayUtils";
@@ -39,7 +39,8 @@ export const ViewBusinessGroup: React.FC<IViewBusinessGroupProps> = (props: IVie
3939
try {
4040
const object: TAPBusinessGroupDisplay = await APBusinessGroupsDisplayService.apsGet_ApBusinessGroupDisplay({
4141
organizationId: props.organizationId,
42-
businessGroupId: props.businessGroupEntityId.id
42+
businessGroupId: props.businessGroupEntityId.id,
43+
fetchAssetReferences: true
4344
});
4445
setManagedObject(object);
4546
} catch(e: any) {
@@ -95,12 +96,57 @@ export const ViewBusinessGroup: React.FC<IViewBusinessGroupProps> = (props: IVie
9596
);
9697
}
9798
const renderMembers = (apUserEntityIdList: TAPEntityIdList): JSX.Element => {
99+
if(apUserEntityIdList.length > 0) {
100+
return (
101+
<React.Fragment>
102+
<div><b>Members:</b></div>
103+
<div className="p-ml-2">
104+
{APDisplayUtils.create_DivList_From_StringList(APEntityIdsService.create_DisplayNameList(apUserEntityIdList))}
105+
</div>
106+
</React.Fragment>
107+
);
108+
}
109+
return (
110+
<div><b>Members</b>: None.</div>
111+
);
112+
}
113+
const renderAssetReferences = (apBusinessGroupAssetReference: TAPBusinessGroupAssetReference): JSX.Element => {
114+
const jsxElementList: Array<JSX.Element> = [];
115+
if(apBusinessGroupAssetReference.apApiProductReferenceEntityIdList.length > 0) {
116+
jsxElementList.push(
117+
<React.Fragment>
118+
<div className="p-ml-2 p-mt-2">
119+
<b>API Products:</b>
120+
<div className="p-ml-2">
121+
{APDisplayUtils.create_DivList_From_StringList(APEntityIdsService.create_DisplayNameList(apBusinessGroupAssetReference.apApiProductReferenceEntityIdList))}
122+
</div>
123+
</div>
124+
</React.Fragment>
125+
);
126+
}
127+
if(apBusinessGroupAssetReference.apBusinessGroupAppReferenceEntityIdList.length > 0) {
128+
jsxElementList.push(
129+
<React.Fragment>
130+
<div className="p-ml-2 p-mt-2">
131+
<b>Business Group Apps:</b>
132+
<div className="p-ml-2">
133+
{APDisplayUtils.create_DivList_From_StringList(APEntityIdsService.create_DisplayNameList(apBusinessGroupAssetReference.apBusinessGroupAppReferenceEntityIdList))}
134+
</div>
135+
</div>
136+
</React.Fragment>
137+
);
138+
}
139+
if(jsxElementList.length === 0) {
140+
jsxElementList.push(
141+
<div>None.</div>
142+
);
143+
}
98144
return (
99145
<React.Fragment>
100-
<div><b>Members:</b></div>
101-
<div className="p-ml-2">
102-
{APDisplayUtils.create_DivList_From_StringList(APEntityIdsService.create_DisplayNameList(apUserEntityIdList))}
103-
</div>
146+
<div><b>Assets:</b></div>
147+
<div className="p-ml-2">
148+
{jsxElementList}
149+
</div>
104150
</React.Fragment>
105151
);
106152
}
@@ -126,6 +172,9 @@ export const ViewBusinessGroup: React.FC<IViewBusinessGroupProps> = (props: IVie
126172
<Divider />
127173
{renderMembers(managedObject.apMemberUserEntityIdList)}
128174

175+
<Divider />
176+
{renderAssetReferences(managedObject.apBusinessGroupAssetReference)}
177+
129178
</div>
130179
<div className="view-detail-right">
131180
<div>Id: {managedObject.apEntityId.id}</div>

apim-portal/src/admin-portal/displayServices/APAdminPortalAppsDisplayService.ts

+32-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
ApiError,
23
AppApiProducts,
34
AppApiProductsComplex,
45
AppConnectionStatus,
@@ -30,6 +31,7 @@ import APRbacDisplayService from '../../displayServices/APRbacDisplayService';
3031
import APOrganizationUsersDisplayService, {
3132
TAPCheckOrganizationUserIdExistsResult, TAPOrganizationUserDisplay, TAPOrganizationUserDisplayList
3233
} from '../../displayServices/APUsersDisplayService/APOrganizationUsersDisplayService';
34+
import { APClientConnectorOpenApi } from '../../utils/APClientConnectorOpenApi';
3335
import { IAPEntityIdDisplay, TAPEntityIdList } from '../../utils/APEntityIdsService';
3436
import APSearchContentService, { IAPSearchContent } from '../../utils/APSearchContentService';
3537
import { Globals } from '../../utils/Globals';
@@ -393,6 +395,35 @@ class APAdminPortalAppsDisplayService extends APAppsDisplayService {
393395

394396
}
395397

398+
/**
399+
* Returns the entityId list of business group / team apps.
400+
* If team does not exist, returns empty list
401+
*/
402+
public apiGetList_TeamAppEntityIdList = async({ organizationId, teamId }: {
403+
organizationId: string;
404+
teamId: string;
405+
}): Promise<TAPEntityIdList> => {
406+
try {
407+
const connectorTeamAppList: Array<AppResponse> = await AppsService.listTeamApps({
408+
organizationName: organizationId,
409+
teamName: teamId
410+
});
411+
const list: TAPEntityIdList = connectorTeamAppList.map( (x) => {
412+
return {
413+
id: x.name,
414+
displayName: x.displayName ? x.displayName : x.name
415+
};
416+
});
417+
return list;
418+
} catch(e: any) {
419+
if(APClientConnectorOpenApi.isInstanceOfApiError(e)) {
420+
const apiError: ApiError = e;
421+
if(apiError.status === 404) return [];
422+
}
423+
throw e;
424+
}
425+
}
426+
396427
/**
397428
* Create a list of apps:
398429
* - if loggedIn user can manage external apps, include also external apps
@@ -660,7 +691,7 @@ class APAdminPortalAppsDisplayService extends APAppsDisplayService {
660691
apDeveloperPortalAppApiProductDisplayList: apDeveloperPortalAppApiProductDisplayList
661692
});
662693

663-
// set to approved, apiProducts list is correctly set here
694+
// set to app to approved, apiProducts list is correctly set here
664695
const update: AppPatch = {
665696
status: AppStatus.APPROVED,
666697
apiProducts: connectorAppApiProductList,

apim-portal/src/components/APDisplayDeveloperPortalApp/APDisplayDeveloperPortalAppAsyncApiSpecs.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ export const APDisplayDeveloperPortalAppAsyncApiSpecs: React.FC<IAPDisplayDevelo
100100
setShowApiEntityId(apAppApiDisplay.apEntityId);
101101
}
102102

103+
const apiBodyTemplate = (row: TAPAppApiDisplay) => {
104+
return (<div className="p-ml-2">Async API: {row.apEntityId.displayName}</div>)
105+
}
103106
const renderComponent = (): JSX.Element => {
104107
const rowGroupHeaderTemplate = (row: TAPAppApiDisplay) => {
105108
return(<span className="p-text-bold">API Product: {row.apApiProductEntityId.displayName}</span>);
@@ -136,7 +139,7 @@ export const APDisplayDeveloperPortalAppAsyncApiSpecs: React.FC<IAPDisplayDevelo
136139
onRowClick={onApAppApiDisplaySelect}
137140
onRowDoubleClick={(e) => onApAppApiDisplayOpen(e)}
138141
>
139-
<Column header="API" field={apiField} sortable />
142+
<Column header="API" body={apiBodyTemplate} field={apiField} sortable />
140143
<Column header="Version" field={versionField} style={{width: '10em', textAlign: 'center'}} />
141144
</DataTable>
142145
);

apim-portal/src/developer-portal/DeveloperPortalAppRoutes.tsx

+2-15
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,23 @@ import { ProtectedRoute } from "../auth/ProtectedRoute";
55
import { EUIDeveloperPortalResourcePaths } from '../utils/Globals';
66

77
import { DeveloperPortalUserHomePage } from "./pages/DeveloperPortalUserHomePage";
8-
import { DeveloperPortalExploreApisPage } from "./pages/DeveloperPortalExploreApisPage";
8+
// import { DeveloperPortalExploreApisPage } from "./pages/DeveloperPortalExploreApisPage";
99
import { DeveloperPortalHealthCheckViewPage } from "./pages/DeveloperPortalHealthCheckViewPage";
1010
import { DeveloperPortalExploreApiProductsPage } from "./pages/DeveloperPortalExploreApiProductsPage";
1111
import { DeveloperPortalManageUserAppsPage } from "./pages/DeveloperPortalManageUserAppsPage";
12-
13-
import { DeveloperPortalManageUserAppsPage as DELETEME_DeveloperPortalManageUserAppsPage } from "./pages/deleteme.DeveloperPortalManageUserAppsPage";
14-
import { DeveloperPortalExploreApiProductsPage as DELETEME_DeveloperPortalExploreApiProductsPage} from "./pages/deleteme.DeveloperPortalExploreApiProductsPage";
1512
import { DeveloperPortalManageBusinessGroupAppsPage } from "./pages/DeveloperPortalManageBusinessGroupAppsPage";
1613

17-
1814
export const DeveloperPortalAppRoutes = (): Array<JSX.Element> => {
1915
// const componentName = 'DeveloperPortalAppRoutes';
2016
return (
2117
[
2218
<Route path={EUIDeveloperPortalResourcePaths.DeveloperPortalConnectorUnavailable} component={DeveloperPortalHealthCheckViewPage} exact key={EUIDeveloperPortalResourcePaths.DeveloperPortalConnectorUnavailable}/>,
2319
<ProtectedRoute path={EUIDeveloperPortalResourcePaths.UserHome} component={DeveloperPortalUserHomePage} exact key={EUIDeveloperPortalResourcePaths.UserHome}/>,
2420

25-
2621
<ProtectedRouteWithRbacAndOrgAccess path={EUIDeveloperPortalResourcePaths.ExploreApiProducts} component={DeveloperPortalExploreApiProductsPage} exact key={EUIDeveloperPortalResourcePaths.ExploreApiProducts} />,
27-
28-
<ProtectedRouteWithRbacAndOrgAccess path={EUIDeveloperPortalResourcePaths.DELETEME_ExploreApiProducts} component={DELETEME_DeveloperPortalExploreApiProductsPage} exact key={EUIDeveloperPortalResourcePaths.DELETEME_ExploreApiProducts} />,
29-
30-
31-
<ProtectedRouteWithRbacAndOrgAccess path={EUIDeveloperPortalResourcePaths.ExploreApis} component={DeveloperPortalExploreApisPage} exact key={EUIDeveloperPortalResourcePaths.ExploreApis} />,
32-
22+
// <ProtectedRouteWithRbacAndOrgAccess path={EUIDeveloperPortalResourcePaths.ExploreApis} component={DeveloperPortalExploreApisPage} exact key={EUIDeveloperPortalResourcePaths.ExploreApis} />,
3323

3424
<ProtectedRouteWithRbacAndOrgAccess path={EUIDeveloperPortalResourcePaths.ManageUserApplications} component={DeveloperPortalManageUserAppsPage} exact key={EUIDeveloperPortalResourcePaths.ManageUserApplications} />,
35-
36-
<ProtectedRouteWithRbacAndOrgAccess path={EUIDeveloperPortalResourcePaths.DELETEME_ManageUserApplications} component={DELETEME_DeveloperPortalManageUserAppsPage} exact key={EUIDeveloperPortalResourcePaths.DELETEME_ManageUserApplications} />,
37-
3825
<ProtectedRouteWithRbacAndOrgAccess path={EUIDeveloperPortalResourcePaths.ManageBusinessGroupApplications} component={DeveloperPortalManageBusinessGroupAppsPage} exact key={EUIDeveloperPortalResourcePaths.ManageBusinessGroupApplications} />,
3926
]
4027
);

0 commit comments

Comments
 (0)