From 99aedb1117cf9b8cfa351d877b6329b58ff1f2ff Mon Sep 17 00:00:00 2001 From: Russell Vinegar Date: Fri, 5 Jul 2024 08:52:18 -0700 Subject: [PATCH] Merge branch 'feature/ns-to-gw' into feature/ns-to-gw-portal-labels --- e2e/cypress/tests/19-api-v3/07-endpoints.ts | 4 +- src/batch/feed-worker.ts | 1 - src/controllers/v3/EndpointsController.ts | 16 +- src/lists/extensions/Namespace.ts | 1 + src/nextapp/.env.local | 2 - .../gateway-get-started.tsx | 71 +++++--- .../components/no-gateway-redirect/index.ts | 1 + .../no-gateway-redirect.tsx | 17 ++ .../publishing-popover/publishing-popover.tsx | 9 +- src/nextapp/pages/manager/activity/index.tsx | 6 +- .../pages/manager/admin-access/index.tsx | 4 + .../manager/authorization-profiles/index.tsx | 4 + src/nextapp/pages/manager/consumers/index.tsx | 4 + src/nextapp/pages/manager/gateways/detail.tsx | 12 +- src/nextapp/pages/manager/gateways/index.tsx | 3 +- src/nextapp/pages/manager/gateways/list.tsx | 168 ++++++++++-------- src/nextapp/pages/manager/products/index.tsx | 4 + .../pages/manager/service-accounts/index.tsx | 4 + src/nextapp/pages/manager/services/index.tsx | 4 + src/nextapp/shared/services/global.tsx | 2 + src/server.ts | 1 + src/services/keycloak/namespace-details.ts | 2 +- 22 files changed, 213 insertions(+), 127 deletions(-) create mode 100644 src/nextapp/components/no-gateway-redirect/index.ts create mode 100644 src/nextapp/components/no-gateway-redirect/no-gateway-redirect.tsx diff --git a/e2e/cypress/tests/19-api-v3/07-endpoints.ts b/e2e/cypress/tests/19-api-v3/07-endpoints.ts index 1ca6a1a90..469887276 100644 --- a/e2e/cypress/tests/19-api-v3/07-endpoints.ts +++ b/e2e/cypress/tests/19-api-v3/07-endpoints.ts @@ -11,8 +11,8 @@ describe('Endpoints', () => { names: ['testme', 'testme-dev', 'testme-test'], hosts: [ 'testme.api.gov.bc.ca', - 'testme.api.dev.gov.bc.ca', - 'testme.api.test.gov.bc.ca', + 'testme.dev.api.gov.bc.ca', + 'testme.test.api.gov.bc.ca', 'testme-api-gov-bc-ca.dev.api.gov.bc.ca', 'testme-api-gov-bc-ca.test.api.gov.bc.ca', ], diff --git a/src/batch/feed-worker.ts b/src/batch/feed-worker.ts index ec620d4ef..9216a7d8f 100644 --- a/src/batch/feed-worker.ts +++ b/src/batch/feed-worker.ts @@ -58,7 +58,6 @@ const transformations = { export const putFeedWorker = async (context: any, req: any, res: any) => { const entity = req.params['entity']; assert.strictEqual(entity in metadata, true); - logger.info('putFeedWorker %s', entity); const md = metadata[entity]; const refKey = md.refKey; diff --git a/src/controllers/v3/EndpointsController.ts b/src/controllers/v3/EndpointsController.ts index 2f386928f..cd7a36a1b 100644 --- a/src/controllers/v3/EndpointsController.ts +++ b/src/controllers/v3/EndpointsController.ts @@ -11,7 +11,11 @@ import { } from 'tsoa'; import { KeystoneService } from '../ioc/keystoneInjector'; import { inject, injectable } from 'tsyringe'; -import { getRecords, removeEmpty } from '../../batch/feed-worker'; +import { + getRecords, + parseJsonString, + removeEmpty, +} from '../../batch/feed-worker'; import { GatewayRoute, GatewayService } from './types'; interface MatchList { @@ -38,9 +42,9 @@ export class EndpointsController extends Controller { @Request() request: any ): Promise { const ctx = this.keystone.sudo(); - const records = await getRecords(ctx, 'GatewayRoute', 'allGatewayRoutes', [ - 'service', - ]); + const records = ( + await getRecords(ctx, 'GatewayRoute', 'allGatewayRoutes', ['service']) + ).map((o) => parseJsonString(o, ['hosts'])); let counter = 0; let matchHostList: MatchList; @@ -67,8 +71,8 @@ export class EndpointsController extends Controller { names: [`${serviceName}`, `${serviceName}-dev`, `${serviceName}-test`], hosts: [ `${serviceName}.api.gov.bc.ca`, - `${serviceName}.api.dev.gov.bc.ca`, - `${serviceName}.api.test.gov.bc.ca`, + `${serviceName}.dev.api.gov.bc.ca`, + `${serviceName}.test.api.gov.bc.ca`, `${serviceName}-api-gov-bc-ca.dev.api.gov.bc.ca`, `${serviceName}-api-gov-bc-ca.test.api.gov.bc.ca`, ], diff --git a/src/lists/extensions/Namespace.ts b/src/lists/extensions/Namespace.ts index 918b93b15..675fadc21 100644 --- a/src/lists/extensions/Namespace.ts +++ b/src/lists/extensions/Namespace.ts @@ -535,6 +535,7 @@ module.exports = { 'Namespace.Manage', 'CredentialIssuer.Admin', 'GatewayConfig.Publish', + 'Access.Manage', ]) { await permissionApi.createPermission( rset.id, diff --git a/src/nextapp/.env.local b/src/nextapp/.env.local index 4fdcfcabd..e2e96408f 100644 --- a/src/nextapp/.env.local +++ b/src/nextapp/.env.local @@ -1,6 +1,5 @@ NEXT_PUBLIC_APP_VERSION=0.0.0 NEXT_PUBLIC_APP_REVISION=000000000000000000000000 -NEXT_PUBLIC_GRAFANA_URL=https://grafana-apps-gov-bc-ca.dev.api.gov.bc.ca NEXT_PUBLIC_KUBE_CLUSTER=local NEXT_PUBLIC_HELP_DESK_URL=https://dpdd.atlassian.net/servicedesk/customer/portal/1/group/2 NEXT_PUBLIC_HELP_CHAT_URL=https://chat.developer.gov.bc.ca/channel/aps-ops @@ -9,4 +8,3 @@ NEXT_PUBLIC_HELP_API_DOCS_URL=/ds/api/v3/console/ NEXT_PUBLIC_HELP_SUPPORT_URL=https://dev.developer.gov.bc.ca/docs/default/component/aps-infra-platform-docs/ NEXT_PUBLIC_HELP_RELEASE_URL=https://dev.developer.gov.bc.ca/docs/default/component/aps-infra-platform-docs/reference/releases/ NEXT_PUBLIC_HELP_STATUS_URL=https://uptime.com/s/bcgov-dss - diff --git a/src/nextapp/components/gateway-get-started/gateway-get-started.tsx b/src/nextapp/components/gateway-get-started/gateway-get-started.tsx index 5d36028d4..409bb4cd4 100644 --- a/src/nextapp/components/gateway-get-started/gateway-get-started.tsx +++ b/src/nextapp/components/gateway-get-started/gateway-get-started.tsx @@ -50,6 +50,8 @@ const GatewayGetStarted: React.FC = () => { const QuickStartUrl = global?.helpLinks.helpSupportUrl + 'tutorials/quick-start' const GwaInstallUrl = global?.helpLinks.helpSupportUrl + 'how-to/gwa-install' const GwaCommandsUrl = global?.helpLinks.helpSupportUrl + 'resources/gwa-commands' + const apiRootUrl = global?.apiRootUrl + const configHost = apiRootUrl ? apiRootUrl.replace('https://', '').replace('http://', '') : '' return ( <> @@ -65,7 +67,7 @@ const GatewayGetStarted: React.FC = () => { No gateways created yet What is a gateway? - + A gateway acts as a central entry point for multiple APIs. Its main purpose is to facilitate communication and control the data flow between your APIs and those who consume them. @@ -111,7 +113,7 @@ const GatewayGetStarted: React.FC = () => { Steps to create and configure your first gateway - Follow these steps to create and configure your first gateway. For more details on how to set up an API, consult our API provider{' '} + Follow these steps to create and configure your first gateway. For a more detailed introduction to setting up an API, consult our{' '} { template - {' '}to set up its configuration: services, routes and plugins. + {' '}to set up service and route configuration. @@ -304,11 +306,13 @@ const GatewayGetStarted: React.FC = () => { Prepare your configuration - + {global?.apiRootUrl && ( + + )} { id='generate-config' title='Generate gateway configuration file' description='Run this command to generate a basic gateway configuration YAML file.' - command='gwa generate-config --template quick-start' + command='gwa generate-config --template basic-service' /> Apply configuration to your gateway @@ -340,31 +344,40 @@ const GatewayGetStarted: React.FC = () => { title='Test your gateway' description={ <> - Visit the{' '} - ...api.gov.bc.ca using this command. + Visit the URL in a browser to see your API gateway in action. + + } + command='gwa status --hosts' + /> + + Next steps + + Congratulations! You have set up your first gateway service, creating a custom route to your service through your API gateway. + + + For a deeper introduction to the API Services Portal, follow the {' '} + Your Products page to request credentials. - Then, get the URL for your newly published gateway service ...api.gov.bc.ca using this command. - Pass the client ID and secret in a POST request to this URL to get a JWT token to access your API. - - } - command='gwa status -hosts' - /> + >Quick Start tutorial + {' '}to create a protected API. + + - Help - - If you are not sure about how to use a specific command, you can type --help after the - command's name to learn more about its usage and syntax. - - } - command='gwa --help' - /> + Help + + If you are not sure about how to use a specific command, you can type --help after the + command's name to learn more about its usage and syntax. + + } + command='gwa --help' + /> diff --git a/src/nextapp/components/no-gateway-redirect/index.ts b/src/nextapp/components/no-gateway-redirect/index.ts new file mode 100644 index 000000000..001eb41b5 --- /dev/null +++ b/src/nextapp/components/no-gateway-redirect/index.ts @@ -0,0 +1 @@ +export { default } from './no-gateway-redirect'; diff --git a/src/nextapp/components/no-gateway-redirect/no-gateway-redirect.tsx b/src/nextapp/components/no-gateway-redirect/no-gateway-redirect.tsx new file mode 100644 index 000000000..414fdb3db --- /dev/null +++ b/src/nextapp/components/no-gateway-redirect/no-gateway-redirect.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { useRouter } from 'next/router'; +import { useAuth } from '@/shared/services/auth'; + +const NoGatewayRedirect = () => { + const router = useRouter(); + const { user } = useAuth(); + const hasNamespace = !!user?.namespace; + + React.useEffect(() => { + if (!hasNamespace) { + router.push('/manager/gateways/list'); + } + }, [hasNamespace]); +}; + +export default NoGatewayRedirect; diff --git a/src/nextapp/components/publishing-popover/publishing-popover.tsx b/src/nextapp/components/publishing-popover/publishing-popover.tsx index 9cdcce5e9..3ac74673b 100644 --- a/src/nextapp/components/publishing-popover/publishing-popover.tsx +++ b/src/nextapp/components/publishing-popover/publishing-popover.tsx @@ -13,11 +13,18 @@ import { } from '@chakra-ui/react'; import { FaClock, FaMinusCircle, FaCheckCircle } from 'react-icons/fa'; +import { useGlobal } from '@/shared/services/global'; + interface PublishingPopoverProps { status: string; } const PublishingPopover: React.FC = ({ status }) => { + const global = useGlobal(); + const DiscoveryUrl = + global?.helpLinks.helpSupportUrl + + 'how-to/api-discovery/#enabling-for-discovery'; + return ( <> {status === 'disabled' && ( @@ -44,7 +51,7 @@ const PublishingPopover: React.FC = ({ status }) => { directory any API contained in this gateway. Request publishing permission by{' '} { + // Redirect to My Gateways page if no gateway selected + NoGatewayRedirect(); + const breadcrumbs = useNamespaceBreadcrumbs([ { text: 'Activity', @@ -248,4 +252,4 @@ const query = gql` blob } } -`; \ No newline at end of file +`; diff --git a/src/nextapp/pages/manager/admin-access/index.tsx b/src/nextapp/pages/manager/admin-access/index.tsx index 9565dca13..0445d0455 100644 --- a/src/nextapp/pages/manager/admin-access/index.tsx +++ b/src/nextapp/pages/manager/admin-access/index.tsx @@ -21,8 +21,12 @@ import { } from '@/components/namespace-access'; import { useAuth } from '@/shared/services/auth'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; +import NoGatewayRedirect from '@/components/no-gateway-redirect'; const AccessRedirectPage: React.FC = () => { + // Redirect to My Gateways page if no gateway selected + NoGatewayRedirect(); + const { user } = useAuth(); const breadcrumbs = useNamespaceBreadcrumbs([ { href: '/manager/admin-access', text: 'Administration Access' }, diff --git a/src/nextapp/pages/manager/authorization-profiles/index.tsx b/src/nextapp/pages/manager/authorization-profiles/index.tsx index 14c1e672d..2fd8dc866 100644 --- a/src/nextapp/pages/manager/authorization-profiles/index.tsx +++ b/src/nextapp/pages/manager/authorization-profiles/index.tsx @@ -41,6 +41,7 @@ import type { Mutation, Query, } from '@/shared/types/query.types'; +import NoGatewayRedirect from '@/components/no-gateway-redirect'; export const getServerSideProps: GetServerSideProps = async (context) => { const queryKey = 'authorizationProfiles'; @@ -69,6 +70,9 @@ export const getServerSideProps: GetServerSideProps = async (context) => { const AuthorizationProfiles: React.FC< InferGetServerSidePropsType > = ({ queryKey }) => { + // Redirect to My Gateways page if no gateway selected + NoGatewayRedirect(); + const breadcrumbs = useNamespaceBreadcrumbs([ { href: '/manager/authorization-profiles', diff --git a/src/nextapp/pages/manager/consumers/index.tsx b/src/nextapp/pages/manager/consumers/index.tsx index 187168192..466f4d7ac 100644 --- a/src/nextapp/pages/manager/consumers/index.tsx +++ b/src/nextapp/pages/manager/consumers/index.tsx @@ -36,6 +36,7 @@ import GrantAccessDialog from '@/components/access-request/grant-access-dialog'; import ConsumerFilters from '@/components/consumer-filters'; import AccessRequestsList from '@/components/access-request/access-requests-list'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; +import NoGatewayRedirect from '@/components/no-gateway-redirect'; const sortDate = new Intl.DateTimeFormat('en-ca', { dateStyle: 'short' }); @@ -76,6 +77,9 @@ export const getServerSideProps: GetServerSideProps = async (context) => { const ConsumersPage: React.FC< InferGetServerSidePropsType > = ({ queryKey }) => { + // Redirect to My Gateways page if no gateway selected + NoGatewayRedirect(); + const toast = useToast(); const breadcrumbs = useNamespaceBreadcrumbs([{ text: 'Consumers' }]); const client = useQueryClient(); diff --git a/src/nextapp/pages/manager/gateways/detail.tsx b/src/nextapp/pages/manager/gateways/detail.tsx index e84daf53c..f12f2b21e 100644 --- a/src/nextapp/pages/manager/gateways/detail.tsx +++ b/src/nextapp/pages/manager/gateways/detail.tsx @@ -61,6 +61,7 @@ import useCurrentNamespace from '@/shared/hooks/use-current-namespace'; import { useGlobal } from '@/shared/services/global'; import EditNamespaceDisplayName from '@/components/edit-display-name'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; +import NoGatewayRedirect from '@/components/no-gateway-redirect'; const actions = [ { @@ -120,6 +121,9 @@ const secondaryActions = [ ]; const NamespacesPage: React.FC = () => { + // Redirect to My Gateways page if no gateway selected + NoGatewayRedirect(); + const { user } = useAuth(); const breadcrumbs = useNamespaceBreadcrumbs(); const hasNamespace = !!user?.namespace; @@ -155,14 +159,6 @@ const NamespacesPage: React.FC = () => { text: 'Your Organization and Business Unit will appear here', }; }, [namespace]); - - // Redirect to My Gateways page if no gateway selected - React.useEffect(() => { - if (!hasNamespace) { - router.push('/manager/gateways/list'); - } - }, [hasNamespace]); - const handleDelete = React.useCallback(async () => { if (user?.namespace) { try { diff --git a/src/nextapp/pages/manager/gateways/index.tsx b/src/nextapp/pages/manager/gateways/index.tsx index 5cdad9e2b..5f3a629cb 100644 --- a/src/nextapp/pages/manager/gateways/index.tsx +++ b/src/nextapp/pages/manager/gateways/index.tsx @@ -7,7 +7,6 @@ import { Container } from '@chakra-ui/react'; import { useApi } from '@/shared/services/api'; import { useAuth } from '@/shared/services/auth'; import PageHeader from '@/components/page-header'; -import { has } from 'lodash'; const GatewaysHome: React.FC = () => { const { data, isSuccess, isError } = useApi( @@ -21,7 +20,7 @@ const GatewaysHome: React.FC = () => { React.useEffect(() => { if (hasNamespace) { - router.push('/manager/gateways/detail'); + router.push('/manager/gateways/list'); } else { if (isSuccess && data.allNamespaces.length === 0) { router.push('/manager/gateways/get-started'); diff --git a/src/nextapp/pages/manager/gateways/list.tsx b/src/nextapp/pages/manager/gateways/list.tsx index f63e29d60..6d71f29cb 100644 --- a/src/nextapp/pages/manager/gateways/list.tsx +++ b/src/nextapp/pages/manager/gateways/list.tsx @@ -12,13 +12,11 @@ import { Spacer, useToast, Select, - Center, } from '@chakra-ui/react'; import Head from 'next/head'; import { gql } from 'graphql-request'; import { FaPlus, FaLaptopCode, FaRocket, FaServer } from 'react-icons/fa'; import { useQueryClient } from 'react-query'; -import { differenceInDays } from 'date-fns'; import PageHeader from '@/components/page-header'; import GridLayout from '@/layouts/grid'; @@ -31,6 +29,7 @@ import PublishingPopover from '@/components/publishing-popover'; import { useRouter } from 'next/router'; import { updateRecentlyViewedNamespaces } from '@/shared/services/utils'; import { useAuth } from '@/shared/services/auth'; +import { useGlobal } from '@/shared/services/global'; type GatewayActions = { title: string; @@ -41,45 +40,56 @@ type GatewayActions = { descriptionEnd: string; }; -const actions: GatewayActions[] = [ - { - title: 'Need to create a new gateway?', - url: - 'https://developer.gov.bc.ca/docs/default/component/aps-infra-platform-docs/tutorials/quick-start/', - urlText: 'API Provider Quick Start', - icon: FaPlus, - description: 'Follow our', - descriptionEnd: 'guide.', - }, - { - title: 'GWA CLI commands', - url: - 'https://developer.gov.bc.ca/docs/default/component/aps-infra-platform-docs/resources/gwa-commands/', - urlText: 'GWA CLI', - icon: FaLaptopCode, - description: 'Explore helpful commands in our', - descriptionEnd: 'guide.', - }, - { - title: 'Ready to deploy to production?', - url: - 'https://developer.gov.bc.ca/docs/default/component/aps-infra-platform-docs/guides/owner-journey-v1/#production-links', - urlText: 'going to production', - icon: FaRocket, - description: 'Check our', - descriptionEnd: 'checklist.', - }, -]; - const MyGatewaysPage: React.FC = () => { const { user } = useAuth(); const managerDisclosure = useDisclosure(); const { data, isLoading, isSuccess, isError } = useApi( 'allNamespaces', { query }, - { suspense: false } + { + suspense: false, + refetchOnWindowFocus: true, + refetchOnReconnect: true, + } ); + // External links + const global = useGlobal(); + const QuickStartUrl = + global?.helpLinks.helpSupportUrl + 'tutorials/quick-start'; + const GwaUrl = global?.helpLinks.helpSupportUrl + 'reference/gwa-commands'; + const ProdChecklistUrl = + global?.helpLinks.helpSupportUrl + + 'unlisted/owner-journey-v1/#production-links'; + + // Action items + const actions: GatewayActions[] = [ + { + title: 'Need to create a new gateway?', + url: QuickStartUrl, + urlText: 'API Provider Quick Start', + icon: FaPlus, + description: 'Follow our', + descriptionEnd: 'guide.', + }, + { + title: 'GWA CLI commands', + url: GwaUrl, + urlText: 'GWA CLI', + icon: FaLaptopCode, + description: 'Explore helpful commands in our', + descriptionEnd: 'guide.', + }, + { + title: 'Ready to deploy to production?', + url: ProdChecklistUrl, + urlText: 'going to production', + icon: FaRocket, + description: 'Check our', + descriptionEnd: 'checklist.', + }, + ]; + // Redirect to Get Started page if no gateways const router = useRouter(); React.useEffect(() => { @@ -255,48 +265,58 @@ const MyGatewaysPage: React.FC = () => { {isError && Gateways failed to load} {isSuccess && ( <> - {namespaceSearchResults.map((namespace) => ( - - - - - - {namespace.displayName - ? namespace.displayName - : namespace.name} - - - - {namespace.name} - - - - {namespace.orgEnabled === false && - !namespace.orgUpdatedAt && ( - + {namespaceSearchResults + .sort( + (a, b) => + a.displayName?.localeCompare(b.displayName) || + a.name?.localeCompare(b.name) + ) + .map((namespace) => ( + + + + + + {namespace.displayName} + + + + {namespace.name} + + + + {namespace.orgEnabled === false && + !namespace.orgUpdatedAt && ( + + )} + {namespace.orgEnabled === false && + namespace.orgUpdatedAt && ( + + )} + {namespace.orgEnabled === true && ( + )} - {namespace.orgEnabled === false && namespace.orgUpdatedAt && ( - - )} - {namespace.orgEnabled === true && ( - - )} - - ))} + + ))} {namespaceSearchResults.length === 0 && ( <> { + // Redirect to My Gateways page if no gateway selected + NoGatewayRedirect(); + const { user } = useAuth(); const breadcrumbs = useNamespaceBreadcrumbs([{ text: 'Products' }]); const client = useQueryClient(); diff --git a/src/nextapp/pages/manager/service-accounts/index.tsx b/src/nextapp/pages/manager/service-accounts/index.tsx index 8801c4447..fcd65ed39 100644 --- a/src/nextapp/pages/manager/service-accounts/index.tsx +++ b/src/nextapp/pages/manager/service-accounts/index.tsx @@ -35,6 +35,7 @@ import { FaCheckCircle } from 'react-icons/fa'; import ServiceAccountCreate from '@/components/service-account-create'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; import EmptyPane from '@/components/empty-pane'; +import NoGatewayRedirect from '@/components/no-gateway-redirect'; export const getServerSideProps: GetServerSideProps = async (context) => { const queryKey = 'getServiceAccounts'; @@ -63,6 +64,9 @@ export const getServerSideProps: GetServerSideProps = async (context) => { const ServiceAccountsPage: React.FC< InferGetServerSidePropsType > = ({ queryKey }) => { + // Redirect to My Gateways page if no gateway selected + NoGatewayRedirect(); + const breadcrumbs = useNamespaceBreadcrumbs([{ text: 'Service Accounts' }]); const client = useQueryClient(); const [credentials, setCredentials] = React.useState>( diff --git a/src/nextapp/pages/manager/services/index.tsx b/src/nextapp/pages/manager/services/index.tsx index a64dec765..bc3199cdd 100644 --- a/src/nextapp/pages/manager/services/index.tsx +++ b/src/nextapp/pages/manager/services/index.tsx @@ -12,6 +12,7 @@ import ServicesFilters from '@/components/services-list/services-filters'; import { useAuth } from '@/shared/services/auth'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; import { GetServerSideProps, InferGetServerSidePropsType } from 'next'; +import NoGatewayRedirect from '@/components/no-gateway-redirect'; import { FilterState } from '@/components/services-list/types'; @@ -26,6 +27,9 @@ export const getServerSideProps: GetServerSideProps = async () => { const ServicesPage: React.FC< InferGetServerSidePropsType > = ({ metricsUrl }) => { + // Redirect to My Gateways page if no gateway selected + NoGatewayRedirect(); + const title = 'Gateway Services'; const breadcrumb = useNamespaceBreadcrumbs([{ text: title }]); const { user } = useAuth(); diff --git a/src/nextapp/shared/services/global.tsx b/src/nextapp/shared/services/global.tsx index 25908941f..346265c91 100644 --- a/src/nextapp/shared/services/global.tsx +++ b/src/nextapp/shared/services/global.tsx @@ -5,6 +5,7 @@ type GlobalContent = { readonly version: string; readonly revision: string; readonly cluster: string; + readonly apiRootUrl: string; readonly accountLinks: Record; readonly helpLinks: Record; readonly identities: { @@ -18,6 +19,7 @@ const defaultState = { version: '', revision: '', cluster: '', + apiRootUrl: '', identities: { developer: ['idir'], provider: ['idir'], diff --git a/src/server.ts b/src/server.ts index c03dcef7a..f1aff5d28 100644 --- a/src/server.ts +++ b/src/server.ts @@ -384,6 +384,7 @@ const configureExpress = (app: any) => { version: process.env.NEXT_PUBLIC_APP_VERSION, revision: process.env.NEXT_PUBLIC_APP_REVISION, cluster: process.env.NEXT_PUBLIC_KUBE_CLUSTER, + apiRootUrl: process.env.NEXT_PUBLIC_API_ROOT, identities: { developer: (process.env.NEXT_PUBLIC_DEVELOPER_IDS || '').split(','), provider: (process.env.NEXT_PUBLIC_PROVIDER_IDS || '').split(','), diff --git a/src/services/keycloak/namespace-details.ts b/src/services/keycloak/namespace-details.ts index 058f4e434..84971d98e 100644 --- a/src/services/keycloak/namespace-details.ts +++ b/src/services/keycloak/namespace-details.ts @@ -31,7 +31,7 @@ export async function getAllNamespaces(envCtx: EnvironmentContext) { const nsList = namespaces.map((ns: ResourceSet) => ({ id: ns.id, name: ns.name, - displayName: ns.displayName, + displayName: ns.displayName || `Gateway ${ns.name}`, scopes: ns.resource_scopes, prodEnvId: envCtx.prodEnv.id, }));