diff --git a/services-js/access-boston/.gitignore b/services-js/access-boston/.gitignore index 2e20105cb..c182928d3 100644 --- a/services-js/access-boston/.gitignore +++ b/services-js/access-boston/.gitignore @@ -4,3 +4,5 @@ service-provider.crt service-provider.key /pingid.properties /apps.yaml + +*.env diff --git a/services-js/access-boston/Dockerfile b/services-js/access-boston/Dockerfile index e5e829338..b75307bda 100644 --- a/services-js/access-boston/Dockerfile +++ b/services-js/access-boston/Dockerfile @@ -87,13 +87,13 @@ CMD ["yarn", "start"] # To use this file: # [a] clone the digital repo # [b] from a terminal, in the access-boston folder, run -# DOCKER_BUILDKIT=1 docker build --pull --cache-from local-test/access-boston:latest -f ./Dockerfile -t local-test/access-boston:latest --secret id=aws,src=$HOME/.aws/credentials ../.. +# DOCKER_BUILDKIT=1 docker build --pull --cache-from local-test/access-boston:latest -f ./Dockerfile -t local-test/access-boston:latest --secret id=aws,src=$HOME/.aws/credentials --platform linux/amd64 ../.. # -> this will create an image tagged local-test/access-boston:latest on the local machine # [c] from a terminal, in the access-boston folder, run # docker compose up --no-build -d access-boston # -> this will create a container which should start on your local machine, with your cloned repo mounted into # so that your changes are immediately effective in the browser. -# -> you should be able to see the webapp at https://127.0.0.1:300/group-mgmt ..etc +# -> you should be able to see the webapp at https://127.0.0.1:3000/group-mgmt ..etc # [d] In a terminal app, open a session in the container by running: # docker exec -it access-boston /bin/sh # -> This has effectively ssh'd you into the container as the defaul (root) user. @@ -107,17 +107,17 @@ CMD ["yarn", "start"] # docker stop access-boston # [2.5] Re-login into ECR with this command --> aws ecr get-login-password --region us-east-1 --profile=cityofboston | docker login --username AWS --password-stdin 251803681989.dkr.ecr.us-east-1.amazonaws.com # [3] Rebuild the container and apps by running: -# DOCKER_BUILDKIT=1 docker build --pull --cache-from local-test/access-boston:latest -f ./Dockerfile -t 251803681989.dkr.ecr.us-east-1.amazonaws.com/cob-digital-apps-staging/access-boston:deploy-new-stage --secret id=aws,src=$HOME/.aws/credentials ../.. +# DOCKER_BUILDKIT=1 docker build --pull --cache-from local-test/access-boston:latest -f ./Dockerfile -t 251803681989.dkr.ecr.us-east-1.amazonaws.com/cob-digital-apps-staging/access-boston:deploy-new-stage-test --secret id=aws,src=$HOME/.aws/credentials --platform linux/amd64 ../.. # -> this is essentially the same command as in [b] above, just uses a different tag and ensures the /app folder # is physically there and not mounted (using the docker-compose command in [c] above mounts the repo over # whatever was added into the the image's /app folder during the docker build command) # [4] Push the image to AWS by running -# docker push 251803681989.dkr.ecr.us-east-1.amazonaws.com/cob-digital-apps-staging/access-boston:deploy-new-stage +# docker push 251803681989.dkr.ecr.us-east-1.amazonaws.com/cob-digital-apps-staging/access-boston:deploy-new-stage-test # -> the deploy should start once the image is transferred/uploaded # # WHEN YOU ARE READY TO DEPLOY TO PROD: # [1] Tag the image you pushed to stage with a production tag: -# docker tag 251803681989.dkr.ecr.us-east-1.amazonaws.com/cob-digital-apps-staging/access-boston:deploy-new-stage 251803681989.dkr.ecr.us-east-1.amazonaws.com/cob-digital-apps-prod/access-boston:deploy-new-prod +# docker tag 251803681989.dkr.ecr.us-east-1.amazonaws.com/cob-digital-apps-staging/access-boston:deploy-new-stage-test 251803681989.dkr.ecr.us-east-1.amazonaws.com/cob-digital-apps-prod/access-boston:deploy-new-prod # [2] Push the image to AWS by running # docker push 251803681989.dkr.ecr.us-east-1.amazonaws.com/cob-digital-apps-prod/access-boston:deploy-new-prod # -> the deploy should start once the image is transferred/uploaded diff --git a/services-js/access-boston/docker-compose.yml b/services-js/access-boston/docker-compose.yml index c76284ded..2a39c6dbb 100644 --- a/services-js/access-boston/docker-compose.yml +++ b/services-js/access-boston/docker-compose.yml @@ -1,17 +1,24 @@ version: '3' services: access-boston: + # EXTRA_HOSTS=group-mgmt-test.digital-staging.boston.gov:172.17.0.3 + # COMPOSE_PORTS=3001:3001 + # AWS_S3_CONFIG_URL=s3://cob-digital-apps-staging-config/access-boston + # image: arm64/local-test/access-boston:latest image: local-test/access-boston:latest container_name: access-boston ports: - - 4000:3000 + - 3001:3001 + # - ${COMPOSE_PORTS} working_dir: /app/services-js/access-boston extra_hosts: - group-mgmt-test.digital-staging.boston.gov:172.17.0.3 + # - ${EXTRA_HOSTS} volumes: - ~/.aws:/root/.aws environment: AWS_S3_CONFIG_URL: s3://cob-digital-apps-staging-config/access-boston + # AWS_S3_CONFIG_URL: ${AWS_S3_CONFIG_URL} DEPLOY_VARIANT: test AWS_DEFAULT_REGION: us-east-1 AWS_REGION: us-east-1 diff --git a/services-js/access-boston/fixtures/apps.yaml b/services-js/access-boston/fixtures/apps.yaml index 4e08dc07c..0acbfe5aa 100644 --- a/services-js/access-boston/fixtures/apps.yaml +++ b/services-js/access-boston/fixtures/apps.yaml @@ -154,7 +154,7 @@ categories: - SG_AB_HCMSECURITY - title: Group Management url: /group-management - target: _blank + # target: _blank - title: Manager Tools apps: diff --git a/services-js/access-boston/src/client/group-management/Index.tsx b/services-js/access-boston/src/client/group-management/Index.tsx index 23b829aa9..4e8ce21eb 100644 --- a/services-js/access-boston/src/client/group-management/Index.tsx +++ b/services-js/access-boston/src/client/group-management/Index.tsx @@ -12,20 +12,17 @@ import InitialView from './InitialView'; import ManagementView from './ManagementView'; import ReviewChangesView from './ReviewChangesView'; import ReviewConfirmationView from './ReviewConfirmationView'; - -import EditableList from './list-components/EditableList'; import SearchComponent from './search-component/SearchComponent'; +import EditView from './list-components/edit'; import { fetchGroupSearch, fetchGroupSearchRemaining, - fetchPersonsGroups, fetchOurContainers, fetchDataURL, fetchMinimumUserGroups, } from './data-fetching/fetch-group-data'; import { - fetchGroupMembers, fetchPersonSearch, fetchPersonSearchRemaining, } from './data-fetching/fetch-person-data'; @@ -58,7 +55,26 @@ export default function Index(props: Props) { const changeMode = (newMode: Mode): void => dispatchState({ type: 'APP/CHANGE_MODE', mode: newMode }); - const changeSelected = (selectedItem: Group | Person): void => { + const changePageCount = (pageCount: number): void => { + dispatchState({ type: 'APP/CHANGE_PAGECOUNT', pageCount }); + }; + + const handleClickListItem = (item: Group | Person): void => { + changeSelected(item); + changeMode(state.mode === 'group' ? 'person' : 'group'); + }; + + const handleToggleItem = (item: Group | Person) => { + if (item.action && item.action === 'new') { + dispatchList({ type: 'LIST/DELETE_ITEM', item }); + } else { + dispatchList({ type: 'LIST/TOGGLE_ITEM_STATUS', item }); + } + }; + + const changeSelected = async ( + selectedItem: Group | Person + ): Promise => { dispatchState({ type: 'APP/SET_SELECTED', selected: selectedItem }); }; @@ -69,26 +85,10 @@ export default function Index(props: Props) { const changePage = (currentPage: number): void => { dispatchState({ type: 'APP/CHANGE_PAGE', currentPage }); - const { mode, selected } = state; - if (mode === 'group') { - if ( - selected.cn && - selected.chunked[currentPage] && - selected.chunked[currentPage].length > 0 - ) - handleFetchGroupMembers(selected, groups, currentPage); - } else { - if ( - selected.cn && - selected.chunked[currentPage] && - selected.chunked[currentPage].length > 0 - ) - handleFetchPersonsGroups(selected, groups, currentPage); - } - }; - - const changePageCount = (pageCount: number): void => { - dispatchState({ type: 'APP/CHANGE_PAGECOUNT', pageCount }); + dispatchList({ + type: 'LIST/LOAD_LIST', + list: state.selected.groupmember[currentPage], + }); }; const handleInitialSelection = (selectedItem: any): void => { @@ -96,11 +96,6 @@ export default function Index(props: Props) { changeView('management'); }; - const handleClickListItem = (item: Group | Person): void => { - changeSelected(item); - changeMode(state.mode === 'group' ? 'person' : 'group'); - }; - const handleAdminListItemClick = (item: any): void => { changeSelected(item); changeView('management'); @@ -119,88 +114,44 @@ export default function Index(props: Props) { const setOus = async () => { fetchOurContainers(groups).then(result => { - dispatchState({ - type: 'APP/SET_OUS', - ous: result.convertOUsToContainers, - }); + if (result !== null) { + dispatchState({ + type: 'APP/SET_OUS', + ous: result.convertOUsToContainers, + }); + } }); }; const getAdminMinGroups = async () => { fetchMinimumUserGroups(groups).then(result => { - let ret = result.getMinimumUserGroups.map((entry: Group | Person) => { - let remappedObj = renameObjectKeys( - { uniquemember: 'members', memberof: 'members' }, - entry - ); - remappedObj['chunked'] = - remappedObj['members'] && remappedObj['members'].length > -1 - ? chunkArray(remappedObj['members'], pageSize) - : []; - remappedObj['isAvailable'] = true; - remappedObj['status'] = 'current'; - - return remappedObj; - }); - - dispatchState({ - type: 'APP/SET_ADMIN_MIN_GROUPS', - dns: ret, - }); - }); - }; - - const handleFetchGroupMembers = ( - selected: Group, - dns: String[] = [], - _currentPage: number = 0 - ): void => { - const { members, chunked } = selected; - const mask_chunked = chunked ? chunked : []; - changePageCount(mask_chunked.length); - - if (members && members.length > 0) { - setLoading(true); - fetchGroupMembers(selected, dns, _currentPage).then(result => { - dispatchList({ - type: 'LIST/LOAD_LIST', - list: result, + // console.log('fetchMinimumUserGroups'); + if (result !== null && result.getMinimumUserGroups !== null) { + // console.log('fetchMinimumUserGroups > results'); + let ret = result.getMinimumUserGroups.map((entry: Group | Person) => { + // console.log('fetchMinimumUserGroups > results > map(entry): ', entry); + let remappedObj = renameObjectKeys( + { uniquemember: 'members', memberof: 'members', member: 'members' }, + entry + ); + remappedObj['chunked'] = + remappedObj['members'] && remappedObj['members'].length > -1 + ? chunkArray(remappedObj['members'], pageSize) + : []; + remappedObj['isAvailable'] = true; + remappedObj['status'] = 'current'; + return remappedObj; }); - setLoading(false); - }); - } - }; - - const handleFetchPersonsGroups = ( - selected: Person, - dns: string[] = [], - _currentPage: number = 0 - ): void => { - const { groups } = selected; - - if (groups && groups.length > 0) { - setLoading(true); - fetchPersonsGroups(selected, [], dns, state.ous, _currentPage).then( - result => { - dispatchList({ - type: 'LIST/LOAD_LIST', - list: result, - }); - setLoading(false); - } - ); - } + dispatchState({ + type: 'APP/SET_ADMIN_MIN_GROUPS', + dns: ret, + }); + } + }); }; useEffect(() => { - const { mode, selected } = state; - if (!viewOnly && mode === 'group') { - if (selected.cn) handleFetchGroupMembers(selected, groups); - } else { - if (selected.cn) handleFetchPersonsGroups(selected, groups); - } - // Update the document title using the browser API if ( !groups || @@ -223,14 +174,6 @@ export default function Index(props: Props) { } }, [state.selected]); - const handleToggleItem = (item: Group | Person) => { - if (item.action && item.action === 'new') { - dispatchList({ type: 'LIST/DELETE_ITEM', item }); - } else { - dispatchList({ type: 'LIST/TOGGLE_ITEM_STATUS', item }); - } - }; - const handleAddToList = (item: Group | Person) => dispatchList({ type: 'LIST/ADD_ITEM', item }); @@ -274,23 +217,29 @@ export default function Index(props: Props) { handleSelectClick={handleAddToList} selectedItem={state.selected} dns={groups} + ous={state.ous} cnArray={cnEntries} currentlist={list} + pageSize={state.pageSize} + setLoading={setLoading} + dispatchState={dispatchState} + dispatchList={dispatchList} + currentPage={state.currentPage} + changePageCount={changePageCount} /> } - editableList={ - } resetAll={resetAll} @@ -348,8 +297,18 @@ export default function Index(props: Props) { } handleSelectClick={handleInitialSelection} dns={groups} + ous={state.ous} + pageSize={state.pageSize} + setLoading={setLoading} + dispatchState={dispatchState} + dispatchList={dispatchList} + currentPage={state.currentPage} + changePageCount={changePageCount} /> } + pageSize={state.pageSize} + dispatchList={dispatchList} + changePageCount={changePageCount} /> ); diff --git a/services-js/access-boston/src/client/group-management/InitialView.tsx b/services-js/access-boston/src/client/group-management/InitialView.tsx index 7c8ac4586..d84b68994 100644 --- a/services-js/access-boston/src/client/group-management/InitialView.tsx +++ b/services-js/access-boston/src/client/group-management/InitialView.tsx @@ -19,7 +19,6 @@ import { Mode } from './types'; import Section from './Section'; import Icon from './Icon'; -// import { Group, Person } from '../group-management/types'; import MinGroupDisplay from './MinGroupDisplay'; interface Props { @@ -29,6 +28,9 @@ interface Props { adminMinGroups?: []; handleAdminGroupClick: (item: any) => void; viewOnly?: boolean; + pageSize: number; + dispatchList: any; + changePageCount: any; } /** @@ -82,6 +84,9 @@ export default function InitialView(props: Props) { ) : ( <>{props.searchComponent} diff --git a/services-js/access-boston/src/client/group-management/InititalView.stories.tsx b/services-js/access-boston/src/client/group-management/InititalView.stories.tsx index 09582dd55..f507a508f 100644 --- a/services-js/access-boston/src/client/group-management/InititalView.stories.tsx +++ b/services-js/access-boston/src/client/group-management/InititalView.stories.tsx @@ -36,8 +36,14 @@ function Wrapper() { } handleSelectClick={() => {}} dns={[]} + currentPage={0} + pageSize={1} + changePageCount={() => {}} /> } + pageSize={150} + dispatchList={() => {}} + changePageCount={() => {}} /> ); } diff --git a/services-js/access-boston/src/client/group-management/ManagementView.stories.tsx b/services-js/access-boston/src/client/group-management/ManagementView.stories.tsx index aa756d1f0..51208418d 100644 --- a/services-js/access-boston/src/client/group-management/ManagementView.stories.tsx +++ b/services-js/access-boston/src/client/group-management/ManagementView.stories.tsx @@ -22,7 +22,7 @@ import allPeople from './fixtures/people.json'; import ManagementView from './ManagementView'; import SearchComponent from './search-component/SearchComponent'; -import EditableList from './list-components/EditableList'; +import EditView from './list-components/edit'; const groups = allGroups.map(group => toGroup(group)); const people = allPeople.map(person => toPerson(person)); @@ -75,10 +75,13 @@ export function Wrapper(props) { handleSelectClick={() => {}} selectedItem={selected} dns={[]} + currentPage={0} + pageSize={1} + changePageCount={() => {}} /> } editableList={ - void; searchComponent: ReactNode; - editableList: ReactNode; + editableList?: ReactNode; + editView?: ReactNode; resetAll: () => void; viewOnly: boolean; } @@ -48,7 +49,8 @@ export default function ManagementView(props: Props) { title={`Current ${mode === 'person' ? 'groups' : 'members'}`} /> - {props.editableList} + {/* {props.editableList} */} + {props.editView && (typeof props.editView && props.editView)}
+ + ); + } else { + return {displayText}; + } + }; + // console.log(`isAvailable: ${isAvailable}`); + + if (handleChange) { + return ( +
  • + + +
  • + ); + } else { + return ( +
  • + {displayElement()} +
  • + ); + } +} diff --git a/services-js/access-boston/src/client/group-management/list-components/edit/styling.ts b/services-js/access-boston/src/client/group-management/list-components/edit/styling.ts new file mode 100644 index 000000000..a4f72a95f --- /dev/null +++ b/services-js/access-boston/src/client/group-management/list-components/edit/styling.ts @@ -0,0 +1,124 @@ +/** @jsx jsx */ + +import { css } from '@emotion/core'; +import { + FREEDOM_RED_DARK, + OPTIMISTIC_BLUE_DARK, + SANS, + BLACK, + GRAY_000, + GRAY_100, + GRAY_200, + OPTIMISTIC_BLUE_LIGHT, + WHITE, +} from '@cityofboston/react-fleet'; + +export const LOADER_STYLING = css({ + display: 'flex', + justifyContent: 'center', + marginTop: '3rem', + color: OPTIMISTIC_BLUE_DARK, +}); + +export const NO_RESULTS_STYLING = css({ + fontFamily: SANS, + color: FREEDOM_RED_DARK, +}); + +export const LIST_STYLING = { + listStyle: 'none', + paddingLeft: 0, + paddingBottom: '0.75rem', + flexGrow: 1, +}; + +export const LIST_ITEM_STYLING = { + listStyle: 'none', + padding: '0.5em 1em', + marginBottom: '0.75rem', +}; + +export const BUTTON_STYLING = css({ + color: OPTIMISTIC_BLUE_DARK, + textDecoration: 'none', + cursor: 'pointer', +}); + +export const REVIEW_LIST_ITEM_STYLING = css({ + backgroundColor: GRAY_000, +}); + +export const EDITABLE_LIST_ITEM_STYLING = css({ + backgroundColor: WHITE, + transition: 'background-color 0.2s', + + label: { + position: 'relative', + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + + cursor: 'pointer', + + '&::before, &::after': { + content: '""', + display: 'block', + position: 'absolute', + right: 0, + height: '1rem', + width: '1rem', + }, + + '&::before': { + border: `2px solid ${BLACK}`, + backgroundColor: WHITE, + }, + + '&::after': { + opacity: 0, + backgroundImage: + 'url(https://patterns.boston.gov/images/public/icons/check.svg)', + backgroundRepeat: 'no-repeat', + backgroundPosition: '0% 50%', + backgroundSize: '0.8em', + }, + }, + + 'input[type="checkbox"]': { + opacity: 0, + position: 'absolute', + height: 0, + width: 0, + margin: 0, + + '&:focus + label::before': { + outline: `2px solid ${OPTIMISTIC_BLUE_DARK}`, + }, + + '&:checked + label::after': { + opacity: 1, + }, + + '&:disabled + label': { + cursor: 'default', + + '&::before, &::after': { + opacity: 0.5, + cursor: 'not-allowed', + }, + + '&::before': { + backgroundColor: GRAY_200, + }, + }, + }, + + '&.unchecked': { + backgroundColor: GRAY_100, + }, +}); + +export const ADDED_STYLING = css({ + outline: `2px solid ${OPTIMISTIC_BLUE_LIGHT}`, + outlineOffset: '-2px', +}); diff --git a/services-js/access-boston/src/client/group-management/pagination-components/Pagination.tsx b/services-js/access-boston/src/client/group-management/pagination-components/Pagination.tsx index 233135412..961dc1d59 100644 --- a/services-js/access-boston/src/client/group-management/pagination-components/Pagination.tsx +++ b/services-js/access-boston/src/client/group-management/pagination-components/Pagination.tsx @@ -6,42 +6,29 @@ import { NORM_HOVER, PAGINATION, } from '../pagination-components/styling'; -import { Group, Person } from '../types'; interface Props { - items: Array; currentPage: number; pageCount: number; pageSize: number; - changePage: (currentPage: number) => any; - handleNextPage: ( - currentPage: number, - pageCount: number, - changePage: any - ) => any; - handlePrevPage: (currentPage: number, changePage: any) => any; - handlePageNumClick: (pageNum: number, changePage: any) => any; + changePage: (currentPage: number) => void; + nextPage: (currentPage: number, pageCount: number, changePage: any) => void; + prevPage: (currentPage: number, changePage: any) => void; } export default function Pagination(props: Props) { - const { - currentPage, - pageCount, - changePage, - handleNextPage, - handlePrevPage, - } = props; + const { currentPage, pageCount, changePage, nextPage, prevPage } = props; const goToPage = (pageNum: number) => { changePage(pageNum); }; const next = () => { - handleNextPage(currentPage, pageCount, changePage); + nextPage(currentPage, pageCount, changePage); }; const prev = () => { - handlePrevPage(currentPage, changePage); + prevPage(currentPage, changePage); }; const lastPage = pageCount - 1; @@ -122,9 +109,7 @@ export default function Pagination(props: Props) { css={HOVER_STYLES} onClick={prev} > - - previous - + previous )} diff --git a/services-js/access-boston/src/client/group-management/pagination-components/styling.ts b/services-js/access-boston/src/client/group-management/pagination-components/styling.ts index 7d81e9daa..0a56383f5 100644 --- a/services-js/access-boston/src/client/group-management/pagination-components/styling.ts +++ b/services-js/access-boston/src/client/group-management/pagination-components/styling.ts @@ -47,9 +47,9 @@ export const PAGINATION = css({ borderLeftColor: CHARLES_BLUE, }, - '.prev-next:hover': { - backgroundColor: FREEDOM_RED_DARK, - }, + // '.prev-next:hover': { + // backgroundColor: FREEDOM_RED_DARK, + // }, '.prev-next a:hover': { backgroundColor: FREEDOM_RED_DARK, diff --git a/services-js/access-boston/src/client/group-management/search-component/AutosuggestWrapper.tsx b/services-js/access-boston/src/client/group-management/search-component/AutosuggestWrapper.tsx index 9afe11acd..ddd9c909c 100644 --- a/services-js/access-boston/src/client/group-management/search-component/AutosuggestWrapper.tsx +++ b/services-js/access-boston/src/client/group-management/search-component/AutosuggestWrapper.tsx @@ -33,6 +33,7 @@ interface Props { duplication: any; warningLabel: string; }; + mode?: string; } /** @@ -46,8 +47,9 @@ export default class AutosuggestWrapper extends Component { // When suggestion is clicked, Autosuggest needs to populate the input // based on the clicked suggestion. Teach Autosuggest how to calculate the // input value for every given suggestion. + getSuggestionValue = (suggestion: Group | Person): string => { - const { cnArray, isSelectionDuplication } = this.props; + const { cnArray, isSelectionDuplication, mode } = this.props; let alreadyAdded = ''; if (cnArray && cnArray.length > 0 && isSelectionDuplication) { @@ -56,11 +58,41 @@ export default class AutosuggestWrapper extends Component { suggestion.cn ); if (isSelection_Duplication.duplication) { - alreadyAdded = ` - ${isSelection_Duplication.warningLabel}`; + alreadyAdded = `${isSelection_Duplication.warningLabel}`; } } - const retVal = `${suggestion.displayName || suggestion.cn}${alreadyAdded}`; - return `${retVal}`; + return `${this.getName(suggestion, mode, alreadyAdded)}`; + }; + + getName = (suggestion, mode, alreadyAdded) => { + const givenName = + suggestion['givenName'] && suggestion['givenName'].length > 0 + ? suggestion['givenName'] + : ``; + const sn = + suggestion['sn'] && suggestion['sn'].length > 0 + ? ` ${suggestion['sn']}` + : ``; + const cOBUserAgency = + suggestion['cOBUserAgency'] && suggestion['cOBUserAgency'].length > 0 + ? ` | ${suggestion['cOBUserAgency']}` + : ``; + const personName = + mode === 'person' && + (suggestion.displayName.split(' ')[0] !== suggestion['givenName'] || + suggestion.displayName.length === 0) + ? `${givenName}${sn}${cOBUserAgency}` + : `${suggestion.displayName}`; + const nameStr = `${ + alreadyAdded.length > 0 ? alreadyAdded + ` ` : `` + }${personName}`; + + const retStr = + mode === 'person' + ? `${nameStr}` + : `${suggestion.displayName || suggestion.cn}`; + // console.log(`retStr: ${retStr}`, suggestion); + return retStr; }; // input handler @@ -84,27 +116,32 @@ export default class AutosuggestWrapper extends Component { renderSuggestion = suggestion => { const { cn, displayName } = suggestion; - const { cnArray, isSelectionDuplication } = this.props; + const { cnArray, isSelectionDuplication, mode } = this.props; + const cutoff = 12; + const trimmedCn = cn.length > cutoff ? `${cn.substring(0, cutoff)}...` : cn; + const nameLabel = this.getName(suggestion, mode, ''); let warningLabel = ''; if (cnArray && cnArray.length > 0 && isSelectionDuplication) { const isSelection_Duplication = isSelectionDuplication(cnArray, cn); warningLabel = isSelection_Duplication.warningLabel; } + if (displayName) { return (
    - {displayName} + {nameLabel} {warningLabel} - {warningLabel === '' && displayName !== cn && {cn}} + {warningLabel === '' && {trimmedCn}}
    ); } else { return ( - <> - {cn} +
    + {nameLabel} {warningLabel} - + {trimmedCn} +
    ); } }; diff --git a/services-js/access-boston/src/client/group-management/search-component/SearchComponent.stories.tsx b/services-js/access-boston/src/client/group-management/search-component/SearchComponent.stories.tsx index 54c7af1be..615aa3fc5 100644 --- a/services-js/access-boston/src/client/group-management/search-component/SearchComponent.stories.tsx +++ b/services-js/access-boston/src/client/group-management/search-component/SearchComponent.stories.tsx @@ -30,6 +30,9 @@ storiesOf('GroupManagementPage/SearchComponent', module) //@ts-ignore selectedItem={mockGroup} dns={[]} + currentPage={0} + pageSize={1} + changePageCount={() => {}} /> )) .add('group add', () => ( @@ -41,6 +44,9 @@ storiesOf('GroupManagementPage/SearchComponent', module) //@ts-ignore selectedItem={mockPerson} dns={[]} + currentPage={0} + pageSize={1} + changePageCount={() => {}} /> )) .add('person search', () => ( @@ -50,6 +56,9 @@ storiesOf('GroupManagementPage/SearchComponent', module) handleFetch={fetchPersonSearch} handleSelectClick={() => {}} dns={[]} + currentPage={0} + pageSize={1} + changePageCount={() => {}} /> )) .add('group search', () => ( @@ -59,6 +68,9 @@ storiesOf('GroupManagementPage/SearchComponent', module) handleFetch={fetchGroupSearch} handleSelectClick={() => {}} dns={[]} + currentPage={0} + pageSize={1} + changePageCount={() => {}} /> )) .add('searching', () => ( @@ -69,6 +81,9 @@ storiesOf('GroupManagementPage/SearchComponent', module) handleSelectClick={() => {}} currentStatus="searching" dns={[]} + currentPage={0} + pageSize={1} + changePageCount={() => {}} /> )) .add('no results', () => ( @@ -79,6 +94,9 @@ storiesOf('GroupManagementPage/SearchComponent', module) handleSelectClick={() => {}} currentStatus="noResults" dns={[]} + currentPage={0} + pageSize={1} + changePageCount={() => {}} /> )) .add('server error/could not reach server', () => ( @@ -89,5 +107,8 @@ storiesOf('GroupManagementPage/SearchComponent', module) handleSelectClick={() => {}} currentStatus="fetchError" dns={[]} + currentPage={0} + pageSize={1} + changePageCount={() => {}} /> )); diff --git a/services-js/access-boston/src/client/group-management/search-component/SearchComponent.tsx b/services-js/access-boston/src/client/group-management/search-component/SearchComponent.tsx index 33e6c2d0e..bf006987c 100644 --- a/services-js/access-boston/src/client/group-management/search-component/SearchComponent.tsx +++ b/services-js/access-boston/src/client/group-management/search-component/SearchComponent.tsx @@ -1,26 +1,21 @@ /** @jsx jsx */ -import { css, jsx } from '@emotion/core'; +import { jsx } from '@emotion/core'; import { MouseEvent, ReactNode, useEffect, useReducer } from 'react'; - -import { - FREEDOM_RED_DARK, - OPTIMISTIC_BLUE_DARK, - SANS, - SectionHeader, -} from '@cityofboston/react-fleet'; - +import { SectionHeader } from '@cityofboston/react-fleet'; +import { FIELD_CONTAINER_STYLING, INPUTS_STYLING } from './styling'; +import { textCopy } from './copy'; import { useDebounce } from '../../utility'; - -import { initialState, reducer, Status } from '../state/search'; - +import { initialSearchState, searchReducer, Status } from '../state/search'; import { Group, Mode, Person, View } from '../types'; - import Spinner from '../Spinner'; import Section from '../Section'; - import AutosuggestWrapper from './AutosuggestWrapper'; +import { + fetchGroupMembers, + fetchPersonGroups, +} from '../data-fetching/fetch-person-data'; interface Props { mode: Mode; @@ -29,14 +24,21 @@ interface Props { selectedItem?: Group | Person; handleFetch: ( value: string, - item, //?: Group | Person; - dns + item: any, // Group | Person, + dns: any ) => Promise; handleSelectClick: (selection: any) => void; currentStatus?: Status; // solely for Storybook - dns: String[]; + dns: string[]; + ous?: string[]; cnArray?: Array; currentlist?: Array; + currentPage: number; + pageSize: number; + setLoading?: any; + dispatchState?: any; + dispatchList?: any; + changePageCount: (pageCount: number) => void; } /** @@ -53,20 +55,32 @@ interface Props { */ export default function SearchComponent(props: Props) { const fetchDelay = 1000; + const [searchState, dispatchSearchState] = useReducer( + searchReducer, + initialSearchState + ); - const [state, dispatch] = useReducer(reducer, initialState); - - const { currentStatus, mode, view, dns, cnArray, currentlist } = props; - const { searchStatus, searchText, searchResults, selection } = state; + const { + mode, + view, + dns, + ous, + cnArray, + pageSize, + // setLoading, + currentPage, + currentlist, + currentStatus, + changePageCount, + } = props; + const { searchStatus, searchText, searchResults, selection } = searchState; // Associate label with search field. const inputId = `search-${view}-${mode}`; - const debouncedValue = useDebounce(searchText, fetchDelay); - const updateSuggestions = (result: Array): void => { let res = result; - dispatch({ + dispatchSearchState({ type: 'SEARCH/UPDATE_SUGGESTIONS', searchResults: res, mode: mode, @@ -75,20 +89,50 @@ export default function SearchComponent(props: Props) { // Note: remember that this is also fired when a user uses the keyboard // to make a selection and then hits “enter” - const handleClick = (event: MouseEvent): void => { + const handleClick = async ( + event: MouseEvent + ): Promise => { event.preventDefault(); - if (cnArray && cnArray.length > 1 && state.searchStatus === 'duplicate') { + if ( + cnArray && + cnArray.length > 1 && + searchState.searchStatus === 'duplicate' + ) { handleChange(''); } else { const new_currentlist = currentlist && currentlist.length > 0 ? currentlist : [{ cn: '' }]; const newArr = new_currentlist.map(entry => entry.cn); const isDup = isSelectionDuplication(newArr, selection.cn); + if (!isDup.duplication) { selection.action = 'new'; - props.handleSelectClick(selection); - dispatch({ type: 'SEARCH/SUBMIT_SELECTION' }); + + const dataFetched = members => { + selection.groupmember = members; + changePageCount(members.length); + if (view !== 'management') { + props.handleSelectClick(selection); + props.dispatchList({ + type: 'LIST/LOAD_LIST', + list: selection.groupmember[currentPage], + }); + } else { + props.handleSelectClick(selection); + props.dispatchState({ type: 'SEARCH/SUBMIT_SELECTION' }); + } + }; + + if (mode === 'group') { + await fetchGroupMembers(selection.dn, pageSize).then(result => + dataFetched(result) + ); + } else { + await fetchPersonGroups(selection.dn, pageSize, ous).then(result => + dataFetched(result) + ); + } } else { handleChange(''); } @@ -96,7 +140,7 @@ export default function SearchComponent(props: Props) { }; const handleChange = (text: string): void => { - dispatch({ + dispatchSearchState({ type: 'SEARCH/UPDATE_SEARCH_TEXT', searchText: text, }); @@ -106,19 +150,30 @@ export default function SearchComponent(props: Props) { selection: Group | Person, selectionValue: string ): void => { - // console.log('SearchComponent > handleSelection > handleSelection > selection: ', selectionValue, selection); - dispatch({ type: 'SEARCH/UPDATE_SELECTION', selection, selectionValue }); + dispatchSearchState({ + type: 'SEARCH/UPDATE_SELECTION', + selection, + selectionValue, + }); }; const handleFetch = (): void => { - dispatch({ type: 'SEARCH/UPDATE_STATUS', searchStatus: 'searching' }); + dispatchSearchState({ + type: 'SEARCH/UPDATE_STATUS', + searchStatus: 'searching', + }); if (view === 'initial') { props .handleFetch(searchText, null, dns) - .then(result => updateSuggestions(result)) + .then(result => { + return updateSuggestions(result); + }) .catch(() => - dispatch({ type: 'SEARCH/UPDATE_STATUS', searchStatus: 'fetchError' }) + dispatchSearchState({ + type: 'SEARCH/UPDATE_STATUS', + searchStatus: 'fetchError', + }) ); } else { props @@ -168,7 +223,11 @@ export default function SearchComponent(props: Props) { }; const buttonLabel = () => { - if (cnArray && cnArray.length > 0 && state.searchStatus === 'duplicate') { + if ( + cnArray && + cnArray.length > 0 && + searchState.searchStatus === 'duplicate' + ) { return textCopy[view][mode].clear; } else { return textCopy[view][mode].button; @@ -176,7 +235,11 @@ export default function SearchComponent(props: Props) { }; const buttonDisabled = () => { - if (cnArray && cnArray.length > 0 && state.searchStatus === 'duplicate') { + if ( + cnArray && + cnArray.length > 0 && + searchState.searchStatus === 'duplicate' + ) { return false; } else { return !selection.cn; @@ -185,28 +248,34 @@ export default function SearchComponent(props: Props) { const defaultSearchText = (_newText: any = 0) => { if (_newText && typeof _newText === 'string') { + // console.log(`defaultSearchText() > _newText: ${_newText}`); return _newText; } else { + // console.log(`defaultSearchText() > !_newText:`, _newText, searchText); return searchText; } }; - // used solely for Storybook; ensures specified status state is displayed. + // used solely for Storybook; ensures specified status searchState is displayed. useEffect(() => { if (currentStatus) { - dispatch({ type: 'SEARCH/UPDATE_STATUS', searchStatus: currentStatus }); + dispatchSearchState({ + type: 'SEARCH/UPDATE_STATUS', + searchStatus: currentStatus, + }); } }, []); // Clear typed input and suggestions if search type changes. useEffect(() => { - if (searchText.length > 0) dispatch({ type: 'SEARCH/RESET_STATE' }); + if (searchText.length > 0) + dispatchSearchState({ type: 'SEARCH/RESET_STATE' }); }, [mode]); // Clear suggestions if search text has been removed. useEffect(() => { if (!searchText && !currentStatus) { - dispatch({ type: 'SEARCH/CLEAR_SUGGESTIONS' }); + dispatchSearchState({ type: 'SEARCH/CLEAR_SUGGESTIONS' }); } }, [searchText]); @@ -217,7 +286,7 @@ export default function SearchComponent(props: Props) { if ( debouncedValue && debouncedValue.length >= 2 && - searchText !== state.selectionValue + searchText !== searchState.selectionValue ) { handleFetch(); } @@ -227,7 +296,9 @@ export default function SearchComponent(props: Props) {
    -
    +
    ); } - -const textCopy = { - initial: { - person: { - title: 'Person search', - label: 'Find a person', - button: 'Select', - clear: 'Clear', - }, - group: { - title: 'Group search', - label: 'Find a group', - button: 'Select', - clear: 'Clear', - }, - }, - management: { - person: { - title: 'Add a new member', - label: 'Find a person to add', - button: 'Add member', - clear: 'Clear', - }, - group: { - title: 'Add to a group', - label: 'Find a group to add', - button: 'Add group', - clear: 'Clear', - }, - }, -}; - -const FIELD_CONTAINER_STYLING = css({ - position: 'relative', - - '.status': { - position: 'absolute', - top: '50%', - transform: 'translateY(-50%)', - right: '1rem', - - display: 'flex', - - fontFamily: SANS, - }, - - '.no-results': { - color: FREEDOM_RED_DARK, - }, - - '.working': { - color: OPTIMISTIC_BLUE_DARK, - }, -}); - -const INPUTS_STYLING = css({ - display: 'flex', - - '> div': { - width: '100%', - }, - - button: { - marginLeft: '0.5em', - flexShrink: 0, - }, - - 'input[type="search"]': { - '&::-webkit-search-cancel-button': { - WebkitAppearance: 'none', - }, - '&::-webkit-calendar-picker-indicator': { - display: 'none', - }, - }, -}); diff --git a/services-js/access-boston/src/client/group-management/search-component/copy.ts b/services-js/access-boston/src/client/group-management/search-component/copy.ts new file mode 100644 index 000000000..3830433ec --- /dev/null +++ b/services-js/access-boston/src/client/group-management/search-component/copy.ts @@ -0,0 +1,30 @@ +export const textCopy = { + initial: { + person: { + title: 'Person search', + label: 'Find a person', + button: 'Select', + clear: 'Clear', + }, + group: { + title: 'Group search', + label: 'Find a group', + button: 'Select', + clear: 'Clear', + }, + }, + management: { + person: { + title: 'Add a new member', + label: 'Find a person to add', + button: 'Add member', + clear: 'Clear', + }, + group: { + title: 'Add to a group', + label: 'Find a group to add', + button: 'Add group', + clear: 'Clear', + }, + }, +}; diff --git a/services-js/access-boston/src/client/group-management/search-component/styling.ts b/services-js/access-boston/src/client/group-management/search-component/styling.ts new file mode 100644 index 000000000..03db7ef42 --- /dev/null +++ b/services-js/access-boston/src/client/group-management/search-component/styling.ts @@ -0,0 +1,57 @@ +/** @jsx jsx */ + +import { css } from '@emotion/core'; +import { + FREEDOM_RED_DARK, + OPTIMISTIC_BLUE_DARK, + SANS, +} from '@cityofboston/react-fleet'; + +export const FIELD_CONTAINER_STYLING = css({ + position: 'relative', + + li: { + marginBottom: 0, + }, + + '.status': { + position: 'absolute', + top: '50%', + transform: 'translateY(-50%)', + right: '1rem', + + display: 'flex', + + fontFamily: SANS, + }, + + '.no-results': { + color: FREEDOM_RED_DARK, + }, + + '.working': { + color: OPTIMISTIC_BLUE_DARK, + }, +}); + +export const INPUTS_STYLING = css({ + display: 'flex', + + '> div': { + width: '100%', + }, + + button: { + marginLeft: '0.5em', + flexShrink: 0, + }, + + 'input[type="search"]': { + '&::-webkit-search-cancel-button': { + WebkitAppearance: 'none', + }, + '&::-webkit-calendar-picker-indicator': { + display: 'none', + }, + }, +}); diff --git a/services-js/access-boston/src/client/group-management/state/app.ts b/services-js/access-boston/src/client/group-management/state/app.ts index 3189bb9fb..5f2909bea 100644 --- a/services-js/access-boston/src/client/group-management/state/app.ts +++ b/services-js/access-boston/src/client/group-management/state/app.ts @@ -14,6 +14,8 @@ import { PageCount, } from '../types'; +// import { fetchGroupMembers } from '../data-fetching/fetch-person-data'; + export type ActionTypes = | 'APP/CHANGE_VIEW' | 'APP/CHANGE_MODE' @@ -36,6 +38,7 @@ interface Action { currentPage?: CurrentPage; pageCount?: PageCount; dns?: []; + groupmembers?: Array; } export const initialState = { @@ -63,6 +66,11 @@ export const reducer = (state, action: Partial) => { ous: currUserOUs, }; + const pageVal = + state.currentPage !== action.currentPage + ? action.currentPage + : state.currentPage; + switch (action.type) { case 'APP/CHANGE_VIEW': return { ...state, view: action.view }; @@ -71,6 +79,19 @@ export const reducer = (state, action: Partial) => { return { ...state, mode: action.mode }; case 'APP/SET_SELECTED': + // If action.selected is empty ... request group members + if ( + action.selected && + Object.keys(action.selected).length > 0 && + action.groupmembers && + typeof action.groupmembers === 'object' && + action.groupmembers.length > 0 + ) + action.selected['groupmember'] = action.groupmembers; + + // console.log(`action.selected: `, action.selected); + // console.log(`action: `, action, state); + return { ...state, selected: action.selected }; case 'APP/SET_OUS': @@ -89,7 +110,14 @@ export const reducer = (state, action: Partial) => { return newInitState; case 'APP/CHANGE_PAGE': - return { ...state, currentPage: action.currentPage }; + // let newCurrPage = state.currentPage; + // console.log( + // `APP/CHANGE_PAGE > ${state.currentPage} | ${action.currentPage}` + // ); + // console.log(`bool: ${state.currentPage === action.currentPage}`); + // console.log('state|action: ', state, '\n', action, '\n'); + // console.log(`pageVal: ${pageVal}`); + return { ...state, currentPage: pageVal }; case 'APP/CHANGE_PAGECOUNT': return { ...state, pageCount: action.pageCount }; diff --git a/services-js/access-boston/src/client/group-management/state/data-helpers.ts b/services-js/access-boston/src/client/group-management/state/data-helpers.ts index 970585285..0eb3fef8d 100644 --- a/services-js/access-boston/src/client/group-management/state/data-helpers.ts +++ b/services-js/access-boston/src/client/group-management/state/data-helpers.ts @@ -49,34 +49,32 @@ export function getAllCns(uniqueMember: string[]): string[] { * Accepts a group object from server response, and returns a usable * Group object. */ -export function toGroup( - dataObject, - _dns: Array = [], - _ous: Array = [] -): Group { +export function toGroup(dataObject, ous: Array = []): Group { let isAvailable = - dataObject.canModify !== undefined ? dataObject.canModify : true; + dataObject.canModify && typeof dataObject.canModify === 'boolean' + ? dataObject.canModify + : true; let inDomain = true; - if (_ous.length > 0) { - inDomain = isDomainNameInOUs(dataObject.dn, _ous); + if (ous.length > 0) { + inDomain = isDomainNameInOUs(dataObject.distinguishedName, ous); if (!inDomain) { isAvailable = false; } } const chunkedResults = - dataObject.uniquemember && dataObject.uniquemember.length > 0 - ? chunkArray(dataObject.uniquemember, pageSize) + dataObject.member && dataObject.member.length > 0 + ? chunkArray(dataObject.member, pageSize) : [[]]; const retObj = { ...commonAttributes(dataObject), - members: dataObject.uniquemember || [], + members: dataObject.member || [], + groupmember: [], isAvailable, chunked: chunkedResults, }; - // console.log('toGroup > retObj: ', retObj, '\n------------'); return retObj; } @@ -92,6 +90,11 @@ export function toPerson(dataObject): Person { : [[]]; // console.log('toPerson > dataObject: '); // console.log('chunked: ', chunkedResults,'\n------------'); + const displayName = dataObject.displayName + ? dataObject.displayName + : dataObject.displayname + ? dataObject.displayname + : ''; const retObj = { ...commonAttributes(dataObject), groups: dataObject.ismemberof || [], @@ -100,6 +103,9 @@ export function toPerson(dataObject): Person { sn: dataObject.sn || '', mail: dataObject.mail || '', isAvailable: !dataObject.inactive, + cOBUserAgency: dataObject.cOBUserAgency ? dataObject.cOBUserAgency : '', + dn: dataObject.dn, + displayName, }; // console.log('toGroup > retObj: ', retObj, '\n------------'); @@ -107,14 +113,25 @@ export function toPerson(dataObject): Person { } function commonAttributes(dataObject): CommonAttributes { - // console.log('CommonAttributes dataObj: ', dataObject); - return { + const displayName = dataObject.displayname || dataObject.cn; + const dn: string = dataObject.distinguishedName + ? dataObject.distinguishedName + : dataObject.dn || ''; + const retObj = { cn: dataObject.cn, - dn: dataObject.dn || '', - displayName: dataObject.displayname || dataObject.cn, + dn, + displayName, status: 'current' as ItemStatus, action: '' as Action, }; + // console.log('CommonAttributes dataObj: ', dataObject); + // console.log('CommonAttributes dataObj.displayname: ', dataObject.displayname); + // console.log('CommonAttributes dataObj.displayName: ', dataObject.displayName); + // console.log('CommonAttributes dataObj.cn: ', dataObject.cn); + // console.log('CommonAttributes displayName: ', displayName); + // console.log('CommonAttributes retObj: ', retObj); + // console.log('---------'); + return retObj; } export const isDomainNameInOUs = (dn: string, dns: Array) => { diff --git a/services-js/access-boston/src/client/group-management/state/list.ts b/services-js/access-boston/src/client/group-management/state/list.ts index 90a8c61b7..6dba9dda8 100644 --- a/services-js/access-boston/src/client/group-management/state/list.ts +++ b/services-js/access-boston/src/client/group-management/state/list.ts @@ -66,10 +66,11 @@ export const reducer = (list, action: Partial) => { case 'LIST/TOGGLE_ITEM_STATUS': return list.map(item => { if (action.item && item.cn === action.item.cn) { - return { + item = { ...item, status: item.status === 'remove' ? 'current' : 'remove', }; + return item; } else { return item; } diff --git a/services-js/access-boston/src/client/group-management/state/search.ts b/services-js/access-boston/src/client/group-management/state/search.ts index 3bfe38509..489e65008 100644 --- a/services-js/access-boston/src/client/group-management/state/search.ts +++ b/services-js/access-boston/src/client/group-management/state/search.ts @@ -30,7 +30,7 @@ interface Action { mode?: string; } -export const initialState = { +export const initialSearchState = { searchResults: [], searchStatus: 'idle', searchText: '', @@ -39,7 +39,7 @@ export const initialState = { mode: '', }; -export const reducer = (state, action: Partial) => { +export const searchReducer = (state, action: Partial) => { //@ts-ignore todo // console.info(action.type); @@ -94,7 +94,7 @@ export const reducer = (state, action: Partial) => { return { ...state, searchText: '', searchResults: [] }; case 'SEARCH/RESET_STATE': - return initialState; + return initialSearchState; default: return state; diff --git a/services-js/access-boston/src/client/group-management/types.ts b/services-js/access-boston/src/client/group-management/types.ts index 63df6e96b..3771c2658 100644 --- a/services-js/access-boston/src/client/group-management/types.ts +++ b/services-js/access-boston/src/client/group-management/types.ts @@ -6,8 +6,9 @@ export type ShowLabel = true | false; export type CurrentPage = number; export type PageCount = number; export type PagedResults = Array>; +export type Loading = true | false | undefined; -export const pageSize = 100; +export const pageSize = 150; export const startPage = 0; export const currentPage = startPage; export const pageCount = 1; @@ -32,6 +33,7 @@ export interface CommonAttributes { export interface Group extends CommonAttributes { members: string[]; chunked?: any; + groupmember?: any; } export interface Person extends CommonAttributes { @@ -40,4 +42,5 @@ export interface Person extends CommonAttributes { givenName: string; sn: string; mail: string; + cOBUserAgency: string; } diff --git a/services-js/access-boston/src/lib/__snapshots__/AppsRegistry.test.ts.snap b/services-js/access-boston/src/lib/__snapshots__/AppsRegistry.test.ts.snap index 0a0c0e136..19c8fbf03 100644 --- a/services-js/access-boston/src/lib/__snapshots__/AppsRegistry.test.ts.snap +++ b/services-js/access-boston/src/lib/__snapshots__/AppsRegistry.test.ts.snap @@ -86,7 +86,7 @@ Array [ "groups": null, "iconUrl": null, "mfaDeviceRequired": false, - "target": "_blank", + "target": "", "title": "Group Management", "url": "/group-management", }, @@ -231,7 +231,7 @@ Array [ "groups": null, "iconUrl": null, "mfaDeviceRequired": false, - "target": "_blank", + "target": "", "title": "Group Management", "url": "/group-management", }, @@ -329,7 +329,7 @@ Array [ "groups": null, "iconUrl": null, "mfaDeviceRequired": false, - "target": "_blank", + "target": "", "title": "Group Management", "url": "/group-management", }, @@ -462,7 +462,7 @@ Array [ "groups": null, "iconUrl": null, "mfaDeviceRequired": false, - "target": "_blank", + "target": "", "title": "Group Management", "url": "/group-management", }, @@ -595,7 +595,7 @@ Array [ "groups": null, "iconUrl": null, "mfaDeviceRequired": false, - "target": "_blank", + "target": "", "title": "Group Management", "url": "/group-management", }, diff --git a/services-js/access-boston/src/server/access-boston.ts b/services-js/access-boston/src/server/access-boston.ts index 9b6c8913a..d264771ae 100644 --- a/services-js/access-boston/src/server/access-boston.ts +++ b/services-js/access-boston/src/server/access-boston.ts @@ -445,6 +445,8 @@ async function addVelocityTemplates(server: HapiServer) { const fetchQ = async this_req => { const query = this_req.payload.query; const variables = this_req.payload.variables; + // console.log('query: ', query); + // console.log('variables: ', variables); return await fetch( `${process.env.GROUP_MANAGEMENT_API_URL}` as string, { diff --git a/services-js/access-boston/src/server/services/SamlAuthFake.ts b/services-js/access-boston/src/server/services/SamlAuthFake.ts index 8ac08b1c1..cb8be2a3c 100644 --- a/services-js/access-boston/src/server/services/SamlAuthFake.ts +++ b/services-js/access-boston/src/server/services/SamlAuthFake.ts @@ -51,18 +51,20 @@ export default class SamlAuthFake implements Required { 'SG_AB_SERVICEDESK_USERS', 'SG_AB_BLDGMAINTREQ', 'SG_AB_CONFIRMID', - // 'SG_AB_GRPMGMT_CIVIS', - // 'SG_AB_GRPMGMT_SERVICEDESKVIEWONLY', + 'SG_AB_Proofpoint', + 'SG_AB_AGILEPOINT', + 'SG_AB_CIVIS', + // 'SG_AB_IAM_TEAM', + // 'SG_AB_IAM_VENTURES', + + 'SG_AB_GRPMGMT_HYPERION', + // 'SG_AB_GRPMGMT_Lagan_Groups', + // 'SG_AB_GRPMGMT_AUDITING', + // 'SG_AB_GRPMGMT_TANIUM', + // 'SG_AB_GRPMGMT_AGILEPOINT', + // 'SG_AB_GRPMGMT_BLDGMAINTREQ', // 'SG_AB_GRPMGMT_EBUILDER', - 'SG_AB_GRPMGMT_AUDITING', - 'SG_AB_GRPMGMT_TANIUM', - 'SG_AB_GRPMGMT_Lagan_Groups', - 'SG_AB_GRPMGMT_BLDGMAINTREQ', - // 'SG_AB_GRPMGMT_PSHCM', - // 'SG_AB_GRPMGMT_BOSTONDOTGOV', - // 'SG_AB_BOSTONDOTGOV', - 'SG_AB_IAM_TEAM', - 'SG_AB_IAM_VENTURES', + // 'SG_AB_GRPMGMT_CIVIS', ], needsNewPassword: isNewUser, needsMfaDevice: isNewUser && userId !== 'NEW88888', diff --git a/services-js/access-boston/src/stories/__snapshots__/Storyshots.test.ts.snap b/services-js/access-boston/src/stories/__snapshots__/Storyshots.test.ts.snap index 4976d5b0e..d236b20d6 100644 --- a/services-js/access-boston/src/stories/__snapshots__/Storyshots.test.ts.snap +++ b/services-js/access-boston/src/stories/__snapshots__/Storyshots.test.ts.snap @@ -5493,7 +5493,9 @@ exports[`Storyshots GroupManagementPage default 1`] = ` Group search
    - +
    @@ -5507,7 +5509,7 @@ exports[`Storyshots GroupManagementPage default 1`] = ` className="css-1f7lh8s-SearchComponent" >
    - +
    @@ -5774,7 +5778,7 @@ exports[`Storyshots GroupManagementPage/Index default 1`] = ` className="css-1f7lh8s-SearchComponent" >
    - +
    @@ -6000,7 +6006,7 @@ Array [ className="css-1f7lh8s-SearchComponent" >
    -
    - This group has no members -
    - -`; - -exports[`Storyshots GroupManagementPage/ListComponents/EditableList editable person view 1`] = ` -
      -
      - This person hasn’t been added to any groups -
      -
    -`; - -exports[`Storyshots GroupManagementPage/ListComponents/EditableList loading view 1`] = ` -
    - - - -
    -`; - -exports[`Storyshots GroupManagementPage/ListComponents/EditableList no results, group view 1`] = ` -
      -
      - This group has no members -
      -
    -`; - -exports[`Storyshots GroupManagementPage/ListComponents/EditableList no results, person view 1`] = ` -
      -
      - This person hasn’t been added to any groups -
      -
    -`; - -exports[`Storyshots GroupManagementPage/ListComponents/ListItemComponent default 1`] = ` -
  • - - -
  • -`; - -exports[`Storyshots GroupManagementPage/ListComponents/ListItemComponent newly added 1`] = ` -
  • - - -
  • -`; - -exports[`Storyshots GroupManagementPage/ListComponents/ListItemComponent no link 1`] = ` -
  • - - Bob Roberts - -
  • -`; - -exports[`Storyshots GroupManagementPage/ListComponents/ListItemComponent not modifiable 1`] = ` -
  • - - -
  • -`; - exports[`Storyshots GroupManagementPage/ListComponents/ReviewList groups added 1`] = ` Array [
    - +
    @@ -6377,7 +6220,7 @@ exports[`Storyshots GroupManagementPage/ManagementView group view 1`] = ` className="css-1f7lh8s-SearchComponent" >
    -
      -
      - This group has no members -
      -
    @@ -6575,7 +6409,9 @@ exports[`Storyshots GroupManagementPage/ManagementView loading view 1`] = ` Add a new member
    - +
    @@ -6589,7 +6425,7 @@ exports[`Storyshots GroupManagementPage/ManagementView loading view 1`] = ` className="css-1f7lh8s-SearchComponent" >
    -
    - - - -
    @@ -6797,7 +6602,9 @@ exports[`Storyshots GroupManagementPage/ManagementView person view 1`] = ` Add to a group
    - +
    @@ -6811,7 +6618,7 @@ exports[`Storyshots GroupManagementPage/ManagementView person view 1`] = ` className="css-1f7lh8s-SearchComponent" >
    -
      -
      - This person hasn’t been added to any groups -
      -
    @@ -6927,7 +6725,9 @@ exports[`Storyshots GroupManagementPage/SearchComponent group add 1`] = ` Add to a group
    - +
    @@ -6941,7 +6741,7 @@ exports[`Storyshots GroupManagementPage/SearchComponent group add 1`] = ` className="css-1f7lh8s-SearchComponent" >
    - +
    @@ -7032,7 +6834,7 @@ exports[`Storyshots GroupManagementPage/SearchComponent group search 1`] = ` className="css-1f7lh8s-SearchComponent" >
    - +
    @@ -7123,7 +6927,7 @@ exports[`Storyshots GroupManagementPage/SearchComponent no results 1`] = ` className="css-1f7lh8s-SearchComponent" >
    - +
    @@ -7214,7 +7020,7 @@ exports[`Storyshots GroupManagementPage/SearchComponent person add 1`] = ` className="css-1f7lh8s-SearchComponent" >
    - +
    @@ -7305,7 +7113,7 @@ exports[`Storyshots GroupManagementPage/SearchComponent person search 1`] = ` className="css-1f7lh8s-SearchComponent" >
    - +
    @@ -7396,7 +7206,7 @@ exports[`Storyshots GroupManagementPage/SearchComponent searching 1`] = ` className="css-1f7lh8s-SearchComponent" >
    - +
    @@ -7487,7 +7299,7 @@ exports[`Storyshots GroupManagementPage/SearchComponent server error/could not r className="css-1f7lh8s-SearchComponent" >