Skip to content

Commit 402a6a2

Browse files
authored
Merge pull request wso2#8928 from HasiniSama/edit-ui
Provide self organization name update via console UI
2 parents 3c1aa00 + e61e28f commit 402a6a2

File tree

14 files changed

+816
-3
lines changed

14 files changed

+816
-3
lines changed

.changeset/beige-carpets-change.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@wso2is/admin.organizations.v1": patch
3+
"@wso2is/admin.tenants.v1": patch
4+
"@wso2is/admin.core.v1": patch
5+
"@wso2is/console": patch
6+
"@wso2is/i18n": patch
7+
---
8+
9+
Provide self organization name update via console UI

apps/console/src/configs/routes.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import {
2020
ArrowRightToBracketPencilIcon,
2121
BuildingIcon,
22+
BuildingPenIcon,
2223
DocumentCheckIcon,
2324
EnvelopeGearIcon,
2425
EnvelopeIcon,
@@ -1760,6 +1761,18 @@ export const getFullScreenViewRoutes = (): RouteInterface[] => {
17601761
*/
17611762
export const getDefaultLayoutRoutes = (): RouteInterface[] => {
17621763
return [
1764+
{
1765+
component: lazy(() => import("@wso2is/admin.tenants.v1/pages/edit-self-organization-page")),
1766+
exact: true,
1767+
icon: {
1768+
icon: <BuildingPenIcon />
1769+
},
1770+
id: "organizations",
1771+
order: 0,
1772+
path: AppConstants.getPaths().get("EDIT_SELF_ORGANIZATION"),
1773+
protected: true,
1774+
showOnSidePanel: true
1775+
},
17631776
{
17641777
children: [
17651778
{

features/admin.core.v1/constants/app-constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright (c) 2022-2024, WSO2 LLC. (https://www.wso2.com).
2+
* Copyright (c) 2022-2025, WSO2 LLC. (https://www.wso2.com).
33
*
44
* WSO2 LLC. licenses this file to you under the Apache License,
55
* Version 2.0 (the "License"); you may not use this file except
@@ -439,6 +439,7 @@ export class AppConstants {
439439
`${AppConstants.getAdminViewBasePath()}/actions/pre-update-profile` ],
440440
[ "TENANTS", `${AppConstants.getDefaultLayoutBasePath()}/organizations` ],
441441
[ "EDIT_TENANT", `${AppConstants.getDefaultLayoutBasePath()}/organizations/:id` ],
442+
[ "EDIT_SELF_ORGANIZATION", `${AppConstants.getDefaultLayoutBasePath()}/organizations/self` ],
442443
[ "SYSTEM_SETTINGS", `${AppConstants.getDefaultLayoutBasePath()}/organizations/system-settings` ],
443444
[ "POLICY_ADMINISTRATION", `${AppConstants.getAdminViewBasePath()}/policy-administration` ],
444445
[ "EDIT_POLICY", `${AppConstants.getAdminViewBasePath()}/policy-administration/edit-policy/:id` ],

features/admin.organizations.v1/components/organization-switch/organization-switch-breadcrumb.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
2+
* Copyright (c) 2023-2025, WSO2 LLC. (https://www.wso2.com).
33
*
44
* WSO2 LLC. licenses this file to you under the Apache License,
55
* Version 2.0 (the "License"); you may not use this file except
@@ -104,6 +104,23 @@ export const OrganizationSwitchBreadcrumb: FunctionComponent<OrganizationSwitchD
104104
mutateOrganizationBreadCrumbFetchRequest();
105105
}, [ organizationId ]);
106106

107+
/**
108+
* Listen for current authenticated organization updates from the organization edit form.
109+
*/
110+
useEffect(() => {
111+
const handleOrganizationUpdate = (event: CustomEvent) => {
112+
if (event.detail?.success) {
113+
mutateOrganizationBreadCrumbFetchRequest();
114+
}
115+
};
116+
117+
window.addEventListener("organization-updated", handleOrganizationUpdate as EventListener);
118+
119+
return () => {
120+
window.removeEventListener("organization-updated", handleOrganizationUpdate as EventListener);
121+
};
122+
}, []);
123+
107124
const isSubOrg: boolean = window[ "AppUtils" ].getConfig().organizationName;
108125

109126
const isShowSwitcher: boolean = organizationConfigs?.showOrganizationDropdown || isSubOrg;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
import { AsgardeoSPAClient, HttpClientInstance } from "@asgardeo/auth-react";
20+
import { store } from "@wso2is/admin.core.v1/store";
21+
import { OrganizationPatchData } from "@wso2is/admin.organizations.v1/models";
22+
import { IdentityAppsApiException } from "@wso2is/core/exceptions";
23+
import { HttpMethods } from "@wso2is/core/models";
24+
import { AxiosError, AxiosResponse } from "axios";
25+
26+
/**
27+
* Get an HTTP client instance.
28+
*/
29+
const httpClient: HttpClientInstance = AsgardeoSPAClient.getInstance()
30+
.httpRequest.bind(AsgardeoSPAClient.getInstance());
31+
32+
/**
33+
* Update details of the currently authenticated organization.
34+
*
35+
* @param operations - Array of patch operations to apply to the organization.
36+
* @returns Promise containing the updated organization response.
37+
*/
38+
const updateSelfAuthenticatedOrganization = (operations: OrganizationPatchData[]): Promise<any> => {
39+
40+
const requestConfig: any = {
41+
data: operations,
42+
headers: {
43+
"Accept": "application/json",
44+
"Content-Type": "application/json"
45+
},
46+
method: HttpMethods.PATCH,
47+
url: `${store.getState().config.endpoints.organizations}/organizations/self`
48+
};
49+
50+
return httpClient(requestConfig)
51+
.then((response: AxiosResponse) => {
52+
return Promise.resolve(response.data);
53+
})
54+
.catch((error: AxiosError) => {
55+
return Promise.reject(new IdentityAppsApiException(
56+
error?.response?.data?.description ||
57+
error?.response?.data?.message ||
58+
error?.message ||
59+
"An error occurred while updating the organization.",
60+
error.stack,
61+
error?.response?.status,
62+
error?.response?.request,
63+
error?.response,
64+
error?.response?.config
65+
));
66+
});
67+
};
68+
69+
export default updateSelfAuthenticatedOrganization;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
import useRequest, {
20+
RequestConfigInterface,
21+
RequestErrorInterface,
22+
RequestResultInterface
23+
} from "@wso2is/admin.core.v1/hooks/use-request";
24+
import { store } from "@wso2is/admin.core.v1/store";
25+
import { HttpMethods } from "@wso2is/core/models";
26+
import { OrganizationSelfResponse } from "../models/tenants";
27+
28+
/**
29+
* Hook to get the current authenticated organization details.
30+
*
31+
* @param shouldFetch - Should fetch the data.
32+
* @returns A response object containing the data, error, isLoading, isValidating, mutate.
33+
*/
34+
const useGetSelfAuthenticatedOrganization = <Data = OrganizationSelfResponse, Error = RequestErrorInterface>
35+
(shouldFetch: boolean = true): RequestResultInterface<Data, Error> => {
36+
37+
const requestConfig: RequestConfigInterface = {
38+
headers: {
39+
Accept: "application/json",
40+
"Content-Type": "application/json"
41+
},
42+
method: HttpMethods.GET,
43+
url: `${ store.getState().config.endpoints.organizations }/organizations/self`
44+
};
45+
46+
const { data, error, isLoading, isValidating, mutate } = useRequest<Data, Error>(
47+
shouldFetch ? requestConfig : null
48+
);
49+
50+
return {
51+
data,
52+
error,
53+
isLoading,
54+
isValidating,
55+
mutate
56+
};
57+
};
58+
59+
export default useGetSelfAuthenticatedOrganization;

features/admin.tenants.v1/components/dropdown/tenant-dropdown.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import {
2424
BuildingAltIcon,
2525
BuildingCircleCheckIcon,
2626
BuildingPenIcon,
27+
EyeIcon,
2728
HierarchyIcon,
29+
PenToSquareIcon,
2830
PlusIcon
2931
} from "@oxygen-ui/react-icons";
3032
import {
@@ -150,6 +152,8 @@ const TenantDropdown: FunctionComponent<TenantDropdownInterface> = (props: Tenan
150152
});
151153

152154
const hasOrganizationReadPermissions: boolean = useRequiredScopes(organizationsFeatureConfig?.scopes?.read);
155+
const hasOrganizationUpdatePermissions: boolean = useRequiredScopes(organizationsFeatureConfig?.scopes?.update);
156+
const hasTenantsReadPermissions: boolean = useRequiredScopes(tenantsFeatureConfig?.scopes?.read);
153157

154158
const isMakingTenantsDefaultEnabled: boolean = useSelector((state: AppState) => {
155159
return !state?.config?.ui?.features?.tenants?.disabledFeatures?.includes(
@@ -246,6 +250,23 @@ const TenantDropdown: FunctionComponent<TenantDropdownInterface> = (props: Tenan
246250
getOrganizationData();
247251
}, [ organizationType ]);
248252

253+
/**
254+
* Listen for current authenticated organization updates from the organization edit form.
255+
*/
256+
useEffect(() => {
257+
const handleOrganizationUpdate = (event: CustomEvent) => {
258+
if (event.detail?.success) {
259+
setOrganizationName(event.detail?.newName);
260+
}
261+
};
262+
263+
window.addEventListener("organization-updated", handleOrganizationUpdate as EventListener);
264+
265+
return () => {
266+
window.removeEventListener("organization-updated", handleOrganizationUpdate as EventListener);
267+
};
268+
}, []);
269+
249270
useEffect(() => {
250271

251272
if (!currentTenant){
@@ -668,7 +689,31 @@ const TenantDropdown: FunctionComponent<TenantDropdownInterface> = (props: Tenan
668689
});
669690
}
670691

671-
if (isManagingTenantsFromDropdownEnabled && isSuperOrganization()) {
692+
options.push(
693+
<Dropdown.Item
694+
className="action-panel"
695+
onClick={ (): void => {
696+
history.push(AppConstants.getPaths().get("EDIT_SELF_ORGANIZATION"));
697+
} }
698+
data-compnentid="edit-self-organization"
699+
>
700+
{
701+
hasOrganizationUpdatePermissions ? (
702+
<>
703+
<PenToSquareIcon />
704+
{ t("tenants:tenantDropdown.options.edit.label") }
705+
</>
706+
) : (
707+
<>
708+
<EyeIcon />
709+
{ t("tenants:tenantDropdown.options.view.label") }
710+
</>
711+
)
712+
}
713+
</Dropdown.Item>
714+
);
715+
716+
if (hasTenantsReadPermissions && isManagingTenantsFromDropdownEnabled && isSuperOrganization()) {
672717
options.push(
673718
<Dropdown.Item
674719
className="action-panel"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
.edit-self-organization-form {
20+
display: flex;
21+
flex-direction: column;
22+
gap: 1.5rem;
23+
max-width: var(--wso2is-admin-form-max-width);
24+
25+
p {
26+
margin-top: -1.5rem;
27+
}
28+
29+
.edit-self-organization-form-submit-button {
30+
align-self: flex-start;
31+
margin-top: var(--oxygen-spacing-2);
32+
}
33+
}

0 commit comments

Comments
 (0)