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

Commit 0b7ac44

Browse files
Merge pull request #18 from solace-iot-team/feature-group-roles
Feature group roles
2 parents 067cd6a + a35e8bd commit 0b7ac44

File tree

215 files changed

+18743
-5786
lines changed

Some content is hidden

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

215 files changed

+18743
-5786
lines changed

ReleaseNotes.md

+36
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,42 @@
22

33
Solace Async API Management.
44

5+
## Version 0.0.37
6+
* [API-M Admin & Developer Portal](https://github.com/solace-iot-team/async-apim/tree/main/apim-portal): 0.0.37
7+
* [API-M Server OpenAPI](https://github.com/solace-iot-team/async-apim/blob/main/apim-server/server/common/api.yml): 0.0.19
8+
* [API-M Server](https://github.com/solace-iot-team/async-apim/tree/main/apim-server): 0.0.13
9+
* [API-M Connector OpenAPI](https://github.com/solace-iot-team/platform-api): 0.6.5
10+
11+
#### API-M Admin & Developer Portal
12+
13+
**New Features:**
14+
- **Organization/Business Groups**
15+
- manage business groups within an organization including import from external systems
16+
- assign organization users to be members of business groups with roles in that group
17+
- user select business group to work in
18+
- top level business group is the organization
19+
- user roles are inherited by all children of business group
20+
- business groups can be imported via API from external systems using the external system id and external system business group id
21+
- **User Selection of Business Group**
22+
- user can select the business group they are working in from toolbar based on calculated roles
23+
- roles are adjusted to settings for that business group
24+
- last business group is saved and on new login automatically selected for the user. On first login, system will assign a default business group).
25+
- **Organization/External Systems**
26+
- define external systems for integration - e.g. import of business groups
27+
- **Organization/Users**
28+
- assign users to business groups with roles per business group
29+
- roles flow down from parent business groups to all children
30+
- **System/Users**
31+
- separated organization users from system user management
32+
- **System/Organization/Manage Users**
33+
- allows for setting organization roles by organization on users
34+
- **User Session Management**
35+
- API calls for session management in case of re-configuration of system and/or organization:
36+
- logout,
37+
- logout all users,
38+
- logout all users logged into an organization,
39+
- API call to login on behalf of a user (loginAs)
40+
541
## Version 0.0.36
642
* [API-M Admin & Developer Portal](https://github.com/solace-iot-team/async-apim/tree/main/apim-portal): 0.0.36
743
* [API-M Server OpenAPI](https://github.com/solace-iot-team/async-apim/blob/main/apim-server/server/common/api.yml): 0.0.18

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.0.36",
3+
"version": "0.0.37",
44
"description": "Solace Async API Management Portal",
55
"repository": {
66
"type": "git",

apim-portal/src/App.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from "react";
22
import { useHistory, Route, Switch } from 'react-router-dom';
33

44
import { Config } from "./Config";
5-
import { UserContext } from './components/UserContextProvider/UserContextProvider';
5+
import { UserContext } from './components/APContextProviders/APUserContextProvider';
66
import { AuthContext } from "./components/AuthContextProvider/AuthContextProvider";
77

88
// * Admin Portal *

apim-portal/src/admin-portal/AdminPortalAppRoutes.tsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import { ProtectedRouteWithRbac } from "../auth/ProtectedRouteWithRbac";
55
import { ProtectedRouteWithRbacAndOrgAccess } from "../auth/ProtectedRouteWithRbacAndOrgAccess";
66
import { EUIAdminPortalResourcePaths } from '../utils/Globals';
77
import { AdminPortalUserHomePage } from "./pages/AdminPortalUserHomePage";
8-
import { ManageUsersPage } from './pages/ManageUsersPage';
9-
import { ManageOrganizationsPage } from "./pages/ManageOrganizationsPage";
108
import { ManageConnectorsPage } from "./pages/ManageConnectorsPage";
119
import { ManageSystemSettingsPage } from "./pages/ManageSystemSettingsPage";
1210
import { MonitorSystemHealthPage } from "./pages/MonitorSystemHealthPage";
@@ -16,10 +14,12 @@ import { ManageApiProductsPage } from "./pages/ManageApiProductsPage";
1614
import { ManageAppsPage } from './pages/ManageAppsPage';
1715
import { AdminPortalHealthCheckViewPage } from "./pages/AdminPortalHealthCheckViewPage";
1816
import { ManageOrgUsersPage } from "./pages/ManageOrgUsersPage";
19-
import { ManageOrgSettingsPage } from "./pages/ManageOrgSettingsPage";
20-
import { MonitorOrgStatusPage } from "./pages/MonitorOrgStatusPage";
2117
import { ManageOrgIntegrationExternalSystemsPage } from "./pages/ManageOrgIntegrationExternalSystemsPage";
2218
import { ManageOrgBusinessGroupsPage } from "./pages/ManageOrgBusinessGroupsPage";
19+
import { ManageSystemUsersPage } from "./pages/ManageSystemUsersPage";
20+
import { ManageOrganizationSettingsPage } from "./pages/ManageOrganizationSettingsPage";
21+
import { ManageSystemOrganizationsPage } from "./pages/ManageSystemOrganizationsPage";
22+
import { MonitorOrganizationStatusPage } from "./pages/MonitorOrganizationStatusPage";
2323

2424
export const AdminPortalAppRoutes = (): Array<JSX.Element> => {
2525
// const componentName = 'AdminPortalAppRoutes';
@@ -31,12 +31,12 @@ export const AdminPortalAppRoutes = (): Array<JSX.Element> => {
3131
/* System */
3232
<ProtectedRouteWithRbac path={EUIAdminPortalResourcePaths.ManageSystemConfigConnectors} component={ManageConnectorsPage} exact key={EUIAdminPortalResourcePaths.ManageSystemConfigConnectors} />,
3333
<ProtectedRouteWithRbac path={EUIAdminPortalResourcePaths.ManageSystemConfigSettings} component={ManageSystemSettingsPage} exact key={EUIAdminPortalResourcePaths.ManageSystemConfigSettings} />,
34-
<ProtectedRouteWithRbac path={EUIAdminPortalResourcePaths.ManageSystemUsers} component={ManageUsersPage} exact key={EUIAdminPortalResourcePaths.ManageSystemUsers} />,
35-
<ProtectedRouteWithRbac path={EUIAdminPortalResourcePaths.ManageSystemOrganizations} component={ManageOrganizationsPage} exact key={EUIAdminPortalResourcePaths.ManageSystemOrganizations} />,
34+
<ProtectedRouteWithRbac path={EUIAdminPortalResourcePaths.ManageSystemUsers} component={ManageSystemUsersPage} exact key={EUIAdminPortalResourcePaths.ManageSystemUsers} />,
35+
<ProtectedRouteWithRbac path={EUIAdminPortalResourcePaths.ManageSystemOrganizations} component={ManageSystemOrganizationsPage} exact key={EUIAdminPortalResourcePaths.ManageSystemOrganizations} />,
3636
<ProtectedRouteWithRbac path={EUIAdminPortalResourcePaths.MonitorSystemHealth} component={MonitorSystemHealthPage} exact key={EUIAdminPortalResourcePaths.MonitorSystemHealth} />,
3737
/* Organization */
38-
<ProtectedRouteWithRbacAndOrgAccess path={EUIAdminPortalResourcePaths.ManageOrganizationSettings} component={ManageOrgSettingsPage} exact key={EUIAdminPortalResourcePaths.ManageOrganizationSettings} />,
39-
<ProtectedRouteWithRbacAndOrgAccess path={EUIAdminPortalResourcePaths.MonitorOrganizationStatus} component={MonitorOrgStatusPage} exact key={EUIAdminPortalResourcePaths.MonitorOrganizationStatus} />,
38+
<ProtectedRouteWithRbacAndOrgAccess path={EUIAdminPortalResourcePaths.ManageOrganizationSettings} component={ManageOrganizationSettingsPage} exact key={EUIAdminPortalResourcePaths.ManageOrganizationSettings} />,
39+
<ProtectedRouteWithRbacAndOrgAccess path={EUIAdminPortalResourcePaths.MonitorOrganizationStatus} component={MonitorOrganizationStatusPage} exact key={EUIAdminPortalResourcePaths.MonitorOrganizationStatus} />,
4040
<ProtectedRouteWithRbacAndOrgAccess path={EUIAdminPortalResourcePaths.ManageOrganizationUsers} component={ManageOrgUsersPage} exact key={EUIAdminPortalResourcePaths.ManageOrganizationUsers} />,
4141
<ProtectedRouteWithRbacAndOrgAccess path={EUIAdminPortalResourcePaths.ManageOrganizationBusinessGroups} component={ManageOrgBusinessGroupsPage} exact key={EUIAdminPortalResourcePaths.ManageOrganizationBusinessGroups} />,
4242
<ProtectedRouteWithRbacAndOrgAccess path={EUIAdminPortalResourcePaths.ManageOrganizationEnvironments} component={ManageOrgEnvironmentsPage} exact key={EUIAdminPortalResourcePaths.ManageOrganizationEnvironments} />,

apim-portal/src/admin-portal/components/AdminPortalSideBar/AdminPortalSideBar.tsx

+6-11
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { MenuItem } from "primereact/components/menuitem/MenuItem";
55
import { PanelMenu } from 'primereact/panelmenu';
66

77
import { AuthContext } from "../../../components/AuthContextProvider/AuthContextProvider";
8-
import { UserContext } from "../../../components/UserContextProvider/UserContextProvider";
8+
import { UserContext } from "../../../components/APContextProviders/APUserContextProvider";
99
import { APHealthCheckSummaryContext } from "../../../components/APHealthCheckSummaryContextProvider";
1010
import { EAPHealthCheckSuccess } from "../../../utils/APHealthCheck";
1111
import { AuthHelper } from "../../../auth/AuthHelper";
@@ -95,16 +95,16 @@ export const AdminPortalSideBar: React.FC<IAdminPortalSideBarProps> = (props: IA
9595
disabled: isDisabledWithConnectorUnavailable(isDisabledWithoutOrg, EUIAdminPortalResourcePaths.ManageOrganizationEnvironments),
9696
command: () => { navigateTo(EUIAdminPortalResourcePaths.ManageOrganizationEnvironments); }
9797
},
98-
{
99-
label: 'Business Groups',
100-
disabled: isDisabledWithConnectorUnavailable(isDisabledWithoutOrg, EUIAdminPortalResourcePaths.ManageOrganizationBusinessGroups),
101-
command: () => { navigateTo(EUIAdminPortalResourcePaths.ManageOrganizationBusinessGroups); }
102-
},
10398
{
10499
label: 'Users',
105100
disabled: isDisabledWithConnectorUnavailable(isDisabledWithoutOrg, EUIAdminPortalResourcePaths.ManageOrganizationUsers),
106101
command: () => { navigateTo(EUIAdminPortalResourcePaths.ManageOrganizationUsers); }
107102
},
103+
{
104+
label: 'Business Groups',
105+
disabled: isDisabledWithConnectorUnavailable(isDisabledWithoutOrg, EUIAdminPortalResourcePaths.ManageOrganizationBusinessGroups),
106+
command: () => { navigateTo(EUIAdminPortalResourcePaths.ManageOrganizationBusinessGroups); }
107+
},
108108
{
109109
label: 'Settings',
110110
disabled: isDisabledWithConnectorUnavailable(isDisabledWithoutOrg, EUIAdminPortalResourcePaths.ManageOrganizationSettings),
@@ -137,11 +137,6 @@ export const AdminPortalSideBar: React.FC<IAdminPortalSideBarProps> = (props: IA
137137
disabled: isDisabled(EUIAdminPortalResourcePaths.ManageSystemUsers),
138138
command: () => { navigateTo(EUIAdminPortalResourcePaths.ManageSystemUsers); }
139139
},
140-
// {
141-
// label: 'Teams',
142-
// disabled: isDisabled(EUIAdminPortalResourcePaths.ManageSystemTeams),
143-
// command: () => { navigateTo(EUIAdminPortalResourcePaths.ManageSystemTeams); }
144-
// },
145140
{
146141
label: 'Organizations',
147142
disabled: isDisabledWithConnectorUnavailable(isDisabled, EUIAdminPortalResourcePaths.ManageSystemOrganizations),

apim-portal/src/admin-portal/components/ManageApiProducts/SearchSelectApis.tsx

+27-11
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { ApiCallStatusError } from "../../../components/ApiCallStatusError/ApiCa
1212
import { APComponentHeader } from "../../../components/APComponentHeader/APComponentHeader";
1313
import { E_CALL_STATE_ACTIONS } from "./ManageApiProductsCommon";
1414
import APEntityIdsService, { TAPEntityIdList } from "../../../utils/APEntityIdsService";
15-
import { TAPApiDisplay, TAPApiDisplayList } from "../../../utils/APApisService";
15+
import APApisService, { TAPApiDisplay, TAPApiDisplayList } from "../../../utils/APApisService";
1616
import { APRenderUtils } from "../../../utils/APRenderUtils";
1717
import APAdminPortalApisService from "../../utils/APAdminPortalApisService";
1818

@@ -37,8 +37,9 @@ export const SearchSelectApis: React.FC<ISearchSelectApisProps> = (props: ISearc
3737
// const GlobalSearchPlaceholder = 'Enter search word list separated by <space> ...';
3838
const GlobalSearchPlaceholder = 'search...';
3939

40-
const [managedObjectTableDataList, setManagedObjectTableDataList] = React.useState<TAPApiDisplayList>([]);
41-
const [selectedManagedObjectTableDataList, setSelectedManagedObjectTableDataList] = React.useState<TAPApiDisplayList>([]);
40+
const [isInitialialized, setIsInitialized] = React.useState<boolean>(false);
41+
const [managedObjectTableDataList, setManagedObjectTableDataList] = React.useState<TAPApiDisplayList>();
42+
const [selectedManagedObjectTableDataList, setSelectedManagedObjectTableDataList] = React.useState<TAPApiDisplayList>();
4243
const [apiCallStatus, setApiCallStatus] = React.useState<TApiCallState | null>(null);
4344
const [globalFilter, setGlobalFilter] = React.useState<string>(); // * Data Table *
4445
const dt = React.useRef<any>(null);
@@ -72,10 +73,19 @@ export const SearchSelectApis: React.FC<ISearchSelectApisProps> = (props: ISearc
7273
}, []); /* eslint-disable-line react-hooks/exhaustive-deps */
7374

7475
React.useEffect(() => {
75-
if(!managedObjectTableDataList) return;
76-
setSelectedManagedObjectTableDataList(APAdminPortalApisService.create_ApApiDisplayList_FilteredBy_EntityIdList(managedObjectTableDataList, props.currentSelectedApiItemList));
76+
if(managedObjectTableDataList === undefined) return;
77+
setSelectedManagedObjectTableDataList(
78+
APEntityIdsService.create_ApDisplayObjectList_FilteredBy_EntityIdList<TAPApiDisplay>({
79+
apDisplayObjectList: managedObjectTableDataList,
80+
filterByEntityIdList: props.currentSelectedApiItemList
81+
})
82+
);
7783
}, [managedObjectTableDataList]); /* eslint-disable-line react-hooks/exhaustive-deps */
7884

85+
React.useEffect(() => {
86+
if(selectedManagedObjectTableDataList === undefined) return;
87+
setIsInitialized(true);
88+
}, [selectedManagedObjectTableDataList]); /* eslint-disable-line react-hooks/exhaustive-deps */
7989

8090
React.useEffect(() => {
8191
if (apiCallStatus !== null) {
@@ -86,8 +96,9 @@ export const SearchSelectApis: React.FC<ISearchSelectApisProps> = (props: ISearc
8696
// * UI Controls *
8797

8898
const onSaveSelectedApis = () => {
89-
// const funcName = ' onSaveSelectedApis';
90-
// const logName = `${componentName}.${funcName}()`;
99+
const funcName = 'onSaveSelectedApis';
100+
const logName = `${componentName}.${funcName}()`;
101+
if(selectedManagedObjectTableDataList === undefined) throw new Error(`${logName}: selectedManagedObjectTableDataList === undefined`);
91102
// console.log(`${logName}: selectedManagedObjectTableDataList=${JSON.stringify(selectedManagedObjectTableDataList, null, 2)}`);
92103
props.onSave(ApiCallState.getInitialCallState(E_CALL_STATE_ACTIONS.SELECT_APIS, `select apis`), APEntityIdsService.create_EntityIdList_From_ApDisplayObjectList<TAPApiDisplay>(selectedManagedObjectTableDataList));
93104
}
@@ -99,10 +110,14 @@ export const SearchSelectApis: React.FC<ISearchSelectApisProps> = (props: ISearc
99110
}
100111

101112
const renderDataTableHeader = (): JSX.Element => {
113+
const funcName = 'renderDataTableHeader';
114+
const logName = `${componentName}.${funcName}()`;
115+
if(selectedManagedObjectTableDataList === undefined) throw new Error(`${logName}: selectedManagedObjectTableDataList === undefined`);
116+
const isSaveDisabled: boolean = selectedManagedObjectTableDataList.length === 0;
102117
return (
103118
<div className="table-header">
104119
<div style={{ whiteSpace: "nowrap"}}>
105-
<Button type="button" label="Save" className="p-button-text p-button-plain p-button-outlined p-mr-2" onClick={onSaveSelectedApis} disabled={selectedManagedObjectTableDataList.length === 0} />
120+
<Button type="button" label="Save" className="p-button-text p-button-plain p-button-outlined p-mr-2" onClick={onSaveSelectedApis} disabled={isSaveDisabled} />
106121
<Button type="button" label="Cancel" className="p-button-text p-button-plain p-mr-2" onClick={props.onCancel} />
107122
</div>
108123
<div style={{ alignContent: "right"}}>
@@ -142,7 +157,8 @@ export const SearchSelectApis: React.FC<ISearchSelectApisProps> = (props: ISearc
142157
// );
143158
// }
144159
const renderManagedObjectDataTable = (): JSX.Element => {
145-
return (
160+
const dataKey = APApisService.nameOf_Entity('id');
161+
return (
146162
<div className="card">
147163
<DataTable
148164
ref={dt}
@@ -152,7 +168,7 @@ export const SearchSelectApis: React.FC<ISearchSelectApisProps> = (props: ISearc
152168
globalFilter={globalFilter}
153169
scrollable
154170
scrollHeight="800px"
155-
dataKey="apEntityId.id"
171+
dataKey={dataKey}
156172
emptyMessage={renderManagedObjectTableEmptyMessage()}
157173
// selection
158174
selection={selectedManagedObjectTableDataList}
@@ -182,7 +198,7 @@ export const SearchSelectApis: React.FC<ISearchSelectApisProps> = (props: ISearc
182198

183199
<ApiCallStatusError apiCallStatus={apiCallStatus} />
184200

185-
{ renderManagedObjectDataTable() }
201+
{ isInitialialized && renderManagedObjectDataTable() }
186202

187203
{/* DEBUG selected managedObjects */}
188204
{/* {managedProductList.length > 0 && tableSelectedApiProductList &&

0 commit comments

Comments
 (0)