Skip to content

Commit

Permalink
Merge pull request #1050 from bcgov/feature/ns-to-gw-selector
Browse files Browse the repository at this point in the history
Feature/ns to gw selector
  • Loading branch information
ikethecoder committed Jun 13, 2024
2 parents f0b75e1 + 7d83ab8 commit 88165cb
Show file tree
Hide file tree
Showing 27 changed files with 846 additions and 226 deletions.
9 changes: 8 additions & 1 deletion .env.local
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
LOG_LEVEL=info
LOG_LEVEL=debug
DISABLE_LOGGING='true'
AUTH_STRATEGY=Oauth2Proxy
KNEX_HOST=kong-db
Expand Down Expand Up @@ -31,3 +31,10 @@ NEXT_PUBLIC_DEVELOPER_IDS=idir,bceid,bcsc,github
NEXT_PUBLIC_PROVIDER_IDS=idir
NEXT_PUBLIC_ACCOUNT_BCEID_URL=https://www.test.bceid.ca/logon.aspx?returnUrl=/profile_management
NEXT_PUBLIC_ACCOUNT_BCSC_URL=https://idtest.gov.bc.ca/account/

# For automated integrated testing
TEST_PORTAL_CLIENT_ID=aps-portal
TEST_PORTAL_CLIENT_SECRET=8e1a17ed-cb93-4806-ac32-e303d1c86018
TEST_PORTAL_USERNAME=janis@idir
TEST_PORTAL_PASSWORD=awsummer

2 changes: 1 addition & 1 deletion .github/workflows/ci-feat-sonar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:

- name: Run Tests
run: |
docker compose up kong-db -d
docker compose up keycloak -d
set -o allexport
source ./.env.local
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@

