Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public class UserOutput {
@Schema(description = "Organization of the user")
private String organizationName;

@JsonProperty("user_organization_id")
@Schema(description = "Organization of the user")
private String organizationId;

@JsonProperty("user_tags")
@Schema(description = "Tags of the user")
private Set<String> tags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public static void select(CriteriaBuilder cb, CriteriaQuery<Tuple> cq, Root<User
userRoot.get("email").alias("user_email"),
userRoot.get("admin").alias("user_admin"),
organizationJoin.get("name").alias("user_organization_name"),
organizationJoin.get("id").alias("user_organization_id"),
tagIdsExpression.alias("user_tags"))
.distinct(true);

Expand All @@ -52,6 +53,7 @@ public static List<UserOutput> execution(TypedQuery<Tuple> query) {
.email(tuple.get("user_email", String.class))
.admin(tuple.get("user_admin", boolean.class))
.organizationName(tuple.get("user_organization_name", String.class))
.organizationId(tuple.get("user_organization_id", String.class))
.tags(Set.of((tuple.get("user_tags", String[].class))))
.build())
.toList();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { delReferential, getReferential, postReferential, putReferential, simplePostCall } from '../utils/Action';
import * as schema from './Schema';
import { delReferential, getReferential, postReferential, putReferential, simplePostCall } from '../../utils/Action.js';
import * as schema from '../Schema.js';

// region players
export const fetchPlayers = () => dispatch => getReferential(schema.arrayOfUsers, '/api/players')(dispatch);
Expand Down
15 changes: 15 additions & 0 deletions openaev-front/src/actions/users/users-helper.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Option } from '../../../../utils/Option';
import { type UpdateUserInput } from '../../utils/api-types';

export type UserInputForm = Omit<
UpdateUserInput,
'user_organization' | 'user_tags'
> & {
user_organization: Option | undefined;
user_tags: Option[];
};

export interface UserResult {
entities: { users: Record<string, User> };
result: string;
}
2 changes: 1 addition & 1 deletion openaev-front/src/admin/components/agents/Agents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useState } from 'react';
import { fetchExecutors } from '../../../actions/Executor';
import { type ExecutorHelper } from '../../../actions/executors/executor-helper';
import { type LoggedHelper, type MeTokensHelper } from '../../../actions/helper';
import { meTokens } from '../../../actions/User';
import { meTokens } from '../../../actions/users/User';
import Breadcrumbs from '../../../components/Breadcrumbs';
import Transition from '../../../components/common/Transition';
import { useFormatter } from '../../../components/i18n';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { type FunctionComponent, useContext, useState } from 'react';
import { makeStyles } from 'tss-react/mui';

import { type OrganizationHelper, type UserHelper } from '../../../../actions/helper';
import { fetchPlayers } from '../../../../actions/User';
import { fetchPlayers } from '../../../../actions/users/User';
import Transition from '../../../../components/common/Transition';
import { useFormatter } from '../../../../components/i18n';
import ItemTags from '../../../../components/ItemTags';
Expand Down
2 changes: 1 addition & 1 deletion openaev-front/src/admin/components/profile/Index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useTheme } from '@mui/material/styles';
import * as R from 'ramda';
import { useDispatch } from 'react-redux';

import { meTokens, renewToken, updateMeInformation, updateMePassword, updateMeProfile } from '../../../actions/User';
import { meTokens, renewToken, updateMeInformation, updateMePassword, updateMeProfile } from '../../../actions/users/User.js';
import Paper from '../../../components/common/Paper';
import { useFormatter } from '../../../components/i18n';
import { useHelper } from '../../../store';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { PersonOutlined } from '@mui/icons-material';
import { Box, Button } from '@mui/material';
import { type FunctionComponent, useEffect, useMemo, useState } from 'react';

import { findUsers, searchUsers } from '../../../../actions/User';
import { findUsers, searchUsers } from '../../../../actions/users/User';
import Drawer from '../../../../components/common/Drawer';
import PaginationComponentV2 from '../../../../components/common/queryable/pagination/PaginationComponentV2';
import { buildSearchPagination } from '../../../../components/common/queryable/QueryableUtils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { searchGroups } from '../../../../actions/Group';
import { fetchOrganizations } from '../../../../actions/Organization';
import { fetchRoles } from '../../../../actions/roles/roles-actions.js';
import { fetchScenarios } from '../../../../actions/scenarios/scenario-actions';
import { fetchUsers } from '../../../../actions/User';
import { fetchUsers } from '../../../../actions/users/User.js';
import Breadcrumbs from '../../../../components/Breadcrumbs';
import PaginationComponent from '../../../../components/common/pagination/PaginationComponent';
import SortHeadersComponent from '../../../../components/common/pagination/SortHeadersComponent';
Expand Down
101 changes: 0 additions & 101 deletions openaev-front/src/admin/components/settings/users/CreateUser.js

