From e0effe9fd43b8d7c0d7fcb9aade9b718cf5dddda Mon Sep 17 00:00:00 2001 From: Pawel Kowalczyk Date: Thu, 6 Dec 2018 18:00:04 +0100 Subject: [PATCH] creating-user-changing-is-admin-is-active-and-redirect-to-projects Feature #14504 Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk --- .../project-panel-middleware-service.ts | 18 ++++---- .../users/user-panel-middleware-service.ts | 2 +- src/store/users/users-actions.ts | 46 ++++++++++++------- src/store/workbench/workbench-actions.ts | 5 +- .../action-sets/user-action-set.ts | 4 +- .../data-explorer/renderers.tsx | 19 ++++---- .../dialog-create/dialog-user-create.tsx | 6 +-- .../form-fields/user-form-fields.tsx | 26 +++++++---- src/views/user-panel/user-panel.tsx | 2 +- 9 files changed, 79 insertions(+), 49 deletions(-) diff --git a/src/store/project-panel/project-panel-middleware-service.ts b/src/store/project-panel/project-panel-middleware-service.ts index 36672e99..257fc044 100644 --- a/src/store/project-panel/project-panel-middleware-service.ts +++ b/src/store/project-panel/project-panel-middleware-service.ts @@ -7,32 +7,32 @@ import { dataExplorerToListParams, getDataExplorerColumnFilters, listResultsToDataExplorerItemsMeta -} from '../data-explorer/data-explorer-middleware-service'; -import { ProjectPanelColumnNames, ProjectPanelFilter } from "~/views/project-panel/project-panel"; -import { RootState } from "../store"; +} from '~/store/data-explorer/data-explorer-middleware-service'; +import { ProjectPanelColumnNames } from "~/views/project-panel/project-panel"; +import { RootState } from "~/store/store"; import { DataColumns } from "~/components/data-table/data-table"; import { ServiceRepository } from "~/services/services"; import { SortDirection } from "~/components/data-table/data-column"; import { OrderBuilder, OrderDirection } from "~/services/api/order-builder"; import { FilterBuilder, joinFilters } from "~/services/api/filter-builder"; import { GroupContentsResource, GroupContentsResourcePrefix } from "~/services/groups-service/groups-service"; -import { updateFavorites } from "../favorites/favorites-actions"; -import { PROJECT_PANEL_CURRENT_UUID, IS_PROJECT_PANEL_TRASHED, projectPanelActions } from './project-panel-action'; +import { updateFavorites } from "~/store/favorites/favorites-actions"; +import { PROJECT_PANEL_CURRENT_UUID, IS_PROJECT_PANEL_TRASHED, projectPanelActions } from '~/store/project-panel/project-panel-action'; import { Dispatch, MiddlewareAPI } from "redux"; import { ProjectResource } from "~/models/project"; import { updateResources } from "~/store/resources/resources-actions"; import { getProperty } from "~/store/properties/properties"; -import { snackbarActions, SnackbarKind } from '../snackbar/snackbar-actions'; +import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions'; import { progressIndicatorActions } from '~/store/progress-indicator/progress-indicator-actions.ts'; -import { DataExplorer, getDataExplorer } from '../data-explorer/data-explorer-reducer'; +import { DataExplorer, getDataExplorer } from '~/store/data-explorer/data-explorer-reducer'; import { ListResults } from '~/services/common-service/common-resource-service'; -import { loadContainers } from '../processes/processes-actions'; +import { loadContainers } from '~/store/processes/processes-actions'; import { ResourceKind } from '~/models/resource'; import { getResource } from "~/store/resources/resources"; import { CollectionResource } from "~/models/collection"; import { resourcesDataActions } from "~/store/resources-data/resources-data-actions"; import { getSortColumn } from "~/store/data-explorer/data-explorer-reducer"; -import { serializeResourceTypeFilters } from '../resource-type-filters/resource-type-filters'; +import { serializeResourceTypeFilters } from '~/store/resource-type-filters/resource-type-filters'; export class ProjectPanelMiddlewareService extends DataExplorerMiddlewareService { constructor(private services: ServiceRepository, id: string) { diff --git a/src/store/users/user-panel-middleware-service.ts b/src/store/users/user-panel-middleware-service.ts index 590e160c..2f602093 100644 --- a/src/store/users/user-panel-middleware-service.ts +++ b/src/store/users/user-panel-middleware-service.ts @@ -44,7 +44,7 @@ export const getParams = (dataExplorer: DataExplorer) => ({ export const getFilters = (dataExplorer: DataExplorer) => { const filters = new FilterBuilder() - .addILike("firstName", dataExplorer.searchValue) + .addILike("username", dataExplorer.searchValue) .getFilters(); return filters; }; diff --git a/src/store/users/users-actions.ts b/src/store/users/users-actions.ts index ca6edd62..7494f983 100644 --- a/src/store/users/users-actions.ts +++ b/src/store/users/users-actions.ts @@ -6,20 +6,13 @@ import { Dispatch } from "redux"; import { bindDataExplorerActions } from '~/store/data-explorer/data-explorer-action'; import { RootState } from '~/store/store'; import { ServiceRepository } from "~/services/services"; -import { navigateToUsers } from "~/store/navigation/navigation-action"; -import { unionize, ofType, UnionOf } from "~/common/unionize"; import { dialogActions } from '~/store/dialog/dialog-actions'; import { startSubmit, reset, stopSubmit } from "redux-form"; import { getCommonResourceServiceError, CommonResourceServiceError } from "~/services/common-service/common-resource-service"; import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions'; import { UserResource } from "~/models/user"; import { getResource } from '~/store/resources/resources'; - -export const usersPanelActions = unionize({ - SET_USERS: ofType(), -}); - -export type UsersActions = UnionOf; +import { navigateToProject } from "~/store/navigation/navigation-action"; export const USERS_PANEL_ID = 'usersPanel'; export const USER_ATTRIBUTES_DIALOG = 'userAttributesDialog'; @@ -45,10 +38,17 @@ export const openUserCreateDialog = () => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const userUuid = await services.authService.getUuid(); const user = await services.userService.get(userUuid!); + const virtualMachines = await services.virtualMachineService.list(); dispatch(reset(USER_CREATE_FORM_NAME)); - dispatch(dialogActions.OPEN_DIALOG({ id: USER_CREATE_FORM_NAME, data: { user } })); + dispatch(dialogActions.OPEN_DIALOG({ id: USER_CREATE_FORM_NAME, data: { user, ...virtualMachines } })); + }; + +export const openUserProjects = (uuid: string) => + async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { + dispatch(navigateToProject(uuid)); }; + export const createUser = (user: UserCreateFormDialogData) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { dispatch(startSubmit(USER_CREATE_FORM_NAME)); @@ -57,7 +57,7 @@ export const createUser = (user: UserCreateFormDialogData) => dispatch(dialogActions.CLOSE_DIALOG({ id: USER_CREATE_FORM_NAME })); dispatch(reset(USER_CREATE_FORM_NAME)); dispatch(snackbarActions.OPEN_SNACKBAR({ message: "User has been successfully created.", hideDuration: 2000, kind: SnackbarKind.SUCCESS })); - dispatch(loadUsersData()); + dispatch(loadUsersPanel()); dispatch(userBindedActions.REQUEST_ITEMS()); return newUser; } catch (e) { @@ -69,17 +69,31 @@ export const createUser = (user: UserCreateFormDialogData) => } }; -export const userBindedActions = bindDataExplorerActions(USERS_PANEL_ID); +export const toggleIsActive = (uuid: string) => + async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { + const { resources } = getState(); + const data = getResource(uuid)(resources); + const isActive = data!.isActive; + const newActivity = await services.userService.update(uuid, { ...data, isActive: !isActive }); + dispatch(loadUsersPanel()); + return newActivity; + }; -export const openUsersPanel = () => - (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { - dispatch(navigateToUsers); +export const toggleIsAdmin = (uuid: string) => + async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { + const { resources } = getState(); + const data = getResource(uuid)(resources); + const isAdmin = data!.isAdmin; + const newActivity = await services.userService.update(uuid, { ...data, isAdmin: !isAdmin }); + dispatch(loadUsersPanel()); + return newActivity; }; +export const userBindedActions = bindDataExplorerActions(USERS_PANEL_ID); + export const loadUsersData = () => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { - const users = await services.userService.list(); - dispatch(usersPanelActions.SET_USERS(users.items)); + await services.userService.list(); }; export const loadUsersPanel = () => diff --git a/src/store/workbench/workbench-actions.ts b/src/store/workbench/workbench-actions.ts index 0d857d09..e7fbd146 100644 --- a/src/store/workbench/workbench-actions.ts +++ b/src/store/workbench/workbench-actions.ts @@ -130,7 +130,10 @@ export const loadProject = (uuid: string) => const userUuid = services.authService.getUuid(); dispatch(setIsProjectPanelTrashed(false)); if (userUuid) { - if (userUuid !== uuid) { + if (extractUuidKind(uuid) === ResourceKind.USER && userUuid!==uuid) { + // Load another users home projects + dispatch(finishLoadingProject(uuid)); + } else if (userUuid !== uuid) { const match = await loadGroupContentsResource({ uuid, userUuid, services }); match({ OWNED: async project => { diff --git a/src/views-components/context-menu/action-sets/user-action-set.ts b/src/views-components/context-menu/action-sets/user-action-set.ts index 68098cff..7b0884e6 100644 --- a/src/views-components/context-menu/action-sets/user-action-set.ts +++ b/src/views-components/context-menu/action-sets/user-action-set.ts @@ -5,7 +5,7 @@ import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set"; import { AdvancedIcon, ProjectIcon, AttributesIcon, UserPanelIcon } from "~/components/icon/icon"; import { openAdvancedTabDialog } from '~/store/advanced-tab/advanced-tab'; -import { openUserAttributes } from "~/store/users/users-actions"; +import { openUserAttributes, openUserProjects } from "~/store/users/users-actions"; export const userActionSet: ContextMenuActionSet = [[{ name: "Attributes", @@ -17,7 +17,7 @@ export const userActionSet: ContextMenuActionSet = [[{ name: "Project", icon: ProjectIcon, execute: (dispatch, { uuid }) => { - dispatch(openAdvancedTabDialog(uuid)); + dispatch(openUserProjects(uuid)); } }, { name: "Advanced", diff --git a/src/views-components/data-explorer/renderers.tsx b/src/views-components/data-explorer/renderers.tsx index 20b2f9ec..16ea7a99 100644 --- a/src/views-components/data-explorer/renderers.tsx +++ b/src/views-components/data-explorer/renderers.tsx @@ -22,6 +22,7 @@ import { getUuidPrefix, openRunProcess } from '~/store/workflow-panel/workflow-p import { getResourceData } from "~/store/resources-data/resources-data"; import { openSharingDialog } from '~/store/sharing-dialog/sharing-dialog-actions'; import { UserResource } from '~/models/user'; +import { toggleIsActive, toggleIsAdmin } from '~/store/users/users-actions'; const renderName = (item: { name: string; uuid: string, kind: string }) => @@ -151,29 +152,31 @@ export const ResourceEmail = connect( return resource || { email: '' }; })(renderEmail); -const renderIsActive = (item: { isActive: boolean }) => +const renderIsActive = (props: { uuid: string, isActive: boolean, toggleIsActive: (uuid: string) => void }) => ; + checked={props.isActive} + onClick={() => props.toggleIsActive(props.uuid)} />; export const ResourceIsActive = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { isActive: false }; - })(renderIsActive); + }, { toggleIsActive } +)(renderIsActive); -const renderIsAdmin = (item: { isAdmin: boolean }) => +const renderIsAdmin = (props: { uuid: string, isAdmin: boolean, toggleIsAdmin: (uuid: string) => void }) => ; + checked={props.isAdmin} + onClick={() => props.toggleIsAdmin(props.uuid)} />; export const ResourceIsAdmin = connect( (state: RootState, props: { uuid: string }) => { const resource = getResource(props.uuid)(state.resources); return resource || { isAdmin: false }; - })(renderIsAdmin); + }, { toggleIsAdmin } +)(renderIsAdmin); const renderUsername = (item: { username: string }) => {item.username}; diff --git a/src/views-components/dialog-create/dialog-user-create.tsx b/src/views-components/dialog-create/dialog-user-create.tsx index bf135e8c..80904397 100644 --- a/src/views-components/dialog-create/dialog-user-create.tsx +++ b/src/views-components/dialog-create/dialog-user-create.tsx @@ -8,7 +8,7 @@ import { WithDialogProps } from '~/store/dialog/with-dialog'; import { FormDialog } from '~/components/form-dialog/form-dialog'; import { UserFirstNameField, UserLastNameField, UserEmailField, UserIdentityUrlField, UserVirtualMachineField, UserGroupsVirtualMachineField } from '~/views-components/form-fields/user-form-fields'; -type DialogUserProps = WithDialogProps<{}> & InjectedFormProps; +export type DialogUserProps = WithDialogProps<{}> & InjectedFormProps; export const UserRepositoryCreate = (props: DialogUserProps) => {...props} />; -const UserAddFields = () => +const UserAddFields = (props: DialogUserProps) => - + ; diff --git a/src/views-components/form-fields/user-form-fields.tsx b/src/views-components/form-fields/user-form-fields.tsx index 6dd635b5..486d90f7 100644 --- a/src/views-components/form-fields/user-form-fields.tsx +++ b/src/views-components/form-fields/user-form-fields.tsx @@ -7,6 +7,8 @@ import { Field } from "redux-form"; import { TextField } from "~/components/text-field/text-field"; import { USER_EMAIL_VALIDATION, USER_LENGTH_VALIDATION } from "~/validators/validators"; import { NativeSelectField } from "~/components/select-field/select-field"; +import { InputLabel } from "@material-ui/core"; +import { VirtualMachinesResource } from "~/models/virtual-machines"; export const UserFirstNameField = () => validate={USER_LENGTH_VALIDATION} label="Identity URL Prefix" />; -export const UserVirtualMachineField = () => - ; +export const UserVirtualMachineField = ({ data }: any) => +
+ Virtual Machine + +
; export const UserGroupsVirtualMachineField = () => ; \ No newline at end of file + label="Groups for virtual machine (comma separated list)" />; + +const getVirtualMachinesList = (virtualMachines: VirtualMachinesResource[]) => { + const mappedVirtualMachines = virtualMachines.map(it => ({ key: it.hostname, value: it.hostname })); + return mappedVirtualMachines; +}; diff --git a/src/views/user-panel/user-panel.tsx b/src/views/user-panel/user-panel.tsx index db44d508..f28cca3b 100644 --- a/src/views/user-panel/user-panel.tsx +++ b/src/views/user-panel/user-panel.tsx @@ -159,7 +159,7 @@ export const UserPanel = compose( return - + {value === 0 && -- 2.30.2