Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Last revision Both sides next revision | ||
devel:documentation:identities:adm:user-type [2020/03/30 11:44] tomiskar |
devel:documentation:identities:adm:user-type [2021/03/26 07:40] tomiskar [User type] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== User type ====== | ====== User type ====== | ||
+ | |||
+ | {{tag> form projection}} | ||
User type (projection) was added in CzechIdM version 10.2.0. Projection defines frontend form to read, create and edit user. We can create and edit user by different form. For example externe and internal employee can be created and edited differently (different attributes has to be filled). Used projection for user creation is set as user type. | User type (projection) was added in CzechIdM version 10.2.0. Projection defines frontend form to read, create and edit user. We can create and edit user by different form. For example externe and internal employee can be created and edited differently (different attributes has to be filled). Used projection for user creation is set as user type. | ||
- | Provided projection can be configured by administrator. New projection type and localization can be provided by developer. | + | Provided projection can be configured by administrator. New projection type and localization can be provided by [[..: |
Configurable form (projection) with configurable features is provided in product: | Configurable form (projection) with configurable features is provided in product: | ||
* **Show user personal data** - show selected or all user personal data (e.g. login, first name, surname). | * **Show user personal data** - show selected or all user personal data (e.g. login, first name, surname). | ||
- | * **Show contract** - prime contract is shown by default. If currenly logged user has permission to read prime contract. First other contract is shown otherwise. Contract are sorted by priority the same way, as prime contract is evaluated. | + | * **Show contract** - prime contract is shown by default. If currenly logged user has permission to read prime contract. First other contract is shown otherwise. Contract are sorted by priority the same way, as prime contract is evaluated. Contracts can be shown n two modes: |
- | * **Show other contract position** - first contract other position | + | * **Show prime contract** - show (and update) prime user contract only. |
+ | * **Show all user contracts** - show (and update) all user contracts. Code list '' | ||
+ | * **Validations** for basic user personal data and basic contract attributes can be defined. | ||
+ | * **Show other contract position** - first contract other position | ||
* **Show extended identity attributes** - show selected extended attributes from selected form definitions. | * **Show extended identity attributes** - show selected extended attributes from selected form definitions. | ||
* **Show extended contract attributes** - show selected extended attributes from selected form definitions. Contract are sorted by priority. Prime contract extended attributes can be edited, if logged user can read and edit prime contract. If logged user cannot read prime contract, next contract which identity can read is shown. | * **Show extended contract attributes** - show selected extended attributes from selected form definitions. Contract are sorted by priority. Prime contract extended attributes can be edited, if logged user can read and edit prime contract. If logged user cannot read prime contract, next contract which identity can read is shown. | ||
Line 17: | Line 22: | ||
<note tip> | <note tip> | ||
- | ===== Configure and use new projection ===== | + | <note tip>Code list '' |
- | ==== Projection agenda | + | ===== Configure and use form projection ===== |
- | New projection | + | How to configure and use product form projection |
- | {{ : | + | How to register new form projection type is described |
- | + | ||
- | ==== Add new projection ==== | + | |
- | + | ||
- | We can configure new projection | + | |
- | * Code - **Externe user**. Projection simple name. | + | |
- | * Module - we can leave it empty, **core** module is used by default. | + | |
- | * Frontend target - we can leave it by default **/ | + | |
- | * Basic attributes - select | + | |
- | * Form definitions - we need to prepare extended attributes | + | |
- | * **default - IdmIdentity** - default form definition for users, select attributes: | + | |
- | * **Mobile phone** - text attribute | + | |
- | * **Reqistration** - boolean attribute | + | |
- | * **default - default - IdmIdentityContract** - default form definition for cntracts, select attributes: | + | |
- | * **Environment** - codelist ith available environments | + | |
- | * **Manager** - user select box | + | |
- | * Description - **Create and edit externe user.** Description | + | |
- | * Inactive - inactive projection will not be available for creating new user. | + | |
- | + | ||
- | {{ : | + | |
- | + | ||
- | <note tip>We filled simple projection name as projection code. Projection name will be shown without localization. Read how to add [[# | + | |
- | + | ||
- | <note tip> | + | |
- | + | ||
- | <note tip> | + | |
- | + | ||
- | ==== Choose projection ==== | + | |
- | + | ||
- | When new user is created (menu **Users** -> **Create user** button.), then newly created projection can be chosen: | + | |
- | + | ||
- | {{ :devel: | + | |
- | + | ||
- | <note tip> | + | |
- | + | ||
- | === User detail for create | + | |
- | + | ||
- | {{ : | + | |
- | + | ||
- | We can create new user with all attributes are filled. We can choose roles, which will have to be assigned (requested) for created user. Used form (projection) is set as user type. After form is saved, the same form is shown and user can be edited if needed. The same form is used and shown as user detail. | + | |
- | + | ||
- | === User detail for edit user by configuration above ==== | + | |
- | + | ||
- | {{ : | + | |
- | + | ||
- | === Default full detail === | + | |
- | + | ||
- | Default full detail can be shown for each user with projection usage. New button was added into user (and projection) detail header: | + | |
- | + | ||
- | {{ :devel: | + | |
- | + | ||
- | Button is available for all logged user without any additional permission is needed. Quick link to default full detail is available from top profile menu. Buttons on dashboard ane any other link to user detail will lead to projection form. | + | |
- | + | ||
- | The same way is posible to go back to form by projection from full default detail. Button is in the same place with different direction. | + | |
- | + | ||
- | ==== Change user type ==== | + | |
- | + | ||
- | User type (projection) can be changed from default full identity detail: | + | |
- | + | ||
- | {{ : | + | |
- | + | ||
- | After user type is changed and user is saved, then button in detail header (see above) can be used for show user in form projection. | + | |
- | + | ||
- | <note tip> | + | |
- | + | ||
- | ==== Set or change user password ==== | + | |
- | + | ||
- | If **password** attribute is added in projection personal data configuration, | + | |
- | * New password can be filled fo newly created user, | + | |
- | * link to change password is available for edited user. | + | |
- | + | ||
- | <note tip> | + | |
- | + | ||
- | <note tip> | + | |
- | + | ||
- | ==== Add or change user roles ==== | + | |
- | + | ||
- | New roles can be requested for newly added user. If user is edited, then assigned roles are shown with button to change assigned roles by role request. | + | |
- | + | ||
- | Identity roles are assigned asynchronously, | + | |
- | + | ||
- | <note tip> | + | |
===== Configuration ===== | ===== Configuration ===== | ||
Line 138: | Line 62: | ||
Manager for create and edit user with form projection usage with all features enabled. | Manager for create and edit user with form projection usage with all features enabled. | ||
+ | |||
+ | <note tip>User detail with form projection usage can be saved (save button is shown), when logged user can update selected user.</ | ||
* Permission to work with identities: Users (IdmIdentity) | View in select box (autocomplete), | * Permission to work with identities: Users (IdmIdentity) | View in select box (autocomplete), | ||
Line 145: | Line 71: | ||
* Permission to request roles (which can be requested): Role (IdmRole) | Can be requested | RoleCanBeRequestedEvaluator | * Permission to request roles (which can be requested): Role (IdmRole) | Can be requested | RoleCanBeRequestedEvaluator | ||
* Permission to read role requests according to identity: Requests for assigned roles (IdmRoleRequest) | - | RoleRequestByIdentityEvaluator | * Permission to read role requests according to identity: Requests for assigned roles (IdmRoleRequest) | - | RoleRequestByIdentityEvaluator | ||
- | * Permission to autocomplete form projections: | + | * Permission to autocomplete form projections: |
- | * Permission to autocomplete form definitions: | + | * Permission to autocomplete form definitions: |
* Permission to read and update all identity attributes in main definition: Forms - values (IdmIdentityFormValue) | View in select box (autocomplete) | IdentityFormValueEvaluator | * Permission to read and update all identity attributes in main definition: Forms - values (IdmIdentityFormValue) | View in select box (autocomplete) | IdentityFormValueEvaluator | ||
* Permission to read and update all contract attributes in main definition: Forms - values (IdmIdentityContractFormValue) | View in select box (autocomplete) | IdentityContractFormValueEvaluator | * Permission to read and update all contract attributes in main definition: Forms - values (IdmIdentityContractFormValue) | View in select box (autocomplete) | IdentityContractFormValueEvaluator | ||
+ | * Permission to read codelist '' | ||
* Enabling the autocomplete for entities: | * Enabling the autocomplete for entities: | ||
* Role (IdmRole) | Displaying in autocomplete, | * Role (IdmRole) | Displaying in autocomplete, | ||
Line 155: | Line 82: | ||
* Accounts (AccAccount) | - | ReadAccountByIdentityEvaluator (← use this only when using acc module) | * Accounts (AccAccount) | - | ReadAccountByIdentityEvaluator (← use this only when using acc module) | ||
* Identity accounts (AccIdentityAccount) | - | IdentityAccountByAccountEvaluator (← use this only when using acc module) | * Identity accounts (AccIdentityAccount) | - | IdentityAccountByAccountEvaluator (← use this only when using acc module) | ||
+ | * Code lists (IdmCodeList) | Displaying in autocomplete, | ||
+ | * Code lists - items (IdmCodeListItem) | Displaying in autocomplete, | ||
=== Manager - create and edit identity only === | === Manager - create and edit identity only === | ||
Line 171: | Line 100: | ||
==== Localization ==== | ==== Localization ==== | ||
- | TODO: move to developer guide | + | Two projections are [[..:dev: |
- | Two projections are localized | + | Localization can be added or changed |
- | <code json> | + | ==== Tips ==== |
- | ... | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | }, | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | " | + | |
- | } | + | |
- | } | + | |
- | }, | + | |
- | ... | + | |
- | </ | + | |
- | Localization can be added to newly configured projection in custom module. Projection localization is based on the same convetions as localization for [form definition]. | + | === Skip user dashboard |
- | Supported properties: | + | If we want to show user detail immediatelly |
- | * **label** - projection name. Used in select boxes and as label for button | + | |
- | * **help** - Used as title (tooltip) for button to create user with projection usage. | + | |
- | * **icon** - Used in select boxes and as icon for button to create user with projection usage (optional, '' | + | |
- | * **level** - Used as level for button to create | + | |
- | ==== Configurable form in product ==== | + | === Validations |
- | Form projection with [[#user-type|configurable features]] was added into product '' | + | Validations for basic user personal |
- | * Frontend: | + | |
- | * Form projection content is placed on path '' | + | |
- | * Route (= frontent target) '' | + | |
- | * Component '' | + | |
- | * Backend: | + | |
- | * '' | + | |
- | * **identity** - identity. | + | |
- | * **contract** - first (~ prime) contract. | + | |
- | * **otherContracts** - all other contracts. | + | |
- | * **otherPositions** - all other positions. | + | |
- | * **identityRoles** - all assigned identity roles. | + | |
- | * '' | + | |
- | * '' | + | |
- | ==== How to register new form ==== | + | ===== Admin tutorials |
+ | * [[tutorial: | ||
- | New projection can be added with the same structure in custom module. Is needed to add new content representing form projection (e.g. copy or reuse form projection from product), register new route in '' | + | ===== Devel guide ===== |
+ | * [[..:dev:user-type]] | ||
- | Projection will obtain '' | ||
- | |||
- | === Example === | ||
- | |||
- | Source codes are placed in example module. Product backend is reused and example provides new frontend form for new projection. Form saves identity username only. | ||
- | |||
- | Create new form '' | ||
- | |||
- | <code javascript> | ||
- | import React from ' | ||
- | import PropTypes from ' | ||
- | import { connect } from ' | ||
- | import Helmet from ' | ||
- | // | ||
- | import { Basic, Advanced, Utils, Managers, Content } from ' | ||
- | |||
- | const identityManager = new Managers.IdentityManager(); | ||
- | const identityProjectionManager = new Managers.IdentityProjectionManager(); | ||
- | const formProjectionManager = new Managers.FormProjectionManager(); | ||
- | |||
- | |||
- | /** | ||
- | * Example | ||
- | * | ||
- | * @author Radek Tomiška | ||
- | * @since 10.2.0 | ||
- | */ | ||
- | class ExampleIdentityProjection extends Basic.AbstractContent { | ||
- | |||
- | |||
- | constructor(props, | ||
- | super(props, | ||
- | this.state = { | ||
- | generatePassword: | ||
- | generatePasswordShowLoading: | ||
- | }; | ||
- | } | ||
- | |||
- | getContentKey() { | ||
- | return ' | ||
- | } | ||
- | |||
- | getNavigationKey() { | ||
- | return ' | ||
- | } | ||
- | |||
- | componentDidMount() { | ||
- | super.componentDidMount(); | ||
- | // | ||
- | const { entityId } = this.props.match.params; | ||
- | const { identityProjection, | ||
- | const isNew = !!Utils.Ui.getUrlParameter(location, | ||
- | // | ||
- | if (isNew) { | ||
- | let formProjectionId; | ||
- | if (identityProjection && identityProjection.identity && identityProjection.identity.formProjection) { | ||
- | formProjectionId = identityProjection.identity.formProjection; | ||
- | } else { | ||
- | formProjectionId = Utils.Ui.getUrlParameter(this.props.location, | ||
- | } | ||
- | if (!formProjectionId) { | ||
- | // form projection not found - default will be shown | ||
- | this._initProjection(entityId, | ||
- | } else { | ||
- | // fetch projection definition | ||
- | this.context.store.dispatch(formProjectionManager.autocompleteEntityIfNeeded(formProjectionId, | ||
- | if (error) { | ||
- | this.addError(error); | ||
- | } else { | ||
- | this._initProjection(entityId, | ||
- | } | ||
- | })); | ||
- | } | ||
- | } else { | ||
- | this.getLogger().debug(`[FormDetail] loading entity detail [id:${ entityId }]`); | ||
- | this.context.store.dispatch(identityProjectionManager.fetchProjection(entityId, | ||
- | if (error) { | ||
- | this.addError(error); | ||
- | } else { | ||
- | this._initProjection(entityId, | ||
- | } | ||
- | })); | ||
- | } | ||
- | } | ||
- | |||
- | _initProjection(entityId, | ||
- | // | ||
- | // prepare form friendly projection | ||
- | let _identityProjection = null; | ||
- | if (identityProjection) { | ||
- | if (!formProjection && identityProjection.identity && identityProjection.identity._embedded) { | ||
- | formProjection = identityProjection.identity._embedded.formProjection; | ||
- | } | ||
- | // | ||
- | _identityProjection = { | ||
- | ...identityProjection.identity | ||
- | }; | ||
- | } else { | ||
- | // new projection | ||
- | _identityProjection = { | ||
- | id: entityId, | ||
- | identity: { | ||
- | id: entityId, | ||
- | formProjection: | ||
- | } | ||
- | }; | ||
- | } | ||
- | // | ||
- | this.setState({ | ||
- | identityProjection: | ||
- | formProjection | ||
- | }, () => { | ||
- | if (this.refs.username) { | ||
- | this.refs.username.focus(); | ||
- | } | ||
- | }); | ||
- | } | ||
- | |||
- | save(event) { | ||
- | if (event) { | ||
- | event.preventDefault(); | ||
- | } | ||
- | if (!this.refs.form.isFormValid()) { | ||
- | return; | ||
- | } | ||
- | const { identityProjection } = this.state; | ||
- | // | ||
- | this.refs.form.processStarted(); | ||
- | const data = this.refs.form.getData(); | ||
- | // construct projection | ||
- | const _identityProjection = { | ||
- | ...identityProjection, | ||
- | id: data.id, | ||
- | identity: data | ||
- | }; | ||
- | // | ||
- | // post => save | ||
- | this.context.store.dispatch(identityProjectionManager.saveProjection(_identityProjection, | ||
- | } | ||
- | |||
- | /** | ||
- | * Just set showloading to false and set processEnded to form. | ||
- | * Call after save/create | ||
- | */ | ||
- | _afterSave(identityProjection, | ||
- | if (error) { | ||
- | this.setState({ | ||
- | validationError: | ||
- | validationDefinition: | ||
- | }, () => { | ||
- | this.addError(error); | ||
- | if (this.refs.form) { | ||
- | this.refs.form.processEnded(); | ||
- | } | ||
- | }); | ||
- | } else { | ||
- | this.addMessage({ | ||
- | message: this.i18n(' | ||
- | }); | ||
- | this.context.history.replace(identityManager.getDetailLink(identityProjection.identity)); | ||
- | if (this.refs.form) { | ||
- | this.refs.form.processEnded(); | ||
- | } | ||
- | } | ||
- | } | ||
- | |||
- | render() { | ||
- | const { | ||
- | match, | ||
- | location, | ||
- | showLoading, | ||
- | _imageUrl | ||
- | } = this.props; | ||
- | const { entityId } = match.params; | ||
- | const { | ||
- | identityProjection, | ||
- | formProjection | ||
- | } = this.state; | ||
- | const isNew = !!Utils.Ui.getUrlParameter(location, | ||
- | // | ||
- | return ( | ||
- | < | ||
- | <Helmet title={ isNew ? this.i18n(' | ||
- | < | ||
- | < | ||
- | < | ||
- | entity={ isNew ? null : identityProjection } | ||
- | back="/ | ||
- | buttons={[ | ||
- | < | ||
- | value=" | ||
- | style={{ marginRight: | ||
- | title={ this.i18n(' | ||
- | onClick={ () => this.context.history.push(`/ | ||
- | rendered={ !isNew }/> | ||
- | ]}> | ||
- | { | ||
- | _imageUrl | ||
- | ? | ||
- | <img src={ _imageUrl } alt=" | ||
- | : | ||
- | < | ||
- | icon={ formProjection ? formProjectionManager.getLocalization(formProjection, | ||
- | identity={ identityProjection }/> | ||
- | } | ||
- | { ' ' } | ||
- | { identityProjectionManager.getNiceLabel(identityProjection) } | ||
- | < | ||
- | { ' ' } | ||
- | { isNew ? this.i18n(' | ||
- | </ | ||
- | </ | ||
- | |||
- | < | ||
- | |||
- | <form onSubmit={ this.save.bind(this) }> | ||
- | |||
- | < | ||
- | < | ||
- | </ | ||
- | |||
- | < | ||
- | |||
- | < | ||
- | < | ||
- | ref=" | ||
- | data={ identityProjection } | ||
- | readOnly={ !identityProjectionManager.canSave(isNew ? null : identityProjection) } | ||
- | style={{ padding: 0 }}> | ||
- | |||
- | < | ||
- | ref=" | ||
- | label={ this.i18n(' | ||
- | max={ 255 }/> | ||
- | |||
- | </ | ||
- | </ | ||
- | < | ||
- | < | ||
- | { this.i18n(' | ||
- | </ | ||
- | < | ||
- | type=" | ||
- | level=" | ||
- | showLoading={ showLoading } | ||
- | showLoadingIcon | ||
- | showLoadingText={ this.i18n(' | ||
- | rendered={ identityProjectionManager.canSave(isNew ? null : identityProjection) }> | ||
- | { this.i18n(' | ||
- | </ | ||
- | </ | ||
- | </ | ||
- | </ | ||
- | </ | ||
- | </ | ||
- | </ | ||
- | ); | ||
- | } | ||
- | } | ||
- | |||
- | ExampleIdentityProjection.propTypes = { | ||
- | identityProjection: | ||
- | }; | ||
- | ExampleIdentityProjection.defaultProps = { | ||
- | identityProjection: | ||
- | _imageUrl: null | ||
- | }; | ||
- | |||
- | function select(state, | ||
- | const { entityId } = component.match.params; | ||
- | const profileUiKey = identityManager.resolveProfileUiKey(entityId); | ||
- | const profile = Managers.DataManager.getData(state, | ||
- | const identityProjection = identityProjectionManager.getEntity(state, | ||
- | // | ||
- | return { | ||
- | identityProjection, | ||
- | showLoading: | ||
- | _imageUrl: profile ? profile.imageUrl : null, | ||
- | passwordChangeType: | ||
- | }; | ||
- | } | ||
- | |||
- | export default connect(select)(ExampleIdentityProjection); | ||
- | </ | ||
- | |||
- | Register new route in ' | ||
- | |||
- | <code javascript> | ||
- | { | ||
- | path: ' | ||
- | component: require(' | ||
- | access: [ { type: ' | ||
- | } | ||
- | </ | ||
- | |||
- | Register new component in '' | ||
- | |||
- | <code javascript> | ||
- | { | ||
- | id: ' | ||
- | type: ' | ||
- | ownerType: ' | ||
- | route: '/ | ||
- | } | ||
- | </ | ||
- | |||
- | ==== Tips ==== | ||
- | |||
- | === Skip user dashboard | ||
- | |||
- | If we want to show user detail immediatelly (skip user dasboard or skip info card), we can hold '' | ||
- | TODO: | ||
- | * split to developer guide + admin tutorial (how to create ) |