From 3abe02eab0ead03397bb5f6b0bb928260e13f4d1 Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Wed, 28 Aug 2024 11:40:31 +0200 Subject: [PATCH 01/10] core: added company_id to api listings --- .../Provider/Domain/Model/Administrator/AdministratorDto.php | 4 ++++ library/Ivoz/Provider/Domain/Model/WebPortal/WebPortalDto.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/library/Ivoz/Provider/Domain/Model/Administrator/AdministratorDto.php b/library/Ivoz/Provider/Domain/Model/Administrator/AdministratorDto.php index a005986583..1db17f7030 100644 --- a/library/Ivoz/Provider/Domain/Model/Administrator/AdministratorDto.php +++ b/library/Ivoz/Provider/Domain/Model/Administrator/AdministratorDto.php @@ -24,6 +24,10 @@ public static function getPropertyMap(string $context = '', string $role = null) 'lastname' => 'lastname', 'email' => 'email' ]; + + if ($role === 'ROLE_BRAND_ADMIN') { + $response['company'] = 'company'; + } } else { $response = parent::getPropertyMap(...func_get_args()); unset($response['internal']); diff --git a/library/Ivoz/Provider/Domain/Model/WebPortal/WebPortalDto.php b/library/Ivoz/Provider/Domain/Model/WebPortal/WebPortalDto.php index 59a5dd6c38..a3ccc6485a 100644 --- a/library/Ivoz/Provider/Domain/Model/WebPortal/WebPortalDto.php +++ b/library/Ivoz/Provider/Domain/Model/WebPortal/WebPortalDto.php @@ -25,6 +25,10 @@ public static function getPropertyMap(string $context = '', string $role = null) 'baseName', ], ]; + + if ($role === 'ROLE_BRAND_ADMIN' || $role === 'ROLE_SUPER_ADMIN') { + $response['brand'] = 'brand'; + } } else { $response = parent::getPropertyMap(...func_get_args()); } From 2a66e2cb9123071bf229dc4b0fe1edaef3895728 Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Thu, 29 Aug 2024 12:51:36 +0200 Subject: [PATCH 02/10] rest/brand: updated api tests --- .../administrator/getAdministrators.feature | 15 ++++++++++----- .../provider/webPortal/getWebPortal.feature | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/web/rest/brand/features/provider/administrator/getAdministrators.feature b/web/rest/brand/features/provider/administrator/getAdministrators.feature index 5f170d16ce..e69fdfaaf2 100644 --- a/web/rest/brand/features/provider/administrator/getAdministrators.feature +++ b/web/rest/brand/features/provider/administrator/getAdministrators.feature @@ -21,7 +21,8 @@ Feature: Retrieve administrators "restricted": true, "name": "Admin Name", "lastname": "Admin Lastname", - "id": 7 + "id": 7, + "company": 1 }, { "username": "test_company_admin", @@ -30,7 +31,8 @@ Feature: Retrieve administrators "restricted": false, "name": "Admin Name", "lastname": "Admin Lastname", - "id": 4 + "id": 4, + "company": 1 }, { "username": "test_residential_admin", @@ -39,7 +41,8 @@ Feature: Retrieve administrators "restricted": false, "name": "Admin Name", "lastname": "Admin Lastname", - "id": 8 + "id": 8, + "company": 4 }, { "username": "test_retail_admin", @@ -48,7 +51,8 @@ Feature: Retrieve administrators "restricted": false, "name": "Admin Name", "lastname": "Admin Lastname", - "id": 9 + "id": 9, + "company": 3 }, { "username": "test_wholesale_admin", @@ -57,7 +61,8 @@ Feature: Retrieve administrators "restricted": false, "name": "Admin Name", "lastname": "Admin Lastname", - "id": 12 + "id": 12, + "company": 5 } ] """ diff --git a/web/rest/brand/features/provider/webPortal/getWebPortal.feature b/web/rest/brand/features/provider/webPortal/getWebPortal.feature index 0b9f0be754..7f649b33f1 100644 --- a/web/rest/brand/features/provider/webPortal/getWebPortal.feature +++ b/web/rest/brand/features/provider/webPortal/getWebPortal.feature @@ -24,6 +24,7 @@ Feature: Retrieve web portals "mimeType": "image/jpeg", "baseName": "client-logo.jpeg" }, + "brand": 1, "company": null }, { @@ -36,6 +37,7 @@ Feature: Retrieve web portals "mimeType": "image/jpeg", "baseName": "user-logo.jpeg" }, + "brand": 1, "company": null }, { @@ -48,6 +50,7 @@ Feature: Retrieve web portals "mimeType": "image/jpeg", "baseName": "user-logo.jpeg" }, + "brand": 1, "company": 1 } ] From 9e68f7116c159cf93ad777303255d7f1c83da59d Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Tue, 10 Sep 2024 21:58:04 +0200 Subject: [PATCH 03/10] rest/platform: updated api tests --- .../features/provider/webPortal/getWebPortal.feature | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/web/rest/platform/features/provider/webPortal/getWebPortal.feature b/web/rest/platform/features/provider/webPortal/getWebPortal.feature index 7ef4421525..e20589b75d 100644 --- a/web/rest/platform/features/provider/webPortal/getWebPortal.feature +++ b/web/rest/platform/features/provider/webPortal/getWebPortal.feature @@ -14,7 +14,7 @@ Feature: Retrieve web portals And the JSON should be equal to: """ [ - { + { "url": "https://brand-ivozprovider.irontec.com", "urlType": "brand", "name": "Irontec Ivozprovider Brand Admin Portal", @@ -23,7 +23,8 @@ Feature: Retrieve web portals "fileSize": 10, "mimeType": "image/jpeg", "baseName": "brand-logo.jpeg" - } + }, + "brand": 1 }, { "url": "https://nologo-platform-ivozprovider.irontec.com", @@ -34,7 +35,8 @@ Feature: Retrieve web portals "fileSize": null, "mimeType": null, "baseName": null - } + }, + "brand": null }, { "url": "https://platform-ivozprovider.irontec.com", @@ -45,7 +47,8 @@ Feature: Retrieve web portals "fileSize": 10, "mimeType": "image/jpeg", "baseName": "logo.jpeg" - } + }, + "brand": null } ] """ From c515d624f25bbdc6fac08f4d7db15df4e1acd1b5 Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Tue, 30 Jul 2024 14:01:04 +0200 Subject: [PATCH 04/10] portal/brand: updated apiSpec --- .../brand/cypress/fixtures/apiSpec.json | 86 ++++++++++++------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/web/portal/brand/cypress/fixtures/apiSpec.json b/web/portal/brand/cypress/fixtures/apiSpec.json index 28dc9b7a5a..2d74fa2c16 100644 --- a/web/portal/brand/cypress/fixtures/apiSpec.json +++ b/web/portal/brand/cypress/fixtures/apiSpec.json @@ -417,29 +417,35 @@ "type": "string" }, { - "name": "email[neq]", + "name": "email[start]", "in": "query", "required": false, "type": "string" }, { - "name": "email[start]", + "name": "email[partial]", "in": "query", "required": false, "type": "string" }, { - "name": "email[partial]", + "name": "email[end]", "in": "query", "required": false, "type": "string" }, { - "name": "email[end]", + "name": "email[neq]", "in": "query", "required": false, "type": "string" }, + { + "name": "exists[company]", + "in": "query", + "required": false, + "type": "boolean" + }, { "name": "exists[lastname]", "in": "query", @@ -477,34 +483,34 @@ "type": "string" }, { - "name": "lastname[neq]", + "name": "lastname[end]", "in": "query", "required": false, "type": "string" }, { - "name": "lastname[start]", + "name": "lastname[exists]", "in": "query", "required": false, - "type": "string" + "type": "boolean" }, { - "name": "lastname[partial]", + "name": "lastname[neq]", "in": "query", "required": false, "type": "string" }, { - "name": "lastname[end]", + "name": "lastname[start]", "in": "query", "required": false, "type": "string" }, { - "name": "lastname[exists]", + "name": "lastname[partial]", "in": "query", "required": false, - "type": "boolean" + "type": "string" }, { "name": "name", @@ -524,12 +530,6 @@ "required": false, "type": "string" }, - { - "name": "name[partial]", - "in": "query", - "required": false, - "type": "string" - }, { "name": "name[end]", "in": "query", @@ -548,6 +548,12 @@ "required": false, "type": "string" }, + { + "name": "name[partial]", + "in": "query", + "required": false, + "type": "string" + }, { "name": "restricted", "in": "query", @@ -34692,6 +34698,12 @@ } }, "parameters": [ + { + "name": "brand", + "in": "query", + "required": false, + "type": "integer" + }, { "name": "company", "in": "query", @@ -34764,12 +34776,6 @@ "required": false, "type": "string" }, - { - "name": "logo.baseName[neq]", - "in": "query", - "required": false, - "type": "string" - }, { "name": "logo.baseName[start]", "in": "query", @@ -34794,6 +34800,12 @@ "required": false, "type": "boolean" }, + { + "name": "logo.baseName[neq]", + "in": "query", + "required": false, + "type": "string" + }, { "name": "logo.fileSize", "in": "query", @@ -34855,31 +34867,31 @@ "type": "string" }, { - "name": "logo.mimeType[start]", + "name": "logo.mimeType[end]", "in": "query", "required": false, "type": "string" }, { - "name": "logo.mimeType[partial]", + "name": "logo.mimeType[exists]", "in": "query", "required": false, - "type": "string" + "type": "boolean" }, { - "name": "logo.mimeType[end]", + "name": "logo.mimeType[neq]", "in": "query", "required": false, "type": "string" }, { - "name": "logo.mimeType[exists]", + "name": "logo.mimeType[start]", "in": "query", "required": false, - "type": "boolean" + "type": "string" }, { - "name": "logo.mimeType[neq]", + "name": "logo.mimeType[partial]", "in": "query", "required": false, "type": "string" @@ -35410,7 +35422,8 @@ "active", "restricted", "username", - "email" + "email", + "company" ], "properties": { "id": { @@ -35451,6 +35464,10 @@ "description": "", "example": "", "type": "string" + }, + "company": { + "description": "", + "type": "integer" } } }, @@ -46089,7 +46106,8 @@ "type": "object", "required": [ "url", - "urlType" + "urlType", + "brand" ], "properties": { "id": { @@ -46123,6 +46141,10 @@ "logo": { "$ref": "#/definitions/WebPortal_Logo" }, + "brand": { + "description": "", + "type": "integer" + }, "company": { "description": "", "type": "integer" From c38ccf0e3f98dc6c63411b481ee22295d6664a30 Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Tue, 10 Sep 2024 22:00:19 +0200 Subject: [PATCH 05/10] portal/platform: updated apiSpec --- .../platform/cypress/fixtures/apiSpec.json | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/web/portal/platform/cypress/fixtures/apiSpec.json b/web/portal/platform/cypress/fixtures/apiSpec.json index 394b88dadc..e16c15e26d 100644 --- a/web/portal/platform/cypress/fixtures/apiSpec.json +++ b/web/portal/platform/cypress/fixtures/apiSpec.json @@ -13526,6 +13526,12 @@ "required": false, "type": "boolean" }, + { + "name": "exists[brand]", + "in": "query", + "required": false, + "type": "boolean" + }, { "name": "exists[logo.baseName]", "in": "query", @@ -13574,12 +13580,6 @@ "required": false, "type": "string" }, - { - "name": "logo.baseName[neq]", - "in": "query", - "required": false, - "type": "string" - }, { "name": "logo.baseName[start]", "in": "query", @@ -13604,6 +13604,12 @@ "required": false, "type": "boolean" }, + { + "name": "logo.baseName[neq]", + "in": "query", + "required": false, + "type": "string" + }, { "name": "logo.fileSize", "in": "query", @@ -13665,34 +13671,34 @@ "type": "string" }, { - "name": "logo.mimeType[neq]", + "name": "logo.mimeType[end]", "in": "query", "required": false, "type": "string" }, { - "name": "logo.mimeType[start]", + "name": "logo.mimeType[exists]", "in": "query", "required": false, - "type": "string" + "type": "boolean" }, { - "name": "logo.mimeType[partial]", + "name": "logo.mimeType[neq]", "in": "query", "required": false, "type": "string" }, { - "name": "logo.mimeType[end]", + "name": "logo.mimeType[start]", "in": "query", "required": false, "type": "string" }, { - "name": "logo.mimeType[exists]", + "name": "logo.mimeType[partial]", "in": "query", "required": false, - "type": "boolean" + "type": "string" }, { "name": "name", @@ -13785,25 +13791,25 @@ "type": "string" }, { - "name": "url[start]", + "name": "url[neq]", "in": "query", "required": false, "type": "string" }, { - "name": "url[partial]", + "name": "url[start]", "in": "query", "required": false, "type": "string" }, { - "name": "url[end]", + "name": "url[partial]", "in": "query", "required": false, "type": "string" }, { - "name": "url[neq]", + "name": "url[end]", "in": "query", "required": false, "type": "string" @@ -18430,6 +18436,10 @@ }, "logo": { "$ref": "#/definitions/WebPortal_Logo" + }, + "brand": { + "description": "", + "type": "integer" } } }, From cd44c6a01b5c2fb0c7f0a0f2cdcce444761abd9d Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Tue, 27 Aug 2024 23:12:01 +0200 Subject: [PATCH 06/10] portal/brand: added custom impersonation link --- .../Administrator/Action/Impersonate.tsx | 30 +++++++++++++- .../entities/Administrator/Administrator.tsx | 7 +--- .../Administrator/ForeignKeyResolver.tsx | 23 ----------- .../brand/src/entities/Administrator/List.tsx | 39 +++++++++++++++++++ .../entities/Company/Action/Impersonate.tsx | 30 +++++++++++++- .../brand/src/entities/Company/Company.tsx | 3 ++ .../src/entities/Company/CompanyProperties.ts | 1 + .../brand/src/entities/Company/List.tsx | 39 +++++++++++++++++++ .../entities/WebPortal/WebPortalProperties.ts | 1 + 9 files changed, 143 insertions(+), 30 deletions(-) delete mode 100644 web/portal/brand/src/entities/Administrator/ForeignKeyResolver.tsx create mode 100644 web/portal/brand/src/entities/Administrator/List.tsx create mode 100644 web/portal/brand/src/entities/Company/List.tsx diff --git a/web/portal/brand/src/entities/Administrator/Action/Impersonate.tsx b/web/portal/brand/src/entities/Administrator/Action/Impersonate.tsx index 76b1322294..92fea26278 100644 --- a/web/portal/brand/src/entities/Administrator/Action/Impersonate.tsx +++ b/web/portal/brand/src/entities/Administrator/Action/Impersonate.tsx @@ -10,22 +10,50 @@ import { import _ from '@irontec/ivoz-ui/services/translations/translate'; import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; import { Tooltip } from '@mui/material'; +import { WebPortalPropertiesList } from 'entities/WebPortal/WebPortalProperties'; import { useStoreState } from 'store'; const Impersonate: ActionFunctionComponent = (props: ActionItemProps) => { const { row, entityService, variant = 'icon' } = props; const token = useStoreState((state) => state.auth.token); + const customData = useStoreState((state) => state.list.customData); if (!row) { return null; } + if (customData === undefined) { + return ( + <> + {variant === 'text' && ( + {_('Impersonate')} + )} + {variant === 'icon' && ( + + + + )} + + ); + } + + const companyUrl = customData.find( + (data: WebPortalPropertiesList) => data.company === row.companyId + )?.url; + + const brandUrl = customData.find( + (data: WebPortalPropertiesList) => data.company === null + )?.url; + + const impersonationUrl = companyUrl ? companyUrl : brandUrl; + const url = impersonationUrl ?? ''; + const { username } = row; const queryString = `username=${username}&token=${token}`; return ( { @@ -163,16 +164,12 @@ const Administrator: EntityInterface = { }, ChildDecorator, customActions: Actions, + List: List, selectOptions: async () => { const module = await import('./SelectOptions'); return module.default; }, - foreignKeyResolver: async () => { - const module = await import('./ForeignKeyResolver'); - - return module.default; - }, foreignKeyGetter: async () => { const module = await import('./ForeignKeyGetter'); diff --git a/web/portal/brand/src/entities/Administrator/ForeignKeyResolver.tsx b/web/portal/brand/src/entities/Administrator/ForeignKeyResolver.tsx deleted file mode 100644 index f4c68fd33b..0000000000 --- a/web/portal/brand/src/entities/Administrator/ForeignKeyResolver.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { autoForeignKeyResolver } from '@irontec/ivoz-ui/entities/DefaultEntityBehavior'; -import { foreignKeyResolverType } from '@irontec/ivoz-ui/entities/EntityInterface'; - -import { AdministratorPropertiesList } from './AdministratorProperties'; - -/** TODO remove this file unless you need to change default behaviour **/ -const foreignKeyResolver: foreignKeyResolverType = async function ({ - data, - cancelToken, - entityService, -}): Promise { - const promises = autoForeignKeyResolver({ - data, - cancelToken, - entityService, - }); - - await Promise.all(promises); - - return data; -}; - -export default foreignKeyResolver; diff --git a/web/portal/brand/src/entities/Administrator/List.tsx b/web/portal/brand/src/entities/Administrator/List.tsx new file mode 100644 index 0000000000..35037d98ee --- /dev/null +++ b/web/portal/brand/src/entities/Administrator/List.tsx @@ -0,0 +1,39 @@ +import { ListContentProps } from '@irontec/ivoz-ui/components/List/Content/ListContent'; +import DefaultEntityList from '@irontec/ivoz-ui/entities/DefaultEntityBehavior'; +import useCancelToken from '@irontec/ivoz-ui/hooks/useCancelToken'; +import { useEffect } from 'react'; +import { useStoreActions, useStoreState } from 'store'; + +import WebPortal from '../WebPortal/WebPortal'; + +const List = (props: ListContentProps): JSX.Element => { + const rows = useStoreState((store) => store.list.rows); + const getAction = useStoreActions((actions) => actions.api.get); + const setCustomData = useStoreActions( + (actions) => actions.list.setCustomData + ); + const [, cancelToken] = useCancelToken(); + + useEffect(() => { + if (rows.length === 0) { + setCustomData([]); + + return; + } + getAction({ + path: `${WebPortal.path}?_order[id]=ASC`, + params: { + urlType: 'admin', + _pagination: false, + }, + cancelToken: cancelToken, + successCallback: async (response) => { + setCustomData(response); + }, + }); + }, []); + + return ; +}; + +export default List; diff --git a/web/portal/brand/src/entities/Company/Action/Impersonate.tsx b/web/portal/brand/src/entities/Company/Action/Impersonate.tsx index e197efd4a9..af3be7a11c 100644 --- a/web/portal/brand/src/entities/Company/Action/Impersonate.tsx +++ b/web/portal/brand/src/entities/Company/Action/Impersonate.tsx @@ -10,22 +10,50 @@ import { import _ from '@irontec/ivoz-ui/services/translations/translate'; import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; import { Tooltip } from '@mui/material'; +import { WebPortalPropertyList } from 'entities/WebPortal/WebPortalProperties'; import { useStoreState } from 'store'; const Impersonate: ActionFunctionComponent = (props: ActionItemProps) => { const { row, entityService, variant = 'icon' } = props; const token = useStoreState((state) => state.auth.token); + const customData = useStoreState((state) => state.list.customData); if (!row) { return null; } + if (customData === undefined) { + return ( + <> + {variant === 'text' && ( + {_('Impersonate')} + )} + {variant === 'icon' && ( + + + + )} + + ); + } + const { id } = row; const queryString = `target=${id}&token=${token}`; + const companyUrl = customData.find( + (data: WebPortalPropertyList) => data.company === row.id + )?.url; + + const brandUrl = customData.find( + (data: WebPortalPropertyList) => data.company === null + )?.url; + + const impersonationUrl = companyUrl ? companyUrl : brandUrl; + const url = impersonationUrl ?? ''; + return ( ) => `${row.name}`, properties, + columns: [ 'name', 'invoicing.nif', @@ -388,6 +390,7 @@ const Company: EntityInterface = { iden: 'Companies', }, customActions: Actions, + List: List, selectOptions: async () => { const module = await import('./SelectOptions'); diff --git a/web/portal/brand/src/entities/Company/CompanyProperties.ts b/web/portal/brand/src/entities/Company/CompanyProperties.ts index 0a748ff4f3..bb304e9c97 100644 --- a/web/portal/brand/src/entities/Company/CompanyProperties.ts +++ b/web/portal/brand/src/entities/Company/CompanyProperties.ts @@ -56,6 +56,7 @@ export type CompanyPropertyList = { routingTagIds?: T; codecIds?: T; corporation?: T; + impersonationUrl?: T; }; export type CompanyProperties = CompanyPropertyList>; diff --git a/web/portal/brand/src/entities/Company/List.tsx b/web/portal/brand/src/entities/Company/List.tsx new file mode 100644 index 0000000000..35037d98ee --- /dev/null +++ b/web/portal/brand/src/entities/Company/List.tsx @@ -0,0 +1,39 @@ +import { ListContentProps } from '@irontec/ivoz-ui/components/List/Content/ListContent'; +import DefaultEntityList from '@irontec/ivoz-ui/entities/DefaultEntityBehavior'; +import useCancelToken from '@irontec/ivoz-ui/hooks/useCancelToken'; +import { useEffect } from 'react'; +import { useStoreActions, useStoreState } from 'store'; + +import WebPortal from '../WebPortal/WebPortal'; + +const List = (props: ListContentProps): JSX.Element => { + const rows = useStoreState((store) => store.list.rows); + const getAction = useStoreActions((actions) => actions.api.get); + const setCustomData = useStoreActions( + (actions) => actions.list.setCustomData + ); + const [, cancelToken] = useCancelToken(); + + useEffect(() => { + if (rows.length === 0) { + setCustomData([]); + + return; + } + getAction({ + path: `${WebPortal.path}?_order[id]=ASC`, + params: { + urlType: 'admin', + _pagination: false, + }, + cancelToken: cancelToken, + successCallback: async (response) => { + setCustomData(response); + }, + }); + }, []); + + return ; +}; + +export default List; diff --git a/web/portal/brand/src/entities/WebPortal/WebPortalProperties.ts b/web/portal/brand/src/entities/WebPortal/WebPortalProperties.ts index c8f8066320..191a0fff4c 100644 --- a/web/portal/brand/src/entities/WebPortal/WebPortalProperties.ts +++ b/web/portal/brand/src/entities/WebPortal/WebPortalProperties.ts @@ -12,6 +12,7 @@ export type WebPortalPropertyList = { id?: T; logo?: T; company?: T; + brand?: T; }; export type WebPortalProperties = WebPortalPropertyList>; From 52c39c45a4180b494162363e6c188b1635dc2003 Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Thu, 29 Aug 2024 12:28:40 +0200 Subject: [PATCH 07/10] portal/brand: updated cypress tests --- .../Clients/VirtualPbxs/VirtualPbxs.tests.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/web/portal/brand/cypress/e2e/Clients/VirtualPbxs/VirtualPbxs.tests.js b/web/portal/brand/cypress/e2e/Clients/VirtualPbxs/VirtualPbxs.tests.js index 00d07cd898..0ee465484d 100644 --- a/web/portal/brand/cypress/e2e/Clients/VirtualPbxs/VirtualPbxs.tests.js +++ b/web/portal/brand/cypress/e2e/Clients/VirtualPbxs/VirtualPbxs.tests.js @@ -1,6 +1,7 @@ import CompaniesItem from '../../../fixtures/Provider/Companies/VirtualPbxs/getItem.json'; import newCompanies from '../../../fixtures/Provider/Companies/VirtualPbxs/post.json'; import editCompanies from '../../../fixtures/Provider/Companies/VirtualPbxs/put.json'; +import webPortals from '../../../fixtures/Provider/WebPortals/getCollection.json'; import { MODE, testPbx } from '../utils/PbxsValidator'; export const postCompany = () => { @@ -78,3 +79,23 @@ export const postWebPortal = () => { cy.get('input[name="urlType"]').should('be.enabled'); }; + +export const checkImpersonationURL = () => { + cy.contains('Virtual PBXs').click(); + + const impersonationURLs = webPortals.body.map((wp) => wp.url); + + cy.get('div.actions-cell a[target="_impersonate-client"]').as( + 'impersonation-links' + ); + + cy.get('a[target="_impersonate-client"]') + .eq(0) + .should('have.attr', 'href') + .should('match', new RegExp(`${impersonationURLs[2]}.*`)); + + cy.get('@impersonation-links') + .eq(1) + .should('have.attr', 'href') + .should('match', new RegExp(`${impersonationURLs[0]}.*`)); +}; From 202ee02db42065da186bfa698f8823c3ea49e3e1 Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Thu, 29 Aug 2024 09:33:46 +0200 Subject: [PATCH 08/10] portal/platform: added custom impersonation link --- .../Administrator/Action/Impersonate.tsx | 32 ++++++++++++++- .../entities/Administrator/Administrator.tsx | 7 +--- .../Administrator/ForeignKeyResolver.tsx | 23 ----------- .../src/entities/Administrator/List.tsx | 40 +++++++++++++++++++ .../src/entities/Brand/Action/Impersonate.tsx | 30 +++++++++++++- .../platform/src/entities/Brand/Brand.tsx | 2 + .../src/entities/Brand/BrandProperties.ts | 1 + .../platform/src/entities/Brand/List.tsx | 36 +++++++++++++++++ 8 files changed, 140 insertions(+), 31 deletions(-) delete mode 100644 web/portal/platform/src/entities/Administrator/ForeignKeyResolver.tsx create mode 100644 web/portal/platform/src/entities/Administrator/List.tsx create mode 100644 web/portal/platform/src/entities/Brand/List.tsx diff --git a/web/portal/platform/src/entities/Administrator/Action/Impersonate.tsx b/web/portal/platform/src/entities/Administrator/Action/Impersonate.tsx index 83c2b89872..efc10fa2dd 100644 --- a/web/portal/platform/src/entities/Administrator/Action/Impersonate.tsx +++ b/web/portal/platform/src/entities/Administrator/Action/Impersonate.tsx @@ -1,3 +1,4 @@ +import { EntityValue } from '@irontec/ivoz-ui'; import { MoreMenuItem } from '@irontec/ivoz-ui/components/List/Content/Shared/MoreChildEntityLinks'; import { StyledTableRowChildEntityLink, @@ -12,20 +13,47 @@ import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; import { Tooltip } from '@mui/material'; import { useStoreState } from 'store'; +import { WebPortalPropertiesList } from '../../WebPortal/WebPortalProperties'; +import { AdministratorPropertyList } from '../AdministratorProperties'; + const Impersonate: ActionFunctionComponent = (props: ActionItemProps) => { - const { row, variant = 'icon', entityService } = props; + type InputProps = Omit & { + row: AdministratorPropertyList; + }; + const { row, variant = 'icon', entityService }: InputProps = props; const token = useStoreState((state) => state.auth.token); + const customData = useStoreState( + (state) => state.list.customData + ) as WebPortalPropertiesList; if (!row) { return null; } + if (customData === undefined) { + return ( + <> + {variant === 'text' && ( + {_('Impersonate')} + )} + {variant === 'icon' && ( + + + + )} + + ); + } + const { username } = row; + const impersonationUrl = customData[0]?.url; + const url = impersonationUrl ?? ''; + const queryString = `username=${username}&token=${token}`; return ( { @@ -164,16 +165,12 @@ const Administrator: EntityInterface = { return module.default; }, - foreignKeyResolver: async () => { - const module = await import('./ForeignKeyResolver'); - - return module.default; - }, foreignKeyGetter: async () => { const module = await import('./ForeignKeyGetter'); return module.foreignKeyGetter; }, + List: List, Form: async () => { const module = await import('./Form'); diff --git a/web/portal/platform/src/entities/Administrator/ForeignKeyResolver.tsx b/web/portal/platform/src/entities/Administrator/ForeignKeyResolver.tsx deleted file mode 100644 index f4c68fd33b..0000000000 --- a/web/portal/platform/src/entities/Administrator/ForeignKeyResolver.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { autoForeignKeyResolver } from '@irontec/ivoz-ui/entities/DefaultEntityBehavior'; -import { foreignKeyResolverType } from '@irontec/ivoz-ui/entities/EntityInterface'; - -import { AdministratorPropertiesList } from './AdministratorProperties'; - -/** TODO remove this file unless you need to change default behaviour **/ -const foreignKeyResolver: foreignKeyResolverType = async function ({ - data, - cancelToken, - entityService, -}): Promise { - const promises = autoForeignKeyResolver({ - data, - cancelToken, - entityService, - }); - - await Promise.all(promises); - - return data; -}; - -export default foreignKeyResolver; diff --git a/web/portal/platform/src/entities/Administrator/List.tsx b/web/portal/platform/src/entities/Administrator/List.tsx new file mode 100644 index 0000000000..f12d478598 --- /dev/null +++ b/web/portal/platform/src/entities/Administrator/List.tsx @@ -0,0 +1,40 @@ +import { ListContentProps } from '@irontec/ivoz-ui/components/List/Content/ListContent'; +import DefaultEntityList from '@irontec/ivoz-ui/entities/DefaultEntityBehavior'; +import useCancelToken from '@irontec/ivoz-ui/hooks/useCancelToken'; +import { useEffect } from 'react'; +import { useStoreActions, useStoreState } from 'store'; + +import WebPortal from '../WebPortal/WebPortal'; + +const List = (props: ListContentProps): JSX.Element => { + const parentRow = useStoreState((store) => store.list.parentRow); + const getAction = useStoreActions((actions) => actions.api.get); + const setCustomData = useStoreActions( + (actions) => actions.list.setCustomData + ); + const [, cancelToken] = useCancelToken(); + + useEffect(() => { + const isBrandEntity = parentRow?.features !== undefined; + if (!isBrandEntity) { + return; + } + + getAction({ + path: `${WebPortal.path}?_order[id]=ASC`, + params: { + brand: parentRow?.id, + urlType: 'brand', + _pagination: false, + }, + cancelToken: cancelToken, + successCallback: async (response) => { + setCustomData(response); + }, + }); + }, [parentRow]); + + return ; +}; + +export default List; diff --git a/web/portal/platform/src/entities/Brand/Action/Impersonate.tsx b/web/portal/platform/src/entities/Brand/Action/Impersonate.tsx index 519ed7fc16..dd8a24d1cc 100644 --- a/web/portal/platform/src/entities/Brand/Action/Impersonate.tsx +++ b/web/portal/platform/src/entities/Brand/Action/Impersonate.tsx @@ -10,22 +10,50 @@ import { import _ from '@irontec/ivoz-ui/services/translations/translate'; import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; import { Tooltip } from '@mui/material'; +import { + WebPortalPropertiesList, + WebPortalPropertyList, +} from 'entities/WebPortal/WebPortalProperties'; import { useStoreState } from 'store'; const Impersonate: ActionFunctionComponent = (props: ActionItemProps) => { const { row, variant = 'icon', entityService } = props; const token = useStoreState((state) => state.auth.token); + const customData = useStoreState( + (state) => state.list.customData + ) as WebPortalPropertiesList; if (!row) { return null; } + if (customData === undefined) { + return ( + <> + {variant === 'text' && ( + {_('Impersonate')} + )} + {variant === 'icon' && ( + + + + )} + + ); + } + const { id } = row; + const impersonationUrl = customData.find( + (data: WebPortalPropertyList) => data.brand === row.id + )?.url; + + const url = impersonationUrl ?? ''; + const queryString = `target=${id}&token=${token}`; return ( { const module = await import('./SelectOptions'); diff --git a/web/portal/platform/src/entities/Brand/BrandProperties.ts b/web/portal/platform/src/entities/Brand/BrandProperties.ts index c2e6a41199..8666b37e52 100644 --- a/web/portal/platform/src/entities/Brand/BrandProperties.ts +++ b/web/portal/platform/src/entities/Brand/BrandProperties.ts @@ -23,6 +23,7 @@ export type BrandPropertyList = { defaultTimezone?: T; maxCalls?: T; currency?: T; + impersonationUrl?: T; }; export type BrandProperties = BrandPropertyList>; diff --git a/web/portal/platform/src/entities/Brand/List.tsx b/web/portal/platform/src/entities/Brand/List.tsx new file mode 100644 index 0000000000..bc1d8c76c8 --- /dev/null +++ b/web/portal/platform/src/entities/Brand/List.tsx @@ -0,0 +1,36 @@ +import { ListContentProps } from '@irontec/ivoz-ui/components/List/Content/ListContent'; +import DefaultEntityList from '@irontec/ivoz-ui/entities/DefaultEntityBehavior'; +import useCancelToken from '@irontec/ivoz-ui/hooks/useCancelToken'; +import WebPortal from 'entities/WebPortal/WebPortal'; +import { useEffect } from 'react'; +import { useStoreActions, useStoreState } from 'store'; + +const List = (props: ListContentProps): JSX.Element => { + const rows = useStoreState((store) => store.list.rows); + const getAction = useStoreActions((actions) => actions.api.get); + const setCustomData = useStoreActions( + (actions) => actions.list.setCustomData + ); + const [, cancelToken] = useCancelToken(); + + useEffect(() => { + const brandIds = rows.map((brand) => brand.id); + + getAction({ + path: `${WebPortal.path}?_order[id]=ASC`, + params: { + brand: brandIds, + urlType: 'brand', + _pagination: false, + }, + cancelToken: cancelToken, + successCallback: async (response) => { + setCustomData(response); + }, + }); + }, []); + + return ; +}; + +export default List; From 4632e8602943a8f7603dd1d9aba2eaa31048a8c8 Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Thu, 29 Aug 2024 12:45:26 +0200 Subject: [PATCH 09/10] portal/platform: updated cypress tests --- .../fixtures/WebPortal/getCollection.json | 45 +++++++++++++++++++ .../prepareGenericPactInterceptors.js | 5 +++ 2 files changed, 50 insertions(+) create mode 100644 web/portal/platform/cypress/fixtures/WebPortal/getCollection.json diff --git a/web/portal/platform/cypress/fixtures/WebPortal/getCollection.json b/web/portal/platform/cypress/fixtures/WebPortal/getCollection.json new file mode 100644 index 0000000000..8959317dc6 --- /dev/null +++ b/web/portal/platform/cypress/fixtures/WebPortal/getCollection.json @@ -0,0 +1,45 @@ +{ + "body": [ + { + "url": "https://brand-ivozprovider.irontec.com", + "urlType": "brand", + "name": "Irontec Ivozprovider Brand Admin Portal", + "id": 2, + "logo": { + "fileSize": 10, + "mimeType": "image/jpeg", + "baseName": "brand-logo.jpeg" + } + }, + { + "url": "https://nologo-platform-ivozprovider.irontec.com", + "urlType": "god", + "name": "No logo", + "id": 5, + "logo": { + "fileSize": null, + "mimeType": null, + "baseName": null + } + }, + { + "url": "https://platform-ivozprovider.irontec.com", + "urlType": "god", + "name": "Platform Administration Portal", + "id": 1, + "logo": { + "fileSize": 10, + "mimeType": "image/jpeg", + "baseName": "logo.jpeg" + } + } + ], + "headers": { + "x-first-page": "/api/brand/web_portals?_page=1", + "x-last-page": "/api/brand/web_portals?_page=1", + "x-next-page": "/api/brand/web_portals?_page=1", + "x-total-items": "3", + "x-total-pages": "1" + }, + "statusCode": 200 +} diff --git a/web/portal/platform/cypress/support/commands/prepareGenericPactInterceptors.js b/web/portal/platform/cypress/support/commands/prepareGenericPactInterceptors.js index ee5e82c00f..bcb9389c38 100644 --- a/web/portal/platform/cypress/support/commands/prepareGenericPactInterceptors.js +++ b/web/portal/platform/cypress/support/commands/prepareGenericPactInterceptors.js @@ -8,6 +8,7 @@ import ThemeItem from '../../fixtures/My/Theme/getTheme.json'; import TerminalManufacturerCollection from '../../fixtures/TerminalManufacturer/getCollection.json'; import TimezonesItem from '../../fixtures/Timezones/getTimezones.json'; import UserCollection from '../../fixtures/Users/getCollection.json'; +import WebPortal from '../../fixtures/WebPortal/getCollection.json'; Cypress.Commands.add('prepareGenericPactInterceptors', (pactContextName) => { cy.setupPact( @@ -53,4 +54,8 @@ Cypress.Commands.add('prepareGenericPactInterceptors', (pactContextName) => { cy.intercept('GET', '**/api/platform/my/active_calls', { ...ActiveCallsItem, }).as('getMyActiveCalls'); + + cy.intercept('GET', '**/api/platform/web_portals*', { + ...WebPortal, + }).as('getWebPortals'); }); From c3dcb05a1bfb911a2f51e004f911c9ce1d88d5e5 Mon Sep 17 00:00:00 2001 From: Dani Garcia Date: Wed, 11 Sep 2024 08:04:31 +0200 Subject: [PATCH 10/10] portal: upgraded ivoz-ui --- web/portal/package.json | 2 +- web/portal/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/portal/package.json b/web/portal/package.json index bd80c5bb0d..62c1cedf83 100644 --- a/web/portal/package.json +++ b/web/portal/package.json @@ -9,7 +9,7 @@ "dependencies": { "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", - "@irontec/ivoz-ui": "^1.4.6", + "@irontec/ivoz-ui": "^1.5.0", "@mui/icons-material": "^5.11.16", "@mui/material": "^5.12.1", "@mui/styles": "^5.12.0", diff --git a/web/portal/yarn.lock b/web/portal/yarn.lock index 1ec29c64e9..d86c3aa5f6 100644 --- a/web/portal/yarn.lock +++ b/web/portal/yarn.lock @@ -781,10 +781,10 @@ resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== -"@irontec/ivoz-ui@^1.4.6": - version "1.4.6" - resolved "https://registry.yarnpkg.com/@irontec/ivoz-ui/-/ivoz-ui-1.4.6.tgz#4c629a94ae4764e3c4836a74c86d052f625509f4" - integrity sha512-pytT+/7agNABpvejRjNG6jZdrPcHSwa4vm+Yz/GHavwouXEcpKsaWhHdEfwEeNQ0t+GbJ7dKCZQOwuXyLWccJg== +"@irontec/ivoz-ui@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@irontec/ivoz-ui/-/ivoz-ui-1.5.0.tgz#c98197d6f0f5d5793795cac44002239af1021240" + integrity sha512-z3RFRX7s0CF9OFrcPp5iuivUCKZtTcWg/LYd/90I7Qcvdd73Ep/U+KN+zWbC2Ai9IMNP+ChIvbi4k3PVT47/4Q== dependencies: "@date-io/date-fns" "^2.10.8" "@types/react-color" "^3.0.12"