This file was deleted.

79 changes: 79 additions & 0 deletions openaev-front/src/admin/components/settings/users/CreateUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { useState } from 'react';

import type { OrganizationHelper } from '../../../../actions/helper';
import { addUser } from '../../../../actions/users/User';
import { type UserInputForm, type UserResult } from '../../../../actions/users/users-helper';
import ButtonCreate from '../../../../components/common/ButtonCreate';
import Drawer from '../../../../components/common/Drawer';
import { useFormatter } from '../../../../components/i18n';
import { useHelper } from '../../../../store';
import { type User } from '../../../../utils/api-types';
import { useAppDispatch } from '../../../../utils/hooks';
import { type Option } from '../../../../utils/Option';
import UserForm from './UserForm';

interface CreateUserProps { onCreate?: (user: User) => void }

const CreateUser = ({ onCreate }: CreateUserProps) => {
const { t } = useFormatter();
const dispatch = useAppDispatch();

const [open, setOpen] = useState(false);

const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);

const { organizationsMap } = useHelper(
(
helper: OrganizationHelper,
) => {
return { organizationsMap: helper.getOrganizationsMap() };
},
);
const onSubmit = (data: UserInputForm) => {
const inputValues = {
...data,
user_organization: data.user_organization?.id,
user_tags: data.user_tags?.map((tag: Option) => tag.id),
};

return dispatch(addUser(inputValues)).then((result: UserResult) => {
if (result?.entities?.users && onCreate) {
const userCreated = result.entities.users[result.result];

const orgId = userCreated.user_organization;
const org = orgId ? organizationsMap[orgId] : undefined;

const userToCreate = {
...userCreated,
user_organization_name: org ? org.organization_name : '',
user_organization_id: org ? org.organization_id : '',
};

onCreate(userToCreate);
}
return result.result ? handleClose() : result;
});
};

return (
<>
<ButtonCreate onClick={handleOpen} style={{ right: 230 }} />

<Drawer
open={open}
handleClose={handleClose}
title={t('Create a new user')}
>
<UserForm
editing={false}
onSubmit={onSubmit}
handleClose={handleClose}
initialValues={{ user_tags: [] }}
/>
</Drawer>
</>
);
};

export default CreateUser;
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
import { Button } from '@mui/material';
import * as PropTypes from 'prop-types';
import { Form } from 'react-final-form';
import { z } from 'zod';

import { type UserInputForm } from '../../../../actions/users/users-helper';
import OldSwitchField from '../../../../components/fields/OldSwitchField';
import OldTextField from '../../../../components/fields/OldTextField';
import { useFormatter } from '../../../../components/i18n';
import OrganizationField from '../../../../components/OrganizationField';
import TagField from '../../../../components/TagField';
import { schemaValidator } from '../../../../utils/Zod.js';

const UserForm = (props) => {
const { onSubmit, initialValues, editing, handleClose } = props;
interface UserFormProps {
onSubmit: (data: UserInputForm) => void;
initialValues?: Partial<UserInputForm>;
editing: boolean;
handleClose: () => void;
}

const UserForm = ({ onSubmit, initialValues = {}, editing, handleClose }: UserFormProps) => {
const { t } = useFormatter();

const requiredFields = editing
? ['user_email']
: ['user_email', 'user_plain_password'];

const phoneRegex = /^\+\d+$/;

const userFormSchemaValidation = z.object({
user_email: z
.string()
Expand All @@ -28,7 +36,25 @@ const UserForm = (props) => {
.string()
.nonempty(t('This field is required.')),
}),
user_phone: z
.string()
.nullable()
.optional()
.refine(
val => !val || phoneRegex.test(val),
t('Phone number must start with + and contain only digits'),
),

user_phone2: z
.string()
.nullable()
.optional()
.refine(
val => !val || phoneRegex.test(val),
t('Phone number must start with + and contain only digits'),
),
});

return (
<Form
keepDirtyOnReinitialize={true}
Expand Down Expand Up @@ -147,10 +173,4 @@ const UserForm = (props) => {
);
};

UserForm.propTypes = {
onSubmit: PropTypes.func.isRequired,
handleClose: PropTypes.func,
editing: PropTypes.bool,
};

export default UserForm;
Loading