query GetCurrentNamespace {
currentNamespace {
id
name
displayName
org
orgUnit
orgUpdatedAt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
allNamespaces {
id
name
displayName
orgEnabled
orgUpdatedAt
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

mutation UpdateNamespaceDisplayName($displayName: String!) {
updateCurrentNamespaceDisplayName(displayName: $displayName)
}
1 change: 1 addition & 0 deletions src/authz/matrix.csv
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ API Owner Role Rules,,forceDeleteNamespace,,,,,,,api-owner,,,allow,
API Owner Role Rules,,namespace,,,,,,,api-owner,,,allow,
API Owner Role Rules,,currentNamespace,,,,,,,,,"portal-user,api-owner,provider-user,access-manager,credential-admin",allow,
API Owner / Provider Role Rules,,updateCurrentNamespace,,,,,,,api-owner,,,allow,
API Owner / Provider Role Rules,,updateCurrentNamespaceDisplayName,,,,,,,api-owner,,,allow,
API Owner Role Rules,,updatePermissions,,,,,,,api-owner,,,allow,
API Owner Role Rules,,grantPermissions,,,,,,,api-owner,,,allow,
API Owner Role Rules,,revokePermissions,,,,,,,api-owner,,,allow,
Expand Down
35 changes: 35 additions & 0 deletions src/lists/extensions/Namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ module.exports = {
const resource: any = await getResource(selectedNS, envCtx);
merged['id'] = resource['id'];
merged['scopes'] = resource['scopes'];
merged['displayName'] = resource['displayName'];
}

if (merged.org) {
Expand Down Expand Up @@ -341,6 +342,39 @@ module.exports = {
return true;
},
},
{
schema:
'updateCurrentNamespaceDisplayName(displayName: String): String',
resolver: async (
item: any,
{ displayName }: any,
context: any,
info: any,
{ query, access }: any
): Promise<boolean> => {
if (
context.req.user?.namespace == null ||
typeof context.req.user?.namespace === 'undefined'
) {
return null;
}

const ns = context.req.user?.namespace;

const prodEnv = await getGwaProductEnvironment(context, true);

await getNamespaceResourceSets(prodEnv); // sets accessToken

const resourcesApi = new UMAResourceRegistrationService(
prodEnv.uma2.resource_registration_endpoint,
prodEnv.accessToken
);

await resourcesApi.updateDisplayName(ns, displayName);
return true;
},
access: EnforcementPoint,
},
{
schema:
'updateCurrentNamespace(org: String, orgUnit: String): String',
Expand Down Expand Up @@ -416,6 +450,7 @@ module.exports = {
});
}
},
access: EnforcementPoint,
},
{
schema:
Expand Down
2 changes: 2 additions & 0 deletions src/mocks/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,14 @@ const allNamespaces = [
{
id: 'n1',
name: 'aps-portal',
displayName: 'API Services Portal gw',
orgEnabled: true,
createdAt: subDays(new Date(), 20).toISOString(),
},
{
id: 'n2',
name: 'loc',
displayName: 'Location services',
orgEnabled: false,
createdAt: subDays(new Date(), 5).toISOString(),
},
Expand Down
2 changes: 2 additions & 0 deletions src/mocks/resolvers/namespace-access.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ let umaPolicies = [
let currentNamespace = {
id: 'ns1',
name: 'aps-portal',
displayName: 'API Services Portal gw',
scopes: [
{ name: 'GatewayConfig.Publish' },
{ name: 'Namespace.Manage' },
Expand Down Expand Up @@ -172,6 +173,7 @@ export const updateCurrentNamesSpaceHandler = (req, res, ctx) => {
...req.variables,
org: req.variables.org ? { title: req.variables.org } : null,
orgUnit: req.variables.orgUnit ? { title: req.variables.orgUnit } : null,
displayName: req.variables.displayName ? { title: req.variables.displayName } : null,
};
return res(ctx.data({}));
};
Expand Down
6 changes: 0 additions & 6 deletions src/nextapp/components/auth-action/auth-action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
makeRedirectUrl,
useAuth,
} from '@/shared/services/auth';
import NamespaceMenu from '../namespace-menu';
import HelpMenu from './help-menu';
import NextLink from 'next/link';
import { useGlobal } from '@/shared/services/global';
Expand Down Expand Up @@ -67,7 +66,6 @@ const Signin: React.FC<AuthActionProps> = ({ site }) => {
return (
<Flex align="center" gridGap={4}>
<HelpMenu />
<Divider orientation="vertical" color="white" height="32px" />
<Menu placement="bottom-end">
<MenuButton
px={2}
Expand Down Expand Up @@ -120,12 +118,8 @@ const Signin: React.FC<AuthActionProps> = ({ site }) => {

return (
<HStack
divider={
<StackDivider borderColor="white" height="24px" alignSelf="center" />
}
spacing={4}
>
{user.roles.includes('portal-user') && <NamespaceMenu user={user} />}
<HelpMenu />
<Box
as="span"
Expand Down
164 changes: 164 additions & 0 deletions src/nextapp/components/edit-display-name/edit-display-name.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import * as React from 'react';
import {
Button,
ButtonGroup,
FormControl,
FormHelperText,
FormLabel,
Icon,
Input,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
useDisclosure,
useToast,
} from '@chakra-ui/react';
import { FaPen } from 'react-icons/fa';
import { QueryKey, useQueryClient } from 'react-query';
import { useApiMutation } from '@/shared/services/api';
import { gql } from 'graphql-request';
import { NamespaceInput } from '@/shared/types/query.types';

interface EditNamespaceDisplayNameProps {
data: NamespaceInput;
queryKey: QueryKey;
}

const EditNamespaceDisplayName: React.FC<EditNamespaceDisplayNameProps> = ({
data,
queryKey,
}) => {
const toast = useToast();
const { isOpen, onOpen, onClose } = useDisclosure();
const queryClient = useQueryClient();
const mutate = useApiMutation(mutation);
const [inputValue, setInputValue] = React.useState(data.displayName || '');
const [charCount, setCharCount] = React.useState(
data.displayName?.length || 0
);
const charLimit = 30;
const handleInputChange = (event) => {
const { value } = event.target;
setInputValue(value);
setCharCount(value.length);
};
const form = React.useRef<HTMLFormElement>();
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (charCount <= charLimit) {
updateNamespaceDisplayName();
}
};
const updateNamespaceDisplayName = async () => {
if (form.current) {
try {
if (form.current.checkValidity()) {
const formData = new FormData(form.current);
const entries = Object.fromEntries(formData);
await mutate.mutateAsync(entries);
queryClient.invalidateQueries(queryKey);
onClose();
toast({
title: 'Display name successfully edited',
status: 'success',
isClosable: true,
});
}
} catch (err) {
toast({
title: 'Display name update failed',
description: err,
status: 'error',
isClosable: true,
});
}
}
};
const handleSaveClick = () => {
form.current?.requestSubmit();
};
return (
<>
<Button
p="0"
leftIcon={<Icon as={FaPen} />}
variant="ghost"
size="sm"
onClick={onOpen}
data-testid="display-name-edit-btn"
>
Edit
</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent borderRadius="4px" px={11}>
<ModalHeader pt={10}>Edit display name</ModalHeader>
<ModalBody pt={0} pb={10}>
<form ref={form} onSubmit={handleSubmit}>
<FormControl isRequired>
<FormLabel></FormLabel>
<FormHelperText pb={4} fontSize={'16px'}>
A meaningful display name makes it easy for anyone to identify
and distinguish this Gateway from others.
</FormHelperText>
<Text
fontSize={'12px'}
color={charCount > charLimit ? 'bc-error' : 'gray.500'}
mt={2}
textAlign="right"
>
{charCount}/{charLimit}
</Text>
<Input
value={inputValue}
onChange={handleInputChange}
name="displayName"
variant="bc-input"
isInvalid={charCount > charLimit}
data-testid="edit-display-name-input"
/>
{charCount > charLimit && (
<Text color="bc-error" mt={2} mb={-8}>
You have reached the character limit
</Text>
)}
</FormControl>
</form>
</ModalBody>
<ModalFooter pt={7} pb={7}>
<ButtonGroup>
<Button
px={7}
onClick={onClose}
variant="secondary"
data-testid="edit-display-name-cancel-btn"
>
Cancel
</Button>
<Button
type="submit"
onClick={handleSaveClick}
data-testid="edit-display-name-submit-btn"
isDisabled={charCount > charLimit}
>
Save
</Button>
</ButtonGroup>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
};

export default EditNamespaceDisplayName;

const mutation = gql`
mutation UpdateNamespaceDisplayName($displayName: String!) {
updateCurrentNamespaceDisplayName(displayName: $displayName)
}
`;
1 change: 1 addition & 0 deletions src/nextapp/components/edit-display-name/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './edit-display-name';
Loading

0 comments on commit 88165cb

Please sign in to comment.