From 3629832db9c92abf23c40eb4b78e6fe29332ce13 Mon Sep 17 00:00:00 2001 From: Chaitali Mane <71449322+chaitali-mane@users.noreply.github.com> Date: Tue, 28 Sep 2021 11:35:05 +0530 Subject: [PATCH] Added users tab in server details page (#5802) * Added Users tab UI Signed-off-by: chaitali-mane * Added enitites api integration Signed-off-by: chaitali-mane * minor changes Signed-off-by: chaitali-mane * Updated minor change Signed-off-by: chaitali-mane --- .../app/entities/servers/server.actions.ts | 31 +++++++++- .../app/entities/servers/server.effects.ts | 24 +++++++- .../src/app/entities/servers/server.model.ts | 10 ++++ .../app/entities/servers/server.reducer.ts | 25 +++++++- .../app/entities/servers/server.requests.ts | 10 +++- .../app/entities/servers/server.selectors.ts | 10 ++++ .../chef-server-details.component.html | 59 ++++++++++++++----- .../chef-server-details.component.scss | 43 ++++++++++++++ .../chef-server-details.component.ts | 39 ++++++++++-- 9 files changed, 225 insertions(+), 26 deletions(-) diff --git a/components/automate-ui/src/app/entities/servers/server.actions.ts b/components/automate-ui/src/app/entities/servers/server.actions.ts index 1156963a7e4..4cc07d9b203 100644 --- a/components/automate-ui/src/app/entities/servers/server.actions.ts +++ b/components/automate-ui/src/app/entities/servers/server.actions.ts @@ -1,7 +1,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Action } from '@ngrx/store'; -import { Server } from './server.model'; +import { Server , User } from './server.model'; export enum ServerActionTypes { GET_ALL = 'SERVER::GET_ALL', @@ -18,7 +18,10 @@ export enum ServerActionTypes { UPDATE_FAILURE = 'SERVER::UPDATE::FAILURE', DELETE = 'SERVER::CREATE::DELETE', DELETE_SUCCESS = 'SERVER::CREATE::DELETE::SUCCESS', - DELETE_FAILURE = 'SERVER::CREATE::DELETE::FAILURE' + DELETE_FAILURE = 'SERVER::CREATE::DELETE::FAILURE', + GET_USERS = 'SERVER::GET_USERS', + GET_USERS_SUCCESS = 'SERVER::GET_USERS::SUCCESS', + GET_USERS_FAILURE = 'SERVER::GET_USERS::FAILURE' } @@ -118,6 +121,25 @@ export class UpdateServerFailure implements Action { constructor(public payload: HttpErrorResponse) { } } +export interface UsersSuccessPayload { + users: User[]; +} + +export class GetUsers implements Action { + readonly type = ServerActionTypes.GET_USERS; + constructor(public payload: {server_id: string} ) { } +} + +export class GetUsersSuccess implements Action { + readonly type = ServerActionTypes.GET_USERS_SUCCESS; + constructor(public payload: UsersSuccessPayload) { } +} + +export class GetUsersFailure implements Action { + readonly type = ServerActionTypes.GET_USERS_FAILURE; + constructor(public payload: HttpErrorResponse) { } +} + export type ServerActions = | GetServers | GetServersSuccess @@ -133,4 +155,7 @@ export type ServerActions = | UpdateServerFailure | DeleteServer | DeleteServerSuccess - | DeleteServerFailure; + | DeleteServerFailure + | GetUsers + | GetUsersSuccess + | GetUsersFailure; diff --git a/components/automate-ui/src/app/entities/servers/server.effects.ts b/components/automate-ui/src/app/entities/servers/server.effects.ts index de03a802d44..0219e15c36a 100644 --- a/components/automate-ui/src/app/entities/servers/server.effects.ts +++ b/components/automate-ui/src/app/entities/servers/server.effects.ts @@ -25,7 +25,11 @@ import { UpdateServerFailure, DeleteServer, DeleteServerSuccess, - DeleteServerFailure + DeleteServerFailure, + GetUsers, + GetUsersSuccess, + GetUsersFailure, + UsersSuccessPayload } from './server.actions'; import { @@ -166,4 +170,22 @@ export class ServerEffects { }); }))); + getUsers$ = createEffect(() => + this.actions$.pipe( + ofType(ServerActionTypes.GET_USERS), + mergeMap((action: GetUsers) => + this.requests.getUser(action.payload).pipe( + map((resp: UsersSuccessPayload) => new GetUsersSuccess(resp)), + catchError((error: HttpErrorResponse) => observableOf(new GetUsersFailure(error))))))); + + getUsersFailure$ = createEffect(() => + this.actions$.pipe( + ofType(ServerActionTypes.GET_USERS_FAILURE), + map(({ payload: {error} }: GetUsersFailure) => { + const msg = error.error; + return new CreateNotification({ + type: Type.error, + message: `Could not get users: ${msg || error}` + }); + }))); } diff --git a/components/automate-ui/src/app/entities/servers/server.model.ts b/components/automate-ui/src/app/entities/servers/server.model.ts index c711b439aae..990f3dfda53 100644 --- a/components/automate-ui/src/app/entities/servers/server.model.ts +++ b/components/automate-ui/src/app/entities/servers/server.model.ts @@ -5,3 +5,13 @@ export interface Server { ip_address: string; orgs_count?: number; } + +export interface User { + id: string; + server_id: string; + infra_server_username: string; + credential_id: string; + connector: string; + automate_user_id: string; + is_server_admin: boolean; +} diff --git a/components/automate-ui/src/app/entities/servers/server.reducer.ts b/components/automate-ui/src/app/entities/servers/server.reducer.ts index abd8b88a8a8..c25b16e5fae 100644 --- a/components/automate-ui/src/app/entities/servers/server.reducer.ts +++ b/components/automate-ui/src/app/entities/servers/server.reducer.ts @@ -3,7 +3,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import { pipe, set, unset } from 'lodash/fp'; import { EntityStatus } from 'app/entities/entities'; import { ServerActionTypes, ServerActions } from './server.actions'; -import { Server } from './server.model'; +import { Server, User } from './server.model'; export interface ServerEntityState extends EntityState { getAllStatus: EntityStatus; @@ -12,6 +12,8 @@ export interface ServerEntityState extends EntityState { getStatus: EntityStatus; updateStatus: EntityStatus; deleteStatus: EntityStatus; + getUsers: User[]; + getUsersStatus: EntityStatus; } const GET_ALL_STATUS = 'getAllStatus'; @@ -20,6 +22,7 @@ const SAVE_ERROR = 'saveError'; const UPDATE_STATUS = 'updateStatus'; const GET_STATUS = 'getStatus'; const DELETE_STATUS = 'deleteStatus'; +const GET_USERS_STATUS = 'getUsersStatus'; export const serverEntityAdapter: EntityAdapter = createEntityAdapter(); @@ -30,7 +33,9 @@ export const ServerEntityInitialState: ServerEntityState = saveError: null, updateStatus: EntityStatus.notLoaded, getStatus: EntityStatus.notLoaded, - deleteStatus: EntityStatus.notLoaded + deleteStatus: EntityStatus.notLoaded, + getUsers: null, + getUsersStatus: EntityStatus.notLoaded }); export function serverEntityReducer( @@ -119,6 +124,22 @@ export function serverEntityReducer( case ServerActionTypes.UPDATE_FAILURE: return set(UPDATE_STATUS, EntityStatus.loadingFailure, state); + case ServerActionTypes.GET_USERS: + return set( + GET_USERS_STATUS, + EntityStatus.loading, + serverEntityAdapter.removeAll(state) + ) as ServerEntityState; + + case ServerActionTypes.GET_USERS_SUCCESS: + return pipe( + set(GET_USERS_STATUS, EntityStatus.loadingSuccess), + set('getUsers', action.payload || []) + )(state) as ServerEntityState; + + case ServerActionTypes.GET_USERS_FAILURE: + return set( + GET_USERS_STATUS, EntityStatus.loadingFailure, state); } return state; diff --git a/components/automate-ui/src/app/entities/servers/server.requests.ts b/components/automate-ui/src/app/entities/servers/server.requests.ts index e0640e1a0e2..f060e890cd2 100644 --- a/components/automate-ui/src/app/entities/servers/server.requests.ts +++ b/components/automate-ui/src/app/entities/servers/server.requests.ts @@ -4,7 +4,7 @@ import { Observable } from 'rxjs'; import { mapKeys, snakeCase } from 'lodash/fp'; import { environment as env } from 'environments/environment'; -import { Server } from './server.model'; +import { Server, User } from './server.model'; import { CreateServerPayload, ServerSuccessPayload } from './server.actions'; export interface ServersResponse { @@ -15,6 +15,10 @@ export interface ServerResponse { server: Server; } +export interface UserResponse { + users: User[]; +} + @Injectable() export class ServerRequests { @@ -41,4 +45,8 @@ export class ServerRequests { public deleteServer(id: string): Observable { return this.http.delete(`${env.infra_proxy_url}/servers/${id}`); } + + public getUser(payload): Observable { + return this.http.get(`${env.infra_proxy_url}/servers/${payload.server_id}/automateinfraserverusers`); + } } diff --git a/components/automate-ui/src/app/entities/servers/server.selectors.ts b/components/automate-ui/src/app/entities/servers/server.selectors.ts index 2027fed19c5..0335aefd626 100644 --- a/components/automate-ui/src/app/entities/servers/server.selectors.ts +++ b/components/automate-ui/src/app/entities/servers/server.selectors.ts @@ -46,3 +46,13 @@ export const deleteStatus = createSelector( serverState, (state) => state.deleteStatus ); + +export const getUsers = createSelector( + serverState, + (state) => state.getUsers +); + +export const getUsersStatus = createSelector( + serverState, + (state) => state.getUsersStatus +); diff --git a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html index 72b7fc81235..0a9821acd44 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html +++ b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html @@ -9,23 +9,24 @@ {{ server?.name }} - {{ server?.name }} - - - - - - - - - - - - - -
FQDNIP Address
{{ server?.fqdn }}{{ server?.ip_address }}
+
+
+ {{ server?.name }} +
    +
  • + FQDN + {{ server?.fqdn }} +
  • +
  • + IP Address + {{ server?.ip_address }} +
  • +
+
+
Orgs + Users Details
@@ -140,6 +141,34 @@ +
+
+ + + + Chef Server User Name + Automate Name + + + + + + {{users.infra_server_username}} + {{users.automate_user_id}} + + + Fetch PEM Key + + + + + +
+
+ No preview +

No users available.

+
+
diff --git a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.scss b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.scss index b7850e7322c..95e5dc24ee4 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.scss +++ b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.scss @@ -5,6 +5,49 @@ chef-page-header { padding-bottom: 0; } +.meta-box { + border: 0.5px solid $chef-key-tab; + border-radius: 4px; + margin-bottom: 4em; + padding: 1em 0 4em; + background: $chef-white; + + .summary-body { + font-size: 14px; + padding: 0 1em; + + .meta-head { + text-transform: uppercase; + font-size: 15px; + font-weight: 600; + color: $chef-black; + } + + ul { + color: $chef-primary-dark; + list-style: none; + padding: 0; + + li { + display: flex; + margin-bottom: 5px; + + span { + font-size: 14px; + line-height: 21px; + letter-spacing: 0.2px; + + &.heading { + display: inline-block; + font-weight: bold; + width: 30%; + } + } + } + } + } +} + chef-toolbar { display: block; position: relative; diff --git a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts index a2a6aaa45f9..6a8822ece0d 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts +++ b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts @@ -13,11 +13,11 @@ import { Regex } from 'app/helpers/auth/regex'; import { LayoutFacadeService, Sidebar } from 'app/entities/layout/layout.facade'; import { pending, EntityStatus, allLoaded } from 'app/entities/entities'; import { - getStatus, serverFromRoute, updateStatus + getStatus, serverFromRoute, updateStatus, getUsers, getUsersStatus } from 'app/entities/servers/server.selectors'; import { Server } from 'app/entities/servers/server.model'; -import { GetServer, UpdateServer } from 'app/entities/servers/server.actions'; +import { GetServer, UpdateServer, GetUsers } from 'app/entities/servers/server.actions'; import { GetOrgs, CreateOrg, DeleteOrg } from 'app/entities/orgs/org.actions'; import { Org } from 'app/entities/orgs/org.model'; import { @@ -29,7 +29,7 @@ import { } from 'app/entities/orgs/org.selectors'; import { ProjectConstants } from 'app/entities/projects/project.model'; -export type ChefServerTabName = 'orgs' | 'details'; +export type ChefServerTabName = 'orgs' | 'users' | 'details'; @Component({ selector: 'app-chef-server-details', templateUrl: './chef-server-details.component.html', @@ -59,6 +59,10 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { private isDestroyed = new Subject(); public unassigned = ProjectConstants.UNASSIGNED_PROJECT_ID; public selected = 'fqdn'; + public isUserLoaded = false; + public users; + public usersListLoading; + public authFailure = false; constructor( private fb: FormBuilder, @@ -85,7 +89,17 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { .subscribe((url: string) => { this.url = url; const [, fragment] = url.split('#'); - this.tabValue = (fragment === 'details') ? 'details' : 'orgs'; + switch (fragment) { + case 'details': + this.tabValue = 'details'; + break; + case 'users': + this.tabValue = 'users'; + break; + case 'attributes': + this.tabValue = 'orgs'; + break; + } }); this.updateServerForm = this.fb.group({ @@ -113,6 +127,7 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { this.id = id; this.store.dispatch(new GetServer({ id })); this.store.dispatch(new GetOrgs({ server_id: id })); + this.store.dispatch(new GetUsers({ server_id: id })); }); combineLatest([ @@ -185,6 +200,22 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { this.ipForm.markAsPristine(); } }); + + combineLatest([ + this.store.select(getUsersStatus), + this.store.select(getUsers) + ]).pipe(takeUntil(this.isDestroyed)) + .subscribe(([getUsersSt, UsersState]) => { + if (getUsersSt === EntityStatus.loadingSuccess && !isNil(UsersState)) { + this.users = UsersState; + this.usersListLoading = false; + this.users.users.length > 0 ? this.isUserLoaded = true : this.isUserLoaded = false; + } else if (getUsersSt === EntityStatus.loadingFailure) { + this.usersListLoading = false; + this.authFailure = true; + this.isUserLoaded = false; + } + }); } ngOnDestroy(): void {